Update app.py
Browse files
app.py
CHANGED
@@ -7,6 +7,8 @@ from datetime import datetime, timedelta
|
|
7 |
import time
|
8 |
import asyncio
|
9 |
import cloudscraper
|
|
|
|
|
10 |
|
11 |
app = Flask(__name__)
|
12 |
ytmusic = YTMusic()
|
@@ -29,11 +31,106 @@ def search():
|
|
29 |
@app.route('/searcht', methods=['POST'])
|
30 |
def searcht():
|
31 |
query = request.json.get('query', '')
|
|
|
32 |
search_results = ytmusic.search(query, filter="songs")
|
33 |
first_song = next((song for song in search_results if 'videoId' in song and song['videoId']), {}) if search_results else {}
|
34 |
return jsonify(first_song)
|
35 |
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
class ApiRotator:
|
38 |
def __init__(self, apis):
|
39 |
self.apis = apis
|
@@ -56,16 +153,16 @@ class ApiRotator:
|
|
56 |
# In your function:
|
57 |
api_rotator = ApiRotator([
|
58 |
"https://cobalt-api.ayo.tf",
|
|
|
59 |
"http://34.107.254.11",
|
60 |
"https://dwnld.nichind.dev",
|
61 |
-
"https://cobalt-api.kwiatekmiki.com",
|
62 |
"https://yt.edd1e.xyz/"
|
63 |
|
64 |
])
|
65 |
|
66 |
|
67 |
|
68 |
-
async def get_track_download_url(track_id: str) -> str:
|
69 |
apis = api_rotator.get_prioritized_apis()
|
70 |
session = cloudscraper.create_scraper() # Requires cloudscraper package
|
71 |
headers = {
|
@@ -81,7 +178,7 @@ async def get_track_download_url(track_id: str) -> str:
|
|
81 |
response = session.post(
|
82 |
api_url,
|
83 |
timeout=20,
|
84 |
-
json={"url": y_url, "audioFormat": "mp3", "downloadMode": "audio"},
|
85 |
headers=headers
|
86 |
)
|
87 |
logger.info(f"Response status: {response.status_code}")
|
@@ -110,16 +207,21 @@ async def get_track_download_url(track_id: str) -> str:
|
|
110 |
|
111 |
|
112 |
@app.route('/track_dl', methods=['POST'])
|
113 |
-
async def track_dl():
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
|
125 |
|
|
|
7 |
import time
|
8 |
import asyncio
|
9 |
import cloudscraper
|
10 |
+
from pydantic import BaseModel
|
11 |
+
from urllib.parse import urlparse, parse_qs
|
12 |
|
13 |
app = Flask(__name__)
|
14 |
ytmusic = YTMusic()
|
|
|
31 |
@app.route('/searcht', methods=['POST'])
|
32 |
def searcht():
|
33 |
query = request.json.get('query', '')
|
34 |
+
logger.info(f"serch query: {query}")
|
35 |
search_results = ytmusic.search(query, filter="songs")
|
36 |
first_song = next((song for song in search_results if 'videoId' in song and song['videoId']), {}) if search_results else {}
|
37 |
return jsonify(first_song)
|
38 |
|
39 |
|
40 |
+
# Function to extract track ID from Amazon Music URL
|
41 |
+
def extract_amazon_track_id(url: str):
|
42 |
+
if "music.amazon.com" in url:
|
43 |
+
# Case 1: URL contains trackAsin (e.g., https://music.amazon.com/albums/B01N48U32A?trackAsin=B01NAE38YO&do=play)
|
44 |
+
parsed_url = urlparse(url)
|
45 |
+
query_params = parse_qs(parsed_url.query)
|
46 |
+
if "trackAsin" in query_params:
|
47 |
+
return query_params["trackAsin"][0]
|
48 |
+
|
49 |
+
# Case 2: URL is a direct track link (e.g., https://music.amazon.com/tracks/B0DNTPYT5S)
|
50 |
+
if "/tracks/" in url:
|
51 |
+
return url.split("/tracks/")[-1].split("?")[0]
|
52 |
+
|
53 |
+
return None
|
54 |
+
|
55 |
+
|
56 |
+
# Function to get track info from Song.link API
|
57 |
+
def get_song_link_info(url: str):
|
58 |
+
# Check if the URL is from Amazon Music
|
59 |
+
if "music.amazon.com" in url:
|
60 |
+
track_id = extract_amazon_track_id(url)
|
61 |
+
if track_id:
|
62 |
+
# Use the working format for Amazon Music tracks
|
63 |
+
api_url = f"https://api.song.link/v1-alpha.1/links?type=song&platform=amazonMusic&id={track_id}&userCountry=US"
|
64 |
+
else:
|
65 |
+
# If no track ID is found, use the original URL
|
66 |
+
api_url = f"https://api.song.link/v1-alpha.1/links?url={url}&userCountry=US"
|
67 |
+
else:
|
68 |
+
# For non-Amazon Music URLs, use the standard format
|
69 |
+
api_url = f"https://api.song.link/v1-alpha.1/links?url={url}&userCountry=US"
|
70 |
+
|
71 |
+
# Make the API call
|
72 |
+
response = requests.get(api_url)
|
73 |
+
if response.status_code == 200:
|
74 |
+
return response.json()
|
75 |
+
else:
|
76 |
+
return None
|
77 |
+
|
78 |
+
# Function to extract Tidal or YouTube URL
|
79 |
+
def extract_url(links_by_platform: dict, platform: str):
|
80 |
+
if platform in links_by_platform:
|
81 |
+
return links_by_platform[platform]["url"]
|
82 |
+
return None
|
83 |
+
|
84 |
+
|
85 |
+
# Function to extract track title and artist from entities
|
86 |
+
def extract_track_info(entities_by_unique_id: dict, platform: str):
|
87 |
+
for entity in entities_by_unique_id.values():
|
88 |
+
if entity["apiProvider"] == platform:
|
89 |
+
return entity["title"], entity["artistName"]
|
90 |
+
return None, None
|
91 |
+
|
92 |
+
|
93 |
+
|
94 |
+
@app.route('/match', methods=['POST'])
|
95 |
+
async def match():
|
96 |
+
data = request.json
|
97 |
+
track_url = data.get('url')
|
98 |
+
|
99 |
+
if not track_url:
|
100 |
+
raise HTTPException(status_code=400, detail="No URL provided")
|
101 |
+
|
102 |
+
track_info = get_song_link_info(track_url)
|
103 |
+
if not track_info:
|
104 |
+
raise HTTPException(status_code=404, detail="Could not fetch track info")
|
105 |
+
|
106 |
+
youtube_url = extract_url(track_info["linksByPlatform"], "youtube")
|
107 |
+
if youtube_url:
|
108 |
+
title, artist = extract_track_info(track_info["entitiesByUniqueId"], "youtube")
|
109 |
+
if title and artist:
|
110 |
+
filename = f"{title} - {artist}"
|
111 |
+
return {"url": youtube_url, "filename": filename}
|
112 |
+
else:
|
113 |
+
return {"url": youtube_url, "filename": "Unknown Track - Unknown Artist"}
|
114 |
+
else:
|
115 |
+
entityUniqueId = track_info["entityUniqueId"]
|
116 |
+
logger.info(f"songlink info: {entityUniqueId}")
|
117 |
+
title = track_info["entitiesByUniqueId"][entityUniqueId]["title"]
|
118 |
+
artist = track_info["entitiesByUniqueId"][entityUniqueId]["artistName"]
|
119 |
+
search_query = f'{title}+{artist}'
|
120 |
+
search_results = ytmusic.search(search_query, filter="songs")
|
121 |
+
first_song = next((song for song in search_results if 'videoId' in song and song['videoId']), {}) if search_results else {}
|
122 |
+
if 'videoId' in first_song:
|
123 |
+
videoId = first_song["videoId"]
|
124 |
+
ym_url = f'https://www.youtube.com/watch?v={videoId}'
|
125 |
+
return {"filename": title, "url": ym_url}
|
126 |
+
else:
|
127 |
+
raise HTTPException(status_code=404, detail="Video ID not found")
|
128 |
+
|
129 |
+
# If no URLs found, return an error
|
130 |
+
raise HTTPException(status_code=404, detail="No matching URL found")
|
131 |
+
|
132 |
+
|
133 |
+
|
134 |
class ApiRotator:
|
135 |
def __init__(self, apis):
|
136 |
self.apis = apis
|
|
|
153 |
# In your function:
|
154 |
api_rotator = ApiRotator([
|
155 |
"https://cobalt-api.ayo.tf",
|
156 |
+
"https://cobalt-api.kwiatekmiki.com",
|
157 |
"http://34.107.254.11",
|
158 |
"https://dwnld.nichind.dev",
|
|
|
159 |
"https://yt.edd1e.xyz/"
|
160 |
|
161 |
])
|
162 |
|
163 |
|
164 |
|
165 |
+
async def get_track_download_url(track_id: str, quality: str) -> str:
|
166 |
apis = api_rotator.get_prioritized_apis()
|
167 |
session = cloudscraper.create_scraper() # Requires cloudscraper package
|
168 |
headers = {
|
|
|
178 |
response = session.post(
|
179 |
api_url,
|
180 |
timeout=20,
|
181 |
+
json={"url": y_url, "audioFormat": "mp3", "downloadMode": "audio", "audioBitrate": quality},
|
182 |
headers=headers
|
183 |
)
|
184 |
logger.info(f"Response status: {response.status_code}")
|
|
|
207 |
|
208 |
|
209 |
@app.route('/track_dl', methods=['POST'])
|
210 |
+
async def track_dl(request: Request):
|
211 |
+
data = await request.json()
|
212 |
+
track_id = data.get('track_id')
|
213 |
+
quality = data.get('quality', '128')
|
214 |
+
try:
|
215 |
+
quality_num = int(quality)
|
216 |
+
if quality_num > 128 or quality.upper() == 'FLAC':
|
217 |
+
return {"error": "Quality above 128 or FLAC is for Premium Users Only."}
|
218 |
+
dl_url = await get_track_download_url(track_id, quality)
|
219 |
+
if dl_url and "http" in dl_url:
|
220 |
+
return {"url": dl_url}
|
221 |
+
else:
|
222 |
+
return {"error": "Failed to Fetch the Track."}
|
223 |
+
except ValueError:
|
224 |
+
return {"error": "Invalid quality value provided. It should be a valid integer or FLAC."}
|
225 |
|
226 |
|
227 |
|