Skip to content
This repository has been archived by the owner on Aug 1, 2021. It is now read-only.

Commit

Permalink
updated udemy-dl, bumped version 1.1, fixed #612 (functionality to re…
Browse files Browse the repository at this point in the history
…set numbers for lectures for each chapter). added switch for session caching on demand --cache.
  • Loading branch information
r0oth3x49 committed Feb 21, 2021
1 parent f623df7 commit 1222b2d
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 38 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![GitHub release](https://img.shields.io/badge/release-v1.0-brightgreen?style=flat-square)](https://github.com/r0oth3x49/udemy-dl/releases/tag/v1.0)
[![GitHub release](https://img.shields.io/badge/release-v1.1-brightgreen?style=flat-square)](https://github.com/r0oth3x49/udemy-dl/releases/tag/v1.0)
[![GitHub stars](https://img.shields.io/github/stars/r0oth3x49/udemy-dl.svg?style=flat-square)](https://github.com/r0oth3x49/udemy-dl/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/r0oth3x49/udemy-dl.svg?style=flat-square)](https://github.com/r0oth3x49/udemy-dl/network)
[![GitHub issues](https://img.shields.io/github/issues/r0oth3x49/udemy-dl.svg?style=flat-square)](https://github.com/r0oth3x49/udemy-dl/issues)
Expand All @@ -7,7 +7,7 @@
# udemy-dl
**A cross-platform python based utility to download courses from udemy for personal offline use.**

[![udemy-dl-v1-0.png](https://i.postimg.cc/4y0fH3Hq/udemy-dl-v1-0.png)](https://postimg.cc/Fkj52NZV)
[![udemy-dl-v1-1.png](https://i.postimg.cc/X7QpzY8q/udemy-dl-v1-1.png)](https://postimg.cc/zVHzL54Y)


### ***Important Note***:
Expand Down Expand Up @@ -48,6 +48,8 @@
- Support multiple courses download from file.
- Supports organization and individual udemy users both.
- Added support to download hls based streams if available.
- Added functionality to reset lecture number to start from 1.
- Added switch for session caching on demand. (option: `--cache`)
- Convert WebVTT to SRT but donot delete WebVTT. (option: `--keep-vtt`)
- Skip fetching HLS streams, This will make the fetching fast. (option: `--skip-hls`)
- List down course contents and video resolution, suggest the best resolution (option: `--info`).
Expand Down Expand Up @@ -155,7 +157,7 @@ You can download the latest version of udemy-dl by cloning the GitHub repository
<pre><code>
Author: Nasir khan (<a href="http://r0oth3x49.herokuapp.com/">r0ot h3x49</a>)

usage: udemy-dl.py [-h] [-v] [-u] [-p] [-k] [-o] [-q] [-c] [-l] [-s] [--chapter-start] [--chapter-end] [--lecture-start] [--lecture-end] [--info]
usage: udemy-dl.py [-h] [-v] [-u] [-p] [-k] [-o] [-q] [-c] [-l] [-s] [--chapter-start] [--chapter-end] [--lecture-start] [--lecture-end] [--info] [--cache]
[--keep-vtt] [--sub-only] [--skip-sub] [--skip-hls] [--assets-only] [--skip-assets]
course

Expand Down Expand Up @@ -186,6 +188,7 @@ Advance:

Others:
--info List all lectures with available resolution.
--cache Cache your session to avoid providing again.
--keep-vtt Keep WebVTT caption(s).
--sub-only Download captions/subtitle only.
--skip-sub Download course but skip captions/subtitle.
Expand Down
41 changes: 31 additions & 10 deletions udemy-dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ def course_download(
def main():
"""main function"""
sys.stdout.write(banner())
version = "%(prog)s {version}".format(version="1.0")
version = "%(prog)s {version}".format(version=udemy.__version__)
description = "A cross-platform python based utility to download courses from udemy for personal offline use."
parser = argparse.ArgumentParser(
description=description, conflict_handler="resolve"
Expand Down Expand Up @@ -502,6 +502,12 @@ def main():
action="store_true",
help="List all lectures with available resolution.",
)
other.add_argument(
"--cache",
dest="cache_session",
action="store_true",
help="Cache your session to avoid providing again.",
)
other.add_argument(
"--keep-vtt",
dest="keep_vtt",
Expand Down Expand Up @@ -546,11 +552,19 @@ def main():
cookies = "\n".join([line for line in (l.strip() for l in f_in) if line])
args.cookies = cookies
if not args.username and not args.password and not args.cookies:
# check if we already have a session..
configs = load_configs()
if not configs:
# if not ask user for user/pass or access token (cookie)
args.username = getpass.getuser(prompt="Username : ")
args.password = getpass.getpass(prompt="Password : ")
print("\n")
if args.username and args.password:
print("\n")
if not args.username and not args.password:
print("")
args.cookies = getpass.get_access_token(prompt="Access Token : ")
if args.cookies:
print("\n")
if configs:
cookies = configs.get("cookies")
if not cookies:
Expand All @@ -562,21 +576,28 @@ def main():
args.output = args.output if args.output else configs.get("output")
args.language = args.language if args.language else configs.get("language")
url_or_courses = extract_url_or_courses(args.course)
if not args.username and not args.password and not args.cookies:
print("\n")
logger.error(
msg=f"You should either provide fresh access token or username/password for udemy.."
)
sys.exit(0)
udemy_obj = Udemy(
url_or_courses=url_or_courses,
username=args.username,
password=args.password,
cookies=args.cookies,
)
# setting the caching default so that we can avoid future login attemps.
_ = to_configs(
username=args.username,
password=args.password,
cookies=args.cookies,
quality=args.quality,
output=args.output,
language=args.language,
)
if args.cache_session:
_ = to_configs(
username=args.username,
password=args.password,
cookies=args.cookies,
quality=args.quality,
output=args.output,
language=args.language,
)
dl_assets = dl_lecture = dl_subtitles = True
if args.assets_only:
dl_lecture = False
Expand Down
16 changes: 8 additions & 8 deletions udemy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
"""
Author : Nasir Khan (r0ot h3x49)
Github : https://github.com/r0oth3x49
Author : Nasir Khan (r0ot h3x49)
Github : https://github.com/r0oth3x49
License : MIT
Expand All @@ -22,11 +22,11 @@
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''
"""

__version__ = "1.0"
__author__ = "Nasir Khan (r0ot h3x49)"
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2018 Nasir Khan (r0ot h3x49)'
__version__ = "1.1"
__author__ = "Nasir Khan (r0ot h3x49)"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2018 Nasir Khan (r0ot h3x49)"

from udemy.udemy import course, fetch_enrolled_courses
10 changes: 5 additions & 5 deletions udemy/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ def authenticate(self, access_token="", client_id=""):

if access_token:
# dump cookies to configs
_ = to_configs(
username=self.username,
password=self.password,
cookies=f"access_token={access_token}",
)
# _ = to_configs(
# username=self.username,
# password=self.password,
# cookies=f"access_token={access_token}",
# )
self._session._set_auth_headers( # pylint: disable=W
access_token=access_token, client_id=client_id
)
Expand Down
5 changes: 3 additions & 2 deletions udemy/colorized/banner.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@
'''

from .colors import *
from udemy import __version__

def banner():
banner = '''
banner = f'''
%s%s __ ____
%s%s __ ______/ /__ ____ ___ __ __ ____/ / /
%s%s / / / / __ / _ \/ __ `__ \/ / / /_____/ __ / /
%s%s / /_/ / /_/ / __/ / / / / / /_/ /_____/ /_/ / /
%s%s \__,_/\__,_/\___/_/ /_/ /_/\__, / \__,_/_/
%s%s /____/
%s%sVersion : %s%s1.0
%s%sVersion : %s%s{__version__}
%s%sAuthor : %s%sNasir Khan (r0ot h3x49)
%s%sGithub : %s%shttps://github.com/r0oth3x49
Expand Down
10 changes: 5 additions & 5 deletions udemy/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@
LOGOUT_URL = "https://www.udemy.com/user/logout"

WISHLIST_URL = "https://{portal_name}.udemy.com/api-2.0/users/me/wishlisted-courses?fields[course]=id,url,published_title&ordering=-access_time&page=1&page_size=1000"
COLLECTION_URL = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses-collections/?collection_has_courses=True&course_limit=20&fields[course]=last_accessed_time,published_title&fields[user_has_subscribed_courses_collection]=@all&page=1&page_size=1000"
MY_COURSES_URL = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses?fields[course]=id,url,published_title&ordering=-last_accessed,-access_time&page=1&page_size=10000"
COURSE_SEARCH = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses?fields[course]=id,url,published_title&page=1&page_size=1000&ordering=-last_accessed,-access_time&search={course_name}"
COLLECTION_URL = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses-collections/?collection_has_courses=True&course_limit=20&fields[course]=last_accessed_time,title,published_title&fields[user_has_subscribed_courses_collection]=@all&page=1&page_size=1000"
MY_COURSES_URL = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses?fields[course]=id,url,title,published_title&ordering=-last_accessed,-access_time&page=1&page_size=10000"
COURSE_SEARCH = "https://{portal_name}.udemy.com/api-2.0/users/me/subscribed-courses?fields[course]=id,url,title,published_title&page=1&page_size=1000&ordering=-last_accessed,-access_time&search={course_name}"
COURSE_URL = "https://{portal_name}.udemy.com/api-2.0/courses/{course_id}/cached-subscriber-curriculum-items?fields[asset]=results,title,external_url,time_estimation,download_urls,slide_urls,filename,asset_type,captions,stream_urls,body&fields[chapter]=object_index,title,sort_order&fields[lecture]=id,title,object_index,asset,supplementary_assets,view_html&page_size=10000"
SUBSCRIBED_COURSES = "https://www.udemy.com/api-2.0/users/me/subscribed-courses/?ordering=-last_accessed&fields[course]=id,url&page=1&page_size=12"
SUBSCRIBED_COURSES = "https://www.udemy.com/api-2.0/users/me/subscribed-courses/?ordering=-last_accessed&fields[course]=id,title,url&page=1&page_size=12"
HEADERS = {
"Origin": "www.udemy.com",
"User-Agent": "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0",
"User-Agent": "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0",
# "Referer": "https://www.udemy.com/join/login-popup/",
"Accept": "*/*",
# "Accept-Language": "en-US,en;q=0.5",
Expand Down
16 changes: 11 additions & 5 deletions udemy/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ def _real_extract(self, url="", skip_hls_stream=False):
course_id, course_info = self._extract_course_info(url)

if course_info and isinstance(course_info, dict):
title = self._clean(course_info.get("title"))
course_title = course_info.get("published_title")
portal_name = course_info.get("portal_name")

Expand Down Expand Up @@ -648,19 +649,21 @@ def _real_extract(self, url="", skip_hls_stream=False):

_udemy["access_token"] = self._access_token
_udemy["course_id"] = course_id
_udemy["title"] = title
_udemy["course_title"] = course_title
_udemy["chapters"] = []

counter = -1

if course:
lecture_counter = 0
for entry in course:

clazz = entry.get("_class")
asset = entry.get("asset")
supp_assets = entry.get("supplementary_assets")

if clazz == "chapter":
lecture_counter = 0
lectures = []
chapter_index = entry.get("object_index")
chapter_title = "{0:02d} ".format(chapter_index) + self._clean(
Expand All @@ -677,7 +680,7 @@ def _real_extract(self, url="", skip_hls_stream=False):
)
counter += 1
elif clazz == "lecture":

lecture_counter += 1
lecture_id = entry.get("id")
if len(_udemy["chapters"]) == 0:
lectures = []
Expand Down Expand Up @@ -732,9 +735,9 @@ def _real_extract(self, url="", skip_hls_stream=False):

logger.progress(msg="Downloading course information .. ")
lecture_index = entry.get("object_index")
lecture_title = "{0:03d} ".format(lecture_index) + self._clean(
entry.get("title")
)
lecture_title = "{0:03d} ".format(
lecture_counter
) + self._clean(entry.get("title"))
data = asset.get("stream_urls")
if data and isinstance(data, dict):
sources = data.get("Video")
Expand All @@ -748,6 +751,7 @@ def _real_extract(self, url="", skip_hls_stream=False):
subtitle_count = len(subtitles)
lectures.append(
{
"index": lecture_counter,
"lecture_index": lecture_index,
"lectures_id": lecture_id,
"lecture_title": lecture_title,
Expand All @@ -763,6 +767,7 @@ def _real_extract(self, url="", skip_hls_stream=False):
else:
lectures.append(
{
"index": lecture_counter,
"lecture_index": lecture_index,
"lectures_id": lecture_id,
"lecture_title": lecture_title,
Expand All @@ -786,6 +791,7 @@ def _real_extract(self, url="", skip_hls_stream=False):
entry.get("title")
)
if chapter_title not in _udemy["chapters"]:
lecture_counter = 0
_udemy["chapters"].append(
{
"chapter_title": chapter_title,
Expand Down

0 comments on commit 1222b2d

Please sign in to comment.