lexicalspace commited on
Commit
80ffb94
·
verified ·
1 Parent(s): 9f0198a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -76
app.py CHANGED
@@ -1,9 +1,10 @@
1
  import streamlit as st
2
- import requests
3
- import json
4
  import re
5
  from bs4 import BeautifulSoup
6
  import markdown
 
 
7
 
8
  # --- PAGE CONFIG ---
9
  st.set_page_config(
@@ -13,7 +14,7 @@ st.set_page_config(
13
  initial_sidebar_state="expanded"
14
  )
15
 
16
- # --- SIDEBAR & SERVER SELECTOR ---
17
  st.sidebar.title("Navigation")
18
  query_params = st.query_params
19
  default_index = 1 if query_params.get("mode") == "downloader" else 0
@@ -24,89 +25,111 @@ app_mode = st.sidebar.radio(
24
  index=default_index
25
  )
26
 
27
- # List of Public Cobalt v10 Instances (Community Hosted)
28
- # If one fails, the user can switch to another.
29
- SERVERS = {
30
- "Auto (US)": "https://co.wuk.sh",
31
- "Backup (EU)": "https://cobalt.api.timelessnesses.me",
32
- "Backup (Asia)": "https://api.cobalt.750.moe",
33
- "Backup (US-East)": "https://cobalt-api.hyper.lol"
34
- }
35
-
36
- if app_mode == "YouTube Downloader":
37
- st.sidebar.markdown("---")
38
- st.sidebar.subheader("⚙️ Server Settings")
39
- selected_server_name = st.sidebar.selectbox("Processing Server", list(SERVERS.keys()))
40
- api_base_url = SERVERS[selected_server_name]
41
-
42
  # ==========================================
43
- # VIEW 1: YOUTUBE DOWNLOADER (v10 API)
44
  # ==========================================
45
  if app_mode == "YouTube Downloader":
46
  st.title("🎥 YouTube Media Extractor")
47
- st.caption(f"Powered by Cobalt v10 Server: {selected_server_name}")
48
-
 
49
  url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/watch?v=...")
50
 
51
  col1, col2 = st.columns(2)
52
  with col1:
53
- format_type = st.radio("Format", ["Video (MP4)", "Audio Only (MP3)"])
 
 
 
54
 
55
- if url and st.button("🚀 Process Media"):
56
- status_area = st.empty()
57
- status_area.info("⏳ Contacting remote server...")
58
 
59
- try:
60
- # v10 API Payload Structure
61
- headers = {
62
- "Accept": "application/json",
63
- "Content-Type": "application/json",
64
- "User-Agent": "LexicalTools/1.0"
65
- }
66
-
67
- payload = {
68
- "url": url,
69
- # v10 uses 'downloadMode' instead of 'isAudioOnly'
70
- "downloadMode": "audio" if "Audio" in format_type else "auto",
71
- "videoQuality": "1080",
72
- "filenameStyle": "basic"
73
- }
 
 
 
 
 
 
 
 
 
74
 
75
- # Send Request to selected instance
76
- response = requests.post(f"{api_base_url}", headers=headers, json=payload)
77
-
78
- try:
79
- data = response.json()
80
- except:
81
- st.error(f"Server Error: {response.text}")
82
- st.stop()
83
 
84
- # Handle Success
85
- if "url" in data:
86
- download_link = data["url"]
87
- status_area.success("✅ Media Ready!")
88
-
89
- # Direct Stream Link (No server storage used)
90
- st.link_button(f"⬇️ Click to Download {format_type}", download_link)
91
-
92
- # Preview
93
- if "Audio" not in format_type:
94
- st.video(download_link)
95
- else:
96
- st.audio(download_link)
97
-
98
- # Handle API Specific Errors
99
- elif "text" in data:
100
- st.error(f"API Error: {data['text']}")
101
- else:
102
- st.error("Unknown error. Try switching the server in the sidebar.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- except Exception as e:
105
- st.error(f"Connection Failed: {str(e)}")
106
- st.info("💡 Tip: Try selecting a different server in the Sidebar.")
107
 
108
  # ==========================================
109
- # VIEW 2: WEBMASTER TOOLKIT (Existing)
110
  # ==========================================
111
  elif app_mode == "Webmaster Toolkit":
112
  st.title("⚡ Webmaster's Toolkit")
@@ -133,14 +156,10 @@ elif app_mode == "Webmaster Toolkit":
133
 
134
  with tab2:
135
  st.write("Convert heavy images to WebP.")
136
- # Need to import PIL and io only here to save memory
137
- from PIL import Image
138
- import io
139
-
140
  uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'])
141
  if uploaded_file:
142
  original_image = Image.open(uploaded_file)
143
- st.image(original_image, caption="Original", use_container_width=True) # Updated for Streamlit 1.39+
144
 
145
  if st.button("Convert to WebP"):
146
  buffer = io.BytesIO()
 
1
  import streamlit as st
2
+ import streamlit.components.v1 as components
 
3
  import re
4
  from bs4 import BeautifulSoup
5
  import markdown
6
+ from PIL import Image
7
+ import io
8
 
9
  # --- PAGE CONFIG ---
10
  st.set_page_config(
 
14
  initial_sidebar_state="expanded"
15
  )
16
 
17
+ # --- SIDEBAR ---
18
  st.sidebar.title("Navigation")
19
  query_params = st.query_params
20
  default_index = 1 if query_params.get("mode") == "downloader" else 0
 
25
  index=default_index
26
  )
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  # ==========================================
29
+ # VIEW 1: YOUTUBE DOWNLOADER (Client-Side JS)
30
  # ==========================================
31
  if app_mode == "YouTube Downloader":
32
  st.title("🎥 YouTube Media Extractor")
33
+ st.caption("🚀 Client-Side Mode: Runs on your browser (No Server Blocks)")
34
+
35
+ # Input Fields
36
  url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/watch?v=...")
37
 
38
  col1, col2 = st.columns(2)
39
  with col1:
40
+ is_audio = st.toggle("Audio Only (MP3)", value=False)
41
+
42
+ # We pass these variables into the HTML/JS block below
43
+ mode_str = "audio" if is_audio else "auto"
44
 
45
+ if url:
46
+ st.info("👇 Click the button below to process.")
 
47
 
48
+ # --- THE MAGIC JAVASCRIPT BLOCK ---
49
+ # This HTML runs in the user's browser, bypassing the server completely.
50
+ html_code = f"""
51
+ <!DOCTYPE html>
52
+ <html>
53
+ <head>
54
+ <style>
55
+ body {{ font-family: sans-serif; color: white; background: transparent; }}
56
+ .btn {{
57
+ background: #FF4B4B; color: white; border: none; padding: 12px 24px;
58
+ border-radius: 8px; font-size: 16px; cursor: pointer; width: 100%;
59
+ transition: 0.3s; font-weight: bold;
60
+ }}
61
+ .btn:hover {{ background: #FF2B2B; }}
62
+ .btn:disabled {{ background: #555; cursor: not-allowed; }}
63
+ .result {{ margin-top: 15px; padding: 10px; border-radius: 5px; display: none; }}
64
+ .success {{ background: #1E3A2F; border: 1px solid #2ecc71; color: #2ecc71; }}
65
+ .error {{ background: #3A1E1E; border: 1px solid #e74c3c; color: #e74c3c; }}
66
+ a {{ color: white; text-decoration: none; display: block; padding: 10px; background: #2ecc71; border-radius: 5px; text-align: center; }}
67
+ </style>
68
+ </head>
69
+ <body>
70
+ <button id="procBtn" class="btn" onclick="fetchMedia()">🚀 Process Media</button>
71
+ <div id="status" class="result"></div>
72
 
73
+ <script>
74
+ async function fetchMedia() {{
75
+ const btn = document.getElementById('procBtn');
76
+ const status = document.getElementById('status');
77
+
78
+ btn.disabled = true;
79
+ btn.innerText = "⏳ Processing...";
80
+ status.style.display = "none";
81
 
82
+ // The Payload
83
+ const data = {{
84
+ url: "{url}",
85
+ downloadMode: "{mode_str}",
86
+ videoQuality: "1080"
87
+ }};
88
+
89
+ try {{
90
+ // We use a public instance that allows CORS (Browser access)
91
+ const response = await fetch("https://co.wuk.sh/api/json", {{
92
+ method: "POST",
93
+ headers: {{
94
+ "Accept": "application/json",
95
+ "Content-Type": "application/json"
96
+ }},
97
+ body: JSON.stringify(data)
98
+ }});
99
+
100
+ const result = await response.json();
101
+
102
+ if (result.url) {{
103
+ status.className = "result success";
104
+ status.innerHTML = `
105
+ <strong>✅ Success!</strong><br><br>
106
+ <a href="${{result.url}}" target="_blank">⬇️ Click to Download</a>
107
+ `;
108
+ status.style.display = "block";
109
+ btn.innerText = "🚀 Process Another";
110
+ }} else {{
111
+ throw new Error(result.text || "Unknown error");
112
+ }}
113
+
114
+ }} catch (err) {{
115
+ status.className = "result error";
116
+ status.innerText = "Error: " + err.message;
117
+ status.style.display = "block";
118
+ btn.innerText = "❌ Retry";
119
+ }}
120
+ btn.disabled = false;
121
+ }}
122
+ </script>
123
+ </body>
124
+ </html>
125
+ """
126
+
127
+ # Inject the HTML/JS into the Streamlit app
128
+ components.html(html_code, height=250)
129
 
 
 
 
130
 
131
  # ==========================================
132
+ # VIEW 2: WEBMASTER TOOLKIT (Server Side)
133
  # ==========================================
134
  elif app_mode == "Webmaster Toolkit":
135
  st.title("⚡ Webmaster's Toolkit")
 
156
 
157
  with tab2:
158
  st.write("Convert heavy images to WebP.")
 
 
 
 
159
  uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'])
160
  if uploaded_file:
161
  original_image = Image.open(uploaded_file)
162
+ st.image(original_image, caption="Original", use_container_width=True)
163
 
164
  if st.button("Convert to WebP"):
165
  buffer = io.BytesIO()