Skip to content

Commit a7a9b7c

Browse files
authored
Merge pull request #7 from mbaraa/refactor/optimize-yt-dl
Feat: optimize yt download
2 parents a60b0ef + 1452808 commit a7a9b7c

File tree

12 files changed

+406
-19
lines changed

12 files changed

+406
-19
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ views/**/*.txt
1313
docker-compose.yml
1414
.github
1515
README.md
16+
ytdl

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ HOSTNAME="http://localhost:${PORT}"
33
JWT_SECRET="spoikoninochi"
44

55
YOUTUBE_SCAPER_URL="http://localhost:1234"
6+
YOUTUBE_DOWNLOADER_URL="http://localhost:4321"
67
YOUTUBE_MUSIC_DOWNLOAD_PATH="."
78

89
GOOGLE_APPLICATION_CREDENTIALS="./google-service-account.json"

Dockerfile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ RUN go install github.com/a-h/templ/cmd/templ@latest &&\
99

1010
FROM alpine:latest as run
1111

12-
RUN apk add yt-dlp
13-
1412
WORKDIR /app
1513
COPY --from=build /app/dankmuzikk ./dankmuzikk
1614
COPY --from=build /app/run.sh ./run.sh

config/env.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ func initEnvVars() {
1515
Hostname: getEnv("HOSTNAME"),
1616
JwtSecret: getEnv("JWT_SECRET"),
1717
YouTube: struct {
18-
ScraperUrl string
19-
MusicDir string
18+
ScraperUrl string
19+
DownloaderUrl string
20+
MusicDir string
2021
}{
21-
ScraperUrl: getEnv("YOUTUBE_SCAPER_URL"),
22-
MusicDir: getEnv("YOUTUBE_MUSIC_DOWNLOAD_PATH"),
22+
ScraperUrl: getEnv("YOUTUBE_SCAPER_URL"),
23+
DownloaderUrl: getEnv("YOUTUBE_DOWNLOADER_URL"),
24+
MusicDir: getEnv("YOUTUBE_MUSIC_DOWNLOAD_PATH"),
2325
},
2426
Google: struct {
2527
ApiServiceAccount string
@@ -60,8 +62,9 @@ type config struct {
6062
Hostname string
6163
JwtSecret string
6264
YouTube struct {
63-
ScraperUrl string
64-
MusicDir string
65+
ScraperUrl string
66+
DownloaderUrl string
67+
MusicDir string
6568
}
6669
Google struct {
6770
ApiServiceAccount string

docker-compose-dev.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,26 @@ services:
2121
ports:
2222
- "1234:8080"
2323

24+
yt-dl:
25+
container_name: "yt-dl"
26+
build:
27+
context: ./ytdl
28+
image: "ytdl"
29+
restart: "always"
30+
ports:
31+
- "4321:8000"
32+
env_file:
33+
- .env.docker
34+
volumes:
35+
- dankuploads-dir:/app/_serve
36+
2437
volumes:
2538
dankuploads-dir:
2639
driver: local
2740
driver_opts:
2841
type: none
2942
o: bind
30-
device: .
43+
device: ./_serve/
3144
db-config:
3245
driver: local
3346
driver_opts:

docker-compose.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ services:
2020
depends_on:
2121
- dank-db
2222
- yt-scraper
23+
- yt-dl
2324

2425
dank-db:
2526
image: "mariadb:10.8"
@@ -41,7 +42,23 @@ services:
4142
image: "baraamasri/yt-scrape"
4243
restart: "always"
4344
ports:
44-
- "8080"
45+
- 8080
46+
networks:
47+
- danknetwork
48+
49+
yt-dl:
50+
container_name: "ytdl"
51+
build:
52+
context: ./ytdl
53+
image: "ytdl"
54+
restart: "always"
55+
ports:
56+
- 8000
57+
stdin_open: true
58+
env_file:
59+
- .env.docker
60+
volumes:
61+
- dankuploads-dir:/app/_serve
4562
networks:
4663
- danknetwork
4764

@@ -54,7 +71,7 @@ volumes:
5471
driver_opts:
5572
type: none
5673
o: bind
57-
device: .
74+
device: ./_serve/
5875
db-config:
5976
driver: local
6077
driver_opts:

services/youtube/download/download.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"dankmuzikk/models"
99
"errors"
1010
"fmt"
11+
"net/http"
1112
"os"
12-
"os/exec"
1313
)
1414

1515
type DownloadService struct {
@@ -24,19 +24,18 @@ func NewDownloadService(repo db.CRUDRepo[models.Song]) *DownloadService {
2424
// YOUTUBE_MUSIC_DOWNLOAD_PATH, where the file name will be <video_id.mp3> to be served under /music/{id}
2525
// and retuens an occurring error
2626
func (d *DownloadService) DownloadYoutubeSong(req entities.SongDownloadRequest) error {
27-
log.Infoln(req)
2827
path := fmt.Sprintf("%s/%s.mp3", config.Env().YouTube.MusicDir, req.Id)
2928
if _, err := os.Stat(path); err == nil {
3029
log.Infof("The song with id %s is already downloaded\n", req.Id)
3130
return nil
3231
}
33-
// TODO: write a downloader instead of using this sub process command thingy.
34-
cmd := exec.Command("yt-dlp", "-x", "--audio-format", "mp3", "--audio-quality", "best", "-o", path, "https://www.youtube.com/watch?v="+req.Id)
35-
cmd.Stdout = os.Stdout
36-
cmd.Stderr = os.Stderr
37-
err := cmd.Run()
32+
33+
resp, err := http.Get(fmt.Sprintf("%s/download/%s", config.Env().YouTube.DownloaderUrl, req.Id))
3834
if err != nil {
39-
return errors.New("Download failed:" + err.Error())
35+
return err
36+
}
37+
if resp.StatusCode != http.StatusOK {
38+
return errors.New("something went wrong when downloading a song; id: " + req.Id)
4039
}
4140

4241
err = d.repo.Add(&models.Song{

ytdl/.dockerinore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
venv
2+
.*
3+
__pycache__

ytdl/.gitignore

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# poetry
98+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99+
# This is especially recommended for binary packages to ensure reproducibility, and is more
100+
# commonly ignored for libraries.
101+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102+
#poetry.lock
103+
104+
# pdm
105+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106+
#pdm.lock
107+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108+
# in version control.
109+
# https://pdm.fming.dev/#use-with-ide
110+
.pdm.toml
111+
112+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113+
__pypackages__/
114+
115+
# Celery stuff
116+
celerybeat-schedule
117+
celerybeat.pid
118+
119+
# SageMath parsed files
120+
*.sage.py
121+
122+
# Environments
123+
.env
124+
.venv
125+
env/
126+
venv/
127+
ENV/
128+
env.bak/
129+
venv.bak/
130+
131+
# Spyder project settings
132+
.spyderproject
133+
.spyproject
134+
135+
# Rope project settings
136+
.ropeproject
137+
138+
# mkdocs documentation
139+
/site
140+
141+
# mypy
142+
.mypy_cache/
143+
.dmypy.json
144+
dmypy.json
145+
146+
# Pyre type checker
147+
.pyre/
148+
149+
# pytype static type analyzer
150+
.pytype/
151+
152+
# Cython debug symbols
153+
cython_debug/
154+
155+
# PyCharm
156+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158+
# and can be added to the global gitignore or merged into this file. For a more nuclear
159+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160+
#.idea/
161+

ytdl/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM python:3.11-slim AS build
2+
3+
WORKDIR /app
4+
5+
ADD requirements.txt /tmp
6+
RUN pip install --upgrade pip && \
7+
pip install -r /tmp/requirements.txt
8+
COPY . /app
9+
10+
11+
FROM python:3.11-slim
12+
13+
RUN apt-get update -y &&\
14+
apt-get install ffmpeg -y
15+
16+
WORKDIR /app
17+
18+
COPY --from=build /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
19+
COPY --from=build /usr/local/bin/ /usr/local/bin/
20+
COPY --from=build /app .
21+
22+
EXPOSE 8000
23+
CMD [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000" ]
24+

0 commit comments

Comments
 (0)