From 209ff53b769dba31f8d602e0939dde6d894f5a5b Mon Sep 17 00:00:00 2001 From: b-hayes Date: Tue, 1 Jul 2025 09:49:08 +1000 Subject: [PATCH 1/4] basic setup i would normally use --- .gitignore | 9 ++++++++- docker-compose.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index ac87c29..37e21f9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ speed-measure-plugin*.json # IDEs and editors /ui/.idea +.idea/ .project .classpath .c9/ @@ -44,6 +45,12 @@ testem.log .DS_Store Thumbs.db - +# Python __pycache__ .venv + +# Environment files +.env + +# Downloads directory +downloads/ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1103e15 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +# MeTube - Self-hosted YouTube downloader with web UI +# This setup allows you to modify the code and see changes reflected in the running container + +services: + metube: + build: . + container_name: MeTube-Dev + restart: unless-stopped + ports: + - "8081:8081" + environment: + # Tells MeTube to use separate directories for video and audio downloads + - DOWNLOAD_DIR=/downloads/video + - AUDIO_DOWNLOAD_DIR=/downloads/audio + # Filename templates for downloads + - OUTPUT_TEMPLATE=%(artist,uploader)s/%(artist,uploader)s - %(title)s%(genre& [%s]|)s (%(release_date>%Y-%m-%d,upload_date>%Y-%m-%d)s).%(ext)s + - OUTPUT_TEMPLATE_PLAYLIST=%(playlist_title)s/%(artist,uploader)s - %(title)s%(genre& [%s]|)s (%(release_date>%Y-%m-%d,upload_date>%Y-%m-%d)s).%(ext)s + # Development environment + - PYTHONUNBUFFERED=1 + volumes: + # Maps your local paths to the container paths + - ${VIDEO_DOWNLOAD_DIR:-./downloads/video}:/downloads/video + - ${AUDIO_DOWNLOAD_DIR:-./downloads/audio}:/downloads/audio + # Mount source code for live editing + - ./app:/app/app + # Override the entrypoint to run Python directly for easier development + command: ["python", "-u", "app/main.py"] From eeb2fbf1dd98221e854d8ab056a15c168af2e405 Mon Sep 17 00:00:00 2001 From: b-hayes Date: Tue, 1 Jul 2025 14:05:45 +1000 Subject: [PATCH 2/4] audio only should donwload corrrectly now --- app/dl_formats.py | 4 +++- app/ytdl.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/dl_formats.py b/app/dl_formats.py index 5640ca4..5147451 100644 --- a/app/dl_formats.py +++ b/app/dl_formats.py @@ -28,7 +28,9 @@ def get_format(format: str, quality: str) -> str: if format in AUDIO_FORMATS: # Audio quality needs to be set post-download, set in opts - return f"bestaudio[ext={format}]/bestaudio/best" + # Use a more robust format string that ensures audio-only download + # and has better fallbacks + return f"bestaudio[ext={format}]/bestaudio[ext=m4a]/bestaudio[ext=mp3]/bestaudio/best[ext!=webm]/best[ext!=webm]" if format in ("mp4", "any"): if quality == "audio": diff --git a/app/ytdl.py b/app/ytdl.py index d4955f3..c8404a9 100644 --- a/app/ytdl.py +++ b/app/ytdl.py @@ -96,7 +96,7 @@ class Download: 'outtmpl': { "default": self.output_template, "chapter": self.output_template_chapter }, 'format': self.format, 'socket_timeout': 30, - 'ignore_no_formats_error': True, + 'ignore_no_formats_error': False, # Changed to False to get better error messages 'progress_hooks': [put_status], 'postprocessor_hooks': [put_status_postprocessor], **self.ytdl_opts, @@ -235,7 +235,7 @@ class DownloadQueue: self.seq_lock = asyncio.Lock() elif self.config.DOWNLOAD_MODE == 'limited': self.semaphore = asyncio.Semaphore(int(self.config.MAX_CONCURRENT_DOWNLOADS)) - + self.done.load() async def __import_queue(self): @@ -301,6 +301,13 @@ class DownloadQueue: 'ignore_no_formats_error': True, 'noplaylist': playlist_strict_mode, 'paths': {"home": self.config.DOWNLOAD_DIR, "temp": self.config.TEMP_DIR}, + 'cookiefile': None, # Allow cookie usage if available + 'age_limit': None, # Don't restrict by age + 'geo_bypass': True, # Attempt to bypass geographic restrictions + 'geo_bypass_country': None, # Let yt-dlp choose the best bypass method + 'extractor_retries': 3, # Retry extraction up to 3 times + 'youtube_include_dash_manifest': True, # Include DASH formats for YouTube Music + 'youtube_skip_dash_manifest': False, # Don't skip DASH manifest **self.config.YTDL_OPTIONS, **({'impersonate': yt_dlp.networking.impersonate.ImpersonateTarget.from_str(self.config.YTDL_OPTIONS['impersonate'])} if 'impersonate' in self.config.YTDL_OPTIONS else {}), }).extract_info(url, download=False) From 0633af7ca9d3567bc95b30fb350ab91185139fa5 Mon Sep 17 00:00:00 2001 From: b-hayes Date: Tue, 1 Jul 2025 14:23:31 +1000 Subject: [PATCH 3/4] Remove playlistend for individual video downloads - it should only be used during playlist extraction --- app/ytdl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/ytdl.py b/app/ytdl.py index c8404a9..a3a09bb 100644 --- a/app/ytdl.py +++ b/app/ytdl.py @@ -385,7 +385,6 @@ class DownloadQueue: ytdl_options = dict(self.config.YTDL_OPTIONS) if playlist_item_limit > 0: log.info(f'playlist limit is set. Processing only first {playlist_item_limit} entries') - ytdl_options['playlistend'] = playlist_item_limit if auto_start is True: download = Download(dldirectory, self.config.TEMP_DIR, output, output_chapter, quality, format, ytdl_options, dl) self.queue.put(download) From 9c4a510f6f494ba10fd91af1c3725e296f00922b Mon Sep 17 00:00:00 2001 From: b-hayes Date: Tue, 22 Jul 2025 01:34:14 +1000 Subject: [PATCH 4/4] update docker compose --- docker-compose.yml => docker-compose-dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename docker-compose.yml => docker-compose-dev.yml (93%) diff --git a/docker-compose.yml b/docker-compose-dev.yml similarity index 93% rename from docker-compose.yml rename to docker-compose-dev.yml index 1103e15..696f45f 100644 --- a/docker-compose.yml +++ b/docker-compose-dev.yml @@ -4,7 +4,7 @@ services: metube: build: . - container_name: MeTube-Dev + container_name: MeTube restart: unless-stopped ports: - "8081:8081" @@ -12,7 +12,7 @@ services: # Tells MeTube to use separate directories for video and audio downloads - DOWNLOAD_DIR=/downloads/video - AUDIO_DOWNLOAD_DIR=/downloads/audio - # Filename templates for downloads + # Sensible filename templates for downloads - OUTPUT_TEMPLATE=%(artist,uploader)s/%(artist,uploader)s - %(title)s%(genre& [%s]|)s (%(release_date>%Y-%m-%d,upload_date>%Y-%m-%d)s).%(ext)s - OUTPUT_TEMPLATE_PLAYLIST=%(playlist_title)s/%(artist,uploader)s - %(title)s%(genre& [%s]|)s (%(release_date>%Y-%m-%d,upload_date>%Y-%m-%d)s).%(ext)s # Development environment