diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 0a993b8..6a15baf 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -37,6 +37,7 @@ steps: - apk add --no-cache git yq - git config --global user.name "woodpecker-bot" - git config --global user.email "ci@dvirlabs.com" + - git clone "https://$${GIT_USERNAME}:$${GIT_TOKEN}@git.dvirlabs.com/dvirlabs/my-apps.git" - cd my-apps - | TAG="${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}" diff --git a/backend/Dockerfile b/backend/Dockerfile index 2cb042a..f72ce76 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -6,8 +6,9 @@ RUN apt update && apt install -y curl ffmpeg && \ WORKDIR /app COPY . . + RUN pip install --no-cache-dir -r requirements.txt ENV MUSIC_DIR=/music -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/backend/config.py b/backend/config.py index 8deafdd..15700b7 100644 --- a/backend/config.py +++ b/backend/config.py @@ -1,11 +1,12 @@ -import os -from pydantic import BaseSettings +from pydantic_settings import BaseSettings +from pydantic import Field class Settings(BaseSettings): - MUSIC_DIR: str = "/music" - NAVIDROME_SCAN_URL: str = "" + MUSIC_DIR: str = Field(default="/music", description="Path where songs are saved") + NAVIDROME_SCAN_URL: str = Field(default="", description="URL to trigger Navidrome rescan") class Config: env_file = ".env" + env_file_encoding = "utf-8" -settings = Settings() \ No newline at end of file +settings = Settings() diff --git a/backend/downloader.py b/backend/downloader.py new file mode 100644 index 0000000..fc0c89e --- /dev/null +++ b/backend/downloader.py @@ -0,0 +1,37 @@ +import subprocess +import os +from config import settings +import requests + +def download_song(query: str): + output_template = os.path.join(settings.MUSIC_DIR, "%(artist)s/%(album)s/%(title)s.%(ext)s") + + + command = [ + "yt-dlp", + f"ytsearch1:{query}", + "--extract-audio", + "--audio-format", "mp3", + "--output", output_template, + "--no-playlist", + "--quiet" + ] + + result = subprocess.run(command, capture_output=True, text=True) + + if result.returncode != 0: + raise Exception(f"❌ Download failed:\n{result.stderr}") + + # Optional: trigger Navidrome rescan + if settings.NAVIDROME_SCAN_URL: + try: + res = requests.get(settings.NAVIDROME_SCAN_URL, timeout=5) + res.raise_for_status() + except Exception as e: + print(f"⚠️ Failed to trigger Navidrome rescan: {e}") + + return { + "status": "success", + "query": query, + "log": result.stdout + "\n" + result.stderr + } diff --git a/backend/main.py b/backend/main.py index e7fffed..f23a499 100644 --- a/backend/main.py +++ b/backend/main.py @@ -14,40 +14,5 @@ def download(query: str = Query(..., description="Song name or YouTube search te except Exception as e: raise HTTPException(status_code=500, detail=str(e)) -# downloader.py -import subprocess -import os -from config import settings -import uuid -import requests - -def download_song(query: str): - output_template = os.path.join(settings.MUSIC_DIR, "%(title)s.%(ext)s") - - command = [ - "yt-dlp", - f"ytsearch1:{query}", - "--extract-audio", - "--audio-format", "mp3", - "--output", output_template - ] - - result = subprocess.run(command, capture_output=True, text=True) - - if result.returncode != 0: - raise Exception(f"Download failed: {result.stderr}") - - # Optional: trigger navidrome scan - if settings.NAVIDROME_SCAN_URL: - try: - requests.post(settings.NAVIDROME_SCAN_URL, timeout=5) - except Exception as e: - pass # non-critical - - return { - "query": query, - "log": result.stdout - } - if __name__ == "__main__": - uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file + uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) diff --git a/backend/requirements.txt b/backend/requirements.txt index 24b4f82..5c71624 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,4 +1,5 @@ fastapi uvicorn -pydantic -requests \ No newline at end of file +requests +pydantic>=2.0 +pydantic-settings>=2.0