init
This commit is contained in:
parent
ceed189dc3
commit
3438b1587c
4
backend/.env
Normal file
4
backend/.env
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# MUSIC_DIR=/music
|
||||||
|
# NAVIDROME_SCAN_URL=http://navidrome:4533/api/rescan
|
||||||
|
MUSIC_DIR=./backend/music
|
||||||
|
NAVIDROME_SCAN_URL=
|
||||||
BIN
backend/__pycache__/config.cpython-313.pyc
Normal file
BIN
backend/__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/downloader.cpython-313.pyc
Normal file
BIN
backend/__pycache__/downloader.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/main.cpython-313.pyc
Normal file
BIN
backend/__pycache__/main.cpython-313.pyc
Normal file
Binary file not shown.
@ -1,8 +1,10 @@
|
|||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
import os
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
MUSIC_DIR: str = Field(default="/music", description="Path where songs are saved")
|
BASE_DIR: str = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
MUSIC_DIR: str = Field(default=os.path.join(BASE_DIR, "music"), description="Path where songs are saved")
|
||||||
NAVIDROME_SCAN_URL: str = Field(default="", description="URL to trigger Navidrome rescan")
|
NAVIDROME_SCAN_URL: str = Field(default="", description="URL to trigger Navidrome rescan")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
|||||||
@ -3,26 +3,52 @@ import os
|
|||||||
from config import settings
|
from config import settings
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
def download_song(query: str):
|
def detect_query_type(query: str):
|
||||||
output_template = os.path.join(settings.MUSIC_DIR, "%(artist)s/%(album)s/%(title)s.%(ext)s")
|
if "youtube.com/playlist" in query or "list=" in query:
|
||||||
|
return "playlist"
|
||||||
|
elif "youtube.com/watch" in query or "youtu.be/" in query:
|
||||||
|
return "video"
|
||||||
|
else:
|
||||||
|
return "search"
|
||||||
|
|
||||||
|
def download_song(query: str):
|
||||||
|
output_template = os.path.join(settings.MUSIC_DIR, "%(uploader)s/%(title)s.%(ext)s")
|
||||||
|
|
||||||
|
query_type = detect_query_type(query)
|
||||||
|
|
||||||
|
if query_type == "video":
|
||||||
|
yt_query = query
|
||||||
|
playlist_flag = "--no-playlist"
|
||||||
|
extra_filters = []
|
||||||
|
elif query_type == "playlist":
|
||||||
|
yt_query = query
|
||||||
|
playlist_flag = None
|
||||||
|
extra_filters = []
|
||||||
|
else:
|
||||||
|
yt_query = f"ytsearch20:{query}"
|
||||||
|
playlist_flag = "--no-playlist"
|
||||||
|
filter_expr = f"'{query.lower()}' in uploader.lower()" # ✅ valid expression
|
||||||
|
extra_filters = ["--match-filter", filter_expr]
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
"yt-dlp",
|
"yt-dlp",
|
||||||
f"ytsearch1:{query}",
|
yt_query,
|
||||||
"--extract-audio",
|
"--extract-audio",
|
||||||
"--audio-format", "mp3",
|
"--audio-format", "mp3",
|
||||||
"--output", output_template,
|
"--output", output_template,
|
||||||
"--no-playlist",
|
|
||||||
"--quiet"
|
"--quiet"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if playlist_flag:
|
||||||
|
command.append(playlist_flag)
|
||||||
|
if extra_filters:
|
||||||
|
command.extend(extra_filters)
|
||||||
|
|
||||||
result = subprocess.run(command, capture_output=True, text=True)
|
result = subprocess.run(command, capture_output=True, text=True)
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise Exception(f"❌ Download failed:\n{result.stderr}")
|
raise Exception(f"❌ Download failed:\n{result.stderr}")
|
||||||
|
|
||||||
# Optional: trigger Navidrome rescan
|
|
||||||
if settings.NAVIDROME_SCAN_URL:
|
if settings.NAVIDROME_SCAN_URL:
|
||||||
try:
|
try:
|
||||||
res = requests.get(settings.NAVIDROME_SCAN_URL, timeout=5)
|
res = requests.get(settings.NAVIDROME_SCAN_URL, timeout=5)
|
||||||
|
|||||||
@ -3,6 +3,10 @@ from fastapi.responses import JSONResponse
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
from downloader import download_song
|
from downloader import download_song
|
||||||
from config import settings
|
from config import settings
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Make sure the music directory exists
|
||||||
|
os.makedirs(settings.MUSIC_DIR, exist_ok=True)
|
||||||
|
|
||||||
app = FastAPI(title="Tunedrop")
|
app = FastAPI(title="Tunedrop")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user