Fill in download_dir or audio_download_dir on launch
This commit is contained in:
parent
8abacc2a36
commit
ba712fc071
@ -35,9 +35,9 @@ Certain values can be set via environment variables, using the `-e` parameter on
|
|||||||
* __GID__: group under which MeTube will run. Defaults to `1000`.
|
* __GID__: group under which MeTube will run. Defaults to `1000`.
|
||||||
* __UMASK__: umask value used by MeTube. Defaults to `022`.
|
* __UMASK__: umask value used by MeTube. Defaults to `022`.
|
||||||
* __DOWNLOAD_DIR__: path to where the downloads will be saved. Defaults to `/downloads` in the docker image, and `.` otherwise.
|
* __DOWNLOAD_DIR__: path to where the downloads will be saved. Defaults to `/downloads` in the docker image, and `.` otherwise.
|
||||||
* __CUSTOM_DIR__: whether to enable downloading videos into folders within the __DOWNLOAD_DIR__. Defaults to `true`.
|
|
||||||
* __AUTO_CREATE_CUSTOM_DIR__: whether to support automatically creating folders within the __DOWNLOAD_DIR__ if they do not exist. Defaults to `false`.
|
|
||||||
* __AUDIO_DOWNLOAD_DIR__: path to where audio-only downloads will be saved, if you wish to separate them from the video downloads. Defaults to the value of `DOWNLOAD_DIR`.
|
* __AUDIO_DOWNLOAD_DIR__: path to where audio-only downloads will be saved, if you wish to separate them from the video downloads. Defaults to the value of `DOWNLOAD_DIR`.
|
||||||
|
* __CUSTOM_DIRS__: whether to enable downloading videos into custom directories within the __DOWNLOAD_DIR__ (or __AUDIO_DOWNLOAD_DIR__). When enabled, a drop-down appears next to the Add button to specify the download directory. Defaults to `true`.
|
||||||
|
* __CREATE_DIRS__: whether to support automatically creating directories within the __DOWNLOAD_DIR__ (or __AUDIO_DOWNLOAD_DIR__) if they do not exist. When enabled, the download directory selector becomes supports free-text input, and the specified directory will be created recursively. Defaults to `false`.
|
||||||
* __STATE_DIR__: path to where the queue persistence files will be saved. Defaults to `/downloads/.metube` in the docker image, and `.` otherwise.
|
* __STATE_DIR__: path to where the queue persistence files will be saved. Defaults to `/downloads/.metube` in the docker image, and `.` otherwise.
|
||||||
* __URL_PREFIX__: base path for the web server (for use when hosting behind a reverse proxy). Defaults to `/`.
|
* __URL_PREFIX__: base path for the web server (for use when hosting behind a reverse proxy). Defaults to `/`.
|
||||||
* __OUTPUT_TEMPLATE__: the template for the filenames of the downloaded videos, formatted according to [this spec](https://github.com/yt-dlp/yt-dlp/blob/master/README.md#output-template). Defaults to `%(title)s.%(ext)s`.
|
* __OUTPUT_TEMPLATE__: the template for the filenames of the downloaded videos, formatted according to [this spec](https://github.com/yt-dlp/yt-dlp/blob/master/README.md#output-template). Defaults to `%(title)s.%(ext)s`.
|
||||||
|
43
app/main.py
43
app/main.py
@ -17,8 +17,8 @@ class Config:
|
|||||||
_DEFAULTS = {
|
_DEFAULTS = {
|
||||||
'DOWNLOAD_DIR': '.',
|
'DOWNLOAD_DIR': '.',
|
||||||
'AUDIO_DOWNLOAD_DIR': '%%DOWNLOAD_DIR',
|
'AUDIO_DOWNLOAD_DIR': '%%DOWNLOAD_DIR',
|
||||||
'CUSTOM_DIR': 'true',
|
'CUSTOM_DIRS': 'true',
|
||||||
'AUTO_CREATE_CUSTOM_DIR': 'false',
|
'CREATE_DIRS': 'false',
|
||||||
'STATE_DIR': '.',
|
'STATE_DIR': '.',
|
||||||
'URL_PREFIX': '',
|
'URL_PREFIX': '',
|
||||||
'OUTPUT_TEMPLATE': '%(title)s.%(ext)s',
|
'OUTPUT_TEMPLATE': '%(title)s.%(ext)s',
|
||||||
@ -101,18 +101,39 @@ async def delete(request):
|
|||||||
async def connect(sid, environ):
|
async def connect(sid, environ):
|
||||||
await sio.emit('all', serializer.encode(dqueue.get()), to=sid)
|
await sio.emit('all', serializer.encode(dqueue.get()), to=sid)
|
||||||
await sio.emit('configuration', serializer.encode(config), to=sid)
|
await sio.emit('configuration', serializer.encode(config), to=sid)
|
||||||
if config.CUSTOM_DIR:
|
if config.CUSTOM_DIRS:
|
||||||
await sio.emit('custom_directories', serializer.encode(get_custom_directories()), to=sid)
|
await sio.emit('custom_dirs', serializer.encode(get_custom_dirs()), to=sid)
|
||||||
|
|
||||||
def get_custom_directories():
|
def get_custom_dirs():
|
||||||
path = pathlib.Path(config.DOWNLOAD_DIR)
|
def recursive_dirs(base):
|
||||||
# Recursively lists all subdirectories, and converts PosixPath objects to string
|
path = pathlib.Path(base)
|
||||||
dirs = list(map(str, path.glob('**')))
|
|
||||||
|
|
||||||
if '.' in dirs:
|
# Converts PosixPath object to string, and remove base/ prefix
|
||||||
dirs.remove('.')
|
def convert(p):
|
||||||
|
s = str(p)
|
||||||
|
if s.startswith(base):
|
||||||
|
s = s[len(base):]
|
||||||
|
|
||||||
return {"directories": dirs}
|
if s.startswith('/'):
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
# Recursively lists all subdirectories of DOWNLOAD_DIR
|
||||||
|
dirs = list(filter(None, map(convert, path.glob('**'))))
|
||||||
|
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
download_dir = recursive_dirs(config.DOWNLOAD_DIR)
|
||||||
|
|
||||||
|
audio_download_dir = download_dir
|
||||||
|
if config.DOWNLOAD_DIR != config.AUDIO_DOWNLOAD_DIR:
|
||||||
|
audio_download_dir = recursive_dirs(config.AUDIO_DOWNLOAD_DIR)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"download_dir": download_dir,
|
||||||
|
"audio_download_dir": audio_download_dir
|
||||||
|
}
|
||||||
|
|
||||||
@routes.get(config.URL_PREFIX)
|
@routes.get(config.URL_PREFIX)
|
||||||
def index(request):
|
def index(request):
|
||||||
|
@ -228,16 +228,17 @@ class DownloadQueue:
|
|||||||
elif etype == 'video' or etype.startswith('url') and 'id' in entry and 'title' in entry:
|
elif etype == 'video' or etype.startswith('url') and 'id' in entry and 'title' in entry:
|
||||||
if not self.queue.exists(entry['id']):
|
if not self.queue.exists(entry['id']):
|
||||||
dl = DownloadInfo(entry['id'], entry['title'], entry.get('webpage_url') or entry['url'], quality, format, folder)
|
dl = DownloadInfo(entry['id'], entry['title'], entry.get('webpage_url') or entry['url'], quality, format, folder)
|
||||||
|
# Keep consistent with frontend
|
||||||
base_directory = self.config.DOWNLOAD_DIR if (quality != 'audio' and format != 'mp3') else self.config.AUDIO_DOWNLOAD_DIR
|
base_directory = self.config.DOWNLOAD_DIR if (quality != 'audio' and format != 'mp3') else self.config.AUDIO_DOWNLOAD_DIR
|
||||||
if folder:
|
if folder:
|
||||||
if self.config.CUSTOM_DIR != 'true':
|
if self.config.CUSTOM_DIRS != 'true':
|
||||||
return {'status': 'error', 'msg': f'A folder for the download was specified but CUSTOM_DIR is not true in the configuration.'}
|
return {'status': 'error', 'msg': f'A folder for the download was specified but CUSTOM_DIRS is not true in the configuration.'}
|
||||||
dldirectory = os.path.realpath(os.path.join(base_directory, folder))
|
dldirectory = os.path.realpath(os.path.join(base_directory, folder))
|
||||||
if not dldirectory.startswith(base_directory):
|
if not dldirectory.startswith(base_directory):
|
||||||
return {'status': 'error', 'msg': f'Folder "{folder}" must resolve inside the base download directory "{base_directory}"'}
|
return {'status': 'error', 'msg': f'Folder "{folder}" must resolve inside the base download directory "{base_directory}"'}
|
||||||
if not os.path.isdir(dldirectory):
|
if not os.path.isdir(dldirectory):
|
||||||
if self.config.AUTO_CREATE_CUSTOM_DIR != 'true':
|
if self.config.CREATE_DIRS != 'true':
|
||||||
return {'status': 'error', 'msg': f'Folder "{folder}" for download does not exist, and AUTO_CREATE_CUSTOM_DIR is not true in the configuration.'}
|
return {'status': 'error', 'msg': f'Folder "{folder}" for download does not exist inside base directory "{base_directory}", and CREATE_DIRS is not true in the configuration.'}
|
||||||
os.makedirs(dldirectory, exist_ok=True)
|
os.makedirs(dldirectory, exist_ok=True)
|
||||||
else:
|
else:
|
||||||
dldirectory = base_directory
|
dldirectory = base_directory
|
||||||
|
@ -32,13 +32,10 @@
|
|||||||
],
|
],
|
||||||
"stylePreprocessorOptions": {
|
"stylePreprocessorOptions": {
|
||||||
"includePaths": [
|
"includePaths": [
|
||||||
"node_modules/@selectize/selectize/dist/scss/selectize.bootstrap5.scss"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"node_modules/jquery/dist/jquery.min.js",
|
|
||||||
"node_modules/bootstrap/dist/js/bootstrap.min.js",
|
"node_modules/bootstrap/dist/js/bootstrap.min.js",
|
||||||
"node_modules/@selectize/selectize/dist/js/standalone/selectize.min.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
|
238
ui/package-lock.json
generated
238
ui/package-lock.json
generated
@ -22,7 +22,7 @@
|
|||||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
|
||||||
"@selectize/selectize": "^0.13.6",
|
"@ng-select/ng-select": "^8.3.0",
|
||||||
"bootstrap": "^5.0.0",
|
"bootstrap": "^5.0.0",
|
||||||
"ngx-cookie-service": "^13.0.0",
|
"ngx-cookie-service": "^13.0.0",
|
||||||
"ngx-socket-io": "^4.2.0",
|
"ngx-socket-io": "^4.2.0",
|
||||||
@ -2530,6 +2530,23 @@
|
|||||||
"rxjs": "^6.5.3 || ^7.4.0"
|
"rxjs": "^6.5.3 || ^7.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ng-select/ng-select": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-AwAuDs+86++D2kEsik2/ZiQuRk0khd1HESofOm1yMBwbzsw+xLSyVOMml/OehDFSOxli7fAkk07wYtzAhxSB3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.20.0",
|
||||||
|
"npm": ">= 6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=13.0.0 <14.0.0",
|
||||||
|
"@angular/core": ">=13.0.0 <14.0.0",
|
||||||
|
"@angular/forms": ">=13.0.0 <14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ngtools/webpack": {
|
"node_modules/@ngtools/webpack": {
|
||||||
"version": "13.3.8",
|
"version": "13.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.8.tgz",
|
||||||
@ -2689,44 +2706,6 @@
|
|||||||
"yarn": ">= 1.13.0"
|
"yarn": ">= 1.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@selectize/selectize": {
|
|
||||||
"version": "0.13.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@selectize/selectize/-/selectize-0.13.6.tgz",
|
|
||||||
"integrity": "sha512-UVkHH92l/4zLH/acfukry419K2yAKiDf6VmFQ9hZzMpWW2epE7xJIgK47mJLjAQnimP0ROo8BStfwelWcoTQyg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@selectize/sifter": "^0.6.2",
|
|
||||||
"microplugin": "0.0.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"jquery-ui": "^1.13.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"jquery": "^1.7.0 || ^2 || ^3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@selectize/sifter": {
|
|
||||||
"version": "0.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@selectize/sifter/-/sifter-0.6.2.tgz",
|
|
||||||
"integrity": "sha512-rpWQuzaCEV2GOEfBmP5NGST3IsA/RGRd3vugOGQVxAaN1xMI9tsrMmx5rC811iInq6OeFH3Jix5EfglYQ3XwKQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"async": "^3.2.3",
|
|
||||||
"cardinal": "^2.1.1",
|
|
||||||
"csv-parse": "^5.0.4",
|
|
||||||
"humanize": "^0.0.9",
|
|
||||||
"optimist": "^0.5.2"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"sifter": "bin/sifter.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@selectize/sifter/node_modules/async": {
|
|
||||||
"version": "3.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
|
||||||
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
|
|
||||||
},
|
|
||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
@ -3338,11 +3317,6 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansicolors": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg=="
|
|
||||||
},
|
|
||||||
"node_modules/anymatch": {
|
"node_modules/anymatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||||
@ -3945,18 +3919,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/cardinal": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansicolors": "~0.3.2",
|
|
||||||
"redeyed": "~2.1.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"cdl": "bin/cdl.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
@ -4760,11 +4722,6 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/csv-parse": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-UXJCGwvJ2fep39purtAn27OUYmxB1JQto+zhZ4QlJpzsirtSFbzLvip1aIgziqNdZp/TptvsKEV5BZSxe10/DQ=="
|
|
||||||
},
|
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -5611,6 +5568,7 @@
|
|||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"esparse": "bin/esparse.js",
|
"esparse": "bin/esparse.js",
|
||||||
"esvalidate": "bin/esvalidate.js"
|
"esvalidate": "bin/esvalidate.js"
|
||||||
@ -6471,14 +6429,6 @@
|
|||||||
"node": ">=10.17.0"
|
"node": ">=10.17.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/humanize": {
|
|
||||||
"version": "0.0.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz",
|
|
||||||
"integrity": "sha512-bvZZ7vXpr1RKoImjuQ45hJb5OvE2oJafHysiD/AL3nkqTZH2hFCjQ3YZfCd63FefDitbJze/ispUPP0gfDsT2Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/humanize-ms": {
|
"node_modules/humanize-ms": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||||
@ -7072,20 +7022,6 @@
|
|||||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jquery": {
|
|
||||||
"version": "3.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
|
|
||||||
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
|
|
||||||
},
|
|
||||||
"node_modules/jquery-ui": {
|
|
||||||
"version": "1.13.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz",
|
|
||||||
"integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"jquery": ">=1.8.0 <4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -7568,14 +7504,6 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/microplugin": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/microplugin/-/microplugin-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-3wKXex4/iyALV0GX2juow66J9dabkEMgHeZAihdLTaRTzm0N+RubXioNPpfIQDPuBRxr3JbjNt7B0Lr/3yE9yQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime": {
|
"node_modules/mime": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
@ -8458,14 +8386,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/optimist": {
|
|
||||||
"version": "0.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.5.2.tgz",
|
|
||||||
"integrity": "sha512-r9M8ZpnM9SXV5Wii7TCqienfcaY3tAiJe9Jchof87icbmbruKgK0xKXngmrnowTDnEawmmI1Qbha59JEoBkBGA==",
|
|
||||||
"dependencies": {
|
|
||||||
"wordwrap": "~0.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ora": {
|
"node_modules/ora": {
|
||||||
"version": "5.4.1",
|
"version": "5.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
||||||
@ -9670,14 +9590,6 @@
|
|||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redeyed": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"esprima": "~4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/reflect-metadata": {
|
"node_modules/reflect-metadata": {
|
||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||||
@ -11622,14 +11534,6 @@
|
|||||||
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
|
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/wordwrap": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi": {
|
"node_modules/wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
@ -13511,6 +13415,14 @@
|
|||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ng-select/ng-select": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-AwAuDs+86++D2kEsik2/ZiQuRk0khd1HESofOm1yMBwbzsw+xLSyVOMml/OehDFSOxli7fAkk07wYtzAhxSB3Q==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ngtools/webpack": {
|
"@ngtools/webpack": {
|
||||||
"version": "13.3.8",
|
"version": "13.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.8.tgz",
|
||||||
@ -13634,35 +13546,6 @@
|
|||||||
"jsonc-parser": "3.0.0"
|
"jsonc-parser": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@selectize/selectize": {
|
|
||||||
"version": "0.13.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@selectize/selectize/-/selectize-0.13.6.tgz",
|
|
||||||
"integrity": "sha512-UVkHH92l/4zLH/acfukry419K2yAKiDf6VmFQ9hZzMpWW2epE7xJIgK47mJLjAQnimP0ROo8BStfwelWcoTQyg==",
|
|
||||||
"requires": {
|
|
||||||
"@selectize/sifter": "^0.6.2",
|
|
||||||
"jquery-ui": "^1.13.0",
|
|
||||||
"microplugin": "0.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@selectize/sifter": {
|
|
||||||
"version": "0.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@selectize/sifter/-/sifter-0.6.2.tgz",
|
|
||||||
"integrity": "sha512-rpWQuzaCEV2GOEfBmP5NGST3IsA/RGRd3vugOGQVxAaN1xMI9tsrMmx5rC811iInq6OeFH3Jix5EfglYQ3XwKQ==",
|
|
||||||
"requires": {
|
|
||||||
"async": "^3.2.3",
|
|
||||||
"cardinal": "^2.1.1",
|
|
||||||
"csv-parse": "^5.0.4",
|
|
||||||
"humanize": "^0.0.9",
|
|
||||||
"optimist": "^0.5.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"async": {
|
|
||||||
"version": "3.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
|
||||||
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@socket.io/component-emitter": {
|
"@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
@ -14208,11 +14091,6 @@
|
|||||||
"color-convert": "^1.9.0"
|
"color-convert": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ansicolors": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg=="
|
|
||||||
},
|
|
||||||
"anymatch": {
|
"anymatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||||
@ -14658,15 +14536,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001358.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001358.tgz",
|
||||||
"integrity": "sha512-hvp8PSRymk85R20bsDra7ZTCpSVGN/PAz9pSAjPSjKC+rNmnUk5vCRgJwiTT/O4feQ/yu/drvZYpKxxhbFuChw=="
|
"integrity": "sha512-hvp8PSRymk85R20bsDra7ZTCpSVGN/PAz9pSAjPSjKC+rNmnUk5vCRgJwiTT/O4feQ/yu/drvZYpKxxhbFuChw=="
|
||||||
},
|
},
|
||||||
"cardinal": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
|
|
||||||
"requires": {
|
|
||||||
"ansicolors": "~0.3.2",
|
|
||||||
"redeyed": "~2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
@ -15267,11 +15136,6 @@
|
|||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"csv-parse": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-UXJCGwvJ2fep39purtAn27OUYmxB1JQto+zhZ4QlJpzsirtSFbzLvip1aIgziqNdZp/TptvsKEV5BZSxe10/DQ=="
|
|
||||||
},
|
|
||||||
"damerau-levenshtein": {
|
"damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -15823,7 +15687,8 @@
|
|||||||
"esprima": {
|
"esprima": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"esrecurse": {
|
"esrecurse": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
@ -16478,11 +16343,6 @@
|
|||||||
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"humanize": {
|
|
||||||
"version": "0.0.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz",
|
|
||||||
"integrity": "sha512-bvZZ7vXpr1RKoImjuQ45hJb5OvE2oJafHysiD/AL3nkqTZH2hFCjQ3YZfCd63FefDitbJze/ispUPP0gfDsT2Q=="
|
|
||||||
},
|
|
||||||
"humanize-ms": {
|
"humanize-ms": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||||
@ -16903,20 +16763,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jquery": {
|
|
||||||
"version": "3.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
|
|
||||||
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
|
|
||||||
},
|
|
||||||
"jquery-ui": {
|
|
||||||
"version": "1.13.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz",
|
|
||||||
"integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==",
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"jquery": ">=1.8.0 <4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -17276,11 +17122,6 @@
|
|||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"microplugin": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/microplugin/-/microplugin-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-3wKXex4/iyALV0GX2juow66J9dabkEMgHeZAihdLTaRTzm0N+RubXioNPpfIQDPuBRxr3JbjNt7B0Lr/3yE9yQ=="
|
|
||||||
},
|
|
||||||
"mime": {
|
"mime": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
@ -17946,14 +17787,6 @@
|
|||||||
"is-wsl": "^2.2.0"
|
"is-wsl": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimist": {
|
|
||||||
"version": "0.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.5.2.tgz",
|
|
||||||
"integrity": "sha512-r9M8ZpnM9SXV5Wii7TCqienfcaY3tAiJe9Jchof87icbmbruKgK0xKXngmrnowTDnEawmmI1Qbha59JEoBkBGA==",
|
|
||||||
"requires": {
|
|
||||||
"wordwrap": "~0.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ora": {
|
"ora": {
|
||||||
"version": "5.4.1",
|
"version": "5.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
|
||||||
@ -18776,14 +18609,6 @@
|
|||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redeyed": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
|
|
||||||
"requires": {
|
|
||||||
"esprima": "~4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"reflect-metadata": {
|
"reflect-metadata": {
|
||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||||
@ -20217,11 +20042,6 @@
|
|||||||
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
|
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"wordwrap": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw=="
|
|
||||||
},
|
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
|
||||||
"@selectize/selectize": "^0.13.6",
|
"@ng-select/ng-select": "^8.3.0",
|
||||||
"bootstrap": "^5.0.0",
|
"bootstrap": "^5.0.0",
|
||||||
"ngx-cookie-service": "^13.0.0",
|
"ngx-cookie-service": "^13.0.0",
|
||||||
"ngx-socket-io": "^4.2.0",
|
"ngx-socket-io": "^4.2.0",
|
||||||
|
@ -58,8 +58,7 @@
|
|||||||
<div ngbDropdownMenu aria-labelledby="advancedButton" class="dropdown-menu dropdown-menu-end folder-dropdown-menu">
|
<div ngbDropdownMenu aria-labelledby="advancedButton" class="dropdown-menu dropdown-menu-end folder-dropdown-menu">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">Download Folder</span>
|
<span class="input-group-text">Download Folder</span>
|
||||||
<select class="form-select" name="folder" #folderSelect [(ngModel)]="folder" (change)="folderChanged()" [disabled]="addInProgress || downloads.loading">
|
<ng-select [items]="customDirs$ | async" placeholder="Default" [addTag]="allowCustomDir()" addTagText="Create directory" [ngStyle]="{'flex-grow':'1'}" bindLabel="folder" [(ngModel)]="folder" [disabled]="addInProgress || downloads.loading"></ng-select>
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,6 +18,11 @@ button.add-url
|
|||||||
.folder-dropdown-menu
|
.folder-dropdown-menu
|
||||||
width: 500px
|
width: 500px
|
||||||
|
|
||||||
|
.folder-dropdown-menu .input-group
|
||||||
|
display: flex
|
||||||
|
padding-left: 5px
|
||||||
|
padding-right: 5px
|
||||||
|
|
||||||
$metube-section-color-bg: rgba(0,0,0,.07)
|
$metube-section-color-bg: rgba(0,0,0,.07)
|
||||||
|
|
||||||
.metube-section-header
|
.metube-section-header
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { Component, ViewChild, ElementRef, AfterViewInit, ChangeDetectorRef } from '@angular/core';
|
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
|
||||||
import { faTrashAlt, faCheckCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons';
|
import { faTrashAlt, faCheckCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { faRedoAlt, faSun, faMoon, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
|
import { faRedoAlt, faSun, faMoon, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { CookieService } from 'ngx-cookie-service';
|
import { CookieService } from 'ngx-cookie-service';
|
||||||
|
import { map, Observable, of } from 'rxjs';
|
||||||
|
|
||||||
import { DownloadsService, Status } from './downloads.service';
|
import { DownloadsService, Status } from './downloads.service';
|
||||||
import { MasterCheckboxComponent } from './master-checkbox.component';
|
import { MasterCheckboxComponent } from './master-checkbox.component';
|
||||||
import { Formats, Format, Quality } from './formats';
|
import { Formats, Format, Quality } from './formats';
|
||||||
|
|
||||||
// jQuery is loaded in angular.json for selectize
|
|
||||||
declare var $: any;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
@ -22,9 +20,9 @@ export class AppComponent implements AfterViewInit {
|
|||||||
quality: string;
|
quality: string;
|
||||||
format: string;
|
format: string;
|
||||||
folder: string;
|
folder: string;
|
||||||
customDirs: string[] = [];
|
|
||||||
addInProgress = false;
|
addInProgress = false;
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
|
customDirs$: Observable<string[]>;
|
||||||
|
|
||||||
@ViewChild('queueMasterCheckbox') queueMasterCheckbox: MasterCheckboxComponent;
|
@ViewChild('queueMasterCheckbox') queueMasterCheckbox: MasterCheckboxComponent;
|
||||||
@ViewChild('queueDelSelected') queueDelSelected: ElementRef;
|
@ViewChild('queueDelSelected') queueDelSelected: ElementRef;
|
||||||
@ -32,7 +30,6 @@ export class AppComponent implements AfterViewInit {
|
|||||||
@ViewChild('doneDelSelected') doneDelSelected: ElementRef;
|
@ViewChild('doneDelSelected') doneDelSelected: ElementRef;
|
||||||
@ViewChild('doneClearCompleted') doneClearCompleted: ElementRef;
|
@ViewChild('doneClearCompleted') doneClearCompleted: ElementRef;
|
||||||
@ViewChild('doneClearFailed') doneClearFailed: ElementRef;
|
@ViewChild('doneClearFailed') doneClearFailed: ElementRef;
|
||||||
@ViewChild('folderSelect') folderSelect: ElementRef;
|
|
||||||
|
|
||||||
faTrashAlt = faTrashAlt;
|
faTrashAlt = faTrashAlt;
|
||||||
faCheckCircle = faCheckCircle;
|
faCheckCircle = faCheckCircle;
|
||||||
@ -50,14 +47,11 @@ export class AppComponent implements AfterViewInit {
|
|||||||
this.setupTheme(cookieService)
|
this.setupTheme(cookieService)
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngOnInit() {
|
||||||
// Trigger folderSelect to update
|
this.customDirs$ = this.getMatchingCustomDir();
|
||||||
this.downloads.customDirsChanged.subscribe((dirs: string[]) => {
|
}
|
||||||
console.log("customDirsChanged:", dirs);
|
|
||||||
$(this.folderSelect.nativeElement).selectize({options: dirs});
|
|
||||||
this.customDirs = dirs;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
this.downloads.queueChanged.subscribe(() => {
|
this.downloads.queueChanged.subscribe(() => {
|
||||||
this.queueMasterCheckbox.selectionChanged();
|
this.queueMasterCheckbox.selectionChanged();
|
||||||
});
|
});
|
||||||
@ -86,11 +80,24 @@ export class AppComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showAdvanced() {
|
showAdvanced() {
|
||||||
return this.downloads.configuration['CUSTOM_DIR'] == 'true';
|
return this.downloads.configuration['CUSTOM_DIRS'] == 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
folderChanged() {
|
allowCustomDir() {
|
||||||
console.log("folder changed", this.folder);
|
return this.downloads.configuration['CREATE_DIRS'] == 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
getMatchingCustomDir() : Observable<string[]> {
|
||||||
|
return this.downloads.customDirs.asObservable().pipe(map((output) => {
|
||||||
|
// Keep logic consistent with app/ytdl.py
|
||||||
|
if (this.quality != 'audio' && this.format != 'mp3') {
|
||||||
|
console.debug("download_dir", output["download_dir"])
|
||||||
|
return output["download_dir"];
|
||||||
|
} else {
|
||||||
|
console.debug("audio_download_dir", output["audio_download_dir"])
|
||||||
|
return output["audio_download_dir"];
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
setupTheme(cookieService) {
|
setupTheme(cookieService) {
|
||||||
|
@ -10,6 +10,7 @@ import { AppComponent } from './app.component';
|
|||||||
import { EtaPipe, SpeedPipe, EncodeURIComponent } from './downloads.pipe';
|
import { EtaPipe, SpeedPipe, EncodeURIComponent } from './downloads.pipe';
|
||||||
import { MasterCheckboxComponent, SlaveCheckboxComponent } from './master-checkbox.component';
|
import { MasterCheckboxComponent, SlaveCheckboxComponent } from './master-checkbox.component';
|
||||||
import { MeTubeSocket } from './metube-socket';
|
import { MeTubeSocket } from './metube-socket';
|
||||||
|
import { NgSelectModule } from '@ng-select/ng-select';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -25,7 +26,8 @@ import { MeTubeSocket } from './metube-socket';
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
FontAwesomeModule
|
FontAwesomeModule,
|
||||||
|
NgSelectModule
|
||||||
],
|
],
|
||||||
providers: [CookieService, MeTubeSocket],
|
providers: [CookieService, MeTubeSocket],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
import { of, Subject } from 'rxjs';
|
import { Observable, of, Subject } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
import { MeTubeSocket } from './metube-socket';
|
import { MeTubeSocket } from './metube-socket';
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ export class DownloadsService {
|
|||||||
done = new Map<string, Download>();
|
done = new Map<string, Download>();
|
||||||
queueChanged = new Subject();
|
queueChanged = new Subject();
|
||||||
doneChanged = new Subject();
|
doneChanged = new Subject();
|
||||||
customDirsChanged = new Subject<string[]>();
|
customDirs = new Subject<Map<string, string[]>>();
|
||||||
configuration = {};
|
configuration = {};
|
||||||
|
|
||||||
constructor(private http: HttpClient, private socket: MeTubeSocket) {
|
constructor(private http: HttpClient, private socket: MeTubeSocket) {
|
||||||
@ -81,11 +81,10 @@ export class DownloadsService {
|
|||||||
console.debug("got configuration:", data);
|
console.debug("got configuration:", data);
|
||||||
this.configuration = data;
|
this.configuration = data;
|
||||||
});
|
});
|
||||||
socket.fromEvent('custom_directories').subscribe((strdata: string) => {
|
socket.fromEvent('custom_dirs').subscribe((strdata: string) => {
|
||||||
let data = JSON.parse(strdata);
|
let data = JSON.parse(strdata);
|
||||||
console.debug("got custom_directories:", data);
|
console.debug("got custom_dirs:", data);
|
||||||
let customDirectories = data["directories"];
|
this.customDirs.next(data);
|
||||||
this.customDirsChanged.next(customDirectories);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
/* Importing Bootstrap SCSS file. */
|
/* Importing Bootstrap SCSS file. */
|
||||||
@import '~bootstrap/scss/bootstrap'
|
@import '~bootstrap/scss/bootstrap'
|
||||||
|
@import '~@ng-select/ng-select/themes/default.theme.css'
|
Loading…
x
Reference in New Issue
Block a user