### 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.26/build-aux/ 0000775 0000000 0000000 00000000000 15047450103 0017015 5 ustar 00root root 0000000 0000000 video-downloader-0.12.26/build-aux/meson/ 0000775 0000000 0000000 00000000000 15047450103 0020136 5 ustar 00root root 0000000 0000000 video-downloader-0.12.26/build-aux/meson/create-gresource.py 0000664 0000000 0000000 00000001570 15047450103 0023752 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.26/build-aux/meson/extract-xml.py 0000664 0000000 0000000 00000001300 15047450103 0022752 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.26/build-aux/meson/merge-xml.py 0000664 0000000 0000000 00000001133 15047450103 0022403 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.26/build-aux/meson/move.py 0000664 0000000 0000000 00000000362 15047450103 0021457 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.26/com.github.unrud.VideoDownloader.json 0000664 0000000 0000000 00000014744 15047450103 0024307 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.23.0.tar.gz",
"sha256": "5a905f0f4237b79aefee47f3e04568db2ecb70c55dd7cb118974c5260aa9e285",
"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/ea/18/bbccb18661a853c3db947152439229b9bf686fe0ab2cc7848ab3a24f2ad2/yt_dlp-2025.4.30-py3-none-any.whl",
"sha256": "53cd82bf13f12a1fe9c564b0004e001156b153c9247fa3cef14d1400ab359150",
"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.26/data/ 0000775 0000000 0000000 00000000000 15047450103 0016034 5 ustar 00root root 0000000 0000000 video-downloader-0.12.26/data/com.github.unrud.VideoDownloader-symbolic.svg 0000664 0000000 0000000 00000001236 15047450103 0026655 0 ustar 00root root 0000000 0000000
video-downloader-0.12.26/data/com.github.unrud.VideoDownloader.Source.svg 0000664 0000000 0000000 00000065363 15047450103 0026310 0 ustar 00root root 0000000 0000000
video-downloader-0.12.26/data/com.github.unrud.VideoDownloader.desktop.in 0000664 0000000 0000000 00000000746 15047450103 0026322 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.26/data/com.github.unrud.VideoDownloader.gschema.xml 0000664 0000000 0000000 00000001334 15047450103 0026444 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.