| 
					
				 | 
			
			
				@@ -3181,54 +3181,94 @@ class YoutubeSearchIE(SearchInfoExtractor, YoutubeSearchBaseInfoExtractor): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _MAX_RESULTS = float('inf') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IE_NAME = 'youtube:search' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _SEARCH_KEY = 'ytsearch' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    _EXTRA_QUERY_ARGS = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    _SEARCH_PARAMS = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _TESTS = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def _get_n_results(self, query, n): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        """Get a specified number of results for a query""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        videos = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        limit = n 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        url_query = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'search_query': query.encode('utf-8'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _entries(self, query, n): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        data = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'context': { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                'client': { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'clientName': 'WEB', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'clientVersion': '2.20201021.03.00', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'query': query, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        url_query.update(self._EXTRA_QUERY_ARGS) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        result_url = 'https://www.youtube.com/results?' + compat_urllib_parse_urlencode(url_query) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for pagenum in itertools.count(1): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data = self._download_json( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                result_url, video_id='query "%s"' % query, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                note='Downloading page %s' % pagenum, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                errnote='Unable to download API page', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                query={'spf': 'navigate'}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            html_content = data[1]['body']['content'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if 'class="search-message' in html_content: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                raise ExtractorError( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    '[youtube] No video results', expected=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            new_videos = list(self._process_page(html_content)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            videos += new_videos 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if not new_videos or len(videos) > limit: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self._SEARCH_PARAMS: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data['params'] = self._SEARCH_PARAMS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        total = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for page_num in itertools.count(1): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            search = self._download_json( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                'https://www.youtube.com/youtubei/v1/search?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                video_id='query "%s"' % query, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                note='Downloading page %s' % page_num, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                errnote='Unable to download API page', fatal=False, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                data=json.dumps(data).encode('utf8'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                headers={'content-type': 'application/json'}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not search: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            next_link = self._html_search_regex( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                r'href="(/results\?[^"]*\bsp=[^"]+)"[^>]*>\s*<span[^>]+class="[^"]*\byt-uix-button-content\b[^"]*"[^>]*>Next', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                html_content, 'next link', default=None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if next_link is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            slr_contents = try_get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                search, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (lambda x: x['contents']['twoColumnSearchResultsRenderer']['primaryContents']['sectionListRenderer']['contents'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 lambda x: x['onResponseReceivedCommands'][0]['appendContinuationItemsAction']['continuationItems']), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not slr_contents: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            result_url = compat_urlparse.urljoin('https://www.youtube.com/', next_link) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            isr_contents = try_get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                slr_contents, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lambda x: x[0]['itemSectionRenderer']['contents'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not isr_contents: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for content in isr_contents: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if not isinstance(content, dict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                video = content.get('videoRenderer') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if not isinstance(video, dict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                video_id = video.get('videoId') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if not video_id: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                title = try_get(video, lambda x: x['title']['runs'][0]['text'], compat_str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                description = try_get(video, lambda x: x['descriptionSnippet']['runs'][0]['text'], compat_str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                duration = parse_duration(try_get(video, lambda x: x['lengthText']['simpleText'], compat_str)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                view_count_text = try_get(video, lambda x: x['viewCountText']['simpleText'], compat_str) or '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                view_count = int_or_none(self._search_regex( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    r'^(\d+)', re.sub(r'\s', '', view_count_text), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'view count', default=None)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                uploader = try_get(video, lambda x: x['ownerText']['runs'][0]['text'], compat_str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                total += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                yield { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    '_type': 'url_transparent', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'ie_key': YoutubeIE.ie_key(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'id': video_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'url': video_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'title': title, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'description': description, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'duration': duration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'view_count': view_count, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'uploader': uploader, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if total == n: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            token = try_get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                slr_contents, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lambda x: x[1]['continuationItemRenderer']['continuationEndpoint']['continuationCommand']['token'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                compat_str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not token: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data['continuation'] = token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if len(videos) > n: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            videos = videos[:n] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return self.playlist_result(videos, query) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _get_n_results(self, query, n): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Get a specified number of results for a query""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self.playlist_result(self._entries(query, n), query) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class YoutubeSearchDateIE(YoutubeSearchIE): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IE_NAME = YoutubeSearchIE.IE_NAME + ':date' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _SEARCH_KEY = 'ytsearchdate' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IE_DESC = 'YouTube.com searches, newest videos first' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    _EXTRA_QUERY_ARGS = {'search_sort': 'video_date_uploaded'} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    _SEARCH_PARAMS = 'CAI%3D' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class YoutubeSearchURLIE(YoutubeSearchBaseInfoExtractor): 
			 |