mobenta commited on
Commit
0ef74be
·
verified ·
1 Parent(s): 4146723

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -107
app.py CHANGED
@@ -1,18 +1,7 @@
1
- import subprocess
2
- import sys
3
-
4
- # Ensure compatible versions of httpx and httpcore are installed
5
- subprocess.check_call([sys.executable, "-m", "pip", "install", "httpx==0.18.2", "httpcore==0.13.6"])
6
-
7
  import gradio as gr
8
  import requests
9
  import os
10
  import re
11
- import yt_dlp
12
- import logging
13
-
14
- # Configure logging for debugging purposes
15
- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
16
 
17
  # Fetch the keys from the environment variable and convert them into a list
18
  YOUTUBE_API_KEYS = os.getenv("YOUTUBE_API_KEYS")
@@ -32,46 +21,8 @@ def get_api_key():
32
  key_index = (key_index + 1) % len(YOUTUBE_API_KEYS) # Rotate to the next key
33
  return api_key
34
 
35
- # Function to search YouTube videos using yt-dlp for better reliability
36
- def youtube_search(query, max_results=50):
37
- ydl_opts = {
38
- 'quiet': False, # Set to False to get more detailed output from yt-dlp
39
- 'extract_flat': 'in_playlist',
40
- 'logger': logging.getLogger(), # Use the logging module to capture yt-dlp logs
41
- 'simulate': True,
42
- 'noplaylist': True, # To avoid playlist entries
43
- }
44
- search_url = f"ytsearch{max_results}:{query}"
45
-
46
- logging.debug(f"Starting YouTube search for query: {query}")
47
-
48
- try:
49
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
50
- result = ydl.extract_info(search_url, download=False)
51
- gallery_items = []
52
-
53
- if 'entries' in result:
54
- logging.debug(f"Number of entries found: {len(result['entries'])}")
55
- for entry in result['entries']:
56
- video_id = entry.get('id')
57
- thumbnail_url = entry.get('thumbnail') if entry.get('thumbnail') else "https://via.placeholder.com/150"
58
- video_title = entry.get('title', "Unknown Title")
59
-
60
- if video_id:
61
- gallery_items.append((thumbnail_url, video_id, video_title))
62
- logging.debug(f"Added video: ID={video_id}, Thumbnail={thumbnail_url}, Title={video_title}")
63
- else:
64
- logging.debug(f"Missing video ID for entry: {entry}")
65
- else:
66
- logging.warning("No entries found in search result.")
67
- return gallery_items, ""
68
- except Exception as e:
69
- error_message = f"Error during YouTube yt-dlp request: {e}"
70
- logging.error(error_message)
71
- return [], error_message
72
-
73
  # Function to search YouTube videos using the API with pagination to get up to 1,000 results
74
- def youtube_api_search(query, max_results=1000):
75
  search_url = "https://www.googleapis.com/youtube/v3/search"
76
  all_results = []
77
  params = {
@@ -88,12 +39,19 @@ def youtube_api_search(query, max_results=1000):
88
 
89
  # If we get a bad response, try the next API key
90
  if response.status_code == 403 or response.status_code == 429:
91
- logging.debug(f"Quota exceeded or forbidden for API key. Trying next key...")
92
  continue
93
  response.raise_for_status() # Raise an error for other bad responses (4xx or 5xx)
94
 
95
  results = response.json().get("items", [])
96
- all_results.extend(results)
 
 
 
 
 
 
 
97
 
98
  # If there is no nextPageToken, we've reached the end
99
  if 'nextPageToken' not in response.json() or len(all_results) >= max_results:
@@ -102,20 +60,11 @@ def youtube_api_search(query, max_results=1000):
102
  # Update params with the nextPageToken to get the next batch of results
103
  params['pageToken'] = response.json()['nextPageToken']
104
 
105
- # Create a list of tuples with thumbnail URL, video ID, and video title
106
- gallery_items = [
107
- (
108
- result["snippet"].get("thumbnails", {}).get("medium", {}).get("url", "https://via.placeholder.com/150"),
109
- result["id"]["videoId"],
110
- result["snippet"].get("title", "No title available")
111
- ) for result in all_results
112
- ]
113
-
114
- return gallery_items
115
 
116
  except requests.exceptions.RequestException as e:
117
  # Print the error message to help debug issues
118
- logging.error(f"Error during YouTube API request: {e}")
119
  return [], f"Error retrieving video results: {str(e)}"
120
 
121
  # Function to display the video using the video URL
@@ -123,27 +72,24 @@ def show_video(video_url):
123
  # Regular expression to extract the YouTube video ID from the URL
124
  video_id = None
125
  patterns = [
126
- r"youtube\.com/watch\?v=([^&?\/]+)",
127
- r"youtube\.com/embed/([^&?\/]+)",
128
- r"youtube\.com/v/([^&?\/]+)",
129
- r"youtu\.be/([^&?\/]+)"
130
  ]
131
 
132
  for pattern in patterns:
133
  match = re.search(pattern, video_url)
134
  if match:
135
  video_id = match.group(1)
136
- logging.debug(f"Extracted video ID: {video_id}")
137
  break
138
 
139
  # If no video ID is found, return an error message
140
  if not video_id:
141
- logging.error("Invalid YouTube URL. Please enter a valid YouTube video link.")
142
  return "Invalid YouTube URL. Please enter a valid YouTube video link."
143
 
144
  # Create the embed URL
145
  embed_url = f"https://www.youtube.com/embed/{video_id}"
146
- logging.debug(f"Embed URL generated: {embed_url}")
147
 
148
  # Return an iframe with the video
149
  html_code = f'''
@@ -161,54 +107,51 @@ with gr.Blocks() as demo:
161
  with gr.Column(scale=3):
162
  search_query_input = gr.Textbox(label="Search YouTube", placeholder="Enter your search query here")
163
  search_button = gr.Button("Search")
164
- search_output = gr.Gallery(label="Search Results", columns=5, height="1500px")
165
- error_output = gr.Textbox(label="Error Message", interactive=False, visible=False)
166
-
167
  with gr.Column(scale=2):
168
- selected_video_link = gr.Textbox(label="Selected Video Link", interactive=False)
169
  play_video_button = gr.Button("Play Video")
170
  video_output = gr.HTML(label="Video Player")
171
 
172
  # Define search button behavior
173
  def update_search_results(query):
174
- gallery_items, error_message = youtube_search(query)
175
- if not gallery_items: # If yt-dlp search fails or returns empty, fall back to YouTube API
176
- gallery_items = youtube_api_search(query)
177
- if error_message:
178
- return [], error_message, gr.update(visible=True)
179
- # Display videos with thumbnails, video IDs, and titles
180
- gallery_items_display = [
181
- (
182
- item[0],
183
- f"""
184
- <div style='display: flex; align-items: center;'>
185
- <img src='{item[0]}' style='width: 150px; height: auto; margin-right: 10px;'>
186
- <div style='flex-grow: 1;'>
187
- <strong>{item[2]}</strong><br>
188
- Video ID: {item[1]}
189
  </div>
190
- </div>
191
- """
192
- ) for item in gallery_items
193
- ]
194
- return gallery_items_display, "", gr.update(visible=False)
195
-
196
- # Update the selected video link field when a video is clicked in the gallery
197
- def on_video_select(evt: gr.SelectData):
198
- # Extract the video ID from the event value, which is a dictionary containing details of the selected item
199
- selected_video_id = evt.value["caption"].split('(')[-1][:-1] # Extract video ID from caption
200
- video_url = f"https://www.youtube.com/watch?v={selected_video_id}"
201
- logging.debug(f"Video selected: {video_url}")
202
- return video_url
203
-
204
  # Play the video when the Play Video button is clicked
205
  def play_video(video_url):
206
- logging.debug(f"Playing video with URL: {video_url}")
207
  return show_video(video_url)
208
 
209
- search_button.click(update_search_results, inputs=search_query_input, outputs=[search_output, error_output, error_output])
210
- search_output.select(on_video_select, inputs=None, outputs=selected_video_link)
211
  play_video_button.click(play_video, inputs=selected_video_link, outputs=video_output)
212
 
213
  # Launch the Gradio interface
214
- demo.launch()
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import requests
3
  import os
4
  import re
 
 
 
 
 
5
 
6
  # Fetch the keys from the environment variable and convert them into a list
7
  YOUTUBE_API_KEYS = os.getenv("YOUTUBE_API_KEYS")
 
21
  key_index = (key_index + 1) % len(YOUTUBE_API_KEYS) # Rotate to the next key
22
  return api_key
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  # Function to search YouTube videos using the API with pagination to get up to 1,000 results
25
+ def youtube_search(query, max_results=50):
26
  search_url = "https://www.googleapis.com/youtube/v3/search"
27
  all_results = []
28
  params = {
 
39
 
40
  # If we get a bad response, try the next API key
41
  if response.status_code == 403 or response.status_code == 429:
42
+ print(f"Quota exceeded or forbidden for API key. Trying next key...")
43
  continue
44
  response.raise_for_status() # Raise an error for other bad responses (4xx or 5xx)
45
 
46
  results = response.json().get("items", [])
47
+ for result in results:
48
+ video_info = {
49
+ 'thumbnail_url': result["snippet"]["thumbnails"]["medium"]["url"],
50
+ 'video_id': result["id"]["videoId"],
51
+ 'title': result["snippet"]["title"],
52
+ 'description': result["snippet"]["description"]
53
+ }
54
+ all_results.append(video_info)
55
 
56
  # If there is no nextPageToken, we've reached the end
57
  if 'nextPageToken' not in response.json() or len(all_results) >= max_results:
 
60
  # Update params with the nextPageToken to get the next batch of results
61
  params['pageToken'] = response.json()['nextPageToken']
62
 
63
+ return all_results
 
 
 
 
 
 
 
 
 
64
 
65
  except requests.exceptions.RequestException as e:
66
  # Print the error message to help debug issues
67
+ print(f"Error during YouTube API request: {e}")
68
  return [], f"Error retrieving video results: {str(e)}"
69
 
70
  # Function to display the video using the video URL
 
72
  # Regular expression to extract the YouTube video ID from the URL
73
  video_id = None
74
  patterns = [
75
+ r"youtube\.com/watch\?v=([^\&\?\/]+)",
76
+ r"youtube\.com/embed/([^\&\?\/]+)",
77
+ r"youtube\.com/v/([^\&\?\/]+)",
78
+ r"youtu\.be/([^\&\?\/]+)"
79
  ]
80
 
81
  for pattern in patterns:
82
  match = re.search(pattern, video_url)
83
  if match:
84
  video_id = match.group(1)
 
85
  break
86
 
87
  # If no video ID is found, return an error message
88
  if not video_id:
 
89
  return "Invalid YouTube URL. Please enter a valid YouTube video link."
90
 
91
  # Create the embed URL
92
  embed_url = f"https://www.youtube.com/embed/{video_id}"
 
93
 
94
  # Return an iframe with the video
95
  html_code = f'''
 
107
  with gr.Column(scale=3):
108
  search_query_input = gr.Textbox(label="Search YouTube", placeholder="Enter your search query here")
109
  search_button = gr.Button("Search")
110
+ search_output = gr.HTML(label="Search Results")
111
+
 
112
  with gr.Column(scale=2):
113
+ selected_video_link = gr.Textbox(label="Selected Video Link", interactive=False, elem_id='selected_video_link')
114
  play_video_button = gr.Button("Play Video")
115
  video_output = gr.HTML(label="Video Player")
116
 
117
  # Define search button behavior
118
  def update_search_results(query):
119
+ search_results = youtube_search(query)
120
+ html_code = '<div>'
121
+ for item in search_results:
122
+ video_id = item['video_id']
123
+ thumbnail_url = item['thumbnail_url']
124
+ title = item['title']
125
+ description = item['description']
126
+ # Create an HTML snippet for this item
127
+ html_code += f'''
128
+ <div class="search-item" style="display:flex; align-items:center; margin-bottom:10px; cursor:pointer;" onclick="selectVideo('{video_id}')">
129
+ <img src="{thumbnail_url}" alt="{title}" style="width:160px; height:auto; margin-right:10px;">
130
+ <div>
131
+ <h4>{title}</h4>
132
+ <p>{description}</p>
133
+ </div>
134
  </div>
135
+ '''
136
+ html_code += '''
137
+ <script>
138
+ function selectVideo(video_id) {
139
+ const gradioApp = document.getElementsByTagName('gradio-app')[0].shadowRoot || document;
140
+ const textbox = gradioApp.querySelector('#selected_video_link textarea');
141
+ textbox.value = 'https://www.youtube.com/watch?v=' + video_id;
142
+ textbox.dispatchEvent(new Event('input', { bubbles: true }));
143
+ }
144
+ </script>
145
+ '''
146
+ html_code += '</div>'
147
+ return html_code
148
+
149
  # Play the video when the Play Video button is clicked
150
  def play_video(video_url):
 
151
  return show_video(video_url)
152
 
153
+ search_button.click(update_search_results, inputs=search_query_input, outputs=search_output)
 
154
  play_video_button.click(play_video, inputs=selected_video_link, outputs=video_output)
155
 
156
  # Launch the Gradio interface
157
+ demo.launch()