diff options
| author | Astounds <kirito@disroot.org> | 2026-05-03 12:32:55 -0500 |
|---|---|---|
| committer | Astounds <kirito@disroot.org> | 2026-05-03 12:32:55 -0500 |
| commit | 8d66143c90c4b86e8ec8dfed67753bef2abf2114 (patch) | |
| tree | f7d73591c228cf52c7a4abd15c855d7d06e80ff8 /youtube/util.py | |
| parent | 50ad959a8051fec95f26b573f9fe067bdf3fdf6a (diff) | |
| download | yt-local-8d66143c90c4b86e8ec8dfed67753bef2abf2114.tar.lz yt-local-8d66143c90c4b86e8ec8dfed67753bef2abf2114.tar.xz yt-local-8d66143c90c4b86e8ec8dfed67753bef2abf2114.zip | |
fix: update innertube clients and fix HLS/DASH quality switching
- Update innertube client versions to match yt-dlp (android 21.02.35,
ios 21.02.3, web 2.20260114.08.00, android_vr 1.65.10)
- Remove obsolete clients (android-test-suite, ios_vr)
- Replace tv_embedded with TVHTML5_SIMPLY (cn 75)
- Add new clients: web_embedded, mweb, tv
- Fix HLS freeze on quality switch: use nextLevel instead of
currentLevel, handle bufferStalledError, stream proxy segments
instead of buffering in memory
- Populate DASH quality selector with actual sources (no Auto)
- Render quality-select empty in template, let JS populate per mode
Diffstat (limited to 'youtube/util.py')
| -rw-r--r-- | youtube/util.py | 183 |
1 files changed, 12 insertions, 171 deletions
diff --git a/youtube/util.py b/youtube/util.py index 7901a89..007ec07 100644 --- a/youtube/util.py +++ b/youtube/util.py @@ -23,6 +23,9 @@ import stem import stem.control import traceback +from youtube.yt_data_extract.common import concat_or_none +from youtube import constants + logger = logging.getLogger(__name__) # The trouble with the requests library: It ships its own certificate bundle via certifi @@ -468,11 +471,11 @@ def head(url, use_tor=False, report_text=None, max_redirects=10): print(f'{report_text} Latency: {round(time.monotonic() - start_time, 3)}') return response -mobile_user_agent = 'Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36' -mobile_ua = (('User-Agent', mobile_user_agent),) -desktop_user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0' -desktop_ua = (('User-Agent', desktop_user_agent),) -json_header = (('Content-Type', 'application/json'),) +mobile_user_agent = constants.MOBILE_USER_AGENT +mobile_ua = constants.mobile_ua +desktop_user_agent = constants.desktop_user_agent +desktop_ua = constants.desktop_ua +json_header = constants.json_header desktop_xhr_headers = ( ('Accept', '*/*'), ('Accept-Language', 'en-US,en;q=0.5'), @@ -641,7 +644,7 @@ def update_query_string(query_string, items): return urllib.parse.urlencode(parameters, doseq=True) -YOUTUBE_DOMAINS = ('youtube.com', 'youtu.be', 'youtube-nocookie.com') +YOUTUBE_DOMAINS = constants.YOUTUBE_DOMAINS YOUTUBE_URL_RE_STR = r'https?://(?:[a-zA-Z0-9_-]*\.)?(?:' YOUTUBE_URL_RE_STR += r'|'.join(map(re.escape, YOUTUBE_DOMAINS)) YOUTUBE_URL_RE_STR += r')(?:/[^"]*)?' @@ -668,16 +671,6 @@ def left_remove(string, substring): return string -def concat_or_none(*strings): - '''Concatenates strings. Returns None if any of the arguments are None''' - result = '' - for string in strings: - if string is None: - return None - result += string - return result - - def prefix_urls(item): if settings.proxy_images: try: @@ -726,24 +719,8 @@ def check_gevent_exceptions(*tasks): # https://stackoverflow.com/a/62888 -replacement_map = collections.OrderedDict([ - ('<', '_'), - ('>', '_'), - (': ', ' - '), - (':', '-'), - ('"', "'"), - ('/', '_'), - ('\\', '_'), - ('|', '-'), - ('?', ''), - ('*', '_'), - ('\t', ' '), -]) - -DOS_names = {'con', 'prn', 'aux', 'nul', 'com0', 'com1', 'com2', 'com3', - 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt0', - 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', - 'lpt8', 'lpt9'} +replacement_map = constants.REPLACEMENT_MAP +DOS_names = constants.DOS_RESERVED_NAMES def to_valid_filename(name): @@ -785,143 +762,7 @@ def to_valid_filename(name): return name -# https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py#L72 -INNERTUBE_CLIENTS = { - 'android': { - 'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w', - 'INNERTUBE_CONTEXT': { - 'client': { - 'hl': 'en', - 'gl': 'US', - 'clientName': 'ANDROID', - 'clientVersion': '19.09.36', - 'osName': 'Android', - 'osVersion': '12', - 'androidSdkVersion': 31, - 'platform': 'MOBILE', - 'userAgent': 'com.google.android.youtube/19.09.36 (Linux; U; Android 12; US) gzip' - }, - # https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287 - #'thirdParty': { - # 'embedUrl': 'https://google.com', # Can be any valid URL - #} - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 3, - 'REQUIRE_JS_PLAYER': False, - }, - - 'android-test-suite': { - 'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w', - 'INNERTUBE_CONTEXT': { - 'client': { - 'hl': 'en', - 'gl': 'US', - 'clientName': 'ANDROID_TESTSUITE', - 'clientVersion': '1.9', - 'osName': 'Android', - 'osVersion': '12', - 'androidSdkVersion': 31, - 'platform': 'MOBILE', - 'userAgent': 'com.google.android.youtube/1.9 (Linux; U; Android 12; US) gzip' - }, - # https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287 - #'thirdParty': { - # 'embedUrl': 'https://google.com', # Can be any valid URL - #} - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 3, - 'REQUIRE_JS_PLAYER': False, - }, - - 'ios': { - 'INNERTUBE_API_KEY': 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc', - 'INNERTUBE_CONTEXT': { - 'client': { - 'hl': 'en', - 'gl': 'US', - 'clientName': 'IOS', - 'clientVersion': '21.03.2', - 'deviceMake': 'Apple', - 'deviceModel': 'iPhone16,2', - 'osName': 'iPhone', - 'osVersion': '18.7.2.22H124', - 'userAgent': 'com.google.ios.youtube/21.03.2 (iPhone16,2; U; CPU iOS 18_7_2 like Mac OS X)' - } - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 5, - 'REQUIRE_JS_PLAYER': False - }, - - # This client can access age restricted videos (unless the uploader has disabled the 'allow embedding' option) - # See: https://github.com/zerodytrash/YouTube-Internal-Clients - 'tv_embedded': { - 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8', - 'INNERTUBE_CONTEXT': { - 'client': { - 'hl': 'en', - 'gl': 'US', - 'clientName': 'TVHTML5_SIMPLY_EMBEDDED_PLAYER', - 'clientVersion': '2.0', - 'clientScreen': 'EMBED', - }, - # https://github.com/yt-dlp/yt-dlp/pull/575#issuecomment-887739287 - 'thirdParty': { - 'embedUrl': 'https://google.com', # Can be any valid URL - } - - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 85, - 'REQUIRE_JS_PLAYER': True, - }, - - 'web': { - 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8', - 'INNERTUBE_CONTEXT': { - 'client': { - 'clientName': 'WEB', - 'clientVersion': '2.20220801.00.00', - 'userAgent': desktop_user_agent, - } - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 1 - }, - 'android_vr': { - 'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w', - 'INNERTUBE_CONTEXT': { - 'client': { - 'clientName': 'ANDROID_VR', - 'clientVersion': '1.60.19', - 'deviceMake': 'Oculus', - 'deviceModel': 'Quest 3', - 'androidSdkVersion': 32, - 'userAgent': 'com.google.android.apps.youtube.vr.oculus/1.60.19 (Linux; U; Android 12L; eureka-user Build/SQ3A.220605.009.A1) gzip', - 'osName': 'Android', - 'osVersion': '12L', - }, - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 28, - 'REQUIRE_JS_PLAYER': False, - }, - - 'ios_vr': { - 'INNERTUBE_API_KEY': 'AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w', - 'INNERTUBE_CONTEXT': { - 'client': { - 'hl': 'en', - 'gl': 'US', - 'clientName': 'IOS_VR', - 'clientVersion': '1.0', - 'deviceMake': 'Apple', - 'deviceModel': 'iPhone16,2', - 'osName': 'iPhone', - 'osVersion': '18.7.2.22H124', - 'userAgent': 'com.google.ios.youtube/1.0 (iPhone16,2; U; CPU iOS 18_7_2 like Mac OS X)' - } - }, - 'INNERTUBE_CONTEXT_CLIENT_NAME': 5, - 'REQUIRE_JS_PLAYER': False - }, -} +INNERTUBE_CLIENTS = constants.INNERTUBE_CLIENTS def get_visitor_data(): visitor_data = None |
