mirror of
https://cdm-project.com/Download-Tools/udemy-downloader.git
synced 2025-04-30 14:24:25 +02:00
Updates
+ Add ability to skip downloading lecture videos + You can now specify the Bearer token and course id as an argument to the program (see advanced usage) + Updated Advanced Usage section of readme
This commit is contained in:
parent
77e57e324d
commit
048fbe09bf
21
README.md
21
README.md
@ -46,7 +46,7 @@ You will need to get a few things before you can use this program:
|
|||||||
- locate the `Request Headers` section
|
- locate the `Request Headers` section
|
||||||
- copy the the text after `Authorization`, it should look like `Bearer xxxxxxxxxxx`
|
- copy the the text after `Authorization`, it should look like `Bearer xxxxxxxxxxx`
|
||||||
- 
|
- 
|
||||||
- enter this in the `.env` file after `UDEMY_BEARER=`
|
- enter this in the `.env` file after `UDEMY_BEARER=` (you can also pass this as an argument, see advanced usage for more information)
|
||||||
|
|
||||||
### Aquire Course ID
|
### Aquire Course ID
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ You will need to get a few things before you can use this program:
|
|||||||
- locate the request url field
|
- locate the request url field
|
||||||
- 
|
- 
|
||||||
- copy the number after `/api-2.0/courses/` as seen highlighed in the above picture
|
- copy the number after `/api-2.0/courses/` as seen highlighed in the above picture
|
||||||
- enter this in the `.env` file after `UDEMY_COURSE_ID=`
|
- enter this in the `.env` file after `UDEMY_COURSE_ID=` (you can also pass this as an argument, see advanced usage for more information)
|
||||||
|
|
||||||
### Key ID and Key
|
### Key ID and Key
|
||||||
|
|
||||||
@ -71,19 +71,27 @@ You can now run `python main.py` to start downloading. The course will download
|
|||||||
# Advanced Usage
|
# Advanced Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: main.py [-h] [-d] [-q] [-l] [--download-assets] [--download-captions]
|
usage: main.py [-h] [-d] [-b BEARER_TOKEN] [-c COURSE_ID] [-q QUALITY] [-l LANG] [--skip-lectures] [--download-assets] [--download-captions]
|
||||||
|
|
||||||
Udemy Downloader
|
Udemy Downloader
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-d, --debug Use test_data.json rather than fetch from the udemy api.
|
-d, --debug Use test_data.json rather than fetch from the udemy api.
|
||||||
-q , --quality Download specific video quality. (144, 360, 480, 720, 1080)
|
-b BEARER_TOKEN, --bearer BEARER_TOKEN
|
||||||
-l , --lang The language to download for captions (Default is en)
|
The Bearer token to use
|
||||||
|
-c COURSE_ID, --course-id COURSE_ID
|
||||||
|
The ID of the course to download
|
||||||
|
-q QUALITY, --quality QUALITY
|
||||||
|
Download specific video quality. (144, 360, 480, 720, 1080)
|
||||||
|
-l LANG, --lang LANG The language to download for captions (Default is en)
|
||||||
|
--skip-lectures If specified, lectures won't be downloaded.
|
||||||
--download-assets If specified, lecture assets will be downloaded.
|
--download-assets If specified, lecture assets will be downloaded.
|
||||||
--download-captions If specified, captions will be downloaded.
|
--download-captions If specified, captions will be downloaded.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- Passing a Bearer Token and Course ID as an argument
|
||||||
|
- `python main.py -b <Bearer Token> -c <Course ID>`
|
||||||
- Download a specific quality
|
- Download a specific quality
|
||||||
- `python main.py -q 720`
|
- `python main.py -q 720`
|
||||||
- Download assets along with lectures
|
- Download assets along with lectures
|
||||||
@ -99,6 +107,9 @@ optional arguments:
|
|||||||
- `python main.py --download-captions -l pl` - Polish Subtitles
|
- `python main.py --download-captions -l pl` - Polish Subtitles
|
||||||
- `python main.py --download-captions -l all` - Downloads all subtitles
|
- `python main.py --download-captions -l all` - Downloads all subtitles
|
||||||
- etc
|
- etc
|
||||||
|
- Skip downloading lecture videos
|
||||||
|
- `python main.py --skip-lectures --download-captions` - Downloads only captions
|
||||||
|
- `python main.py --skip-lectures --download-assets` - Downloads only assets
|
||||||
|
|
||||||
# Getting an error about "Accepting the latest terms of service"?
|
# Getting an error about "Accepting the latest terms of service"?
|
||||||
|
|
||||||
|
57
main.py
57
main.py
@ -11,13 +11,8 @@ from mpegdash.utils import (parse_attr_value, parse_child_nodes,
|
|||||||
from utils import extract_kid
|
from utils import extract_kid
|
||||||
from vtt_to_srt import convert
|
from vtt_to_srt import convert
|
||||||
|
|
||||||
load_dotenv()
|
course_id = None
|
||||||
|
header_bearer = None
|
||||||
course_id = os.getenv("UDEMY_COURSE_ID") # the course id to download
|
|
||||||
bearer_token = os.getenv(
|
|
||||||
"UDEMY_BEARER"
|
|
||||||
) # you can find this in the network tab, its a request header under Authorization/x-udemy-authorization
|
|
||||||
header_bearer = "Bearer " + bearer_token
|
|
||||||
download_dir = "%s\out_dir" % os.getcwd()
|
download_dir = "%s\out_dir" % os.getcwd()
|
||||||
working_dir = "%s\working_dir" % os.getcwd(
|
working_dir = "%s\working_dir" % os.getcwd(
|
||||||
) # set the folder to download segments for DRM videos
|
) # set the folder to download segments for DRM videos
|
||||||
@ -26,6 +21,7 @@ home_dir = os.getcwd()
|
|||||||
keyfile_path = "%s\keyfile.json" % os.getcwd()
|
keyfile_path = "%s\keyfile.json" % os.getcwd()
|
||||||
dl_assets = False
|
dl_assets = False
|
||||||
dl_captions = False
|
dl_captions = False
|
||||||
|
skip_lectures = False
|
||||||
caption_locale = "en"
|
caption_locale = "en"
|
||||||
quality = None # None will download the best possible
|
quality = None # None will download the best possible
|
||||||
valid_qualities = [144, 360, 480, 720, 1080]
|
valid_qualities = [144, 360, 480, 720, 1080]
|
||||||
@ -361,6 +357,7 @@ def process_caption(caption,
|
|||||||
def process_lecture(lecture, lecture_index, lecture_path, lecture_dir):
|
def process_lecture(lecture, lecture_index, lecture_path, lecture_dir):
|
||||||
lecture_title = lecture["title"]
|
lecture_title = lecture["title"]
|
||||||
lecture_asset = lecture["asset"]
|
lecture_asset = lecture["asset"]
|
||||||
|
if not skip_lectures:
|
||||||
if lecture_asset["media_license_token"] == None:
|
if lecture_asset["media_license_token"] == None:
|
||||||
# not encrypted
|
# not encrypted
|
||||||
media_sources = lecture_asset["media_sources"]
|
media_sources = lecture_asset["media_sources"]
|
||||||
@ -397,7 +394,8 @@ def process_lecture(lecture, lecture_index, lecture_path, lecture_dir):
|
|||||||
mpd_url = next((x["src"] for x in media_sources
|
mpd_url = next((x["src"] for x in media_sources
|
||||||
if x["type"] == "application/dash+xml"), None)
|
if x["type"] == "application/dash+xml"), None)
|
||||||
if not mpd_url:
|
if not mpd_url:
|
||||||
print("> Couldn't find dash url for lecture '%s', skipping...",
|
print(
|
||||||
|
"> Couldn't find dash url for lecture '%s', skipping...",
|
||||||
lecture_title)
|
lecture_title)
|
||||||
return
|
return
|
||||||
base_url = mpd_url.split("index.mpd")[0]
|
base_url = mpd_url.split("index.mpd")[0]
|
||||||
@ -505,13 +503,26 @@ if __name__ == "__main__":
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Use test_data.json rather than fetch from the udemy api.",
|
help="Use test_data.json rather than fetch from the udemy api.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
"--bearer",
|
||||||
|
dest="bearer_token",
|
||||||
|
type=str,
|
||||||
|
help="The Bearer token to use",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c",
|
||||||
|
"--course-id",
|
||||||
|
dest="course_id",
|
||||||
|
type=str,
|
||||||
|
help="The ID of the course to download",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-q",
|
"-q",
|
||||||
"--quality",
|
"--quality",
|
||||||
dest="quality",
|
dest="quality",
|
||||||
type=int,
|
type=int,
|
||||||
help="Download specific video quality. (144, 360, 480, 720, 1080)",
|
help="Download specific video quality. (144, 360, 480, 720, 1080)",
|
||||||
metavar="",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-l",
|
"-l",
|
||||||
@ -519,7 +530,12 @@ if __name__ == "__main__":
|
|||||||
dest="lang",
|
dest="lang",
|
||||||
type=str,
|
type=str,
|
||||||
help="The language to download for captions (Default is en)",
|
help="The language to download for captions (Default is en)",
|
||||||
metavar="",
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--skip-lectures",
|
||||||
|
dest="skip_lectures",
|
||||||
|
action="store_true",
|
||||||
|
help="If specified, lectures won't be downloaded.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--download-assets",
|
"--download-assets",
|
||||||
@ -541,6 +557,8 @@ if __name__ == "__main__":
|
|||||||
caption_locale = args.lang
|
caption_locale = args.lang
|
||||||
if args.download_captions:
|
if args.download_captions:
|
||||||
dl_captions = True
|
dl_captions = True
|
||||||
|
if args.skip_lectures:
|
||||||
|
skip_lectures = True
|
||||||
if args.quality:
|
if args.quality:
|
||||||
if not args.quality in valid_qualities:
|
if not args.quality in valid_qualities:
|
||||||
print("Invalid quality specified! %s" % quality)
|
print("Invalid quality specified! %s" % quality)
|
||||||
@ -548,6 +566,25 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
quality = args.quality
|
quality = args.quality
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
if args.bearer_token:
|
||||||
|
header_bearer = f"Bearer %s" % args.bearer_token
|
||||||
|
else:
|
||||||
|
header_bearer = f"Bearer %s" % os.getenv("UDEMY_BEARER")
|
||||||
|
if args.course_id:
|
||||||
|
course_id = args.course_id
|
||||||
|
else:
|
||||||
|
course_id = os.getenv("UDEMY_COURSE_ID")
|
||||||
|
|
||||||
|
if not course_id:
|
||||||
|
print("> Missing Course ID!")
|
||||||
|
sys.exit(1)
|
||||||
|
if not header_bearer:
|
||||||
|
print("> Missing Bearer Token!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"> Using course ID {course_id}")
|
||||||
|
|
||||||
if args.debug:
|
if args.debug:
|
||||||
# this is for development purposes so we dont need to make tons of requests when testing
|
# this is for development purposes so we dont need to make tons of requests when testing
|
||||||
# course data json is just stored and read from a file
|
# course data json is just stored and read from a file
|
||||||
|
Loading…
x
Reference in New Issue
Block a user