Comprendre, construire et publier Downloader Studio
Cette documentation couvre l'architecture réelle du
code, le fonctionnement interne de l'application,
les dépendances utilisées et le processus de build
multiplateforme. Utilisez le menu à gauche pour
naviguer par section.
Downloader Studio est une application de bureau
écrite en Python avec
PyQt5 pour l'interface graphique
et yt-dlp comme moteur
d'extraction/téléchargement. Elle permet de
rechercher des médias, de les mettre en file
d'attente et de les télécharger en audio ou vidéo,
avec post-traitement FFmpeg pour les conversions
de format.
Points clés
Interface à onglets latéraux : Recherche, File d'attente, Paramètres, Logs.
Mode flottant minimaliste activable avec Ctrl+M.
Thèmes clair et sombre appliqués globalement via une feuille de styles Qt générée en Python.
Interface traduite en 4 langues (FR, EN, DE, ES), reconstruite dynamiquement au changement de langue.
Paramètres persistés en JSON dans le dossier de données utilisateur.
Le point d'entrée est main.py :
il instancie QApplication, affiche
un splash screen, puis construit la fenêtre
principale Downloader définie dans
app/ui/main_window.py.
L'application suit une séparation classique
UI / logique métier :
UI (app/ui/) : widgets PyQt5, mise en page, thèmes, événements utilisateur. Ne contient aucune logique de téléchargement directe.
Core (app/core/) : DownloadEngine gère la file d'attente et orchestre des DownloadWorker (QThread) qui appellent yt-dlp. Aucune dépendance à PyQt Widgets, uniquement à QThread/pyqtSignal pour communiquer avec l'UI de façon thread-safe.
i18n (i18n/) : dictionnaire de chaînes centralisé, aucune chaîne UI n'est codée en dur dans les widgets.
Utils (app/utils/) : fonctions transverses (icônes, résolution de chemins) sans état.
Résolution des chemins (resources.py)
resource_path() gère trois contextes
d'exécution différents pour que le code fonctionne
identiquement en dev et une fois packagé :
Contexte
Détection
Base de chemin utilisée
Script Python normal
sys.frozen absent
Racine du dépôt (3 niveaux au-dessus du fichier)
Exécutable PyInstaller (--onefile)
sys.frozen et sys._MEIPASS
Dossier d'extraction temporaire PyInstaller
Exécutable installé (Inno Setup / onedir)
sys.frozen sans _MEIPASS
Dossier contenant l'exécutable
03Fonctionnement de l'application
Cycle de vie du téléchargement
1. Recherche
search_page.py appelle DownloadEngine.search_youtube() ou search_soundcloud(), qui interrogent yt-dlp en mode extraction seule (ytsearch10: / scsearch10:).
2. File d'attente
Chaque résultat sélectionné devient un DownloadTask (URL, format, qualité). add_task() refuse les doublons déjà en file ou en cours.
3. Téléchargement
_process_next() lance un DownloadWorker (QThread) par tâche, séquentiellement. Il configure les options yt-dlp selon le format demandé.
4. Post-traitement
Pour l'audio (MP3/WAV/M4A), un postprocessor FFmpeg extrait et convertit la piste. Pour la vidéo, un format combiné vidéo+audio est sélectionné selon la qualité choisie.
Sources supportées
L'interface expose deux cases à cocher de
recherche : YouTube et
SoundCloud. Le moteur reconnaît
en plus Twitch et
TikTok par simple collage d'URL
(pas de recherche par mot-clé pour ces deux
sources) ; la détection se fait par correspondance
de domaine dans search_page.py.
Source
Recherche par mot-clé
Collage d'URL directe
YouTube
Oui
Oui
SoundCloud
Oui
Oui
Twitch
Non
Oui
TikTok
Non
Oui
Résolution des lecteurs intégrés (iframe)
Certains sites "portail" n'exposent pas
directement une page lisible par yt-dlp : la
vidéo réelle vit dans un <iframe>.
Quand yt-dlp échoue avec une erreur
Unsupported URL,
resolve_embedded_media_url()
télécharge la page HTML, cherche le premier
src d'iframe qui ressemble à un
lecteur, puis retente le téléchargement sur cette
URL résolue.
Sélection du meilleur flux vidéo+audio selon la résolution max choisie (480p à 4K)
Mode minimaliste
Ctrl+M bascule vers
minimal_window.py : une fenêtre
flottante compacte qui garde l'essentiel (coller
une URL, lancer le téléchargement, ouvrir le
dossier de sortie) sans afficher l'interface
complète.
Persistance des paramètres
À la fermeture, save_app_settings()
écrit un fichier JSON contenant le thème, la
langue, le dossier de sortie, les sources
activées, les formats activés et les préférences
de qualité. Il est relu au démarrage par
load_app_settings().
Clé JSON
Rôle
theme
Thème actif (dark ou light)
language
Langue active de l'interface
output_dir
Dossier de destination des téléchargements
sources_enabled
Sources de recherche activées/désactivées
enabled_formats
Formats proposés dans l'UI
quality / audio_quality
Qualité vidéo et bitrate audio par défaut
Le fichier est stocké dans
%LOCALAPPDATA%\Downloader Studio\downloader_settings.json
(voir config.py,
USER_DATA_DIR). Il est ignoré par
Git.
04Internationalisation (i18n)
Toutes les chaînes affichées passent par
i18n/translations.py. La classe
Translator charge un dictionnaire par
langue depuis TRANSLATIONS et expose
une fonction globale t(key) utilisée
partout dans l'UI.
Quand la langue change (page Paramètres), un
signal global signal_manager.language_changed
(app/signals.py) est émis. Chaque
page abonnée reconstruit ses widgets texte pour
éviter de garder des libellés dans l'ancienne
langue.
Extraction et téléchargement de médias (YouTube, SoundCloud, Twitch, TikTok, etc.)
requests
2.31.0
Appels HTTP : résolution d'iframes, vérification des mises à jour GitHub
Dépendance externe non-Python
Outil
Rôle
Origine
FFmpeg (ffmpeg + ffprobe)
Extraction et conversion audio, mux vidéo+audio
Détecté localement, sinon téléchargé automatiquement depuis gyan.dev (build release-essentials) au moment du build ou de l'installation
Dépendances de build (non incluses dans requirements.txt)
Outil
Rôle
pyinstaller
Génère l'exécutable onedir à partir de main.py
Inno Setup 6
Compile l'installateur Windows depuis packaging/Downloader_Studio.iss
Python 3.14/3.15 non supportés pour le
build release. Les specs PyInstaller
du projet lèvent une erreur explicite en
dehors de la plage 3.10 – 3.13
: ces versions récentes ont produit des
exécutables qui plantent au lancement avec
Failed to load Python DLL.
Validation de la version Python (3.10–3.13 final).
Build PyInstaller en mode onedir (voir pourquoi ci-dessous).
Récupération de FFmpeg (cache local, installation système, ou téléchargement).
Compilation de l'installateur avec Inno Setup 6 (si détecté).
Pourquoi onedir plutôt que onefile
Le mode onefile extrait Python dans
%TEMP%\_MEI... à chaque lancement.
Un antivirus ou une politique de droits peut
bloquer ou supprimer python313.dll à
ce moment-là, provoquant
Failed to load Python DLL. Le mode
onedir garde le runtime Python, les
DLL Qt et FFmpeg à côté de l'exécutable installé,
donc le lancement ne dépend plus d'une extraction
temporaire.
Build multiplateforme (CI GitHub Actions)
.github/workflows/release.yml se
déclenche sur un tag v*.*.* et
construit en parallèle les trois plateformes,
puis publie tout sur une GitHub Release :
Plateforme
Runner
Artefacts produits
Windows
windows-latest
ZIP portable + installateur Inno Setup (_Setup.exe)
Linux
ubuntu-latest
AppImage + archive .tar.gz
macOS
macos-latest
Bundle .app zippé (non signé)
# Déclencher une release complète
git tag v2.17.0
git push origin v2.17.0
Mise à jour automatique
app/core/update_checker.py interroge
l'API GitHub Releases (/releases/latest)
au démarrage. Il compare la version distante à
APP_VERSION (config.py),
puis sélectionne l'asset correspondant au système
d'exploitation courant (sys.platform)
grâce à une correspondance de suffixe de nom de
fichier, avec repli générique si aucun asset
spécifique à la plateforme n'est trouvé.
07Configuration
config.py centralise les constantes
globales de l'application.
Constante
Exemple
Usage
APP_VERSION
2.17.0
Version affichée et comparée par le vérificateur de mise à jour
APP_GITHUB_REPO
batsave/downloader-studio
Dépôt utilisé pour les releases et la doc
USER_DATA_DIR
%LOCALAPPDATA%\Downloader Studio
Dossier des données utilisateur (settings, logs)
DEFAULT_OUTPUT_DIR
%USERPROFILE%\Downloads
Dossier de téléchargement par défaut
LANGUAGES
{"fr", "en", "de", "es"}
Langues disponibles dans les paramètres
THEMES_AVAILABLE
["dark", "light"]
Thèmes disponibles
08Limites & avertissements
Downloader Studio n'est affilié à aucune des plateformes qu'il interroge (YouTube, SoundCloud, Twitch, TikTok).
Le téléchargement dépend entièrement de yt-dlp : toute évolution des sites cibles peut casser l'extraction jusqu'à mise à jour de la dépendance.
Respectez les conditions d'utilisation des plateformes et les droits d'auteur du contenu téléchargé.
Le build release nécessite CPython 3.10–3.13 ; toute autre version est bloquée volontairement.
This documentation covers the actual code
architecture, the app's internal behavior, the
dependencies it relies on, and the multiplatform
build process. Use the left menu to jump between
sections.
Downloader Studio is a desktop application
written in Python, using
PyQt5 for the GUI and
yt-dlp as the extraction/download
engine. It lets users search for media, queue it
up, and download audio or video with FFmpeg
post-processing for format conversion.
Dark and light themes applied globally via a Python-generated Qt stylesheet.
UI translated into 4 languages (FR, EN, DE, ES), rebuilt dynamically on language change.
Settings persisted as JSON in the user data directory.
The entry point is main.py: it
creates the QApplication, shows a
splash screen, then builds the
Downloader main window defined in
app/ui/main_window.py.
The app follows a classic UI / business-logic split:
UI (app/ui/): PyQt5 widgets, layout, themes, user events. No direct download logic.
Core (app/core/): DownloadEngine manages the queue and drives DownloadWorker instances (QThread) that call yt-dlp. No dependency on PyQt Widgets, only on QThread/pyqtSignal for thread-safe UI communication.
i18n (i18n/): centralized string dictionary, no UI string is hardcoded in widgets.
resource_path() handles three
different execution contexts so the code behaves
identically in dev and once packaged:
Context
Detection
Path base used
Plain Python script
sys.frozen absent
Repo root (3 levels above the file)
PyInstaller executable (--onefile)
sys.frozen and sys._MEIPASS
PyInstaller's temporary extraction folder
Installed executable (Inno Setup / onedir)
sys.frozen without _MEIPASS
Folder containing the executable
03How it works
Download lifecycle
1. Search
search_page.py calls DownloadEngine.search_youtube() or search_soundcloud(), which query yt-dlp in extract-only mode (ytsearch10: / scsearch10:).
2. Queue
Each selected result becomes a DownloadTask (URL, format, quality). add_task() rejects duplicates already queued or in progress.
3. Download
_process_next() starts one DownloadWorker (QThread) per task, sequentially. It builds yt-dlp options based on the requested format.
4. Post-processing
For audio (MP3/WAV/M4A), an FFmpeg postprocessor extracts and converts the track. For video, a combined video+audio format is selected based on the chosen quality.
Supported sources
The UI exposes two search checkboxes:
YouTube and
SoundCloud. The engine also
recognizes Twitch and
TikTok by pasting a direct URL
(no keyword search for these two); detection is
done via domain matching in
search_page.py.
Source
Keyword search
Direct URL paste
YouTube
Yes
Yes
SoundCloud
Yes
Yes
Twitch
No
Yes
TikTok
No
Yes
Embedded player resolution (iframe)
Some "portal" sites don't expose a page yt-dlp can
read directly: the real video lives inside an
<iframe>. When yt-dlp fails
with Unsupported URL,
resolve_embedded_media_url()
downloads the HTML page, looks for the first
iframe src that looks like a player,
then retries the download on that resolved URL.
Best combined video+audio stream selected by max resolution (480p to 4K)
Minimal mode
Ctrl+M switches to
minimal_window.py: a compact floating
window that keeps the essentials (paste a URL,
start the download, open the output folder)
without showing the full interface.
Settings persistence
On close, save_app_settings() writes
a JSON file with the theme, language, output
folder, enabled sources, enabled formats, and
quality preferences. It's read back on startup by
load_app_settings().
JSON key
Purpose
theme
Active theme (dark or light)
language
Active UI language
output_dir
Download destination folder
sources_enabled
Enabled/disabled search sources
enabled_formats
Formats offered in the UI
quality / audio_quality
Default video quality and audio bitrate
The file is stored at
%LOCALAPPDATA%\Downloader Studio\downloader_settings.json
(see config.py,
USER_DATA_DIR). It's ignored by
Git.
04Internationalization (i18n)
Every displayed string goes through
i18n/translations.py. The
Translator class loads a
per-language dictionary from
TRANSLATIONS and exposes a global
t(key) function used throughout the
UI.
When the language changes (Settings page), a
global signal
signal_manager.language_changed
(app/signals.py) is emitted. Each
subscribed page rebuilds its text widgets to
avoid keeping labels in the old language.
Code
Language
Status
fr
French
Default language
en
English
Complete
de
German
Complete
es
Spanish
Complete
05Dependencies
Runtime dependencies (requirements.txt)
Package
Pinned version
Role
PyQt5
5.15.11
GUI framework (windows, widgets, themes)
PyQt5-Qt5
5.15.2
Qt5 binaries required by PyQt5
PyQt5-sip
12.18.0
SIP bindings between Python and Qt5
yt-dlp
2026.6.9
Media extraction and download (YouTube, SoundCloud, Twitch, TikTok, etc.)
Detected locally, otherwise downloaded automatically from gyan.dev (release-essentials build) at build or install time
Build-time dependencies (not in requirements.txt)
Tool
Role
pyinstaller
Builds the onedir executable from main.py
Inno Setup 6
Compiles the Windows installer from packaging/Downloader_Studio.iss
Python 3.14/3.15 are not supported for
release builds. The project's
PyInstaller specs raise an explicit error
outside the 3.10 – 3.13
range: those newer versions have produced
executables that crash on launch with
Failed to load Python DLL.
FFmpeg retrieval (local cache, system install, or download).
Installer compilation with Inno Setup 6 (if detected).
Why onedir instead of onefile
onefile mode extracts Python into
%TEMP%\_MEI... on every launch. An
antivirus or permission policy can block or
delete python313.dll at that moment,
causing Failed to load Python DLL.
onedir mode keeps the Python runtime,
Qt DLLs, and FFmpeg next to the installed
executable, so launching no longer depends on a
temporary extraction.
Multiplatform build (GitHub Actions CI)
.github/workflows/release.yml
triggers on a v*.*.* tag and builds
all three platforms in parallel, then publishes
everything to a GitHub Release:
Platform
Runner
Artifacts produced
Windows
windows-latest
Portable ZIP + Inno Setup installer (_Setup.exe)
Linux
ubuntu-latest
AppImage + .tar.gz archive
macOS
macos-latest
Zipped .app bundle (unsigned)
# Trigger a full release
git tag v2.17.0
git push origin v2.17.0
Automatic updates
app/core/update_checker.py queries
the GitHub Releases API
(/releases/latest) on startup. It
compares the remote version against
APP_VERSION (config.py),
then selects the asset matching the current OS
(sys.platform) via filename suffix
matching, with a generic fallback if no
platform-specific asset is found.
07Configuration
config.py centralizes the app's global constants.
Constant
Example
Usage
APP_VERSION
2.17.0
Displayed version, compared by the update checker
APP_GITHUB_REPO
batsave/downloader-studio
Repo used for releases and docs
USER_DATA_DIR
%LOCALAPPDATA%\Downloader Studio
User data folder (settings, logs)
DEFAULT_OUTPUT_DIR
%USERPROFILE%\Downloads
Default download folder
LANGUAGES
{"fr", "en", "de", "es"}
Languages available in settings
THEMES_AVAILABLE
["dark", "light"]
Available themes
08Limitations & disclaimers
Downloader Studio is not affiliated with any platform it queries (YouTube, SoundCloud, Twitch, TikTok).
Downloading fully depends on yt-dlp: any change on the target sites can break extraction until the dependency is updated.
Respect each platform's terms of service and the copyright of downloaded content.
Release builds require CPython 3.10–3.13; any other version is intentionally blocked.
Downloader Studio verstehen, bauen und veröffentlichen
Diese Dokumentation beschreibt die tatsächliche
Code-Architektur, das interne Verhalten der App,
die verwendeten Abhängigkeiten und den
plattformübergreifenden Build-Prozess. Nutze das
Menü links, um zwischen den Abschnitten zu
springen.
Downloader Studio ist eine Desktop-Anwendung in
Python, mit PyQt5
für die Oberfläche und yt-dlp als
Extraktions-/Download-Engine. Nutzer können Medien
suchen, in eine Warteschlange stellen und als
Audio oder Video herunterladen, mit
FFmpeg-Nachbearbeitung für Formatkonvertierung.
Minimalistischer Schwebemodus, umschaltbar mit Strg+M.
Helles und dunkles Design, global über ein in Python erzeugtes Qt-Stylesheet angewendet.
Oberfläche in 4 Sprachen (FR, EN, DE, ES), bei Sprachwechsel dynamisch neu aufgebaut.
Einstellungen als JSON im Benutzerdatenordner gespeichert.
Einstiegspunkt ist main.py: Es
erstellt die QApplication, zeigt
einen Splashscreen und baut dann das
Hauptfenster Downloader aus
app/ui/main_window.py auf.
Die App folgt einer klassischen UI/Geschäftslogik-Trennung:
UI (app/ui/): PyQt5-Widgets, Layout, Designs, Benutzerereignisse. Keine direkte Download-Logik.
Core (app/core/): DownloadEngine verwaltet die Warteschlange und steuert DownloadWorker-Instanzen (QThread), die yt-dlp aufrufen. Keine Abhängigkeit von PyQt-Widgets, nur von QThread/pyqtSignal für Thread-sichere UI-Kommunikation.
i18n (i18n/): zentrales String-Wörterbuch, keine UI-Zeichenkette ist fest in Widgets kodiert.
resource_path() behandelt drei
verschiedene Ausführungskontexte, damit der Code
in der Entwicklung und nach dem Packaging
identisch funktioniert:
Kontext
Erkennung
Verwendete Pfadbasis
Normales Python-Skript
sys.frozen fehlt
Repo-Wurzel (3 Ebenen über der Datei)
PyInstaller-Executable (--onefile)
sys.frozen und sys._MEIPASS
Temporärer Extraktionsordner von PyInstaller
Installierte Executable (Inno Setup / onedir)
sys.frozen ohne _MEIPASS
Ordner, der die Executable enthält
03Funktionsweise
Download-Lebenszyklus
1. Suche
search_page.py ruft DownloadEngine.search_youtube() oder search_soundcloud() auf, die yt-dlp im reinen Extraktionsmodus abfragen (ytsearch10: / scsearch10:).
2. Warteschlange
Jedes ausgewählte Ergebnis wird zu einem DownloadTask (URL, Format, Qualität). add_task() lehnt bereits eingereihte oder laufende Duplikate ab.
3. Download
_process_next() startet pro Aufgabe nacheinander einen DownloadWorker (QThread). Er konfiguriert die yt-dlp-Optionen je nach gewünschtem Format.
4. Nachbearbeitung
Bei Audio (MP3/WAV/M4A) extrahiert und konvertiert ein FFmpeg-postprocessor die Spur. Bei Video wird ein kombinierter Video+Audio-Stream je nach gewählter Qualität ausgewählt.
Unterstützte Quellen
Die Oberfläche bietet zwei Such-Kontrollkästchen:
YouTube und
SoundCloud. Die Engine erkennt
zusätzlich Twitch und
TikTok durch direktes Einfügen
einer URL (keine Stichwortsuche für diese beiden);
die Erkennung erfolgt über
Domain-Übereinstimmung in
search_page.py.
Quelle
Stichwortsuche
Direkte URL-Eingabe
YouTube
Ja
Ja
SoundCloud
Ja
Ja
Twitch
Nein
Ja
TikTok
Nein
Ja
Auflösung eingebetteter Player (iframe)
Manche "Portal"-Seiten stellen keine direkt von
yt-dlp lesbare Seite bereit: Das eigentliche
Video steckt in einem
<iframe>. Wenn yt-dlp mit
Unsupported URL fehlschlägt, lädt
resolve_embedded_media_url() die
HTML-Seite herunter, sucht nach der ersten
iframe-src, die wie ein Player
aussieht, und versucht den Download erneut mit
dieser aufgelösten URL.
Formate und Qualität
Format
Typ
Verarbeitung
mp3
Audio
FFmpeg-Extraktion, konfigurierbare Qualität (z. B. 320 kbps)
Bester kombinierter Video+Audio-Stream nach gewählter Maximalauflösung (480p bis 4K)
Minimalmodus
Strg+M wechselt zu
minimal_window.py: ein kompaktes
Schwebefenster, das nur das Wesentliche behält
(URL einfügen, Download starten, Zielordner
öffnen), ohne die vollständige Oberfläche
anzuzeigen.
Speicherung der Einstellungen
Beim Schließen schreibt
save_app_settings() eine JSON-Datei
mit Design, Sprache, Zielordner, aktivierten
Quellen, aktivierten Formaten und
Qualitätspräferenzen. Sie wird beim Start von
load_app_settings() wieder
eingelesen.
JSON-Schlüssel
Zweck
theme
Aktives Design (dark oder light)
language
Aktive UI-Sprache
output_dir
Zielordner für Downloads
sources_enabled
Aktivierte/deaktivierte Suchquellen
enabled_formats
In der UI angebotene Formate
quality / audio_quality
Standard-Videoqualität und Audio-Bitrate
Die Datei liegt unter
%LOCALAPPDATA%\Downloader Studio\downloader_settings.json
(siehe config.py,
USER_DATA_DIR). Sie wird von Git
ignoriert.
04Internationalisierung (i18n)
Jede angezeigte Zeichenkette läuft über
i18n/translations.py. Die Klasse
Translator lädt ein
sprachspezifisches Wörterbuch aus
TRANSLATIONS und stellt eine globale
Funktion t(key) bereit, die überall
in der UI verwendet wird.
Bei Sprachwechsel (Einstellungsseite) wird ein
globales Signal
signal_manager.language_changed
(app/signals.py) ausgelöst. Jede
abonnierte Seite baut ihre Text-Widgets neu auf,
um Beschriftungen in der alten Sprache zu
vermeiden.
Code
Sprache
Status
fr
Französisch
Standardsprache
en
Englisch
Vollständig
de
Deutsch
Vollständig
es
Spanisch
Vollständig
05Abhängigkeiten
Laufzeitabhängigkeiten (requirements.txt)
Paket
Fixierte Version
Rolle
PyQt5
5.15.11
GUI-Framework (Fenster, Widgets, Designs)
PyQt5-Qt5
5.15.2
Von PyQt5 benötigte Qt5-Binärdateien
PyQt5-sip
12.18.0
SIP-Bindings zwischen Python und Qt5
yt-dlp
2026.6.9
Medienextraktion und -download (YouTube, SoundCloud, Twitch, TikTok usw.)
Lokal erkannt, sonst automatisch von gyan.dev heruntergeladen (release-essentials-Build) beim Build oder bei der Installation
Build-Abhängigkeiten (nicht in requirements.txt)
Tool
Rolle
pyinstaller
Erzeugt die onedir-Executable aus main.py
Inno Setup 6
Kompiliert den Windows-Installer aus packaging/Downloader_Studio.iss
Python 3.14/3.15 werden für
Release-Builds nicht unterstützt.
Die PyInstaller-Specs des Projekts werfen
außerhalb des Bereichs
3.10 – 3.13 einen expliziten
Fehler: Diese neueren Versionen haben
Executables erzeugt, die beim Start mit
Failed to load Python DLL
abstürzen.
PyInstaller-Build im onedir-Modus (siehe unten, warum).
Beschaffung von FFmpeg (lokaler Cache, Systeminstallation oder Download).
Kompilierung des Installers mit Inno Setup 6 (falls erkannt).
Warum onedir statt onefile
Der onefile-Modus extrahiert Python
bei jedem Start nach
%TEMP%\_MEI.... Ein Antivirenprogramm
oder eine Rechterichtlinie kann
python313.dll in diesem Moment
blockieren oder löschen, was zu
Failed to load Python DLL führt. Der
onedir-Modus behält die
Python-Laufzeit, Qt-DLLs und FFmpeg neben der
installierten Executable, sodass der Start nicht
mehr von einer temporären Extraktion abhängt.
Plattformübergreifender Build (GitHub Actions CI)
.github/workflows/release.yml wird
bei einem Tag v*.*.* ausgelöst und
baut alle drei Plattformen parallel, um dann
alles in einer GitHub Release zu
veröffentlichen:
Plattform
Runner
Erzeugte Artefakte
Windows
windows-latest
Portables ZIP + Inno-Setup-Installer (_Setup.exe)
Linux
ubuntu-latest
AppImage + .tar.gz-Archiv
macOS
macos-latest
Gezipptes .app-Bundle (unsigniert)
# Eine vollständige Release auslösen
git tag v2.17.0
git push origin v2.17.0
Automatische Updates
app/core/update_checker.py fragt
beim Start die GitHub-Releases-API
(/releases/latest) ab. Es vergleicht
die entfernte Version mit
APP_VERSION (config.py)
und wählt dann das zum aktuellen Betriebssystem
passende Asset (sys.platform) über
eine Dateinamen-Suffix-Übereinstimmung aus, mit
generischem Fallback, falls kein
plattformspezifisches Asset gefunden wird.
07Konfiguration
config.py zentralisiert die globalen Konstanten der App.
Konstante
Beispiel
Verwendung
APP_VERSION
2.17.0
Angezeigte Version, vom Update-Checker verglichen
APP_GITHUB_REPO
batsave/downloader-studio
Repo für Releases und Dokumentation
USER_DATA_DIR
%LOCALAPPDATA%\Downloader Studio
Benutzerdatenordner (Einstellungen, Logs)
DEFAULT_OUTPUT_DIR
%USERPROFILE%\Downloads
Standard-Download-Ordner
LANGUAGES
{"fr", "en", "de", "es"}
In den Einstellungen verfügbare Sprachen
THEMES_AVAILABLE
["dark", "light"]
Verfügbare Designs
08Einschränkungen & Hinweise
Downloader Studio ist nicht mit den abgefragten Plattformen verbunden (YouTube, SoundCloud, Twitch, TikTok).
Der Download hängt vollständig von yt-dlp ab: Änderungen an den Zielseiten können die Extraktion brechen, bis die Abhängigkeit aktualisiert wird.
Beachte die Nutzungsbedingungen der Plattformen und das Urheberrecht der heruntergeladenen Inhalte.
Release-Builds erfordern CPython 3.10–3.13; jede andere Version wird absichtlich blockiert.
Esta documentación cubre la arquitectura real del
código, el funcionamiento interno de la
aplicación, las dependencias utilizadas y el
proceso de compilación multiplataforma. Usa el
menú de la izquierda para navegar entre
secciones.
Downloader Studio es una aplicación de escritorio
escrita en Python, con
PyQt5 para la interfaz gráfica y
yt-dlp como motor de
extracción/descarga. Permite buscar medios,
encolarlos y descargarlos en audio o video, con
post-procesamiento FFmpeg para la conversión de
formato.
Puntos clave
Interfaz con pestañas laterales: Búsqueda, Cola, Configuración, Logs.
Modo flotante minimalista activable con Ctrl+M.
Temas claro y oscuro aplicados globalmente mediante una hoja de estilos Qt generada en Python.
Interfaz traducida a 4 idiomas (FR, EN, DE, ES), reconstruida dinámicamente al cambiar de idioma.
Configuración persistida en JSON en el directorio de datos del usuario.
El punto de entrada es main.py:
crea la QApplication, muestra una
pantalla de bienvenida y luego construye la
ventana principal Downloader
definida en app/ui/main_window.py.
02Arquitectura del proyecto
Árbol de archivos
downloader-studio/
├── main.py # Punto de entrada (QApplication, splash screen)
├── config.py # Constantes globales (versión, rutas, idiomas)
├── requirements.txt # Dependencias en tiempo de ejecución
├── app/
│ ├── signals.py # SignalManager global (ej. language_changed)
│ ├── core/
│ │ ├── download_engine.py # Cola + integración con yt-dlp
│ │ └── update_checker.py # Verificación de actualizaciones vía GitHub Releases
│ ├── ui/
│ │ ├── main_window.py # Ventana principal, barra lateral, temas, configuración
│ │ ├── minimal_window.py # Modo flotante compacto (Ctrl+M)
│ │ └── pages/
│ │ ├── search_page.py # Búsqueda + resultados + agregar a la cola
│ │ ├── queue_page.py # Cola, progreso, historial
│ │ ├── settings_page.py # Idioma, tema, fuentes, formatos, calidad
│ │ └── logs_page.py # Registro de actividad + exportación
│ └── utils/
│ ├── icons.py # Íconos SVG generados al vuelo (QIcon)
│ └── resources.py # Resolución de rutas (dev / PyInstaller / Inno)
├── i18n/
│ ├── __init__.py # Fachada: t(), set_language(), get_translator()
│ └── translations.py # Diccionario TRANSLATIONS + clase Translator
├── assets/ # Logo, íconos, recursos visuales
├── docs/ # Este sitio (landing page + documentación)
├── packaging/
│ ├── build_exe.py # Script de compilación completo (PyInstaller + Inno Setup)
│ └── Downloader_Studio.iss # Script de Inno Setup (instalador de Windows)
Separación de responsabilidades
La aplicación sigue una separación clásica de UI / lógica de negocio:
UI (app/ui/): widgets de PyQt5, diseño, temas, eventos de usuario. Sin lógica de descarga directa.
Core (app/core/): DownloadEngine gestiona la cola y coordina instancias de DownloadWorker (QThread) que llaman a yt-dlp. Sin dependencia de PyQt Widgets, solo de QThread/pyqtSignal para comunicación segura entre hilos con la UI.
i18n (i18n/): diccionario de cadenas centralizado, ninguna cadena de la UI está escrita directamente en los widgets.
Utils (app/utils/): utilidades transversales sin estado (íconos, resolución de rutas).
Resolución de rutas (resources.py)
resource_path() gestiona tres
contextos de ejecución distintos para que el
código funcione igual en desarrollo y una vez
empaquetado:
Contexto
Detección
Base de ruta usada
Script Python normal
Sin sys.frozen
Raíz del repositorio (3 niveles por encima del archivo)
Ejecutable PyInstaller (--onefile)
sys.frozen y sys._MEIPASS
Carpeta temporal de extracción de PyInstaller
Ejecutable instalado (Inno Setup / onedir)
sys.frozen sin _MEIPASS
Carpeta que contiene el ejecutable
03Funcionamiento
Ciclo de vida de la descarga
1. Búsqueda
search_page.py llama a DownloadEngine.search_youtube() o search_soundcloud(), que consultan yt-dlp en modo de solo extracción (ytsearch10: / scsearch10:).
2. Cola
Cada resultado seleccionado se convierte en un DownloadTask (URL, formato, calidad). add_task() rechaza duplicados ya en cola o en curso.
3. Descarga
_process_next() inicia un DownloadWorker (QThread) por tarea, de forma secuencial. Configura las opciones de yt-dlp según el formato solicitado.
4. Post-procesamiento
Para audio (MP3/WAV/M4A), un postprocessor de FFmpeg extrae y convierte la pista. Para video, se selecciona un formato combinado video+audio según la calidad elegida.
Fuentes compatibles
La interfaz expone dos casillas de búsqueda:
YouTube y
SoundCloud. El motor también
reconoce Twitch y
TikTok pegando directamente una
URL (sin búsqueda por palabra clave para estas
dos); la detección se hace por coincidencia de
dominio en search_page.py.
Fuente
Búsqueda por palabra clave
Pegado de URL directa
YouTube
Sí
Sí
SoundCloud
Sí
Sí
Twitch
No
Sí
TikTok
No
Sí
Resolución de reproductores incrustados (iframe)
Algunos sitios "portal" no exponen directamente
una página legible por yt-dlp: el video real vive
dentro de un <iframe>. Cuando
yt-dlp falla con Unsupported URL,
resolve_embedded_media_url()
descarga la página HTML, busca el primer
src de iframe que parezca un
reproductor y reintenta la descarga con esa URL
resuelta.
Mejor flujo combinado video+audio según la resolución máxima elegida (480p a 4K)
Modo minimalista
Ctrl+M cambia a
minimal_window.py: una ventana
flotante compacta que conserva lo esencial (pegar
una URL, iniciar la descarga, abrir la carpeta de
salida) sin mostrar la interfaz completa.
Persistencia de la configuración
Al cerrar, save_app_settings()
escribe un archivo JSON con el tema, el idioma,
la carpeta de salida, las fuentes activadas, los
formatos activados y las preferencias de calidad.
Se vuelve a leer al iniciar mediante
load_app_settings().
Clave JSON
Propósito
theme
Tema activo (dark o light)
language
Idioma activo de la interfaz
output_dir
Carpeta de destino de las descargas
sources_enabled
Fuentes de búsqueda activadas/desactivadas
enabled_formats
Formatos ofrecidos en la UI
quality / audio_quality
Calidad de video y bitrate de audio predeterminados
El archivo se guarda en
%LOCALAPPDATA%\Downloader Studio\downloader_settings.json
(ver config.py,
USER_DATA_DIR). Git lo ignora.
04Internacionalización (i18n)
Todas las cadenas mostradas pasan por
i18n/translations.py. La clase
Translator carga un diccionario por
idioma desde TRANSLATIONS y expone
una función global t(key) usada en
toda la UI.
Cuando cambia el idioma (página de
Configuración), se emite una señal global
signal_manager.language_changed
(app/signals.py). Cada página
suscrita reconstruye sus widgets de texto para
evitar mantener etiquetas en el idioma anterior.
Código
Idioma
Estado
fr
Francés
Idioma predeterminado
en
Inglés
Completo
de
Alemán
Completo
es
Español
Completo
05Dependencias
Dependencias en tiempo de ejecución (requirements.txt)
Paquete
Versión fijada
Rol
PyQt5
5.15.11
Framework de interfaz gráfica (ventanas, widgets, temas)
PyQt5-Qt5
5.15.2
Binarios de Qt5 requeridos por PyQt5
PyQt5-sip
12.18.0
Bindings SIP entre Python y Qt5
yt-dlp
2026.6.9
Extracción y descarga de medios (YouTube, SoundCloud, Twitch, TikTok, etc.)
requests
2.31.0
Llamadas HTTP: resolución de iframes, verificación de actualizaciones en GitHub
Dependencia externa no Python
Herramienta
Rol
Origen
FFmpeg (ffmpeg + ffprobe)
Extracción/conversión de audio, mux de video+audio
Detectado localmente; si no, descargado automáticamente desde gyan.dev (build release-essentials) durante la compilación o instalación
Dependencias de compilación (no incluidas en requirements.txt)
Herramienta
Rol
pyinstaller
Genera el ejecutable onedir a partir de main.py
Inno Setup 6
Compila el instalador de Windows desde packaging/Downloader_Studio.iss
Python 3.14/3.15 no son compatibles
con el build de release. Los specs
de PyInstaller del proyecto lanzan un error
explícito fuera del rango
3.10 – 3.13: estas versiones
más recientes han producido ejecutables que
fallan al iniciar con
Failed to load Python DLL.
Validación de la versión de Python (3.10–3.13 final).
Compilación con PyInstaller en modo onedir (ver por qué abajo).
Obtención de FFmpeg (caché local, instalación del sistema o descarga).
Compilación del instalador con Inno Setup 6 (si se detecta).
Por qué onedir en lugar de onefile
El modo onefile extrae Python en
%TEMP%\_MEI... en cada inicio. Un
antivirus o una política de permisos puede
bloquear o eliminar python313.dll en
ese momento, provocando
Failed to load Python DLL. El modo
onedir mantiene el runtime de
Python, las DLL de Qt y FFmpeg junto al
ejecutable instalado, por lo que el inicio ya no
depende de una extracción temporal.
Compilación multiplataforma (CI de GitHub Actions)
.github/workflows/release.yml se
activa con una etiqueta v*.*.* y
compila las tres plataformas en paralelo, luego
publica todo en una GitHub Release:
Plataforma
Runner
Artefactos generados
Windows
windows-latest
ZIP portable + instalador Inno Setup (_Setup.exe)
Linux
ubuntu-latest
AppImage + archivo .tar.gz
macOS
macos-latest
Paquete .app comprimido (sin firmar)
# Activar una release completa
git tag v2.17.0
git push origin v2.17.0
Actualizaciones automáticas
app/core/update_checker.py consulta
la API de GitHub Releases
(/releases/latest) al iniciar.
Compara la versión remota con
APP_VERSION (config.py)
y luego selecciona el activo correspondiente al
sistema operativo actual (sys.platform)
mediante coincidencia de sufijo de nombre de
archivo, con reserva genérica si no se encuentra
un activo específico de la plataforma.
07Configuración
config.py centraliza las constantes globales de la aplicación.
Constante
Ejemplo
Uso
APP_VERSION
2.17.0
Versión mostrada, comparada por el verificador de actualizaciones
APP_GITHUB_REPO
batsave/downloader-studio
Repositorio usado para releases y documentación
USER_DATA_DIR
%LOCALAPPDATA%\Downloader Studio
Carpeta de datos del usuario (configuración, logs)
DEFAULT_OUTPUT_DIR
%USERPROFILE%\Downloads
Carpeta de descarga predeterminada
LANGUAGES
{"fr", "en", "de", "es"}
Idiomas disponibles en la configuración
THEMES_AVAILABLE
["dark", "light"]
Temas disponibles
08Límites y avisos
Downloader Studio no está afiliado a ninguna de las plataformas que consulta (YouTube, SoundCloud, Twitch, TikTok).
La descarga depende totalmente de yt-dlp: cualquier cambio en los sitios de destino puede romper la extracción hasta que se actualice la dependencia.
Respeta los términos de uso de las plataformas y los derechos de autor del contenido descargado.
El build de release requiere CPython 3.10–3.13; cualquier otra versión se bloquea intencionalmente.