lexicalspace commited on
Commit
01d7fc7
Β·
verified Β·
1 Parent(s): 5aab74f

Rename stop to app.py

Browse files
Files changed (1) hide show
  1. stop β†’ app.py +133 -46
stop β†’ app.py RENAMED
@@ -2,14 +2,18 @@ import yt_dlp
2
  import os
3
  import gradio as gr
4
  import random
 
5
  import threading
 
 
6
  import requests
7
  from gradio_client import Client
8
  from huggingface_hub import InferenceClient
9
 
10
  # =====================================================
11
- # CONFIG & CLIENTS
12
  # =====================================================
 
13
  PROXY_SPACE_URL = "lexicalspace/Proxy-Server"
14
  OUTPUT_DIR = "downloads"
15
  os.makedirs(OUTPUT_DIR, exist_ok=True)
@@ -17,18 +21,26 @@ os.makedirs(OUTPUT_DIR, exist_ok=True)
17
  MAX_CONCURRENCY = 6
18
  MAX_QUEUE = 20
19
 
20
- # SEO Tool Configuration
21
- REPO_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
22
- seo_client = InferenceClient(model=REPO_ID)
 
 
 
 
 
 
 
 
23
 
24
  # =====================================================
25
- # GLOBAL STATE
26
  # =====================================================
27
  active_jobs = {}
28
  job_lock = threading.Lock()
29
 
30
  # =====================================================
31
- # DOWNLOADER HELPERS & LOGIC
32
  # =====================================================
33
  def get_proxy_batch():
34
  try:
@@ -78,111 +90,186 @@ def build_format_selector(quality_mode):
78
  return {}
79
 
80
  def fetch_metadata(url):
81
- if not url:
82
- return None, "⚠️ Please enter a URL first.", None, None, None
83
  api_url = f"https://noembed.com/embed?url={url}"
84
  try:
85
  response = requests.get(api_url, timeout=10)
86
  data = response.json()
87
- if "error" in data:
88
- return None, f"❌ API Error: {data.get('error')}", gr.update(interactive=False), None, None
89
  title = data.get('title', 'Unknown Title')
90
  uploader = data.get('author_name', 'Unknown Channel')
91
  thumb = data.get('thumbnail_url', None)
92
- desc = f"### 🎬 {title}\n**πŸ‘€ Channel:** {uploader}\n**⏱️ Duration:** N/A\n**πŸ‘οΈ Views:** N/A"
93
  safe_title = "".join([c for c in title if c.isalnum() or c in " ._-"])
94
  return thumb, desc, gr.update(interactive=True), gr.update(value=safe_title), "βœ… Metadata fetched"
95
  except Exception as e:
96
  return None, f"❌ Error: {str(e)}", gr.update(interactive=False), None, None
97
 
98
  def run_downloader(engine_name, url, quality, start_time, end_time, custom_name, cookies, progress):
99
- log = [f"πŸš€ Engine: {engine_name}"]
100
  with job_lock:
101
  if active_jobs.get(url) == "running": return None, "β›” Already running", "Blocked"
102
  active_jobs[url] = "running"
103
 
104
  format_opts = build_format_selector(quality)
105
  filename_tmpl = f"{custom_name}.%(ext)s" if custom_name else '%(title)s.%(ext)s'
 
106
  proxies = get_proxy_batch() if "V1" in engine_name else ([get_best_proxy()] if get_best_proxy() else [None])
107
- strategies = ["android", "ios", "web"]
108
 
109
  s_sec, e_sec = parse_time(start_time), parse_time(end_time)
110
  download_ranges = (lambda info, ydl: [{'start_time': s_sec or 0, 'end_time': e_sec or float('inf')}]) if (s_sec or e_sec) else None
111
 
112
- success, final_file = False, None
 
 
 
 
113
  for proxy in proxies:
114
  if success: break
115
  for strat in strategies:
 
116
  ydl_opts = {
117
- 'outtmpl': os.path.join(OUTPUT_DIR, filename_tmpl),
118
- 'noplaylist': True, 'quiet': True, 'force_ipv4': True,
119
  'extractor_args': {'youtube': {'player_client': [strat]}}, **format_opts
120
  }
121
  if proxy: ydl_opts['proxy'] = proxy
122
  if download_ranges: ydl_opts['download_ranges'] = download_ranges
 
 
 
 
 
 
 
 
123
  try:
124
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
125
  info = ydl.extract_info(url, download=True)
126
  name = ydl.prepare_filename(info)
127
  base, _ = os.path.splitext(name)
128
  final_file = f"{base}.{format_opts.get('ext', 'mp4')}"
129
- if os.path.exists(final_file): success = True; break
 
 
 
130
  except: continue
131
 
 
132
  with job_lock: active_jobs.pop(url, None)
133
  return (final_file, "βœ… Complete", "\n".join(log)) if success else (None, "❌ Failed", "\n".join(log))
134
 
 
 
 
 
 
135
  # =====================================================
136
- # SEO TOOL LOGIC
137
  # =====================================================
138
  def generate_seo(code_snippet, file_type):
139
- if not code_snippet.strip(): return "Please paste some code first."
140
- prompt = f"Expert SEO analysis for {file_type} code:\n{code_snippet}\nGenerate Title, Meta Description, Keywords, and JSON-LD."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  try:
142
- return seo_client.text_generation(prompt, max_new_tokens=1024, temperature=0.3)
 
 
 
 
 
143
  except Exception as e:
144
- return f"Error: {str(e)}"
145
 
146
  # =====================================================
147
- # COMBINED GRADIO UI
148
  # =====================================================
149
- with gr.Blocks(title="Lexical Space Tools", theme=gr.themes.Soft()) as demo:
150
- gr.Markdown("# πŸ› οΈ Lexical Space Multi-Tool")
 
 
 
 
 
 
151
 
152
- with gr.Tabs():
 
 
 
 
 
 
 
 
 
 
153
  # --- TAB 1: DOWNLOADER ---
154
- with gr.TabItem("πŸš€ UltraMax Downloader"):
 
155
  with gr.Row(variant="panel"):
156
- url_input = gr.Textbox(label="Media URL", placeholder="Paste link here...")
157
- fetch_btn = gr.Button("πŸ” Fetch Info", variant="primary")
 
158
  with gr.Row():
159
  thumb_preview = gr.Image(label="Thumbnail", interactive=False, height=180)
160
- info_display = gr.Markdown("### ⏳ Waiting for link...")
161
-
 
 
162
  with gr.Row(variant="panel"):
163
- quality_select = gr.Dropdown(["Audio Only (Best)", "Video (4K / Best)", "Video (1080p)", "Video (720p)"], value="Audio Only (Best)", label="Quality")
164
  engine_mode = gr.Radio(["Auto (Smart)", "V1 (Stable)", "V2 (Fast)"], value="Auto (Smart)", label="Engine")
165
- custom_filename = gr.Textbox(label="Rename File", placeholder="MyFile")
166
-
167
- dl_btn = gr.Button("⬇️ START DOWNLOAD", variant="stop", interactive=False)
168
- file_out = gr.File(label="Output")
169
- log_out = gr.Textbox(label="Logs", lines=3)
 
 
 
 
 
 
 
 
170
 
171
- fetch_btn.click(fetch_metadata, [url_input], [thumb_preview, info_display, dl_btn, custom_filename])
172
- dl_btn.click(run_downloader, [engine_mode, url_input, quality_select, gr.State(""), gr.State(""), custom_filename, gr.State("")], [file_out, gr.State(), log_out])
 
173
 
174
  # --- TAB 2: SEO GENERATOR ---
175
- with gr.TabItem("πŸ” AI Code SEO"):
176
- gr.Markdown("### πŸš€ AI Code-to-SEO Generator")
177
  with gr.Row():
178
  with gr.Column():
179
  input_type = gr.Radio(["python", "html"], label="File Type", value="python")
180
- code_input = gr.Code(language="python", label="Paste Code", lines=10)
181
- submit_btn = gr.Button("Generate SEO Strategy", variant="primary")
182
  with gr.Column():
183
- output_markdown = gr.Markdown(label="Generated Result")
184
 
 
185
  input_type.change(lambda x: gr.Code(language=x), inputs=input_type, outputs=code_input)
186
- submit_btn.click(generate_seo, [code_input, input_type], [output_markdown])
 
 
 
 
187
 
188
- demo.queue(max_size=MAX_QUEUE).launch()
 
 
2
  import os
3
  import gradio as gr
4
  import random
5
+ import time
6
  import threading
7
+ import datetime
8
+ import re
9
  import requests
10
  from gradio_client import Client
11
  from huggingface_hub import InferenceClient
12
 
13
  # =====================================================
14
+ # CONFIG & SECRETS
15
  # =====================================================
16
+ # Downloader Config
17
  PROXY_SPACE_URL = "lexicalspace/Proxy-Server"
18
  OUTPUT_DIR = "downloads"
19
  os.makedirs(OUTPUT_DIR, exist_ok=True)
 
21
  MAX_CONCURRENCY = 6
22
  MAX_QUEUE = 20
23
 
24
+ # SEO Config
25
+ # Ensure 'HF_TOKEN' is set in your Space Settings > Secrets
26
+ HF_TOKEN = os.getenv("HF_TOKEN")
27
+ SEO_MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
28
+
29
+ # Initialize SEO Client
30
+ # We wrap this in a try/except to prevent crash if token is missing
31
+ try:
32
+ seo_client = InferenceClient(api_key=HF_TOKEN)
33
+ except Exception:
34
+ seo_client = None
35
 
36
  # =====================================================
37
+ # GLOBAL STATE (Downloader)
38
  # =====================================================
39
  active_jobs = {}
40
  job_lock = threading.Lock()
41
 
42
  # =====================================================
43
+ # PART 1: DOWNLOADER LOGIC
44
  # =====================================================
45
  def get_proxy_batch():
46
  try:
 
90
  return {}
91
 
92
  def fetch_metadata(url):
93
+ if not url: return None, "⚠️ Please enter a URL first.", None, None, None
 
94
  api_url = f"https://noembed.com/embed?url={url}"
95
  try:
96
  response = requests.get(api_url, timeout=10)
97
  data = response.json()
98
+ if "error" in data: return None, f"❌ API Error: {data.get('error')}", gr.update(interactive=False), None, None
99
+
100
  title = data.get('title', 'Unknown Title')
101
  uploader = data.get('author_name', 'Unknown Channel')
102
  thumb = data.get('thumbnail_url', None)
103
+ desc = f"### 🎬 {title}\n**πŸ‘€ Channel:** {uploader}\n**⏱️ Duration:** N/A (API Limit)\n**πŸ‘οΈ Views:** N/A (API Limit)"
104
  safe_title = "".join([c for c in title if c.isalnum() or c in " ._-"])
105
  return thumb, desc, gr.update(interactive=True), gr.update(value=safe_title), "βœ… Metadata fetched"
106
  except Exception as e:
107
  return None, f"❌ Error: {str(e)}", gr.update(interactive=False), None, None
108
 
109
  def run_downloader(engine_name, url, quality, start_time, end_time, custom_name, cookies, progress):
110
+ log = [f"πŸš€ Engine: {engine_name} | Quality: {quality}"]
111
  with job_lock:
112
  if active_jobs.get(url) == "running": return None, "β›” Already running", "Blocked"
113
  active_jobs[url] = "running"
114
 
115
  format_opts = build_format_selector(quality)
116
  filename_tmpl = f"{custom_name}.%(ext)s" if custom_name else '%(title)s.%(ext)s'
117
+
118
  proxies = get_proxy_batch() if "V1" in engine_name else ([get_best_proxy()] if get_best_proxy() else [None])
119
+ strategies = ["android", "ios", "web"] if "V1" in engine_name else ["android", "ios", "web", "tv"]
120
 
121
  s_sec, e_sec = parse_time(start_time), parse_time(end_time)
122
  download_ranges = (lambda info, ydl: [{'start_time': s_sec or 0, 'end_time': e_sec or float('inf')}]) if (s_sec or e_sec) else None
123
 
124
+ success, final_file, cookie_path = False, None, None
125
+ if cookies:
126
+ cookie_path = f"cookies_{random.randint(1000,9999)}.txt"
127
+ with open(cookie_path, "w") as f: f.write(cookies)
128
+
129
  for proxy in proxies:
130
  if success: break
131
  for strat in strategies:
132
+ if success: break
133
  ydl_opts = {
134
+ 'outtmpl': os.path.join(OUTPUT_DIR, filename_tmpl), 'noplaylist': True, 'quiet': True, 'force_ipv4': True,
 
135
  'extractor_args': {'youtube': {'player_client': [strat]}}, **format_opts
136
  }
137
  if proxy: ydl_opts['proxy'] = proxy
138
  if download_ranges: ydl_opts['download_ranges'] = download_ranges
139
+ if cookie_path: ydl_opts['cookiefile'] = cookie_path
140
+
141
+ def hook(d):
142
+ if d['status'] == 'downloading':
143
+ total = d.get('total_bytes') or d.get('total_bytes_estimate')
144
+ if total: progress(d.get('downloaded_bytes', 0) / total)
145
+ ydl_opts['progress_hooks'] = [hook]
146
+
147
  try:
148
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
149
  info = ydl.extract_info(url, download=True)
150
  name = ydl.prepare_filename(info)
151
  base, _ = os.path.splitext(name)
152
  final_file = f"{base}.{format_opts.get('ext', 'mp4')}"
153
+ if not os.path.exists(final_file):
154
+ for f in os.listdir(OUTPUT_DIR):
155
+ if f.startswith(os.path.basename(base)): final_file = os.path.join(OUTPUT_DIR, f); break
156
+ if os.path.exists(final_file): success = True
157
  except: continue
158
 
159
+ if cookie_path and os.path.exists(cookie_path): os.remove(cookie_path)
160
  with job_lock: active_jobs.pop(url, None)
161
  return (final_file, "βœ… Complete", "\n".join(log)) if success else (None, "❌ Failed", "\n".join(log))
162
 
163
+ def download_router(mode, quality, start, end, custom_name, cookies, url, progress=gr.Progress()):
164
+ engine = "V2 β€’ Fast Engine" if "V2" in mode else "V1 β€’ Stable Engine"
165
+ if "Auto" in mode: engine = "V2 β€’ Fast Engine" if (len(url) > 70 or "list=" in url) else "V1 β€’ Stable Engine"
166
+ return run_downloader(engine, url, quality, start, end, custom_name, cookies, progress)
167
+
168
  # =====================================================
169
+ # PART 2: SEO GENERATOR LOGIC
170
  # =====================================================
171
  def generate_seo(code_snippet, file_type):
172
+ if not seo_client: return "πŸ”’ Error: 'HF_TOKEN' not found in Secrets."
173
+ if not code_snippet.strip(): return "⚠️ Error: Please paste some code first."
174
+
175
+ system_instruction = f"""
176
+ You are an expert Technical SEO Specialist. Analyze the user's {file_type} code.
177
+ Your Goal: Generate Google-compliant JSON-LD structured data and SEO meta tags.
178
+ Output Format (Strict Markdown):
179
+ ## SEO Metadata
180
+ **Title:** [Engaging Title, max 60 chars]
181
+ **Description:** [Summary including keywords, max 160 chars]
182
+ **Keywords:** [5-8 comma-separated keywords]
183
+ ## JSON-LD Structured Data
184
+ ```json
185
+ [Insert VALID JSON-LD here]
186
+ ```
187
+ """
188
  try:
189
+ response = seo_client.chat_completion(
190
+ model=SEO_MODEL_ID,
191
+ messages=[{"role": "system", "content": system_instruction}, {"role": "user", "content": f"Analyze:\n{code_snippet}"}],
192
+ max_tokens=1500, temperature=0.2
193
+ )
194
+ return response.choices[0].message.content
195
  except Exception as e:
196
+ return f"❌ Error: {str(e)}"
197
 
198
  # =====================================================
199
+ # PART 3: COMBINED UI WITH ROUTING
200
  # =====================================================
201
+ def handle_deep_link(request: gr.Request):
202
+ """
203
+ Reads the URL parameters to decide which tab to open.
204
+ Example: ?mode=seo -> Opens SEO Tab
205
+ Example: ?mode=downloader -> Opens Downloader Tab
206
+ """
207
+ params = request.query_params
208
+ mode = params.get("mode") or params.get("tool")
209
 
210
+ if mode == "seo":
211
+ return gr.Tabs(selected="seo_tab")
212
+ else:
213
+ return gr.Tabs(selected="dl_tab")
214
+
215
+ # MAIN APP BLOCK
216
+ with gr.Blocks(title="Lexical Space Tools", theme=gr.themes.Soft()) as app:
217
+
218
+ # We assign IDs to tabs so we can select them programmatically
219
+ with gr.Tabs() as main_tabs:
220
+
221
  # --- TAB 1: DOWNLOADER ---
222
+ with gr.TabItem("πŸš€ UltraMax Downloader", id="dl_tab"):
223
+ gr.Markdown("### πŸ“₯ Universal Media Downloader")
224
  with gr.Row(variant="panel"):
225
+ url_input = gr.Textbox(label="Media URL", placeholder="Paste YouTube/Insta/TikTok link...", show_label=False, scale=4)
226
+ fetch_btn = gr.Button("πŸ” Fetch Info", variant="primary", scale=1)
227
+
228
  with gr.Row():
229
  thumb_preview = gr.Image(label="Thumbnail", interactive=False, height=180)
230
+ with gr.Column(scale=3):
231
+ info_display = gr.Markdown("### ⏳ Waiting for link...")
232
+ fetch_status = gr.Label(value="Idle", show_label=False)
233
+
234
  with gr.Row(variant="panel"):
235
+ quality_select = gr.Dropdown(["Audio Only (Best)", "Video (4K / Best)", "Video (1080p)", "Video (720p)", "Video (360p / Data Saver)"], value="Audio Only (Best)", label="Quality")
236
  engine_mode = gr.Radio(["Auto (Smart)", "V1 (Stable)", "V2 (Fast)"], value="Auto (Smart)", label="Engine")
237
+
238
+ with gr.Accordion("βš™οΈ Advanced (Cut / Rename / Auth)", open=False):
239
+ with gr.Row():
240
+ start_time = gr.Textbox(label="Start", placeholder="00:00")
241
+ end_time = gr.Textbox(label="End", placeholder="01:30")
242
+ custom_filename = gr.Textbox(label="Filename", placeholder="MyFile")
243
+ cookies_input = gr.Textbox(label="Cookies", placeholder="Netscape format...", lines=1)
244
+
245
+ dl_btn = gr.Button("⬇️ START DOWNLOAD", variant="stop", interactive=False, size="lg")
246
+ with gr.Accordion("πŸ“‚ Output & Logs", open=True):
247
+ with gr.Row():
248
+ file_out = gr.File(label="Output")
249
+ log_out = gr.Textbox(label="Logs", lines=4)
250
 
251
+ # Downloader Events
252
+ fetch_btn.click(fetch_metadata, [url_input], [thumb_preview, info_display, dl_btn, custom_filename, fetch_status])
253
+ dl_btn.click(download_router, [engine_mode, quality_select, start_time, end_time, custom_filename, cookies_input, url_input], [file_out, fetch_status, log_out], concurrency_limit=MAX_CONCURRENCY)
254
 
255
  # --- TAB 2: SEO GENERATOR ---
256
+ with gr.TabItem("⚑ SEO Generator", id="seo_tab"):
257
+ gr.Markdown("### πŸ” AI SEO & JSON-LD Generator")
258
  with gr.Row():
259
  with gr.Column():
260
  input_type = gr.Radio(["python", "html"], label="File Type", value="python")
261
+ code_input = gr.Code(language="python", label="Paste Code", lines=15)
262
+ seo_btn = gr.Button("✨ Generate SEO Data", variant="primary", size="lg")
263
  with gr.Column():
264
+ output_markdown = gr.Markdown(label="Results")
265
 
266
+ # SEO Events
267
  input_type.change(lambda x: gr.Code(language=x), inputs=input_type, outputs=code_input)
268
+ seo_btn.click(generate_seo, [code_input, input_type], [output_markdown])
269
+
270
+ # --- DEEP LINKING EVENT ---
271
+ # This runs when the page loads to check the URL
272
+ app.load(fn=handle_deep_link, inputs=None, outputs=main_tabs)
273
 
274
+ if __name__ == "__main__":
275
+ app.queue(max_size=MAX_QUEUE).launch()