### Alternative installation methods
* [Snap Store](https://snapcraft.io/video-downloader)
* [Fedora](https://src.fedoraproject.org/rpms/video-downloader): `sudo dnf install video-downloader`
* [Arch User Repository](https://aur.archlinux.org/packages/video-downloader)
## Translation
We use [Weblate](https://hosted.weblate.org/engage/video-downloader/) to translate the UI, so feel free to contribute translations over there.
## Screenshots



## Hidden configuration options
The behavior of the program can be tweaked with GSettings.
### Automatic Subtitles
List of additional automatic subtitles to download. The entry `all` matches all languages.
The default is `[]`.
#### Flatpak
```
flatpak run --command=gsettings com.github.unrud.VideoDownloader set com.github.unrud.VideoDownloader automatic-subtitles "['de','en']"
```
#### Snap
```
snap run --shell video-downloader -c 'gsettings "$@"' '' set com.github.unrud.VideoDownloader automatic-subtitles "['de','en']"
```
## Debug
To display messages from **yt-dlp** run program with the environment variable `G_MESSAGES_DEBUG=yt-dlp`.
To display information about GOBject references, start the program with the environment variable `G_MESSAGES_DEBUG=gobject-ref`.
video-downloader-0.12.24/build-aux/ 0000775 0000000 0000000 00000000000 14773321552 0017025 5 ustar 00root root 0000000 0000000 video-downloader-0.12.24/build-aux/meson/ 0000775 0000000 0000000 00000000000 14773321552 0020146 5 ustar 00root root 0000000 0000000 video-downloader-0.12.24/build-aux/meson/create-gresource.py 0000664 0000000 0000000 00000001570 14773321552 0023762 0 ustar 00root root 0000000 0000000 import contextlib
import os
import sys
import xml.etree.ElementTree as ET
base_dirs = [
os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']),
os.path.join(os.environ['MESON_BUILD_ROOT'], os.environ['MESON_SUBDIR']),
]
_, prefix, *paths = sys.argv
xml = ET.ElementTree()
root_element = ET.Element('gresources')
xml._setroot(root_element)
resource_element = ET.Element('gresource')
root_element.append(resource_element)
resource_element.set('prefix', prefix)
for path in paths:
alias = path
for base_dir in base_dirs:
with contextlib.suppress(ValueError):
alias = min(alias, os.path.relpath(path, base_dir), key=len)
file_element = ET.Element('file')
resource_element.append(file_element)
file_element.set('alias', alias)
file_element.text = path
xml.write(sys.stdout.buffer, encoding='utf-8', xml_declaration=True)
video-downloader-0.12.24/build-aux/meson/extract-xml.py 0000664 0000000 0000000 00000001300 14773321552 0022762 0 ustar 00root root 0000000 0000000 import io
import sys
import xml.etree.ElementTree as ET
from xml.sax import saxutils
class CommentTreeBuilder(ET.TreeBuilder):
def comment(self, data):
self.start(ET.Comment, {})
self.data(data)
self.end(ET.Comment)
def make_xml_parser():
return ET.XMLParser(target=CommentTreeBuilder())
_, *flags, xml_path, search_xpath = sys.argv
xml = ET.parse(xml_path, parser=make_xml_parser())
for element in xml.findall(search_xpath):
xml._setroot(element)
f = io.StringIO()
xml.write(f, encoding='unicode')
xml_text = f.getvalue()
if '--escape' in flags:
xml_text = saxutils.escape(xml_text)
sys.stdout.buffer.write(xml_text.encode('utf-8'))
video-downloader-0.12.24/build-aux/meson/merge-xml.py 0000664 0000000 0000000 00000001133 14773321552 0022413 0 ustar 00root root 0000000 0000000 import sys
import xml.etree.ElementTree as ET
class CommentTreeBuilder(ET.TreeBuilder):
def comment(self, data):
self.start(ET.Comment, {})
self.data(data)
self.end(ET.Comment)
def make_xml_parser():
return ET.XMLParser(target=CommentTreeBuilder())
_, main_xml_path, insert_xml_path, insert_xpath = sys.argv
main_xml = ET.parse(main_xml_path, parser=make_xml_parser())
insert_xml = ET.parse(insert_xml_path, parser=make_xml_parser())
main_xml.find(insert_xpath).append(insert_xml.getroot())
main_xml.write(sys.stdout.buffer, encoding='utf-8', xml_declaration=True)
video-downloader-0.12.24/build-aux/meson/move.py 0000664 0000000 0000000 00000000362 14773321552 0021467 0 ustar 00root root 0000000 0000000 from os import environ, path, sys
from shutil import move
destdir = environ.get('DESTDIR', '')
prefix = environ['MESON_INSTALL_PREFIX']
source, dest = sys.argv[1:]
move(destdir + path.join(prefix, source), destdir + path.join(prefix, dest))
video-downloader-0.12.24/com.github.unrud.VideoDownloader.json 0000664 0000000 0000000 00000014744 14773321552 0024317 0 ustar 00root root 0000000 0000000 {
"app-id": "com.github.unrud.VideoDownloader",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "video-downloader",
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland",
"--filesystem=xdg-download/VideoDownloader:create"
],
"cleanup": [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"cleanup-commands": [
"mkdir -p /app/lib/ffmpeg"
],
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"directory": "lib/ffmpeg",
"version": "24.08",
"add-ld-path": "."
}
},
"modules": [
{
"name": "pyxattr",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=/app ."
],
"sources": [
{
"type": "archive",
"url": "https://github.com/iustin/pyxattr/archive/refs/tags/v0.8.1.tar.gz",
"sha256": "ce7ef783e751b96610a6eb32fc49a89340b5dc575fbe15054ce7935ebaf49edb",
"x-checker-data": {
"type": "json",
"url": "https://api.github.com/repos/iustin/pyxattr/releases/latest",
"version-query": ".tag_name",
"url-query": "\"https://github.com/iustin/pyxattr/archive/refs/tags/\" + $version + \".tar.gz\""
}
}
]
},
{
"name": "mutagen",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-build-isolation --prefix=/app ."
],
"sources": [
{
"type": "archive",
"url": "https://github.com/quodlibet/mutagen/archive/refs/tags/release-1.47.0.tar.gz",
"sha256": "f7489e19d375c31ba1962ab19e11eca8b9f86f05bfd99cef467f8dd875d8941e",
"x-checker-data": {
"type": "json",
"url": "https://api.github.com/repos/quodlibet/mutagen/releases/latest",
"version-query": ".tag_name",
"url-query": "\"https://github.com/quodlibet/mutagen/archive/refs/tags/\" + $version + \".tar.gz\""
}
}
]
},
{
"name": "pycryptodomex",
"buildsystem": "simple",
"build-commands": [
"touch .separate_namespace",
"pip3 install --no-build-isolation --prefix=/app ."
],
"sources": [
{
"type": "archive",
"url": "https://github.com/Legrandin/pycryptodome/archive/refs/tags/v3.22.0.tar.gz",
"sha256": "d1499d50dfe0628fe45157956e9c522011f37043a2d3f2457631c97e56f9e6c1",
"x-checker-data": {
"type": "json",
"url": "https://api.github.com/repos/Legrandin/pycryptodome/tags",
"version-query": "[.[].name | select(test(\"^v?[0-9.]+$\"))] | sort_by(sub(\"^v\"; \"\") | split(\".\") | map(tonumber))[-1]",
"url-query": "\"https://github.com/Legrandin/pycryptodome/archive/refs/tags/\" + $version + \".tar.gz\""
}
}
]
},
{
"name": "websockets",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-build-isolation --prefix=/app ."
],
"sources": [
{
"type": "archive",
"url": "https://github.com/aaugustin/websockets/archive/refs/tags/15.0.1.tar.gz",
"sha256": "8451495265af3e368f794c4dc15c99ce90c771d95560f542bff8c64b5455af3b",
"x-checker-data": {
"type": "json",
"url": "https://api.github.com/repos/aaugustin/websockets/tags",
"version-query": "[.[].name | select(test(\"^v?[0-9.]+$\"))] | sort_by(sub(\"^v\"; \"\") | split(\".\") | map(tonumber))[-1]",
"url-query": "\"https://github.com/aaugustin/websockets/archive/refs/tags/\" + $version + \".tar.gz\""
}
}
]
},
{
"name": "brotli",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=/app ."
],
"sources": [
{
"type": "archive",
"url": "https://github.com/google/brotli/archive/refs/tags/v1.1.0.tar.gz",
"sha256": "e720a6ca29428b803f4ad165371771f5398faba397edf6778837a18599ea13ff",
"x-checker-data": {
"type": "json",
"url": "https://api.github.com/repos/google/brotli/releases/latest",
"version-query": ".tag_name",
"url-query": "\"https://github.com/google/brotli/archive/refs/tags/\" + $version + \".tar.gz\""
}
}
]
},
{
"name": "yt-dlp",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-dependencies --prefix=/app \"$(echo *.whl)[default]\""
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/a8/bf/7b0affb8f163376309696cfd1c677818fa0969fbb9d88225087208799afe/yt_dlp-2025.3.31-py3-none-any.whl",
"sha256": "8ecb3aa218a3bebe431119f513a8972b9b9d992edf67168c00ab92329a03baec",
"x-checker-data": {
"type": "pypi",
"name": "yt-dlp",
"packagetype": "bdist_wheel"
}
}
]
},
{
"name": "video-downloader",
"builddir": true,
"buildsystem": "meson",
"sources": [
{
"type": "git",
"path": "."
}
]
}
]
}
video-downloader-0.12.24/data/ 0000775 0000000 0000000 00000000000 14773321552 0016044 5 ustar 00root root 0000000 0000000 video-downloader-0.12.24/data/com.github.unrud.VideoDownloader-symbolic.svg 0000664 0000000 0000000 00000001236 14773321552 0026665 0 ustar 00root root 0000000 0000000
video-downloader-0.12.24/data/com.github.unrud.VideoDownloader.Source.svg 0000664 0000000 0000000 00000065363 14773321552 0026320 0 ustar 00root root 0000000 0000000
video-downloader-0.12.24/data/com.github.unrud.VideoDownloader.desktop.in 0000664 0000000 0000000 00000000746 14773321552 0026332 0 ustar 00root root 0000000 0000000 [Desktop Entry]
Name=Video Downloader
Comment=Download web videos
Exec=video-downloader
Icon=com.github.unrud.VideoDownloader
Terminal=false
Type=Application
Categories=Network;GTK;
StartupNotify=true
X-GNOME-UsesNotifications=true
Actions=new-window;
# TRANSLATORS: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=YouTube;Download;
[Desktop Action new-window]
Name=New Window
Exec=video-downloader
video-downloader-0.12.24/data/com.github.unrud.VideoDownloader.gschema.xml 0000664 0000000 0000000 00000001334 14773321552 0026454 0 ustar 00root root 0000000 0000000
Fix format selection for extractors that provide either video width or height.
Stop downloader in case of error.
Fix link to download folder.
Remember last settings and switch to GTK.
Adjust menu colors to theme.
Fix crash with non-integer X DPI.
Move AppData to metainfo.
Download all videos in playlist.
Set window icon.
Make window resizeable and fix font sizes.
Stop progress bar jumping around.
Support videos with emoticons in the title.
Initial release.
Download videos from websites with an easy-to-use interface. Provides the following features:
Based on yt-dlp.