initial commit
This commit is contained in:
commit
669d865ffb
65
.woodpecker.yaml
Normal file
65
.woodpecker.yaml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
steps:
|
||||||
|
build-backend:
|
||||||
|
name: Build & Push Backend
|
||||||
|
image: woodpeckerci/plugin-kaniko
|
||||||
|
when:
|
||||||
|
branch: [ master, develop ]
|
||||||
|
event: [ push, pull_request, tag ]
|
||||||
|
path:
|
||||||
|
include: [ backend/** ]
|
||||||
|
settings:
|
||||||
|
registry: harbor.dvirlabs.com
|
||||||
|
repo: my-apps/${CI_REPO_NAME}-backend
|
||||||
|
dockerfile: backend/Dockerfile
|
||||||
|
context: backend
|
||||||
|
tags:
|
||||||
|
- latest
|
||||||
|
- ${CI_COMMIT_TAG:-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}}
|
||||||
|
username:
|
||||||
|
from_secret: DOCKER_USERNAME
|
||||||
|
password:
|
||||||
|
from_secret: DOCKER_PASSWORD
|
||||||
|
|
||||||
|
update-values-backend:
|
||||||
|
name: Update backend tag in values.yaml
|
||||||
|
image: alpine:3.19
|
||||||
|
when:
|
||||||
|
branch: [ master, develop ]
|
||||||
|
event: [ push ]
|
||||||
|
path:
|
||||||
|
include: [ backend/** ]
|
||||||
|
environment:
|
||||||
|
GIT_USERNAME:
|
||||||
|
from_secret: GIT_USERNAME
|
||||||
|
GIT_TOKEN:
|
||||||
|
from_secret: GIT_TOKEN
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache git yq
|
||||||
|
- git config --global user.name "woodpecker-bot"
|
||||||
|
- git config --global user.email "ci@dvirlabs.com"
|
||||||
|
- cd my-apps
|
||||||
|
- |
|
||||||
|
TAG="${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}"
|
||||||
|
echo "💡 Setting backend tag to: $TAG"
|
||||||
|
yq -i ".backend.tag = \"$TAG\"" manifests/${CI_REPO_NAME}/values.yaml
|
||||||
|
git add manifests/${CI_REPO_NAME}/values.yaml
|
||||||
|
git commit -m "backend: update tag to $TAG" || echo "No changes"
|
||||||
|
git push origin HEAD
|
||||||
|
|
||||||
|
trigger-gitops-via-push:
|
||||||
|
name: Trigger apps-gitops via Git push
|
||||||
|
image: alpine/git
|
||||||
|
environment:
|
||||||
|
GIT_USERNAME:
|
||||||
|
from_secret: GIT_USERNAME
|
||||||
|
GIT_TOKEN:
|
||||||
|
from_secret: GIT_TOKEN
|
||||||
|
commands: |
|
||||||
|
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/apps-gitops.git"
|
||||||
|
cd apps-gitops
|
||||||
|
echo "# trigger at $(date) by $${CI_REPO_NAME}" >> .trigger
|
||||||
|
git add .trigger
|
||||||
|
git commit -m "ci: trigger apps-gitops build" || echo "no changes"
|
||||||
|
git push origin HEAD
|
||||||
13
backend/Dockerfile
Normal file
13
backend/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
RUN apt update && apt install -y curl ffmpeg && \
|
||||||
|
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp && \
|
||||||
|
chmod a+rx /usr/local/bin/yt-dlp
|
||||||
|
|
||||||
|
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"]
|
||||||
11
backend/config.py
Normal file
11
backend/config.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import os
|
||||||
|
from pydantic import BaseSettings
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
MUSIC_DIR: str = "/music"
|
||||||
|
NAVIDROME_SCAN_URL: str = ""
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
env_file = ".env"
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
49
backend/main.py
Normal file
49
backend/main.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from fastapi import FastAPI, Query, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from downloader import download_song
|
||||||
|
from config import settings
|
||||||
|
|
||||||
|
app = FastAPI(title="Tunedrop")
|
||||||
|
|
||||||
|
@app.get("/download")
|
||||||
|
def download(query: str = Query(..., description="Song name or YouTube search term")):
|
||||||
|
try:
|
||||||
|
result = download_song(query)
|
||||||
|
return JSONResponse(content={"status": "success", **result})
|
||||||
|
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
|
||||||
|
}
|
||||||
4
backend/requirements.txt
Normal file
4
backend/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
pydantic
|
||||||
|
requests
|
||||||
9
tunedrop-chart/Chart.yaml
Normal file
9
tunedrop-chart/Chart.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: tunedrop
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
description: Tunedrop - Music Downloader API
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
|
|
||||||
|
type: application
|
||||||
30
tunedrop-chart/templates/deployment.yaml
Normal file
30
tunedrop-chart/templates/deployment.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: tunedrop
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: tunedrop
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: tunedrop
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: tunedrop
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: MUSIC_DIR
|
||||||
|
value: {{ .Values.env.MUSIC_DIR | quote }}
|
||||||
|
- name: NAVIDROME_SCAN_URL
|
||||||
|
value: {{ .Values.env.NAVIDROME_SCAN_URL | quote }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: music
|
||||||
|
mountPath: {{ .Values.persistence.mountPath }}
|
||||||
|
volumes:
|
||||||
|
- name: music
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: tunedrop-pvc
|
||||||
11
tunedrop-chart/templates/pvc.yaml
Normal file
11
tunedrop-chart/templates/pvc.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: tunedrop-pvc
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.persistence.accessMode }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size }}
|
||||||
|
storageClassName: {{ .Values.persistence.storageClass }}
|
||||||
27
tunedrop-chart/values.yaml
Normal file
27
tunedrop-chart/values.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
image:
|
||||||
|
repository: my-apps/tunedrop
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: traefik
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||||
|
hosts:
|
||||||
|
- host: tunedrop.dvirlabs.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
|
||||||
|
env:
|
||||||
|
MUSIC_DIR: /music
|
||||||
|
NAVIDROME_SCAN_URL: http://navidrome.my-apps.svc.cluster.local:4533/api/rescan
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
mountPath: /music
|
||||||
|
size: 100Gi
|
||||||
|
accessMode: ReadWriteMany
|
||||||
|
storageClass: nfs-client
|
||||||
Loading…
x
Reference in New Issue
Block a user