+ _YT_DEFAULT_YTCFGS = {
+ 'WEB': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'WEB',
+ 'INNERTUBE_CLIENT_VERSION': '2.20210622.10.00',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'WEB',
+ 'clientVersion': '2.20210622.10.00',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 1
+ },
+ 'WEB_AGEGATE': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'WEB',
+ 'INNERTUBE_CLIENT_VERSION': '2.20210622.10.00',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'WEB',
+ 'clientVersion': '2.20210622.10.00',
+ 'clientScreen': 'EMBED',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 1
+ },
+ 'WEB_REMIX': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'WEB_REMIX',
+ 'INNERTUBE_CLIENT_VERSION': '1.20210621.00.00',
+ 'INNERTUBE_API_KEY': 'AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'WEB_REMIX',
+ 'clientVersion': '1.20210621.00.00',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 67
+ },
+ 'WEB_EMBEDDED_PLAYER': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'WEB_EMBEDDED_PLAYER',
+ 'INNERTUBE_CLIENT_VERSION': '1.20210620.0.1',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'WEB_EMBEDDED_PLAYER',
+ 'clientVersion': '1.20210620.0.1',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 56
+ },
+ 'ANDROID': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'ANDROID',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'ANDROID',
+ 'clientVersion': '16.20',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 3
+ },
+ 'ANDROID_AGEGATE': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'ANDROID',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'ANDROID',
+ 'clientVersion': '16.20',
+ 'clientScreen': 'EMBED',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 3
+ },
+ 'ANDROID_EMBEDDED_PLAYER': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'ANDROID_EMBEDDED_PLAYER',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'ANDROID_EMBEDDED_PLAYER',
+ 'clientVersion': '16.20',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 55
+ },
+ 'ANDROID_MUSIC': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'ANDROID_MUSIC',
+ 'INNERTUBE_CLIENT_VERSION': '4.32',
+ 'INNERTUBE_API_KEY': 'AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'ANDROID_MUSIC',
+ 'clientVersion': '4.32',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 21
+ },
+ 'IOS': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'IOS',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'IOS',
+ 'clientVersion': '16.20',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 5
+ },
+ 'IOS_AGEGATE': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'IOS',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'IOS',
+ 'clientVersion': '16.20',
+ 'clientScreen': 'EMBED',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 5
+ },
+ 'IOS_MUSIC': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'IOS_MUSIC',
+ 'INNERTUBE_CLIENT_VERSION': '4.32',
+ 'INNERTUBE_API_KEY': 'AIzaSyDK3iBpDP9nHVTk2qL73FLJICfOC3c51Og',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'IOS_MUSIC',
+ 'clientVersion': '4.32',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 26
+ },
+ 'IOS_MESSAGES_EXTENSION': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'IOS_MESSAGES_EXTENSION',
+ 'INNERTUBE_CLIENT_VERSION': '16.20',
+ 'INNERTUBE_API_KEY': 'AIzaSyDCU8hByM-4DrUqRUYnGn-3llEO78bcxq8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'IOS_MESSAGES_EXTENSION',
+ 'clientVersion': '16.20',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 66
+ },
+ 'MWEB': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'MWEB',
+ 'INNERTUBE_CLIENT_VERSION': '2.20210721.07.00',
+ 'INNERTUBE_API_KEY': 'AIzaSyDCU8hByM-4DrUqRUYnGn-3llEO78bcxq8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'MWEB',
+ 'clientVersion': '2.20210721.07.00',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 2
+ },
+ 'MWEB_AGEGATE': {
+ 'INNERTUBE_API_VERSION': 'v1',
+ 'INNERTUBE_CLIENT_NAME': 'MWEB',
+ 'INNERTUBE_CLIENT_VERSION': '2.20210721.07.00',
+ 'INNERTUBE_API_KEY': 'AIzaSyDCU8hByM-4DrUqRUYnGn-3llEO78bcxq8',
+ 'INNERTUBE_CONTEXT': {
+ 'client': {
+ 'clientName': 'MWEB',
+ 'clientVersion': '2.20210721.07.00',
+ 'clientScreen': 'EMBED',
+ 'hl': 'en',
+ }
+ },
+ 'INNERTUBE_CONTEXT_CLIENT_NAME': 2
+ },
+ }
+
+ _YT_DEFAULT_INNERTUBE_HOSTS = {
+ 'DIRECT': 'youtubei.googleapis.com',
+ 'WEB': 'www.youtube.com',
+ 'WEB_REMIX': 'music.youtube.com',
+ 'ANDROID_MUSIC': 'music.youtube.com'
+ }
+
+ # clients starting with _ cannot be explicity requested by the user
+ _YT_CLIENTS = {
+ 'android': 'ANDROID',
+ 'android_music': 'ANDROID_MUSIC',
+ 'android_embedded': 'ANDROID_EMBEDDED_PLAYER',
+ 'android_agegate': 'ANDROID_AGEGATE',
+ 'ios': 'IOS',
+ 'ios_music': 'IOS_MUSIC',
+ 'ios_embedded': 'IOS_MESSAGES_EXTENSION',
+ 'ios_agegate': 'IOS_AGEGATE',
+ 'web': 'WEB',
+ 'web_music': 'WEB_REMIX',
+ 'web_embedded': 'WEB_EMBEDDED_PLAYER',
+ 'web_agegate': 'WEB_AGEGATE',
+ 'mweb': 'MWEB',
+ 'mweb_agegate': 'MWEB_AGEGATE',
+ }
+
+ def _get_default_ytcfg(self, client='WEB'):
+ if client in self._YT_DEFAULT_YTCFGS:
+ return copy.deepcopy(self._YT_DEFAULT_YTCFGS[client])
+ self.write_debug(f'INNERTUBE default client {client} does not exist - falling back to WEB client.')
+ return copy.deepcopy(self._YT_DEFAULT_YTCFGS['WEB'])
+
+ def _get_innertube_host(self, client='WEB'):
+ return dict_get(self._YT_DEFAULT_INNERTUBE_HOSTS, (client, 'WEB'))
+
+ def _ytcfg_get_safe(self, ytcfg, getter, expected_type=None, default_client='WEB'):
+ # try_get but with fallback to default ytcfg client values when present
+ _func = lambda y: try_get(y, getter, expected_type)
+ return _func(ytcfg) or _func(self._get_default_ytcfg(default_client))
+
+ def _extract_client_name(self, ytcfg, default_client='WEB'):
+ return self._ytcfg_get_safe(ytcfg, lambda x: x['INNERTUBE_CLIENT_NAME'], compat_str, default_client)
+
+ @staticmethod
+ def _extract_session_index(*data):
+ for ytcfg in data:
+ session_index = int_or_none(try_get(ytcfg, lambda x: x['SESSION_INDEX']))
+ if session_index is not None:
+ return session_index
+
+ def _extract_client_version(self, ytcfg, default_client='WEB'):
+ return self._ytcfg_get_safe(ytcfg, lambda x: x['INNERTUBE_CLIENT_VERSION'], compat_str, default_client)
+
+ def _extract_api_key(self, ytcfg=None, default_client='WEB'):
+ return self._ytcfg_get_safe(ytcfg, lambda x: x['INNERTUBE_API_KEY'], compat_str, default_client)
+
+ def _extract_context(self, ytcfg=None, default_client='WEB'):
+ _get_context = lambda y: try_get(y, lambda x: x['INNERTUBE_CONTEXT'], dict)
+ context = _get_context(ytcfg)
+ if context:
+ return context
+
+ context = _get_context(self._get_default_ytcfg(default_client))
+ if not ytcfg:
+ return context
+
+ # Recreate the client context (required)
+ context['client'].update({
+ 'clientVersion': self._extract_client_version(ytcfg, default_client),
+ 'clientName': self._extract_client_name(ytcfg, default_client),
+ })
+ visitor_data = try_get(ytcfg, lambda x: x['VISITOR_DATA'], compat_str)
+ if visitor_data:
+ context['client']['visitorData'] = visitor_data
+ return context
+
+ def _generate_sapisidhash_header(self, origin='https://www.youtube.com'):