mirror of
https://cdm-project.com/Download-Tools/udemy-downloader.git
synced 2025-04-30 02:24:25 +02:00
updates to README and some minor code changes
+ Use proper exit code of 1 on errors + Added error handling for subscription based course info extraction failure + Slightly more verbose login failure message + Updates to README to improve clarification among other things
This commit is contained in:
parent
a06ef516ad
commit
97ca2cf401
50
README.md
50
README.md
@ -13,22 +13,21 @@
|
||||
- **This tool will not work without decryption keys, and there currently no public way to get those keys. Do not bother installing unless you already have keys!**
|
||||
- This program is WIP, the code is provided as-is and I am not held resposible for any legal issues resulting from the use of this program.
|
||||
|
||||
# Support
|
||||
|
||||
if you want help using the program, join [my discord server](https://discord.gg/5B3XVb4RRX) or use [github issues](https://github.com/Puyodead1/udemy-downloader/issues)
|
||||
|
||||
# License
|
||||
|
||||
All code is licensed under the MIT license
|
||||
|
||||
# Description
|
||||
|
||||
Utility script to download Udemy courses, has support for DRM videos but requires the user to aquire the decryption key (for legal reasons).<br>
|
||||
Windows is the primary development OS, but I've made an effort to support Linux also.
|
||||
Windows is the primary development OS, but I've made an effort to support Linux also (Mac untested).
|
||||
|
||||
# Requirements
|
||||
|
||||
1. You will need to download `ffmpeg`, `aria2c`, `mp4decrypt` (from Bento4 SDK) and `yt-dlp` (`pip install yt-dlp`). Ensure they are in the system path (typing their name in cmd should invoke them).
|
||||
The following are a list of required third-party tools, you will need to ensure they are in your systems path and that typing their name in a terminal invokes them.
|
||||
|
||||
_**Note**:_ _These are seperate requirements that are not installed with the pip command! You will need to download and install these manually!_
|
||||
|
||||
- [ffmpeg](https://www.ffmpeg.org/) - This tool is available in Linux package repositories
|
||||
- [aria2/aria2c](https://github.com/aria2/aria2/) - This tool is available in Linux package repositories
|
||||
- [mp4decrypt](https://www.bento4.com/)
|
||||
- [yt-dlp](https://github.com/yt-dlp/yt-dlp/) - This tool is available in Linux package repositories, but can also be installed using pip if desired (`pip install yt-dlp`)
|
||||
|
||||
# Usage
|
||||
|
||||
@ -40,27 +39,28 @@ You will need to get a few things before you can use this program:
|
||||
- Decryption Key
|
||||
- Udemy Course URL
|
||||
- Udemy Bearer Token (aka acccess token for udemy-dl users)
|
||||
- Udemy cookies (only required for subscription plans - see [Udemy Subscription Plans](#udemy-subscription-plans))
|
||||
|
||||
### Setting up
|
||||
## Setting up
|
||||
|
||||
- rename `.env.sample` to `.env` _(you only need to do this if you plan to use the .env file to store your bearer token)_
|
||||
- rename `keyfile.example.json` to `keyfile.json`
|
||||
|
||||
### Aquire Bearer Token
|
||||
## Aquire Bearer Token
|
||||
|
||||
- Firefox: [Udemy-DL Guide](https://github.com/r0oth3x49/udemy-dl/issues/389#issuecomment-491903900)
|
||||
- Chrome: [Udemy-DL Guide](https://github.com/r0oth3x49/udemy-dl/issues/389#issuecomment-492569372)
|
||||
- If you want to use the .env file to store your Bearer Token, edit the .env and add your token.
|
||||
|
||||
### Key ID and Key
|
||||
## Key ID and Key
|
||||
|
||||
It is up to you to aquire the key and key ID. Please **DO NOT** ask me for help acquiring these, decrypting DRM protected content can be considered piracy.
|
||||
It is up to you to aquire the key and key ID. Please **DO NOT** ask me for help acquiring these, decrypting DRM protected content can be considered piracy. The tool required for this has already been discused in a GitHub issue.
|
||||
|
||||
- Enter the key and key id in the `keyfile.json`
|
||||
- 
|
||||
- 
|
||||
|
||||
### Start Downloading
|
||||
## Start Downloading
|
||||
|
||||
You can now run the program, see the examples below. The course will download to `out_dir`.
|
||||
|
||||
@ -68,6 +68,8 @@ You can now run the program, see the examples below. The course will download to
|
||||
|
||||
To download a course included in a subscription plan that you did not purchase individually, you will need to follow a few more steps to get setup.
|
||||
|
||||
_**NOTE**:_ _You do **NOT** need to follow this section if you don't have a **Udemy Pro** or **Udemy Personal** subscription plan! This section is not for individually purchased courses._
|
||||
|
||||
## Getting your cookies
|
||||
|
||||
- Go to the page of the course you want to download
|
||||
@ -82,6 +84,10 @@ To download a course included in a subscription plan that you did not purchase i
|
||||
- Paste the cookie into the file
|
||||
- save and close the file
|
||||
|
||||
You will also need to ensure the link is in the following format: `https://www.udemy.com/course/<course name>/learn/`.
|
||||
|
||||
Note the link is `/course` not `/program-taking`. It is also important that the link has `/learn`, otherwise you will see an error when trying to fetch the course information.
|
||||
|
||||
# Advanced Usage
|
||||
|
||||
```
|
||||
@ -142,6 +148,10 @@ optional arguments:
|
||||
- `python main.py -c <Course URL> --concurrent-downloads 20`
|
||||
- `python main.py -c <Course URL> -cd 20`
|
||||
|
||||
# Support
|
||||
|
||||
if you want help using the program, join my [Discord](https://discord.gg/5B3XVb4RRX) server or use [GitHub Issues](https://github.com/Puyodead1/udemy-downloader/issues)
|
||||
|
||||
# Credits
|
||||
|
||||
- https://github.com/Jayapraveen/Drm-Dash-stream-downloader - For the original code which this is based on
|
||||
@ -149,3 +159,13 @@ optional arguments:
|
||||
- https://github.com/alastairmccormack/pymp4parse - For code related to mp4 box parsing (used by pywvpssh)
|
||||
- https://github.com/lbrayner/vtt-to-srt - For code related to converting subtitles from vtt to srt format
|
||||
- https://github.com/r0oth3x49/udemy-dl - For some of the informaton related to using the udemy api
|
||||
|
||||
## License
|
||||
|
||||
All code is licensed under the MIT license
|
||||
|
||||
## and finally, donations!
|
||||
|
||||
Woo, you made it this far!
|
||||
|
||||
I spend a lot of time coding things, and almost all of them are for nothing in return. When theres a lot of use of a program I make, I try to keep it updated, fix bugs, and even implement new features! But after a while, I do run out of motivation to keep doing it. If you like my work, and can help me out even a little, it would really help me out. If you are interested, you can find all the available options [here](https://github.com/Puyodead1/#supporting-me). Even if you don't, thank you anyways!
|
||||
|
50
main.py
50
main.py
@ -92,7 +92,7 @@ class Udemy:
|
||||
})
|
||||
print("Login Success")
|
||||
else:
|
||||
print("Login Failure!")
|
||||
print("Login Failure! You are probably missing an access token!")
|
||||
sys.exit(1)
|
||||
|
||||
def _extract_supplementary_assets(self, supp_assets):
|
||||
@ -400,11 +400,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error} on {url}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
return results
|
||||
@ -418,7 +418,7 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
return resp
|
||||
|
||||
@ -437,7 +437,7 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception):
|
||||
resp = self._extract_large_course_content(url=url)
|
||||
return resp
|
||||
@ -451,7 +451,7 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
_next = data.get("next")
|
||||
while _next:
|
||||
@ -461,7 +461,7 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
_next = resp.get("next")
|
||||
results = resp.get("results")
|
||||
@ -489,11 +489,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
return results
|
||||
@ -506,11 +506,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
if results:
|
||||
@ -529,11 +529,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
return results
|
||||
@ -546,11 +546,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
return results
|
||||
@ -563,11 +563,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
if results:
|
||||
@ -586,11 +586,11 @@ class Udemy:
|
||||
except conn_error as error:
|
||||
print(f"Udemy Says: Connection error, {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
except (ValueError, Exception) as error:
|
||||
print(f"Udemy Says: {error}")
|
||||
time.sleep(0.8)
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
else:
|
||||
results = webpage.get("results", [])
|
||||
return results
|
||||
@ -619,8 +619,14 @@ class Udemy:
|
||||
if not course:
|
||||
course_html = self.session._get(url).text
|
||||
soup = BeautifulSoup(course_html, "lxml")
|
||||
data_args = soup.find(
|
||||
"div", {"class": "ud-component--course-taking--app"}).attrs["data-module-args"]
|
||||
data = soup.find(
|
||||
"div", {"class": "ud-component--course-taking--app"})
|
||||
if not data:
|
||||
print(
|
||||
"Unable to extract arguments from course page! Make sure you have a cookies.txt file!")
|
||||
self.session.terminate()
|
||||
sys.exit(1)
|
||||
data_args = data.attrs["data-module-args"]
|
||||
data_json = json.loads(data_args)
|
||||
course_id = data_json.get("courseId", None)
|
||||
portal_name = self.extract_portal_name(url)
|
||||
@ -638,7 +644,7 @@ class Udemy:
|
||||
print("Trying to logout now...", )
|
||||
self.session.terminate()
|
||||
print("Logged out successfully.", )
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class Session(object):
|
||||
|
Loading…
x
Reference in New Issue
Block a user