Skip to content

Commit

Permalink
Merge pull request #117 from bigmadkev/headers-for-corporate-account
Browse files Browse the repository at this point in the history
Headers for corporate account
  • Loading branch information
knowbee authored Mar 14, 2024
2 parents c5cbace + 6dfce6b commit 6626959
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 6 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ local.*
*.egg-info
build
dist
*.txt
*.txt
*.srt
*.zip
venv
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
- [Common questions](#common)
- [How do I find the course slug?](#course-slug)
- [Cookie-based authentication](#setup-cookie-based)
- [Header-based authentication](#setup-header-based)
- [Examples](#examples)
- [Accessing llvd documentation](#llvd-doc)
- [Using cookie-based authentication](#use-cookie-based)
- [Using header-based authentication](#use-header-based)
- [Download a course at a specific resolution](#specific-res)
- [Download a course with subtitles](#with-sub)
- [Download a course path with throttling between 30 to 120 seconds](#course-path)
Expand Down Expand Up @@ -105,6 +107,25 @@ li_at=xxxxx
JSESSIONID="ajax:xxxxxx"
```

<a name="setup-header-based"/>

## How do I setup header-based corporate account access?

If you have a corporate connected account you can fix the download issue by using a `headers.txt` as per below.

1. Create a file named `headers.txt` and place it in the folder you want to download your courses to
2. Right click on the page and select view source
- You can also reach here by using the keyboard combination: `ctrl`+`U`.
3. Search for `enterpriseProfileHash` using `ctrl`+`F`
4. `enterpriseProfileHash&quot;:&quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&quot;,&quot;` copy the code between the double `&quot;`
<img src="https://raw.githubusercontent.com/bigmadkev/knowbee-hosting/master/assets/llvd_FindCodeInSourceCode.png" width="auto" height="auto"/>
5. Open the `headers.txt` file and paste in the values of `x-li-identity` from the above.

```sh
x-li-identity=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
```

<a name="examples"/>

# Examples
Expand All @@ -124,6 +145,15 @@ $ llvd --help
$ llvd -c "course-slug" --cookies
```

<a name="use-headers-based"/>

## Using header-based authentication
Has to use cookies in conjection with headers

```cli
$ llvd -c "course-slug" --cookies --headers
```

<a name="specific-res"/>

## Download a course at a specific resolution
Expand Down
2 changes: 2 additions & 0 deletions cookies.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
JSESSIONID="ajax:813767358989e02053245"
li_at=
2 changes: 2 additions & 0 deletions headers.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x-li-identity=
User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
2 changes: 1 addition & 1 deletion llvd/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- encoding: utf-8 -*-
"""Linkedin Learning Video Downloader."""
__version__ = "3.0.6"
__version__ = "3.0.7"
4 changes: 3 additions & 1 deletion llvd/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def login(self, session, login_data):
)
)

def run(self, cookies=None):
def run(self, cookies=None, headers={}):
"""
Main function, tries to login the user and when it succeeds, tries to download the course
"""
Expand All @@ -76,6 +76,8 @@ def run(self, cookies=None):
if cookies is not None:
self.cookies["JSESSIONID"] = cookies.get("JSESSIONID")
self.cookies["li_at"] = cookies.get("li_at")

self.headers=headers
self.headers["Csrf-Token"] = cookies.get("JSESSIONID")

# remove empty files
Expand Down
16 changes: 13 additions & 3 deletions llvd/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import click
import sys
from llvd import config
from llvd.process_io import parse_cookie_file
from llvd.process_io import parse_cookie_file, parse_header_file
from llvd.utils import clean_dir


Expand All @@ -21,6 +21,11 @@
is_flag=True,
help="Authenticate with cookies by following the guidelines provided in the documentation",
)
@click.option(
"--headers",
is_flag=True,
help="Change request headers",
)
@click.option(
"--resolution",
"-r",
Expand All @@ -40,7 +45,7 @@
"-t",
help="A min,max wait in seconds before downloading next video. Example: -t 30,120",
)
def main(cookies, course, resolution, caption, exercise, path, throttle):
def main(cookies, headers, course, resolution, caption, exercise, path, throttle):
"""
Linkedin learning video downloader cli tool
example: llvd --course "java-8-essential"
Expand Down Expand Up @@ -93,7 +98,12 @@ def main(cookies, course, resolution, caption, exercise, path, throttle):
click.echo(click.style(f"Using cookie info from cookies.txt", fg="green"))

app = App(email, password, course_slug, resolution, caption, exercise, throttle)
app.run(cookie_dict)
if headers:
header_dict = parse_header_file()
app.run(cookie_dict, header_dict)
else:
app.run(cookie_dict)

else:
if email == "":
email = click.prompt("Please enter your Linkedin email address")
Expand Down
15 changes: 15 additions & 0 deletions llvd/process_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,18 @@ def parse_cookie_file():
click.echo(
click.style(f"cookies.txt not found or is empty", fg="red"))
sys.exit(0)

def parse_header_file(path = "headers.txt"):
headers = {}
try:
with open(path, "r", encoding="utf8") as cookies_file:
lines = cookies_file.readlines()
for line in lines:
parts = line.split("=",1)
key, value = parts + [None]*(2-len(parts))
headers[key] = value.replace("\"", "").strip()
return headers
except FileNotFoundError:
click.echo(
click.style(f"{path} not found or is empty", fg="red"))
sys.exit(0)

0 comments on commit 6626959

Please sign in to comment.