mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-15 01:00:56 +03:00
Compare commits
72 Commits
GlassedSil
...
GlassedSil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fc659dc0a | ||
|
|
8dac9d1806 | ||
|
|
0f6742f11b | ||
|
|
d6aaca9233 | ||
|
|
7333edf6c8 | ||
|
|
5d9cb19bde | ||
|
|
a21dc85d15 | ||
|
|
a57a25133c | ||
|
|
d6f5b87d3f | ||
|
|
2678215e08 | ||
|
|
95203a47d0 | ||
|
|
7f4119febe | ||
|
|
02f758c33d | ||
|
|
554f7c9787 | ||
|
|
d37287541f | ||
|
|
da226df72a | ||
|
|
6199157687 | ||
|
|
d2e1b04326 | ||
|
|
4bff50a5f0 | ||
|
|
6ffa9d1ffd | ||
|
|
5a80b7aafa | ||
|
|
4d00960fcf | ||
|
|
6e8ca9d843 | ||
|
|
83a9d93ce5 | ||
|
|
2707b09627 | ||
|
|
8118906b0a | ||
|
|
2ad42ebf27 | ||
|
|
2b3490e52c | ||
|
|
55fd60acd3 | ||
|
|
664b635439 | ||
|
|
692d6eeaac | ||
|
|
9515d5a1b0 | ||
|
|
24df238ff9 | ||
|
|
f5e6815200 | ||
|
|
0e5efd003e | ||
|
|
3e7ef766de | ||
|
|
17fdd0d788 | ||
|
|
ce3e645129 | ||
|
|
acca2d0de2 | ||
|
|
31b4fcb9fc | ||
|
|
336d7a09bd | ||
|
|
7c31a10498 | ||
|
|
a94b8f376e | ||
|
|
84d33b0f82 | ||
|
|
3abf8ecfc3 | ||
|
|
5b919b2b18 | ||
|
|
e290dc0a25 | ||
|
|
a54f07e93a | ||
|
|
8336d886e9 | ||
|
|
6a56b5b065 | ||
|
|
7aca8ab060 | ||
|
|
8cc5c4f733 | ||
|
|
c5eacbb70c | ||
|
|
7268242691 | ||
|
|
d0f5518d31 | ||
|
|
713a97f75a | ||
|
|
0bdcfa3244 | ||
|
|
849c1927d3 | ||
|
|
06ca9cbe76 | ||
|
|
8e4a3119ab | ||
|
|
ec1ccf6888 | ||
|
|
c33e8010b3 | ||
|
|
57fd991d5c | ||
|
|
44c1a34c67 | ||
|
|
9f740020af | ||
|
|
4d4bc76549 | ||
|
|
93ce498e94 | ||
|
|
02e683add9 | ||
|
|
d90b2d3687 | ||
|
|
32b68033e8 | ||
|
|
08027a5c0b | ||
|
|
25aac19cfb |
38
.github/workflows/close-issue-if-noresponse.yml
vendored
Normal file
38
.github/workflows/close-issue-if-noresponse.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: No Response
|
||||
|
||||
# Both `issue_comment` and `scheduled` event types are required for this Action
|
||||
# to work properly.
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
schedule:
|
||||
# Schedule for five minutes after the hour, every hour
|
||||
- cron: '5 * * * *'
|
||||
|
||||
# By specifying the access of one of the scopes, all of those that are not
|
||||
# specified are set to 'none'.
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
noResponse:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'Tzahi12345/YoutubeDL-Material' }}
|
||||
steps:
|
||||
- uses: lee-dohm/no-response@v0.5.0
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further. We will re-open this issue if you provide us
|
||||
with the requested information with a comment under this issue.
|
||||
Thank you for your understanding and for trying to help make this application
|
||||
a better one!
|
||||
# Number of days of inactivity before an issue is closed for lack of response.
|
||||
daysUntilClose: 21
|
||||
# Label requiring a response.
|
||||
responseRequiredLabel: "💬 response-needed"
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -8,9 +8,9 @@ on:
|
||||
- '.vscode/**'
|
||||
- 'chrome-extension/**'
|
||||
- 'releases/**'
|
||||
- '**/**.md'
|
||||
- '**.crx'
|
||||
- '**.pem'
|
||||
- '**.md'
|
||||
- '.dockerignore'
|
||||
- '.gitignore'
|
||||
|
||||
|
||||
119
Dockerfile
119
Dockerfile
@@ -1,71 +1,66 @@
|
||||
FROM ubuntu:20.04 AS ffmpeg
|
||||
|
||||
# Fetching our ffmpeg
|
||||
FROM ubuntu:22.04 AS ffmpeg
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
# Use script due local build compability
|
||||
COPY ffmpeg-fetch.sh .
|
||||
RUN sh ./ffmpeg-fetch.sh
|
||||
|
||||
COPY docker-build.sh .
|
||||
RUN sh ./docker-build.sh
|
||||
|
||||
FROM ubuntu:20.04 as frontend
|
||||
|
||||
# Create our Ubuntu 22.04 with node 16
|
||||
# Go to 20.04
|
||||
FROM ubuntu:20.04 AS base
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install \
|
||||
curl \
|
||||
gnupg && \
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | bash - && \
|
||||
apt-get -y install \
|
||||
nodejs \
|
||||
# YARN: brings along npm, solves dependency conflicts,
|
||||
# spares us this spaghetti approach: https://stackoverflow.com/a/60547197
|
||||
yarn && \
|
||||
apt-get install -f && \
|
||||
npm config set strict-ssl false && \
|
||||
npm install -g @angular/cli
|
||||
|
||||
WORKDIR /build
|
||||
COPY [ "package.json", "package-lock.json", "/build/" ]
|
||||
RUN npm install
|
||||
|
||||
COPY [ "angular.json", "tsconfig.json", "/build/" ]
|
||||
COPY [ "src/", "/build/src/" ]
|
||||
RUN npm run build
|
||||
|
||||
#--------------#
|
||||
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV UID=1000 \
|
||||
GID=1000 \
|
||||
USER=youtube \
|
||||
NO_UPDATE_NOTIFIER=true
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN groupadd -g $GID $USER && useradd --system -g $USER --uid $UID $USER
|
||||
|
||||
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
RUN apt-get update && apt-get -y install \
|
||||
npm \
|
||||
python2 \
|
||||
python3 \
|
||||
atomicparsley && \
|
||||
apt-get install -f && \
|
||||
apt-get autoremove --purge && \
|
||||
apt-get autoremove && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=ffmpeg /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
|
||||
COPY --from=ffmpeg /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
||||
COPY --chown=$UID:$GID [ "backend/package.json", "backend/package-lock.json", "/app/" ]
|
||||
ENV UID=1000
|
||||
ENV GID=1000
|
||||
ENV USER=youtube
|
||||
ENV NO_UPDATE_NOTIFIER=true
|
||||
ENV PM2_HOME=/app/pm2
|
||||
RUN npm config set strict-ssl false && \
|
||||
npm install pm2 -g && \
|
||||
npm install && chown -R $UID:$GID ./
|
||||
RUN groupadd -g $GID $USER && useradd --system -m -g $USER --uid $UID $USER && \
|
||||
apt update && \
|
||||
apt install -y --no-install-recommends curl ca-certificates && \
|
||||
curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \
|
||||
apt install -y --no-install-recommends nodejs && \
|
||||
npm -g install npm && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Build frontend
|
||||
FROM base as frontend
|
||||
RUN npm install -g @angular/cli
|
||||
WORKDIR /build
|
||||
COPY [ "package.json", "package-lock.json", "angular.json", "tsconfig.json", "/build/" ]
|
||||
COPY [ "src/", "/build/src/" ]
|
||||
RUN npm install && \
|
||||
npm run build && \
|
||||
ls -al /build/backend/public
|
||||
|
||||
|
||||
# Install backend deps
|
||||
FROM base as backend
|
||||
WORKDIR /app
|
||||
COPY [ "backend/","/app/" ]
|
||||
RUN npm config set strict-ssl false && \
|
||||
npm install --prod && \
|
||||
ls -al
|
||||
|
||||
|
||||
# Final image
|
||||
FROM base
|
||||
RUN npm install -g pm2 && \
|
||||
apt update && \
|
||||
apt install -y --no-install-recommends gosu python3-minimal python-is-python3 atomicparsley && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
# User 1000 already exist from base image
|
||||
COPY --chown=$UID:$GID --from=ffmpeg [ "/usr/local/bin/ffmpeg", "/usr/local/bin/ffmpeg" ]
|
||||
COPY --chown=$UID:$GID --from=ffmpeg [ "/usr/local/bin/ffprobe", "/usr/local/bin/ffprobe" ]
|
||||
COPY --chown=$UID:$GID --from=backend ["/app/","/app/"]
|
||||
COPY --chown=$UID:$GID --from=frontend [ "/build/backend/public/", "/app/public/" ]
|
||||
COPY --chown=$UID:$GID [ "/backend/", "/app/" ]
|
||||
# Add some persistence data
|
||||
#VOLUME ["/app/appdata"]
|
||||
|
||||
EXPOSE 17442
|
||||
# ENTRYPOINT [ "/app/entrypoint.sh" ]
|
||||
CMD [ "pm2-runtime", "pm2.config.js" ]
|
||||
ENTRYPOINT [ "/app/entrypoint.sh" ]
|
||||
CMD [ "pm2-runtime","--raw","pm2.config.js" ]
|
||||
|
||||
2
Dockerfile.heroku
Normal file
2
Dockerfile.heroku
Normal file
@@ -0,0 +1,2 @@
|
||||
FROM tzahi12345/youtubedl-material:nightly
|
||||
CMD [ "pm2-runtime", "pm2.config.js" ]
|
||||
1
app.json
1
app.json
@@ -2,6 +2,7 @@
|
||||
"name": "YoutubeDL-Material",
|
||||
"description": "An open-source and self-hosted YouTube downloader based on Google's Material Design specifications.",
|
||||
"repository": "https://github.com/Tzahi12345/YoutubeDL-Material",
|
||||
"stack": "container",
|
||||
"logo": "https://i.imgur.com/GPzvPiU.png",
|
||||
"keywords": ["youtube-dl", "youtubedl-material", "nodejs"]
|
||||
}
|
||||
@@ -249,14 +249,6 @@ async function startServer() {
|
||||
});
|
||||
}
|
||||
|
||||
async function restartServer(is_update = false) {
|
||||
logger.info(`${is_update ? 'Update complete! ' : ''}Restarting server...`);
|
||||
|
||||
// the following line restarts the server through nodemon
|
||||
fs.writeFileSync(`restart${is_update ? '_update' : '_general'}.json`, 'internal use only');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function updateServer(tag) {
|
||||
// no tag provided means update to the latest version
|
||||
if (!tag) {
|
||||
@@ -297,7 +289,7 @@ async function updateServer(tag) {
|
||||
updating: true,
|
||||
'details': 'Update complete! Restarting server...'
|
||||
}
|
||||
restartServer(true);
|
||||
utils.restartServer(true);
|
||||
}, err => {
|
||||
logger.error(err);
|
||||
updaterStatus = {
|
||||
@@ -676,6 +668,7 @@ async function getUrlInfos(url) {
|
||||
|
||||
async function startYoutubeDL() {
|
||||
// auto update youtube-dl
|
||||
youtubedl_api.verifyBinaryExistsLinux();
|
||||
const update_available = await youtubedl_api.checkForYoutubeDLUpdate();
|
||||
if (update_available) await youtubedl_api.updateYoutubeDL(update_available);
|
||||
}
|
||||
@@ -764,7 +757,7 @@ app.get('/api/versionInfo', (req, res) => {
|
||||
|
||||
app.post('/api/restartServer', optionalJwt, (req, res) => {
|
||||
// delayed by a little bit so that the client gets a response
|
||||
setTimeout(() => {restartServer()}, 100);
|
||||
setTimeout(() => {utils.restartServer()}, 100);
|
||||
res.send({success: true});
|
||||
});
|
||||
|
||||
@@ -1802,6 +1795,7 @@ app.post('/api/updateTaskData', optionalJwt, async (req, res) => {
|
||||
|
||||
app.post('/api/getDBBackups', optionalJwt, async (req, res) => {
|
||||
const backup_dir = path.join('appdata', 'db_backup');
|
||||
fs.ensureDirSync(backup_dir);
|
||||
const db_backups = [];
|
||||
|
||||
const candidate_backups = await utils.recFindByExt(backup_dir, 'bak', null, [], false);
|
||||
|
||||
@@ -222,4 +222,83 @@ exports.AVAILABLE_PERMISSIONS = [
|
||||
|
||||
exports.DETAILS_BIN_PATH = 'node_modules/youtube-dl/bin/details'
|
||||
|
||||
// args that have a value after it (e.g. -o <output> or -f <format>)
|
||||
const YTDL_ARGS_WITH_VALUES = [
|
||||
'--default-search',
|
||||
'--config-location',
|
||||
'--proxy',
|
||||
'--socket-timeout',
|
||||
'--source-address',
|
||||
'--geo-verification-proxy',
|
||||
'--geo-bypass-country',
|
||||
'--geo-bypass-ip-block',
|
||||
'--playlist-start',
|
||||
'--playlist-end',
|
||||
'--playlist-items',
|
||||
'--match-title',
|
||||
'--reject-title',
|
||||
'--max-downloads',
|
||||
'--min-filesize',
|
||||
'--max-filesize',
|
||||
'--date',
|
||||
'--datebefore',
|
||||
'--dateafter',
|
||||
'--min-views',
|
||||
'--max-views',
|
||||
'--match-filter',
|
||||
'--age-limit',
|
||||
'--download-archive',
|
||||
'-r',
|
||||
'--limit-rate',
|
||||
'-R',
|
||||
'--retries',
|
||||
'--fragment-retries',
|
||||
'--buffer-size',
|
||||
'--http-chunk-size',
|
||||
'--external-downloader',
|
||||
'--external-downloader-args',
|
||||
'-a',
|
||||
'--batch-file',
|
||||
'-o',
|
||||
'--output',
|
||||
'--output-na-placeholder',
|
||||
'--autonumber-start',
|
||||
'--load-info-json',
|
||||
'--cookies',
|
||||
'--cache-dir',
|
||||
'--encoding',
|
||||
'--user-agent',
|
||||
'--referer',
|
||||
'--add-header',
|
||||
'--sleep-interval',
|
||||
'--max-sleep-interval',
|
||||
'-f',
|
||||
'--format',
|
||||
'--merge-output-format',
|
||||
'--sub-format',
|
||||
'--sub-lang',
|
||||
'-u',
|
||||
'--username',
|
||||
'-p',
|
||||
'--password',
|
||||
'-2',
|
||||
'--twofactor',
|
||||
'--video-password',
|
||||
'--ap-mso',
|
||||
'--ap-username',
|
||||
'--ap-password',
|
||||
'--audio-format',
|
||||
'--audio-quality',
|
||||
'--recode-video',
|
||||
'--postprocessor-args',
|
||||
'--metadata-from-title',
|
||||
'--fixup',
|
||||
'--ffmpeg-location',
|
||||
'--exec',
|
||||
'--convert-subs'
|
||||
];
|
||||
|
||||
// we're using a Set here for performance
|
||||
exports.YTDL_ARGS_WITH_VALUES = new Set(YTDL_ARGS_WITH_VALUES);
|
||||
|
||||
exports.CURRENT_VERSION = 'v4.2';
|
||||
|
||||
@@ -85,8 +85,6 @@ exports.initialize = (input_db, input_users_db) => {
|
||||
}
|
||||
|
||||
exports.connectToDB = async (retries = 5, no_fallback = false, custom_connection_string = null) => {
|
||||
using_local_db = config_api.getConfigItem('ytdl_use_local_db'); // verify
|
||||
if (using_local_db && !custom_connection_string) return;
|
||||
const success = await exports._connectToDB(custom_connection_string);
|
||||
if (success) return true;
|
||||
|
||||
|
||||
@@ -485,7 +485,7 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f
|
||||
}
|
||||
|
||||
if (options.additionalArgs && options.additionalArgs !== '') {
|
||||
downloadConfig = downloadConfig.concat(options.additionalArgs.split(',,'));
|
||||
downloadConfig = utils.injectArgs(downloadConfig, options.additionalArgs.split(',,'));
|
||||
}
|
||||
|
||||
const rate_limit = config_api.getConfigItem('ytdl_download_rate_limit');
|
||||
|
||||
@@ -11,7 +11,7 @@ fi
|
||||
# chown current working directory to current user
|
||||
if [ "$*" = "$CMD" ] && [ "$(id -u)" = "0" ]; then
|
||||
find . \! -user "$UID" -exec chown "$UID:$GID" -R '{}' + || echo "WARNING! Could not change directory ownership. If you manage permissions externally this is fine, otherwise you may experience issues when downloading or deleting videos."
|
||||
exec su-exec "$UID:$GID" "$0" "$@"
|
||||
exec gosu "$UID:$GID" "$0" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
58
backend/fix-scripts/001-fix_download_permissions.sh
Normal file
58
backend/fix-scripts/001-fix_download_permissions.sh
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
# INTERACTIVE PERMISSIONS FIX SCRIPT FOR YTDL-M
|
||||
# Date: 2022-05-03
|
||||
|
||||
# If you want to run this script on a bare-metal installation instead of within Docker
|
||||
# make sure that the paths configured below match your paths! (it's wise to use the full paths)
|
||||
# USAGE: within your container's bash shell:
|
||||
# chmod -R +x ./fix-scripts/
|
||||
# ./fix-scripts/001-fix_download_permissions.sh
|
||||
|
||||
# User defines / Docker env defaults
|
||||
PATH_SUBS=/app/subscriptions
|
||||
PATH_AUDIO=/app/audio
|
||||
PATH_VIDS=/app/video
|
||||
|
||||
clear -x
|
||||
echo "\n"
|
||||
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - # horizontal line
|
||||
echo "Welcome to the INTERACTIVE PERMISSIONS FIX SCRIPT FOR YTDL-M."
|
||||
echo "This script will set YTDL-M's download paths' owner to ${USER} (${UID}:${GID})"
|
||||
echo "and permissions to the default of 644."
|
||||
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - # horizontal line
|
||||
echo "\n"
|
||||
|
||||
# check whether dirs exist
|
||||
i=0
|
||||
[ -d $PATH_SUBS ] && i=$((i+1)) && echo "✔ (${i}/3) Found Subscriptions directory at ${PATH_SUBS}"
|
||||
[ -d $PATH_AUDIO ] && i=$((i+1)) && echo "✔ (${i}/3) Found Audio directory at ${PATH_AUDIO}"
|
||||
[ -d $PATH_VIDS ] && i=$((i+1)) && echo "✔ (${i}/3) Found Video directory at ${PATH_VIDS}"
|
||||
|
||||
# Ask to proceed or cancel, exit on missing paths
|
||||
case $i in
|
||||
0)
|
||||
echo "\nCouldn't find any download path to fix permissions for! \nPlease edit this script to configure!"
|
||||
exit 2;;
|
||||
3)
|
||||
echo "\nFound all download paths to fix permissions for. \nProceed? (Y/N)";;
|
||||
*)
|
||||
echo "\nOnly found ${i} out of 3 download paths! Something about this script's config must be wrong. \nProceed anyways? (Y/N)";;
|
||||
esac
|
||||
old_stty_cfg=$(stty -g)
|
||||
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
|
||||
if echo "$answer" | grep -iq "^y" ;then
|
||||
echo "\n Running jobs now... (this may take a while)\n"
|
||||
[ -d $PATH_SUBS ] && chown "$UID:$GID" -R $PATH_SUBS && echo "✔ Set owner of ${PATH_SUBS} to ${USER}."
|
||||
[ -d $PATH_SUBS ] && chmod 644 -R $PATH_SUBS && echo "✔ Set permissions of ${PATH_SUBS} to 644."
|
||||
[ -d $PATH_AUDIO ] && chown "$UID:$GID" -R $PATH_AUDIO && echo "✔ Set owner of ${PATH_AUDIO} to ${USER}."
|
||||
[ -d $PATH_AUDIO ] && chmod 644 -R $PATH_AUDIO && echo "✔ Set permissions of ${PATH_AUDIO} to 644."
|
||||
[ -d $PATH_VIDS ] && chown "$UID:$GID" -R $PATH_VIDS && echo "✔ Set owner of ${PATH_VIDS} to ${USER}."
|
||||
[ -d $PATH_VIDS ] && chmod 644 -R $PATH_VIDS && echo "✔ Set permissions of ${PATH_VIDS} to 644."
|
||||
echo "\n✔ Done."
|
||||
echo "\n If you noticed file access errors those MAY be due to currently running downloads."
|
||||
echo " Feel free to re-run this script, however download parts should have correct file permissions anyhow. :)"
|
||||
exit
|
||||
else
|
||||
echo "\nOkay, bye."
|
||||
fi
|
||||
@@ -386,6 +386,21 @@ describe('Downloader', function() {
|
||||
assert(fs.existsSync(nfo_file_path), true);
|
||||
fs.unlinkSync(nfo_file_path);
|
||||
});
|
||||
|
||||
it('Inject args', async function() {
|
||||
const original_args1 = ['--no-resize-buffer', '-o', '%(title)s', '--no-mtime'];
|
||||
const new_args1 = ['--age-limit', '25', '--yes-playlist', '--abort-on-error', '-o', '%(id)s'];
|
||||
const updated_args1 = utils.injectArgs(original_args1, new_args1);
|
||||
const expected_args1 = ['--no-resize-buffer', '--no-mtime', '--age-limit', '25', '--yes-playlist', '--abort-on-error', '-o', '%(id)s'];
|
||||
assert(JSON.stringify(updated_args1), JSON.stringify(expected_args1));
|
||||
|
||||
const original_args2 = ['-o', '%(title)s.%(ext)s', '--write-info-json', '--print-json', '--audio-quality', '0', '-x', '--audio-format', 'mp3'];
|
||||
const new_args2 = ['--add-metadata', '--embed-thumbnail', '--convert-thumbnails', 'jpg'];
|
||||
const updated_args2 = utils.injectArgs(original_args2, new_args2);
|
||||
const expected_args2 = ['-o', '%(title)s.%(ext)s', '--write-info-json', '--print-json', '--audio-quality', '0', '-x', '--audio-format', 'mp3', '--add-metadata', '--embed-thumbnail', '--convert_thumbnails', 'jpg'];
|
||||
console.log(updated_args2);
|
||||
assert(JSON.stringify(updated_args2), JSON.stringify(expected_args2));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tasks', function() {
|
||||
|
||||
@@ -415,6 +415,47 @@ async function fetchFile(url, path, file_label) {
|
||||
});
|
||||
}
|
||||
|
||||
async function restartServer(is_update = false) {
|
||||
logger.info(`${is_update ? 'Update complete! ' : ''}Restarting server...`);
|
||||
|
||||
// the following line restarts the server through nodemon
|
||||
fs.writeFileSync(`restart${is_update ? '_update' : '_general'}.json`, 'internal use only');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// adds or replaces args according to the following rules:
|
||||
// - if it already exists and has value, then replace both arg and value
|
||||
// - if already exists and doesn't have value, ignore
|
||||
// - if it doesn't exist and has value, add both arg and value
|
||||
// - if it doesn't exist and doesn't have value, add arg
|
||||
function injectArgs(original_args, new_args) {
|
||||
const updated_args = original_args.slice();
|
||||
try {
|
||||
for (let i = 0; i < new_args.length; i++) {
|
||||
const new_arg = new_args[i];
|
||||
if (!new_arg.startsWith('-') && !new_arg.startsWith('--') && i > 0 && original_args.includes(new_args[i - 1])) continue;
|
||||
|
||||
if (CONSTS.YTDL_ARGS_WITH_VALUES.has(new_arg)) {
|
||||
if (original_args.includes(new_arg)) {
|
||||
const original_index = original_args.indexOf(new_arg);
|
||||
original_args.splice(original_index, 2);
|
||||
}
|
||||
|
||||
updated_args.push(new_arg, new_args[i + 1]);
|
||||
} else {
|
||||
if (!original_args.includes(new_arg)) {
|
||||
updated_args.push(new_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn(err);
|
||||
logger.warn(`Failed to inject args (${new_args}) into (${original_args})`);
|
||||
}
|
||||
|
||||
return updated_args;
|
||||
}
|
||||
|
||||
// objects
|
||||
|
||||
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description, view_count, height, abr) {
|
||||
@@ -458,5 +499,7 @@ module.exports = {
|
||||
wait: wait,
|
||||
checkExistsWithTimeout: checkExistsWithTimeout,
|
||||
fetchFile: fetchFile,
|
||||
restartServer: restartServer,
|
||||
injectArgs: injectArgs,
|
||||
File: File
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ const utils = require('./utils');
|
||||
const CONSTS = require('./consts');
|
||||
const config_api = require('./config.js');
|
||||
|
||||
const OUTDATED_VERSION = "2020.00.00";
|
||||
|
||||
const is_windows = process.platform === 'win32';
|
||||
|
||||
const download_sources = {
|
||||
@@ -31,7 +33,7 @@ exports.checkForYoutubeDLUpdate = async () => {
|
||||
let current_app_details_exists = fs.existsSync(CONSTS.DETAILS_BIN_PATH);
|
||||
if (!current_app_details_exists) {
|
||||
logger.warn(`Failed to get youtube-dl binary details at location '${CONSTS.DETAILS_BIN_PATH}'. Generating file...`);
|
||||
fs.writeJSONSync(CONSTS.DETAILS_BIN_PATH, {"version":"2020.00.00", "downloader": default_downloader});
|
||||
fs.writeJSONSync(CONSTS.DETAILS_BIN_PATH, {"version": OUTDATED_VERSION, "downloader": default_downloader});
|
||||
}
|
||||
let current_app_details = JSON.parse(fs.readFileSync(CONSTS.DETAILS_BIN_PATH));
|
||||
let current_version = current_app_details['version'];
|
||||
@@ -86,6 +88,18 @@ exports.updateYoutubeDL = async (latest_update_version) => {
|
||||
await download_sources[default_downloader]['func'](latest_update_version);
|
||||
}
|
||||
|
||||
exports.verifyBinaryExistsLinux = () => {
|
||||
const details_json = fs.readJSONSync(CONSTS.DETAILS_BIN_PATH);
|
||||
if (!is_windows && details_json && details_json['path'] && details_json['path'].includes('.exe')) {
|
||||
details_json['path'] = 'node_modules/youtube-dl/bin/youtube-dl';
|
||||
details_json['exec'] = 'youtube-dl';
|
||||
details_json['version'] = OUTDATED_VERSION;
|
||||
fs.writeJSONSync(CONSTS.DETAILS_BIN_PATH, details_json);
|
||||
|
||||
utils.restartServer();
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadLatestYoutubeDLBinary(new_version) {
|
||||
const file_ext = is_windows ? '.exe' : '';
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMX9Wk5SM5cIfY
|
||||
6ReKX3ybY1rsbNbOzG8ceN7yyeXB0mor8pVsX1MOna2HewOyBuaaYNJRO4tJBxic
|
||||
7a8zQErfgHL/i/QrVvVCpfJ7xKvq6zij5NYoqd/FBUwawqjeH5/voIcAp9z5Vmsr
|
||||
kL0sxJUKy6b4IWNp3noU7Nvq2RwxnXQbKDhz8FrX6oQAnDC6gsG5a2OSPsaE4oqw
|
||||
6nmonORJypmpP5hqyHY8ffXBT2lAxjHT7OnYbaCBe2TQP8+rH6rDBOhjVNtUJ089
|
||||
ocTQL6LtQEPkcF4yKJmtcOwHl8OPGZs5l9i8xb4j9RuSPkm2lbzZX8sOsdGGoqJZ
|
||||
q68nYhsHAgMBAAECggEAXmtKEzfPObq88B/kAcgSk+FngMHZzcmR7bgD3GwdSxnQ
|
||||
dkRI9zvk7eQ35tcUwntAr4Lat6/ILjFqlBmVLxrdXHuF5Xz9jcZLYgKzz61xdYM9
|
||||
dC6FKF0u5eGIIvbauGAo7jaeGFX1F3Zu5b4lP9kEOGwU1B7sxF0FzsQM5+dtCJgv
|
||||
We/hWQeF+9gtoVnkCSS/Mq2p0UomXXHW0Bz4+HuHlTR9aiYbviYnotABiLUhZyzt
|
||||
v5yUaktb9qniBfdLpRlq8cp06xYlTEA9gJpa4Pnok8OWUsbAiW6EiXUSaZ/cchVa
|
||||
AnO8WWYvVOnnt6WHI3+QdFTnqVjE5TBX4N/7bVhHGQKBgQD0dtbFqp7vZK/jVYvE
|
||||
z0WPdySOg2ZDmoSfk5ZlR1+Y9zWToHv0qu8zqoOjL8Ubxrh9fGlOow+cCVdkEuaa
|
||||
jWC2AWetuRvW0Z5A3XMXr0/N/1fgOkTqtp3WNrUPjVJahEg3lN+90opgFoT8swSi
|
||||
s1oxW0oLcVIlrjhGBXAPCfsAuQKBgQDWBLRhHsRAvGcK5wGuVnxVApTIyBOermsW
|
||||
3bJt+7+UI+4sYrBAwkWdQG93IG0cQtn48TEPBgmR2fjRF5IFT9M4/u+QOeeByT7I
|
||||
we7nVtHgSY5ByC9N0mjWbcmSg8fktz/LonjldNC4kWdOFb75fxGf8kOGS5rUaMA4
|
||||
zHucfB6ZvwKBgQCPHJrysMXGY21MaqIeHzEboaX3ABl37hdBzAa5V6UxSVdGCydF
|
||||
vmO2HVZey/JaJmWOoKyNaowSzq0oWqBBTg6VvhDR9JHFmoVId9uOvAS+FYN+Mt5x
|
||||
gWK5KuGoLxVNBC+6yh6JY526TrSfsrU+Aj0Es+qO9FIg2PL8muZVB4S3kQKBgH/5
|
||||
CDMaxpc/EQ5/2413wZjDllwI51J3USm3Hz6Mzp2ybnSz/lh60k2Zfg1polTH1Lb6
|
||||
4i7tmUNRZ2sAARyUAuWN64n+VeRRhe1dqZFDZPQMh7fmEAMk0fOGaoXlrt2ghdEq
|
||||
Mchi9Xun1nHmpu9hgBR4NNBU3RwuFuLfwvprbZDZAoGAWa62QJChE86xQGP1MrL2
|
||||
SbIzw3cfeP5xdQ3MKldJiy5IkbMR7Z13WZ7FwvPTy0g/onLHD1rqlm1kUMsGRHpD
|
||||
5vH06PNpKXQ6x8BYaRGtE6P39jLycO/X+WK/lYTrWo1bR+mGCebDh4B5XrwT3gI6
|
||||
x4Gvz134pZCTyQCf5JCwbQs=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -40,4 +40,4 @@ echo "(4/5) PROVISION - Provide ffmpeg and ffprobe from ffmpeg obtain layer"
|
||||
cp /tmp/ffmpeg/*/ffmpeg /usr/local/bin/ffmpeg
|
||||
cp /tmp/ffmpeg/*/ffprobe /usr/local/bin/ffprobe
|
||||
echo "(5/5) CLEANUP - Remove temporary downloads from ffmpeg obtain layer"
|
||||
rm -rf /tmp/ffmpeg ffmpeg.txz
|
||||
rm -rf /tmp/ffmpeg ffmpeg.txz
|
||||
3
heroku.yml
Normal file
3
heroku.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker:
|
||||
web: Dockerfile.heroku
|
||||
@@ -12,7 +12,8 @@
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"electron": "ng build --base-href ./ && electron .",
|
||||
"generate": "openapi --input ./\"Public API v1.yaml\" --output ./src/api-types --exportCore false --exportServices false --exportModels true"
|
||||
"generate": "openapi --input ./\"Public API v1.yaml\" --output ./src/api-types --exportCore false --exportServices false --exportModels true",
|
||||
"i18n-source": "ng extract-i18n --output-path=src/assets/i18n"
|
||||
},
|
||||
"engines": {
|
||||
"node": "12.3.1",
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<ng-container i18n="Subscription playlist not available text">Name not available. Playlist retrieval in progress.</ng-container>
|
||||
</div>
|
||||
</a>
|
||||
<button mat-icon-button (click)="editSubscription(sub)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="showSubInfo(sub)">
|
||||
<mat-icon>info</mat-icon>
|
||||
</button>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en-US" datatype="plaintext" original="ng2.template" target-language="es">
|
||||
<body>
|
||||
@@ -1630,6 +1630,198 @@
|
||||
<context context-type="linenumber">469</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2f933b826a570836cab04f683970a2d22068458c" datatype="html">
|
||||
<source>Date</source>
|
||||
<target>Fecha</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">7</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Date</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="fdf7cbdc140d0aab0f0b6c06065a0fd448ed6a2e" datatype="html">
|
||||
<source>Title</source>
|
||||
<target>Título</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">13</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">6</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="47bbc861efa59ba4135e6aa8f63213420e3f3b91" datatype="html">
|
||||
<source>Subscription</source>
|
||||
<target>Suscripción</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">23</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Subscription</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="15793f4cbc261bedbc60f7105533dde536a3f42b" datatype="html">
|
||||
<source>Progress</source>
|
||||
<target>Progreso</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">42</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Progress</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="586a5fd72602b5b14ec0c55f84814de47bb21e3a" datatype="html">
|
||||
<source>Tasks</source>
|
||||
<target>Tareas</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||
<context context-type="linenumber">47</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Navigation menu Tasks Page title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="73a7ade062c611e4bc92f3a4c672bee29b8aae9d" datatype="html">
|
||||
<source>Watch content</source>
|
||||
<target>Ver archivo</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">64</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Watch content</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2827589726081052618" datatype="html">
|
||||
<source>Creating download</source>
|
||||
<target>Creando descarga</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">58</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="9b2084f9aea764292cf0978cb083907d8be51bf7" datatype="html">
|
||||
<source>Resume all downloads</source>
|
||||
<target>Reanudar todas las descargas</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">84</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Resume all downloads</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="72c341bca7ebacc66e8a13f1a527d500619e89ff" datatype="html">
|
||||
<source>Stage</source>
|
||||
<target>Etapa</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">36</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Stage</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="030b4423b92167200e39519599f9b863b4f7c62c" datatype="html">
|
||||
<source>Actions</source>
|
||||
<target>Acciones</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">55</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">49</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Actions</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b2838c6165a9672a17db188f4dd9676574353dd8" datatype="html">
|
||||
<source>Pause</source>
|
||||
<target>Pausa</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">59</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Pause</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="99ee4faa69cd2ea8e3678c1f557c0ff1f05aae46" datatype="html">
|
||||
<source>Clear</source>
|
||||
<target>Quitar</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">68</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Clear</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4cd979821c89535df23df1c8ac8f260673610d90" datatype="html">
|
||||
<source>Resume</source>
|
||||
<target>Resumir</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Resume</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b6d79c6ff771d7b86ce572306867a1705200f957" datatype="html">
|
||||
<source>Restart</source>
|
||||
<target>Reanudar</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">66</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Restart</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b36b7458192b833592e13029fa8a0b3555e0d9bd" datatype="html">
|
||||
<source>Pause all downloads</source>
|
||||
<target>Pausar todas las descargas</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">83</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Pause all downloads</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7724483709075923163" datatype="html">
|
||||
<source>Downloading file</source>
|
||||
<target>Descargando archivo</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="54cb4c7c3a0da911ebda5a07666b448868020308" datatype="html">
|
||||
<source>Show error</source>
|
||||
<target>Mostrar error</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">65</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Show error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="601a28988581b5398ca6471027487e098d236e0e" datatype="html">
|
||||
<source>Clear finished downloads</source>
|
||||
<target>Quitar descargas finalizadas</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||
<context context-type="linenumber">85</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Clear finished downloads</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4027175717527633324" datatype="html">
|
||||
<source>Getting info</source>
|
||||
<target>Cogiendo info</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">59</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8384225360105280028" datatype="html">
|
||||
<source>Complete</source>
|
||||
<target>Completo</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">61</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7180002287537831534" datatype="html">
|
||||
<source>Clear finished downloads</source>
|
||||
<target>Borrar descargas terminadas</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">129</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -1392,7 +1392,7 @@
|
||||
<note priority="1" from="description">Allow subscriptions setting</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4bee2a4bef2d26d37c9b353c278e24e5cd309ce3" datatype="html">
|
||||
<source>Base bath for subscriptions</source>
|
||||
<source>Subscriptions base path</source>
|
||||
<target>Abonnementenbasispad</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||
@@ -1545,8 +1545,8 @@
|
||||
<note priority="1" from="description">Custom args input placeholder</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="6b995e7130b4d667eaab6c5f61b362ace486d26d" datatype="html">
|
||||
<source>Global custom args for downloads on the home page. Args are delimited using two commas like so: ,,</source>
|
||||
<target>Algemene aanvullende opties voor downloads op de overzichtspagina. Scheidt deze met komma's: ,,</target>
|
||||
<source>Global custom args for downloads on the home page. (Set args for subscriptions for each subscriptions separately!) Args are delimited using two commas like so: ,,</source>
|
||||
<target>Algemene aanvullende opties voor downloads op de overzichtspagina. (Stel de opties per abonnement in!) Scheidt deze met komma's: ,,</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||
<context context-type="linenumber">134</context>
|
||||
@@ -2854,8 +2854,8 @@
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2560364143605631750" datatype="html">
|
||||
<source>Error for <x id="url" equiv-text="}); retu"/></source>
|
||||
<target>Foutmelding bij <x id="url" equiv-text="}); retu"/></target>
|
||||
<source>Error for <x id="url" equiv-text="download['url']"/></source>
|
||||
<target>Foutmelding bij <x id="url" equiv-text="download['url']"/></target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||
<context context-type="linenumber">238</context>
|
||||
@@ -3097,13 +3097,303 @@
|
||||
<note priority="1" from="description">Autoplay checkbox</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7220285196408439810" datatype="html">
|
||||
<source>Download for <x id="url" equiv-text="d, cropF"/> has been queued!</source>
|
||||
<target><x id="url" equiv-text="d, cropF"/> staat in de wachtrij!</target>
|
||||
<source>Download for <x id="url" equiv-text="url"/> has been queued!</source>
|
||||
<target><x id="url" equiv-text="url"/> staat in de wachtrij!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/main/main.component.ts</context>
|
||||
<context context-type="linenumber">469</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="586a5fd72602b5b14ec0c55f84814de47bb21e3a" datatype="html">
|
||||
<source>Tasks</source>
|
||||
<target>Taken</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||
<context context-type="linenumber">47</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Navigation menu Tasks Page title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="84a36cb75660b736773fe36ffa3d54f0f0fe363e" datatype="html">
|
||||
<source>N/A</source>
|
||||
<target>n/b</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">19</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">28</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">N/A</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="698f716f927f633b16cbe2308d90b2dba51f7556" datatype="html">
|
||||
<source>Last confirmed</source>
|
||||
<target>Laatst bevestigd:</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">25</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Last confirmed</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="81b97b8ea996ad1e4f9fca8415021850214884b1" datatype="html">
|
||||
<source>Status</source>
|
||||
<target>Status</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">34</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Status</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="d97425ce76bf3df50bcb643b5f409844770458f6" datatype="html">
|
||||
<source>Busy</source>
|
||||
<target>Bezig</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">36</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Busy</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="3b7d6ff5d14ab177ce3e2d217b1927fb2e4aefd1" datatype="html">
|
||||
<source>Not scheduled</source>
|
||||
<target>Niet ingepland</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">42</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Not scheduled</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="5ff9ae1f4c26bf2ddf6e9d5e4136916c5ce6a941" datatype="html">
|
||||
<source>Clear missing files from DB:</source>
|
||||
<target>Ontbrekende bestanden wissen uit DB:</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">57</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Clear missing files from DB</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4391397241847e675f6c38bbdec6b2883157fb1a" datatype="html">
|
||||
<source>Clear duplicate files from DB:</source>
|
||||
<target>Gedupliceerde bestanden wissen uit DB:</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Clear duplicate files from DB</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="9562dd1e902acc4cc6a6e09cba66a2775daf7794" datatype="html">
|
||||
<source>Update binary to:</source>
|
||||
<target>Uitvoerbaar bestand bijwerken naar</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">63</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Update binary to</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="9b3d305551358858e1892169a94527e0cc4dbf5b" datatype="html">
|
||||
<source>Run</source>
|
||||
<target>Uitvoeren</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">69</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Run</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4a4f46a2dcec36bd5c8c371ceee55c2226dec27f" datatype="html">
|
||||
<source>Schedule</source>
|
||||
<target>Inplannen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">72</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Schedule</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2106110452479146311" datatype="html">
|
||||
<source>Failed to run task!</source>
|
||||
<target>De taak kan niet worden uitgevoerd!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">79</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">81</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4707127982271899773" datatype="html">
|
||||
<source>Successfully confirmed task!</source>
|
||||
<target>De taak is bevestigd!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">89</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="9121124215111024650" datatype="html">
|
||||
<source>Failed to confirm task!</source>
|
||||
<target>De taak kan niet worden bevestigd!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">90</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">92</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4334913030311371594" datatype="html">
|
||||
<source>Would you like to reset your tasks? All your schedules will be removed as well.</source>
|
||||
<target>Weet je zeker dat je alle taken wilt herstellen? Alle schema's worden hierdoor gewist.</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">133</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7808756054397155068" datatype="html">
|
||||
<source>Reset</source>
|
||||
<target>Herstellen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">134</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1709994363138824316" datatype="html">
|
||||
<source>Failed to reset tasks!</source>
|
||||
<target>De taken kunnen niet worden hersteld!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">144</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">147</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="d5cec7468241d72cafd86ad1af6d55b09a6e3ae5" datatype="html">
|
||||
<source>Restore</source>
|
||||
<target>Herstellen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/restore-db-dialog/restore-db-dialog.component.html</context>
|
||||
<context context-type="linenumber">25</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Restore button</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="998793c78895d53576f462054f13d6e515e923d9" datatype="html">
|
||||
<source>Update task schedule</source>
|
||||
<target>Taakschema bijwerken</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.html</context>
|
||||
<context context-type="linenumber">1</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Update task schedule</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="f50a33d3c339f8f4a465141f8caa5d2d8c005251" datatype="html">
|
||||
<source>Enabled</source>
|
||||
<target>Ingeschakeld</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.html</context>
|
||||
<context context-type="linenumber">7</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Enabled</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="67aed6c588eb854f2f30ef642e85147da0027a61" datatype="html">
|
||||
<source>Recurring</source>
|
||||
<target>Herhalen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.html</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Recurring</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="047f50bc5b5d17b5bec0196355953e1a5c590ddb" datatype="html">
|
||||
<source>Update</source>
|
||||
<target>Bijwerken</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.html</context>
|
||||
<context context-type="linenumber">52</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Update button</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="e4c3cd97461b220b9cea67cfe08c5399799cfeed" datatype="html">
|
||||
<source>Last ran</source>
|
||||
<target>Laatst uitgevoerd:</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">16</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Last ran</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7e121a443a8e9d92218f987001b650c59504d815" datatype="html">
|
||||
<source>Scheduled for</source>
|
||||
<target>Ingepland om</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">38</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Scheduled</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="40bd7093f5fbd3fbeff9a50baaf5d4c8416add1e" datatype="html">
|
||||
<source>Restore DB from backup</source>
|
||||
<target>DB herstellen uit back-up</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">89</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/dialogs/restore-db-dialog/restore-db-dialog.component.html</context>
|
||||
<context context-type="linenumber">1</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Restore DB from backup button</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="5588424857086384816" datatype="html">
|
||||
<source>Reset tasks</source>
|
||||
<target>Taken herstellen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">132</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5615896113581458384" datatype="html">
|
||||
<source>Successfully ran task!</source>
|
||||
<target>De taak is uitgevoerd!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">78</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="f8a2361f3bd8fb05bf92080e2755bddd56ab64d7" datatype="html">
|
||||
<source>Reset tasks</source>
|
||||
<target>Taken herstellen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">90</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Reset tasks button</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="5e96c9d4528bf259da3944daac3171d7462b065a" datatype="html">
|
||||
<source>No tasks available!</source>
|
||||
<target>Er zijn geen taken beschikbaar!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||
<context context-type="linenumber">94</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">No tasks label</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="8612475568724527886" datatype="html">
|
||||
<source>Tasks successfully reset!</source>
|
||||
<target>De taken zijn hersteld!</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||
<context context-type="linenumber">142</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="fd374bee82dab66055b933496860f82b7b780159" datatype="html">
|
||||
<source>Global custom args for downloads on the home page. (Set args for subscriptions for each subscriptions separately!) Args are delimited using two commas like so: ,,</source>
|
||||
<target>Globale aanvullende opties voor downloades. (Stel ze per abonnement in!) Scheid de opties met twee komma's, dus ,,</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||
<context context-type="linenumber">128</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">Custom args setting input hint</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en-US" datatype="plaintext" original="ng2.template" target-language="zh-Hans">
|
||||
<body>
|
||||
@@ -733,7 +733,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="4bee2a4bef2d26d37c9b353c278e24e5cd309ce3" datatype="html">
|
||||
<source>Subscriptions base path</source>
|
||||
<target>订阅文件路径</target>
|
||||
<target>订阅基路径</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
||||
<context context-type="linenumber">72</context>
|
||||
@@ -902,8 +902,8 @@
|
||||
<note priority="1" from="description">Video path setting input hint</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="6b995e7130b4d667eaab6c5f61b362ace486d26d" datatype="html">
|
||||
<source>Global custom args for downloads on the home page. Args are delimited using two commas like so: ,,</source>
|
||||
<target>开始页面上用于下载的全局自定义参数。参数由两个逗号分隔:,,</target>
|
||||
<source>Global custom args for downloads on the home page. (Set args for subscriptions for each subscriptions separately!) Args are delimited using two commas like so: ,,</source>
|
||||
<target>开始页面上用于下载的全局自定义参数。(单独为每个订阅设置订阅参数!) 参数由两个逗号分隔:,,</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
||||
<context context-type="linenumber">146</context>
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user