fix: download phase label not working during downloads
- _download_phase_from_status now falls back to checking requested_formats when top-level vcodec/acodec are both 'none' (common when yt-dlp uses separate downloaders for video+audio streams) - Clear download_phase on download completion/error (was persisting stale phase value in finished state) - Add debug logging in put_status for phase detection - Update docker-compose.local.yml to match docker-compose.yml structure with local image build (adds TARGETARCH build arg)
This commit is contained in:
parent
0791d08e7b
commit
03cee14948
2 changed files with 136 additions and 15 deletions
31
app/ytdl.py
31
app/ytdl.py
|
|
@ -488,8 +488,30 @@ class Download:
|
|||
info_dict = st.get('info_dict') if isinstance(st, dict) else None
|
||||
if not isinstance(info_dict, dict):
|
||||
return None
|
||||
|
||||
vcodec = str(info_dict.get('vcodec') or '').lower()
|
||||
acodec = str(info_dict.get('acodec') or '').lower()
|
||||
|
||||
# Check requested_formats when top-level codecs are both "none"
|
||||
# (common when yt-dlp uses separate downloaders for video+audio streams)
|
||||
if (not vcodec or vcodec == 'none') and (not acodec or acodec == 'none'):
|
||||
requested = info_dict.get('requested_formats')
|
||||
if isinstance(requested, list) and requested:
|
||||
has_video = any(
|
||||
str(f.get('vcodec') or '').lower() not in ('', 'none')
|
||||
for f in requested if isinstance(f, dict)
|
||||
)
|
||||
has_audio = any(
|
||||
str(f.get('acodec') or '').lower() not in ('', 'none')
|
||||
for f in requested if isinstance(f, dict)
|
||||
)
|
||||
if has_video and has_audio:
|
||||
return 'media'
|
||||
if has_video:
|
||||
return 'video'
|
||||
if has_audio:
|
||||
return 'audio'
|
||||
|
||||
if vcodec and vcodec != 'none' and (not acodec or acodec == 'none'):
|
||||
return 'video'
|
||||
if acodec and acodec != 'none' and (not vcodec or vcodec == 'none'):
|
||||
|
|
@ -517,6 +539,9 @@ class Download:
|
|||
phase = self._download_phase_from_status(st)
|
||||
if phase:
|
||||
status['download_phase'] = phase
|
||||
log.debug(f"put_status: status={status.get('status')}, phase={phase}, "
|
||||
f"vcodec={st.get('info_dict', {}).get('vcodec') if isinstance(st.get('info_dict'), dict) else 'N/A'}, "
|
||||
f"acodec={st.get('info_dict', {}).get('acodec') if isinstance(st.get('info_dict'), dict) else 'N/A'}")
|
||||
self.status_queue.put(status)
|
||||
|
||||
def put_status_postprocessor(d):
|
||||
|
|
@ -605,11 +630,11 @@ class Download:
|
|||
)
|
||||
|
||||
ret = yt_dlp.YoutubeDL(params=ytdl_params).download([self.info.url])
|
||||
self.status_queue.put({'status': 'finished' if ret == 0 else 'error'})
|
||||
self.status_queue.put({'status': 'finished' if ret == 0 else 'error', 'download_phase': None})
|
||||
log.info(f"Finished download for: {self.info.title}")
|
||||
except yt_dlp.utils.YoutubeDLError as exc:
|
||||
log.error(f"Download error for {self.info.title}: {str(exc)}")
|
||||
self.status_queue.put({'status': 'error', 'msg': str(exc)})
|
||||
self.status_queue.put({'status': 'error', 'msg': str(exc), 'download_phase': None})
|
||||
|
||||
async def start(self, notifier):
|
||||
log.info(f"Preparing download for: {self.info.title}")
|
||||
|
|
@ -759,7 +784,7 @@ class Download:
|
|||
self.info.status = status['status']
|
||||
self.info.msg = status.get('msg')
|
||||
if 'download_phase' in status:
|
||||
self.info.download_phase = status.get('download_phase')
|
||||
self.info.download_phase = status['download_phase']
|
||||
if 'downloaded_bytes' in status:
|
||||
total = status.get('total_bytes') or status.get('total_bytes_estimate')
|
||||
if total:
|
||||
|
|
|
|||
|
|
@ -2,25 +2,121 @@ services:
|
|||
mytube:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
TARGETARCH: amd64
|
||||
image: mytube
|
||||
container_name: mytube-local
|
||||
container_name: mytube
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8081:8081"
|
||||
volumes:
|
||||
- ./downloads:/downloads
|
||||
# Required: download directory (matches DOWNLOAD_DIR, STATE_DIR, TEMP_DIR)
|
||||
- /path/to/downloads:/downloads
|
||||
|
||||
# Optional: environment configuration file
|
||||
# - /path/to/.env:/app/.env:ro
|
||||
|
||||
# Optional: yt-dlp global options file
|
||||
# - /path/to/ytdl-options.json:/config/ytdl-options.json:ro
|
||||
|
||||
# Optional: yt-dlp presets file
|
||||
# - /path/to/ytdl-presets.json:/config/ytdl-presets.json:ro
|
||||
|
||||
# Optional: HTTPS certificates (if HTTPS=true)
|
||||
# - /path/to/ssl/crt.pem:/ssl/crt.pem:ro
|
||||
# - /path/to/ssl/key.pem:/ssl/key.pem:ro
|
||||
|
||||
# Optional: custom robots.txt
|
||||
# - /path/to/robots.txt:/etc/robots.txt:ro
|
||||
|
||||
environment:
|
||||
DOWNLOAD_DIR: /downloads
|
||||
STATE_DIR: /downloads/.metube
|
||||
TEMP_DIR: /downloads
|
||||
HOST: 0.0.0.0
|
||||
PORT: "8081"
|
||||
PUBLIC_MODE: "false"
|
||||
CUSTOM_DIRS: "true"
|
||||
CREATE_CUSTOM_DIRS: "true"
|
||||
LOGLEVEL: INFO
|
||||
ENV_FILE: ""
|
||||
|
||||
# === Container Setup ===
|
||||
# PUID: "1000"
|
||||
# PGID: "1000"
|
||||
# UMASK: "022"
|
||||
# DEFAULT_THEME: auto
|
||||
# LOGLEVEL: INFO
|
||||
# ENABLE_ACCESSLOG: "false"
|
||||
|
||||
# === Directory Configuration ===
|
||||
# DOWNLOAD_DIR: /downloads
|
||||
# STATE_DIR: /downloads/.metube
|
||||
# TEMP_DIR: /downloads
|
||||
# AUDIO_DOWNLOAD_DIR: /audio
|
||||
|
||||
# === Web Server ===
|
||||
# HOST: 0.0.0.0
|
||||
# PORT: "8081"
|
||||
# PUBLIC_MODE: "false"
|
||||
# URL_PREFIX: /mytube/
|
||||
# PUBLIC_HOST_URL: download/
|
||||
# PUBLIC_HOST_AUDIO_URL: audio_download/
|
||||
# HTTPS: "false"
|
||||
# CERTFILE: /ssl/crt.pem
|
||||
# KEYFILE: /ssl/key.pem
|
||||
# CORS_ALLOWED_ORIGINS: ""
|
||||
# ROBOTS_TXT: ""
|
||||
|
||||
# === Download Behavior ===
|
||||
# MAX_CONCURRENT_DOWNLOADS: "3"
|
||||
# DELETE_FILE_ON_TRASHCAN: "false"
|
||||
# DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT: "0"
|
||||
# SUBSCRIPTION_DEFAULT_CHECK_INTERVAL: "60"
|
||||
# SUBSCRIPTION_SCAN_PLAYLIST_END: "50"
|
||||
# SUBSCRIPTION_MAX_SEEN_IDS: "50000"
|
||||
# CLEAR_COMPLETED_AFTER: "0"
|
||||
|
||||
# === File Naming & Output ===
|
||||
# OUTPUT_TEMPLATE: "%(title)s.%(ext)s"
|
||||
# OUTPUT_TEMPLATE_CHAPTER: "%(title)s - %(section_number)02d - %(section_title)s.%(ext)s"
|
||||
# OUTPUT_TEMPLATE_PLAYLIST: "%(playlist_title)s/%(title)s.%(ext)s"
|
||||
# OUTPUT_TEMPLATE_CHANNEL: "%(channel)s/%(title)s.%(ext)s"
|
||||
|
||||
# === yt-dlp Options ===
|
||||
# YTDL_OPTIONS: "{}"
|
||||
# YTDL_OPTIONS_FILE: /config/ytdl-options.json
|
||||
# YTDL_OPTIONS_PRESETS: "{}"
|
||||
# YTDL_OPTIONS_PRESETS_FILE: /config/ytdl-presets.json
|
||||
# ALLOW_YTDL_OPTIONS_OVERRIDES: "false"
|
||||
|
||||
# === Directory Features ===
|
||||
# CUSTOM_DIRS: "true"
|
||||
# CREATE_CUSTOM_DIRS: "true"
|
||||
# DOWNLOAD_DIRS_INDEXABLE: "false"
|
||||
# CUSTOM_DIRS_EXCLUDE_REGEX: "(^|/)[.@].*$"
|
||||
# CHOWN_DIRS: "true"
|
||||
|
||||
# === Custom Environment File ===
|
||||
# ENV_FILE: /path/to/custom.env
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8081/"]
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:${PORT:-8081}/"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
|
||||
# Optional: set working user
|
||||
# user: "${PUID:-1000}:${PGID:-1000}"
|
||||
|
||||
# Optional: network configuration
|
||||
# networks:
|
||||
# - default
|
||||
|
||||
# Optional: resource limits
|
||||
# deploy:
|
||||
# resources:
|
||||
# limits:
|
||||
# cpus: '1'
|
||||
# memory: 1G
|
||||
# reservations:
|
||||
# cpus: '0.5'
|
||||
# memory: 512M
|
||||
|
||||
# Optional: define custom network
|
||||
# networks:
|
||||
# default:
|
||||
# name: mytube-network
|
||||
# driver: bridge
|
||||
|
|
|
|||
Loading…
Reference in a new issue