docker: alpine, autodownload
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
app/__pycache__
|
||||
app/__pycache__
|
||||
downloads/
|
||||
16
Dockerfile
16
Dockerfile
@@ -1,9 +1,7 @@
|
||||
FROM python:3.12-slim
|
||||
FROM python:3.12-alpine
|
||||
|
||||
# Install ffmpeg (required for merging video+audio streams and MP3 conversion)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends ffmpeg && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# Install ffmpeg and dcron (lightweight cron daemon for Alpine)
|
||||
RUN apk add --no-cache ffmpeg dcron
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -17,10 +15,10 @@ COPY app/ .
|
||||
# Downloads are stored here (mount a host volume to persist them)
|
||||
RUN mkdir -p /downloads
|
||||
|
||||
# Setup Cronjob
|
||||
RUN apt-get update && apt-get install -y cron && \
|
||||
echo "0 4 * * * pip install --upgrade yt-dlp >> /var/log/yt-dlp-upgrade.log 2>&1" | crontab -
|
||||
# Setup Cronjob (fails)
|
||||
RUN echo "0 4 * * * pip install --upgrade yt-dlp >> /var/log/yt-dlp-upgrade.log 2>&1" | crontab -
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||
# Launch
|
||||
CMD uvicorn main:app --host 0.0.0.0 --port 8080
|
||||
@@ -96,6 +96,7 @@
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 11px 20px;
|
||||
margin: 1px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -290,15 +291,7 @@
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="logo">
|
||||
<svg aria-label="yt-dlp downloader" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" rx="8" fill="#e53935"/>
|
||||
<path d="M10 13l8 5-8 5V13z" fill="white"/>
|
||||
<path d="M20 13h6M20 18h6M20 23h6" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<h1>yt-dlp Downloader</h1>
|
||||
</div>
|
||||
<p class="subtitle">Download videos & audio from YouTube and 1000+ sites</p>
|
||||
<h1>hier könnte ihre werbung stehen</h1>
|
||||
</header>
|
||||
|
||||
<div class="card">
|
||||
@@ -315,28 +308,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options-row">
|
||||
<div class="option-group">
|
||||
<label class="opt-label" for="format-select">Format</label>
|
||||
<select id="format-select" onchange="onFormatChange()">
|
||||
<option value="video">Video (MP4)</option>
|
||||
<option value="audio">Audio (MP3)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="option-group" id="quality-group">
|
||||
<label class="opt-label" for="quality-select">Quality</label>
|
||||
<select id="quality-select">
|
||||
<option value="best">Best available</option>
|
||||
<option value="1080">1080p</option>
|
||||
<option value="720">720p</option>
|
||||
<option value="480">480p</option>
|
||||
<option value="360">360p</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 16px; display: flex;">
|
||||
<button class="btn" id="dl-btn-video" onclick="startDownload(true)" style="width:50%">Download Video</button>
|
||||
|
||||
<div style="margin-top:16px;">
|
||||
<button class="btn" id="dl-btn" onclick="startDownload()" style="width:100%">Download</button>
|
||||
<button class="btn" id="dl-btn-audio" onclick="startDownload(false)" style="width:50%">Download Audio</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -359,12 +334,6 @@
|
||||
return n + ' views';
|
||||
}
|
||||
|
||||
function onFormatChange() {
|
||||
const fmt = document.getElementById('format-select').value;
|
||||
document.getElementById('quality-group').style.opacity = fmt === 'audio' ? '0.4' : '1';
|
||||
document.getElementById('quality-select').disabled = fmt === 'audio';
|
||||
}
|
||||
|
||||
async function fetchInfo() {
|
||||
const url = document.getElementById('url-input').value.trim();
|
||||
if (!url) return;
|
||||
@@ -390,15 +359,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function startDownload() {
|
||||
async function startDownload(isVideo) {
|
||||
const url = document.getElementById('url-input').value.trim();
|
||||
if (!url) { alert('Please enter a URL first.'); return; }
|
||||
const format = document.getElementById('format-select').value;
|
||||
const quality = document.getElementById('quality-select').value;
|
||||
const format = isVideo ? "video" : "audio";
|
||||
const quality = "best";
|
||||
|
||||
const btn = document.getElementById('dl-btn');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner"></span>Starting…';
|
||||
const btnv = document.getElementById('dl-btn-video');
|
||||
btnv.disabled = true;
|
||||
btnv.innerHTML = '<span class="spinner"></span>Starting…';
|
||||
|
||||
const btna = document.getElementById('dl-btn-audio');
|
||||
btna.disabled = true;
|
||||
btna.innerHTML = '<span class="spinner"></span>Starting…';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/download', {
|
||||
@@ -413,8 +386,11 @@
|
||||
} catch (e) {
|
||||
alert('Failed to start download: ' + e.message);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Download';
|
||||
btna.disabled = false;
|
||||
btna.textContent = 'Download Audio';
|
||||
|
||||
btnv.disabled = false;
|
||||
btnv.textContent = 'Download Video';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +458,8 @@
|
||||
} else if (job.status === 'processing') {
|
||||
meta.textContent = 'Post-processing (merging / converting)…';
|
||||
} else if (job.status === 'done') {
|
||||
meta.textContent = 'Complete · ' + job.filename.split('_').slice(1).join('_');
|
||||
const goodname = job.filename.split('_').slice(1).join('_');
|
||||
meta.textContent = 'Complete · ' + goodname;
|
||||
if (!actions.querySelector('a')) {
|
||||
const a = document.createElement('a');
|
||||
a.href = '/api/file/' + job.id;
|
||||
@@ -490,8 +467,9 @@
|
||||
a.style.fontSize = '0.82rem';
|
||||
a.style.padding = '7px 14px';
|
||||
a.textContent = '⬇ Download File';
|
||||
a.download = '';
|
||||
a.download = goodname;
|
||||
actions.appendChild(a);
|
||||
window.location.href = '/api/file/' + job.id;
|
||||
}
|
||||
} else if (job.status === 'error') {
|
||||
meta.textContent = '';
|
||||
@@ -502,7 +480,7 @@
|
||||
|
||||
// Allow pressing Enter in the URL field
|
||||
document.getElementById('url-input').addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') startDownload();
|
||||
if (e.key === 'Enter') startDownload(true);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user