add the ability to reload 'YTDL_OPTIONS' when file is modified

This commit is contained in:
xerdream 2025-07-21 11:20:53 +08:00
parent ca0aac4051
commit afbf8b07d6
7 changed files with 215 additions and 2 deletions

View File

@ -12,6 +12,7 @@ python-socketio = "~=5.0"
yt-dlp = "*" yt-dlp = "*"
mutagen = "*" mutagen = "*"
curl-cffi = "*" curl-cffi = "*"
watchfiles = "*"
[requires] [requires]
python_version = "3.13" python_version = "3.13"

131
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "0059b3e28e6bdffb0cb683014be12e747d67ba50c78953a1f49d1418e877807b" "sha256": "b987a00631108daa5b36fc6f461bd285b5817f524ac986ae57d3d12744685a38"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -125,6 +125,14 @@
"markers": "python_version >= '3.9'", "markers": "python_version >= '3.9'",
"version": "==1.3.2" "version": "==1.3.2"
}, },
"anyio": {
"hashes": [
"sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028",
"sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"
],
"markers": "python_version >= '3.9'",
"version": "==4.9.0"
},
"attrs": { "attrs": {
"hashes": [ "hashes": [
"sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3",
@ -621,6 +629,127 @@
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==1.1.0" "version": "==1.1.0"
}, },
"sniffio": {
"hashes": [
"sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",
"sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
],
"markers": "python_version >= '3.7'",
"version": "==1.3.1"
},
"watchfiles": {
"hashes": [
"sha256:00645eb79a3faa70d9cb15c8d4187bb72970b2470e938670240c7998dad9f13a",
"sha256:04e4ed5d1cd3eae68c89bcc1a485a109f39f2fd8de05f705e98af6b5f1861f1f",
"sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6",
"sha256:0ece16b563b17ab26eaa2d52230c9a7ae46cf01759621f4fbbca280e438267b3",
"sha256:11ee4444250fcbeb47459a877e5e80ed994ce8e8d20283857fc128be1715dac7",
"sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a",
"sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259",
"sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297",
"sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1",
"sha256:199207b2d3eeaeb80ef4411875a6243d9ad8bc35b07fc42daa6b801cc39cc41c",
"sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a",
"sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b",
"sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb",
"sha256:27f30e14aa1c1e91cb653f03a63445739919aef84c8d2517997a83155e7a2fcc",
"sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b",
"sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339",
"sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9",
"sha256:3366f56c272232860ab45c77c3ca7b74ee819c8e1f6f35a7125556b198bbc6df",
"sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb",
"sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4",
"sha256:3a6fd40bbb50d24976eb275ccb55cd1951dfb63dbc27cae3066a6ca5f4beabd5",
"sha256:3aba215958d88182e8d2acba0fdaf687745180974946609119953c0e112397dc",
"sha256:406520216186b99374cdb58bc48e34bb74535adec160c8459894884c983a149c",
"sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8",
"sha256:42f92befc848bb7a19658f21f3e7bae80d7d005d13891c62c2cd4d4d0abb3433",
"sha256:48aa25e5992b61debc908a61ab4d3f216b64f44fdaa71eb082d8b2de846b7d12",
"sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30",
"sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0",
"sha256:51556d5004887045dba3acdd1fdf61dddea2be0a7e18048b5e853dcd37149b86",
"sha256:51b81e55d40c4b4aa8658427a3ee7ea847c591ae9e8b81ef94a90b668999353c",
"sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5",
"sha256:54062ef956807ba806559b3c3d52105ae1827a0d4ab47b621b31132b6b7e2866",
"sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb",
"sha256:622d6b2c06be19f6e89b1d951485a232e3b59618def88dbeda575ed8f0d8dbf2",
"sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e",
"sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575",
"sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f",
"sha256:7049e52167fc75fc3cc418fc13d39a8e520cbb60ca08b47f6cedb85e181d2f2a",
"sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f",
"sha256:7738027989881e70e3723c75921f1efa45225084228788fc59ea8c6d732eb30d",
"sha256:7a7bd57a1bb02f9d5c398c0c1675384e7ab1dd39da0ca50b7f09af45fa435277",
"sha256:7b3443f4ec3ba5aa00b0e9fa90cf31d98321cbff8b925a7c7b84161619870bc9",
"sha256:7c55b0f9f68590115c25272b06e63f0824f03d4fc7d6deed43d8ad5660cabdbf",
"sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92",
"sha256:8076a5769d6bdf5f673a19d51da05fc79e2bbf25e9fe755c47595785c06a8c72",
"sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b",
"sha256:8412eacef34cae2836d891836a7fff7b754d6bcac61f6c12ba5ca9bc7e427b68",
"sha256:865c8e95713744cf5ae261f3067861e9da5f1370ba91fc536431e29b418676fa",
"sha256:86b1e28d4c37e89220e924305cd9f82866bb0ace666943a6e4196c5df4d58dcc",
"sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b",
"sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd",
"sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4",
"sha256:90ebb429e933645f3da534c89b29b665e285048973b4d2b6946526888c3eb2c7",
"sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792",
"sha256:935f9edd022ec13e447e5723a7d14456c8af254544cefbc533f6dd276c9aa0d9",
"sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0",
"sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297",
"sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef",
"sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179",
"sha256:9f811079d2f9795b5d48b55a37aa7773680a5659afe34b54cc1d86590a51507d",
"sha256:a2726d7bfd9f76158c84c10a409b77a320426540df8c35be172444394b17f7ea",
"sha256:a479466da6db5c1e8754caee6c262cd373e6e6c363172d74394f4bff3d84d7b5",
"sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee",
"sha256:a89c75a5b9bc329131115a409d0acc16e8da8dfd5867ba59f1dd66ae7ea8fa82",
"sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011",
"sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e",
"sha256:aa0cc8365ab29487eb4f9979fd41b22549853389e22d5de3f134a6796e1b05a4",
"sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf",
"sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db",
"sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20",
"sha256:b7c5f6fe273291f4d414d55b2c80d33c457b8a42677ad14b4b47ff025d0893e4",
"sha256:b915daeb2d8c1f5cee4b970f2e2c988ce6514aace3c9296e58dd64dc9aa5d575",
"sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa",
"sha256:bda8136e6a80bdea23e5e74e09df0362744d24ffb8cd59c4a95a6ce3d142f79c",
"sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f",
"sha256:c588c45da9b08ab3da81d08d7987dae6d2a3badd63acdb3e206a42dbfa7cb76f",
"sha256:c600e85f2ffd9f1035222b1a312aff85fd11ea39baff1d705b9b047aad2ce267",
"sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018",
"sha256:c9649dfc57cc1f9835551deb17689e8d44666315f2e82d337b9f07bd76ae3aa2",
"sha256:cb45350fd1dc75cd68d3d72c47f5b513cb0578da716df5fba02fff31c69d5f2d",
"sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd",
"sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47",
"sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb",
"sha256:cd17a1e489f02ce9117b0de3c0b1fab1c3e2eedc82311b299ee6b6faf6c23a29",
"sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147",
"sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8",
"sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670",
"sha256:d1caf40c1c657b27858f9774d5c0e232089bca9cb8ee17ce7478c6e9264d2587",
"sha256:d7642b9bc4827b5518ebdb3b82698ada8c14c7661ddec5fe719f3e56ccd13c97",
"sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c",
"sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5",
"sha256:da71945c9ace018d8634822f16cbc2a78323ef6c876b1d34bbf5d5222fd6a72e",
"sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e",
"sha256:df32d59cb9780f66d165a9a7a26f19df2c7d24e3bd58713108b41d0ff4f929c6",
"sha256:df670918eb7dd719642e05979fc84704af913d563fd17ed636f7c4783003fdcc",
"sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e",
"sha256:ed8fc66786de8d0376f9f913c09e963c66e90ced9aa11997f93bdb30f7c872a8",
"sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895",
"sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7",
"sha256:f2bcdc54ea267fe72bfc7d83c041e4eb58d7d8dc6f578dfddb52f037ce62f432",
"sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc",
"sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633",
"sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f",
"sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77",
"sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12",
"sha256:fe4371595edf78c41ef8ac8df20df3943e13defd0efcb732b2e393b5a8a7a71f"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.1.0"
},
"wsproto": { "wsproto": {
"hashes": [ "hashes": [
"sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065",

View File

@ -61,6 +61,7 @@ Certain values can be set via environment variables, using the `-e` parameter on
* __DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT__: Maximum number of playlist items that can be downloaded. Defaults to `0` (no limit). * __DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT__: Maximum number of playlist items that can be downloaded. Defaults to `0` (no limit).
* __YTDL_OPTIONS__: Additional options to pass to yt-dlp, in JSON format. [See available options here](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L220). They roughly correspond to command-line options, though some do not have exact equivalents here, for example `--recode-video` has to be specified via `postprocessors`. Also note that dashes are replaced with underscores. You may find [this script](https://github.com/yt-dlp/yt-dlp/blob/master/devscripts/cli_to_api.py) helpful for converting from command line options to `YTDL_OPTIONS`. * __YTDL_OPTIONS__: Additional options to pass to yt-dlp, in JSON format. [See available options here](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L220). They roughly correspond to command-line options, though some do not have exact equivalents here, for example `--recode-video` has to be specified via `postprocessors`. Also note that dashes are replaced with underscores. You may find [this script](https://github.com/yt-dlp/yt-dlp/blob/master/devscripts/cli_to_api.py) helpful for converting from command line options to `YTDL_OPTIONS`.
* __YTDL_OPTIONS_FILE__: A path to a JSON file that will be loaded and used for populating `YTDL_OPTIONS` above. Please note that if both `YTDL_OPTIONS_FILE` and `YTDL_OPTIONS` are specified, the options in `YTDL_OPTIONS` take precedence. * __YTDL_OPTIONS_FILE__: A path to a JSON file that will be loaded and used for populating `YTDL_OPTIONS` above. Please note that if both `YTDL_OPTIONS_FILE` and `YTDL_OPTIONS` are specified, the options in `YTDL_OPTIONS` take precedence.
* __YTDL_OPTIONS_FILE_RELOAD__:Reload `YTDL_OPTIONS` when file is modified. Defaults to `false`.
* __ROBOTS_TXT__: A path to a `robots.txt` file mounted in the container * __ROBOTS_TXT__: A path to a `robots.txt` file mounted in the container
* __DOWNLOAD_MODE__ :This flag controls how downloads are scheduled and executed. Options are `sequential`, `concurrent`, and `limited`. Defaults to `limited`: * __DOWNLOAD_MODE__ :This flag controls how downloads are scheduled and executed. Options are `sequential`, `concurrent`, and `limited`. Defaults to `limited`:
* `sequential`: Downloads are processed one at a time. A new download wont start until the previous one has finished. This mode is useful for conserving system resources or ensuring downloads occur in a strict order. * `sequential`: Downloads are processed one at a time. A new download wont start until the previous one has finished. This mode is useful for conserving system resources or ensuring downloads occur in a strict order.

View File

@ -3,6 +3,8 @@
import os import os
import sys import sys
import asyncio
from pathlib import Path
from aiohttp import web from aiohttp import web
from aiohttp.log import access_logger from aiohttp.log import access_logger
import ssl import ssl
@ -12,6 +14,7 @@ import logging
import json import json
import pathlib import pathlib
import re import re
from watchfiles import DefaultFilter, Change, awatch
from ytdl import DownloadQueueNotifier, DownloadQueue from ytdl import DownloadQueueNotifier, DownloadQueue
from yt_dlp.version import __version__ as yt_dlp_version from yt_dlp.version import __version__ as yt_dlp_version
@ -39,6 +42,7 @@ class Config:
'DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT' : '0', 'DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT' : '0',
'YTDL_OPTIONS': '{}', 'YTDL_OPTIONS': '{}',
'YTDL_OPTIONS_FILE': '', 'YTDL_OPTIONS_FILE': '',
'YTDL_OPTIONS_FILE_RELOAD': 'false',
'ROBOTS_TXT': '', 'ROBOTS_TXT': '',
'HOST': '0.0.0.0', 'HOST': '0.0.0.0',
'PORT': '8081', 'PORT': '8081',
@ -53,7 +57,7 @@ class Config:
'ENABLE_ACCESSLOG': 'false', 'ENABLE_ACCESSLOG': 'false',
} }
_BOOLEAN = ('DOWNLOAD_DIRS_INDEXABLE', 'CUSTOM_DIRS', 'CREATE_CUSTOM_DIRS', 'DELETE_FILE_ON_TRASHCAN', 'DEFAULT_OPTION_PLAYLIST_STRICT_MODE', 'HTTPS', 'ENABLE_ACCESSLOG') _BOOLEAN = ('DOWNLOAD_DIRS_INDEXABLE', 'CUSTOM_DIRS', 'CREATE_CUSTOM_DIRS', 'DELETE_FILE_ON_TRASHCAN', 'DEFAULT_OPTION_PLAYLIST_STRICT_MODE', 'HTTPS', 'ENABLE_ACCESSLOG','YTDL_OPTIONS_FILE_RELOAD')
def __init__(self): def __init__(self):
for k, v in self._DEFAULTS.items(): for k, v in self._DEFAULTS.items():
@ -92,6 +96,33 @@ class Config:
sys.exit(1) sys.exit(1)
self.YTDL_OPTIONS.update(opts) self.YTDL_OPTIONS.update(opts)
if self.YTDL_OPTIONS_FILE_RELOAD and not self.YTDL_OPTIONS_FILE:
log.error('YTDL_OPTIONS_FILE_RELOAD is enabled but YTDL_OPTIONS_FILE is not set. ')
sys.exit(1)
def load_ytdl_options_file(self) -> tuple[bool, str]:
msg = ''
if not self.YTDL_OPTIONS_FILE:
msg='YTDL_OPTIONS_FILE is not set'
log.error(msg)
return (False, msg)
log.info(f'Loading yt-dlp custom options from "{self.YTDL_OPTIONS_FILE}"')
if not os.path.exists(self.YTDL_OPTIONS_FILE):
msg = f'File "{self.YTDL_OPTIONS_FILE}" not found'
log.error(msg)
return (False, msg)
try:
with open(self.YTDL_OPTIONS_FILE) as json_data:
opts = json.load(json_data)
assert isinstance(opts, dict)
except (json.decoder.JSONDecodeError, AssertionError):
msg = 'YTDL_OPTIONS_FILE contents is invalid'
log.error(msg)
return (False, msg)
self.YTDL_OPTIONS.update(opts)
return (True, msg)
config = Config() config = Config()
class ObjectSerializer(json.JSONEncoder): class ObjectSerializer(json.JSONEncoder):
@ -131,6 +162,31 @@ class Notifier(DownloadQueueNotifier):
dqueue = DownloadQueue(config, Notifier()) dqueue = DownloadQueue(config, Notifier())
app.on_startup.append(lambda app: dqueue.initialize()) app.on_startup.append(lambda app: dqueue.initialize())
class FileOpsFilter(DefaultFilter):
def __call__(self, change_type: int, path: str) -> bool:
return (os.path.samefile(path, config.YTDL_OPTIONS_FILE) and
change_type in (Change.modified,Change.added))
def get_options_update_time(success=True, msg=''):
result = {
'success': success,
'msg': msg,
'update_time': os.path.getmtime(config.YTDL_OPTIONS_FILE)
}
return result
async def watch_files():
path_to_watch = Path(config.YTDL_OPTIONS_FILE).resolve()
async def _watch_files():
async for changes in awatch(path_to_watch, watch_filter=FileOpsFilter()):
success, msg = config.load_ytdl_options_file()
result = get_options_update_time(success, msg)
await sio.emit('ytdl_options_changed', serializer.encode(result))
log.info(f'Starting Watch File: {path_to_watch}')
asyncio.create_task(_watch_files())
if config.YTDL_OPTIONS_FILE_RELOAD:
app.on_startup.append(lambda app: watch_files())
@routes.post(config.URL_PREFIX + 'add') @routes.post(config.URL_PREFIX + 'add')
async def add(request): async def add(request):
log.info("Received request to add download") log.info("Received request to add download")
@ -203,6 +259,8 @@ async def connect(sid, environ):
await sio.emit('configuration', serializer.encode(config), to=sid) await sio.emit('configuration', serializer.encode(config), to=sid)
if config.CUSTOM_DIRS: if config.CUSTOM_DIRS:
await sio.emit('custom_dirs', serializer.encode(get_custom_dirs()), to=sid) await sio.emit('custom_dirs', serializer.encode(get_custom_dirs()), to=sid)
if config.YTDL_OPTIONS_FILE_RELOAD:
await sio.emit('ytdl_options_changed', serializer.encode(get_options_update_time()), to=sid)
def get_custom_dirs(): def get_custom_dirs():
def recursive_dirs(base): def recursive_dirs(base):

View File

@ -388,6 +388,11 @@
<span class="version-value">{{metubeVersion}}</span> <span class="version-value">{{metubeVersion}}</span>
</div> </div>
<div class="version-separator"></div> <div class="version-separator"></div>
<div class="version-item" *ngIf="ytDlpOptionsUpdateTime">
<span class="version-label">yt-dlp-options</span>
<span class="version-value">{{ytDlpOptionsUpdateTime}}</span>
</div>
<div class="version-separator" *ngIf="ytDlpOptionsUpdateTime"></div>
<a href="https://github.com/alexta69/metube" target="_blank" class="github-link"> <a href="https://github.com/alexta69/metube" target="_blank" class="github-link">
<fa-icon [icon]="faGithub"></fa-icon> <fa-icon [icon]="faGithub"></fa-icon>
<span>GitHub</span> <span>GitHub</span>

View File

@ -39,6 +39,7 @@ export class AppComponent implements AfterViewInit {
batchImportStatus = ''; batchImportStatus = '';
importInProgress = false; importInProgress = false;
cancelImportFlag = false; cancelImportFlag = false;
ytDlpOptionsUpdateTime: string | null = null;
ytDlpVersion: string | null = null; ytDlpVersion: string | null = null;
metubeVersion: string | null = null; metubeVersion: string | null = null;
isAdvancedOpen = false; isAdvancedOpen = false;
@ -101,6 +102,7 @@ export class AppComponent implements AfterViewInit {
ngOnInit() { ngOnInit() {
this.getConfiguration(); this.getConfiguration();
this.getYtdlOptionsUpdateTime();
this.customDirs$ = this.getMatchingCustomDir(); this.customDirs$ = this.getMatchingCustomDir();
this.setTheme(this.activeTheme); this.setTheme(this.activeTheme);
@ -174,6 +176,18 @@ export class AppComponent implements AfterViewInit {
); );
} }
getYtdlOptionsUpdateTime() {
this.downloads.ytdlOptionsChanged.subscribe({
next: (data) => {
if (data['success']){
const date = new Date(data['update_time'] * 1000);
this.ytDlpOptionsUpdateTime=date.toLocaleString();
}else{
alert("Error reload yt-dlp options: "+data['msg']);
}
}
});
}
getConfiguration() { getConfiguration() {
this.downloads.configurationChanged.subscribe({ this.downloads.configurationChanged.subscribe({
next: (config) => { next: (config) => {

View File

@ -39,6 +39,7 @@ export class DownloadsService {
queueChanged = new Subject(); queueChanged = new Subject();
doneChanged = new Subject(); doneChanged = new Subject();
customDirsChanged = new Subject(); customDirsChanged = new Subject();
ytdlOptionsChanged = new Subject();
configurationChanged = new Subject(); configurationChanged = new Subject();
updated = new Subject(); updated = new Subject();
@ -98,6 +99,10 @@ export class DownloadsService {
this.customDirs = data; this.customDirs = data;
this.customDirsChanged.next(data); this.customDirsChanged.next(data);
}); });
socket.fromEvent('ytdl_options_changed').subscribe((strdata: string) => {
let data = JSON.parse(strdata);
this.ytdlOptionsChanged.next(data);
});
} }
handleHTTPError(error: HttpErrorResponse) { handleHTTPError(error: HttpErrorResponse) {