Compare commits

..

1 Commits

Author SHA1 Message Date
Isaac Abadi
51512a60da Fixed docker build issues 2022-05-01 00:22:28 -04:00
28 changed files with 7604 additions and 2072 deletions

View File

@@ -1,27 +0,0 @@
name: docker-pr
on:
pull_request:
branches: [master]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v2
- name: Set hash
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Get current date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- name: create-json
id: create-json
uses: jsdaniell/create-json@1.1.2
with:
name: "version.json"
json: '{"type": "docker", "tag": "nightly", "commit": "${{ steps.vars.outputs.sha_short }}", "date": "${{ steps.date.outputs.date }}"}'
dir: 'backend/'
- name: Build docker images
run: docker build . -t tzahi12345/youtubedl-material:nightly-pr

View File

@@ -3,16 +3,6 @@ name: docker
on:
push:
branches: [master]
paths-ignore:
- '.github/**'
- '.vscode/**'
- 'chrome-extension/**'
- 'releases/**'
- '**/**.md'
- '**.crx'
- '**.pem'
- '.dockerignore'
- '.gitignore'
jobs:
build-and-push:
@@ -31,7 +21,7 @@ jobs:
uses: jsdaniell/create-json@1.1.2
with:
name: "version.json"
json: '{"type": "docker", "tag": "${{secrets.DOCKERHUB_MASTER_TAG}}", "commit": "${{ steps.vars.outputs.sha_short }}", "date": "${{ steps.date.outputs.date }}"}'
json: '{"type": "docker", "tag": "nightly", "commit": "${{ steps.vars.outputs.sha_short }}", "date": "${{ steps.date.outputs.date }}"}'
dir: 'backend/'
- name: setup platform emulator
uses: docker/setup-qemu-action@v1
@@ -49,8 +39,4 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64,linux/arm,linux/arm64/v8
push: true
# Defaults:
# DOCKERHUB_USERNAME : tzahi12345
# DOCKERHUB_REPO : youtubedl-material
# DOCKERHUB_MASTER_TAG: nightly
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{secrets.DOCKERHUB_MASTER_TAG}}
tags: tzahi12345/youtubedl-material:nightly

View File

@@ -1,26 +1,18 @@
FROM ubuntu:22.04 AS ffmpeg
ENV DEBIAN_FRONTEND=noninteractive
FROM ubuntu:20.04 AS ffmpeg
RUN apt-get update && apt-get -y install curl xz-utils
COPY docker-build.sh .
RUN sh ./docker-build.sh
#--------------# Stage 2
FROM ubuntu:22.04 as frontend
FROM ubuntu:20.04 as frontend
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install \
curl \
gnupg \
# Ubuntu 22.04 ships Node.JS 12 by default :)
nodejs \
# needed on 21.10 and before, maybe not on 22.04 YARN: brings along npm, solves dependency conflicts,
# spares us this spaghetti approach: https://stackoverflow.com/a/60547197
npm && \
apt-get install -f && \
npm config set strict-ssl false && \
npm install -g @angular/cli
RUN apt-get update
RUN apt-get -y install curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get -y install nodejs
RUN npm install -g @angular/cli
WORKDIR /build
COPY [ "package.json", "package-lock.json", "/build/" ]
@@ -30,43 +22,37 @@ COPY [ "angular.json", "tsconfig.json", "/build/" ]
COPY [ "src/", "/build/src/" ]
RUN npm run build
#--------------# Final Stage
#--------------#
FROM ubuntu:22.04
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 apt-get update && apt-get -y install curl
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get update && apt-get -y install \
npm \
nodejs \
python2 \
python3 \
gosu \
atomicparsley && \
apt-get install -f && \
apt-get autoremove --purge && \
apt-get autoremove && \
apt-get clean && \
rm -rf /var/lib/apt
atomicparsley
WORKDIR /app
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 --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 PM2_HOME=/app/pm2
RUN npm config set strict-ssl false && \
npm install pm2 -g && \
RUN npm install pm2 -g && \
npm install && chown -R $UID:$GID ./
COPY --chown=$UID:$GID --from=frontend [ "/build/backend/public/", "/app/public/" ]
COPY --chown=$UID:$GID [ "/backend/", "/app/" ]
EXPOSE 17442
ENTRYPOINT [ "/app/entrypoint.sh" ]
# ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD [ "pm2-runtime", "pm2.config.js" ]

View File

@@ -6,7 +6,7 @@
[![GitHub issues badge](https://img.shields.io/github/issues/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/issues)
[![License badge](https://img.shields.io/github/license/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/blob/master/LICENSE.md)
YoutubeDL-Material is a Material Design frontend for [youtube-dl](https://rg3.github.io/youtube-dl/). It's coded using [Angular 13](https://angular.io/) for the frontend, and [Node.js](https://nodejs.org/) on the backend.
YoutubeDL-Material is a Material Design frontend for [youtube-dl](https://rg3.github.io/youtube-dl/). It's coded using [Angular 11](https://angular.io/) for the frontend, and [Node.js](https://nodejs.org/) on the backend.
Now with [Docker](#Docker) support!

49
armhf.Dockerfile Normal file
View File

@@ -0,0 +1,49 @@
FROM alpine:3.12 as frontend
RUN apk add --no-cache \
npm \
curl
RUN npm install -g @angular/cli
WORKDIR /build
RUN curl -L https://github.com/balena-io/qemu/releases/download/v3.0.0%2Bresin/qemu-3.0.0+resin-arm.tar.gz | tar zxvf - -C . && mv qemu-3.0.0+resin-arm/qemu-arm-static .
COPY [ "package.json", "package-lock.json", "/build/" ]
RUN npm install
COPY [ "angular.json", "tsconfig.json", "/build/" ]
COPY [ "src/", "/build/src/" ]
RUN ng build --prod
#--------------#
FROM arm32v7/alpine:3.12
COPY --from=frontend /build/qemu-arm-static /usr/bin
ENV UID=1000 \
GID=1000 \
USER=youtube
RUN addgroup -S $USER -g $GID && adduser -D -S $USER -G $USER -u $UID
RUN apk add --no-cache \
ffmpeg \
npm \
python2 \
su-exec \
&& apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ \
atomicparsley
WORKDIR /app
COPY --chown=$UID:$GID [ "backend/package.json", "backend/package-lock.json", "/app/" ]
RUN npm install && chown -R $UID:$GID ./
COPY --chown=$UID:$GID --from=frontend [ "/build/backend/public/", "/app/public/" ]
COPY --chown=$UID:$GID [ "/backend/", "/app/" ]
EXPOSE 17442
ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD [ "node", "app.js" ]

View File

@@ -222,83 +222,4 @@ 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';

View File

@@ -85,6 +85,8 @@ 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;
@@ -495,7 +497,6 @@ exports.deleteFile = async (uid, uuid = null, blacklistMode = false) => {
let useYoutubeDLArchive = config_api.getConfigItem('ytdl_use_youtubedl_archive');
if (useYoutubeDLArchive) {
const usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
const archive_path = uuid ? path.join(usersFileFolder, uuid, 'archives', `archive_${type}.txt`) : path.join('appdata', 'archives', `archive_${type}.txt`);
// get ID from JSON

View File

@@ -485,7 +485,7 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f
}
if (options.additionalArgs && options.additionalArgs !== '') {
downloadConfig = utils.injectArgs(downloadConfig, options.additionalArgs.split(',,'));
downloadConfig = downloadConfig.concat(options.additionalArgs.split(',,'));
}
const rate_limit = config_api.getConfigItem('ytdl_download_rate_limit');

View File

@@ -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 gosu "$UID:$GID" "$0" "$@"
exec su-exec "$UID:$GID" "$0" "$@"
fi
exec "$@"

View File

@@ -1,58 +0,0 @@
#!/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

View File

@@ -141,7 +141,6 @@ async function unsubscribe(sub, deleteMode, user_uid = null) {
if (sub.archive && (await fs.pathExists(sub.archive))) {
const archive_file_path = path.join(sub.archive, 'archive.txt');
// deletes archive if it exists
// TODO: Keep entries in blacklist_video.txt by moving them to a global blacklist
if (await fs.pathExists(archive_file_path)) {
await fs.unlink(archive_file_path);
}
@@ -380,11 +379,7 @@ async function generateArgsForSubscription(sub, user_uid, redownload = false, de
if (useArchive && !redownload) {
if (sub.archive) {
archive_dir = sub.archive;
if (sub.type && sub.type === 'audio') {
archive_path = path.join(archive_dir, 'merged_audio.txt');
} else {
archive_path = path.join(archive_dir, 'merged_video.txt');
}
archive_path = path.join(archive_dir, 'archive.txt')
}
downloadConfig.push('--download-archive', archive_path);
}

View File

@@ -386,21 +386,6 @@ 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() {

View File

@@ -415,39 +415,6 @@ async function fetchFile(url, path, file_label) {
});
}
// 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) {
@@ -491,6 +458,5 @@ module.exports = {
wait: wait,
checkExistsWithTimeout: checkExistsWithTimeout,
fetchFile: fetchFile,
injectArgs: injectArgs,
File: File
}

View File

@@ -4,6 +4,8 @@
# and also optimizing some code with this commit.
# xoxo :D
# set -xeuo pipefail
case $(uname -m) in
x86_64)
ARCH=amd64;;
@@ -20,24 +22,15 @@ case $(uname -m) in
exit 1
esac
echo "(INFO) Architecture detected: $ARCH"
echo "(1/5) READY - Acquire temp dependencies in ffmpeg obtain layer"
apt-get update && apt-get -y install curl xz-utils
echo "(2/5) DOWNLOAD - Acquire latest ffmpeg and ffprobe from John van Sickle's master-sourced builds in ffmpeg obtain layer"
curl -o ffmpeg.txz \
--connect-timeout 5 \
echo "Architecture: $ARCH"
curl --connect-timeout 5 \
--max-time 10 \
--retry 5 \
--retry-delay 0 \
--retry-max-time 40 \
"https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-${ARCH}-static.tar.xz"
"https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-${ARCH}-static.tar.xz" -o ffmpeg.txz
mkdir /tmp/ffmpeg
tar xf ffmpeg.txz -C /tmp/ffmpeg
echo "(3/5) CLEANUP - Remove temp dependencies from ffmpeg obtain layer"
apt-get -y remove curl xz-utils
apt-get -y autoremove
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

View File

@@ -12,8 +12,7 @@
"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",
"i18n-source": "ng extract-i18n --output-path=src/assets/i18n"
"generate": "openapi --input ./\"Public API v1.yaml\" --output ./src/api-types --exportCore false --exportServices false --exportModels true"
},
"engines": {
"node": "12.3.1",

View File

@@ -51,7 +51,7 @@
</ng-container>
<ng-container *ngIf="postsService.config && allowSubscriptions && postsService.subscriptions && postsService.hasPermission('subscriptions')">
<mat-divider *ngIf="postsService.subscriptions.length > 0"></mat-divider>
<a *ngFor="let subscription of postsService.subscriptions" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" [routerLink]="['/subscription', { id: subscription.id }]"><ngx-avatars [style.margin-right]="'10px'" size="32" [name]="subscription.name"></ngx-avatars>{{subscription.name}}</a>
<a *ngFor="let subscription of postsService.subscriptions" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" [routerLink]="['/subscription', { id: subscription.id }]"><ngx-avatar [style.margin-right]="'10px'" size="32" [name]="subscription.name"></ngx-avatar>{{subscription.name}}</a>
</ng-container>
</mat-nav-list>
</mat-sidenav>

View File

@@ -42,11 +42,6 @@ export class ConcurrentStreamComponent implements OnInit {
}
ngOnDestroy(): void {
if (this.check_timeout) { clearInterval(this.check_timeout); }
if (this.update_timeout) { clearInterval(this.update_timeout); }
}
startServer() {
this.started = true;
this.server_started = true;

View File

@@ -1,4 +1,4 @@
import { Component, ElementRef, Input, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { AfterViewInit, Component, ElementRef, Input, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { PostsService } from 'app/posts.services';
@Component({
@@ -6,7 +6,7 @@ import { PostsService } from 'app/posts.services';
templateUrl: './twitch-chat.component.html',
styleUrls: ['./twitch-chat.component.scss']
})
export class TwitchChatComponent implements OnInit, OnDestroy {
export class TwitchChatComponent implements OnInit, AfterViewInit {
full_chat = null;
visible_chat = null;
@@ -33,8 +33,7 @@ export class TwitchChatComponent implements OnInit, OnDestroy {
this.getFullChat();
}
ngOnDestroy(): void {
if (this.chat_check_interval_obj) { clearInterval(this.chat_check_interval_obj); }
ngAfterViewInit() {
}
private isUserNearBottom(): boolean {

View File

@@ -445,7 +445,7 @@ export const isoLangs = {
'name': 'Navajo, Navaho',
'nativeName': 'Diné bizaad, Dinékʼehǰí'
},
'nb-NO': {
'nb': {
'name': 'Norwegian Bokmål',
'nativeName': 'Norsk bokmål',
'ngID': 'nb'

View File

@@ -52,8 +52,6 @@ export class SubscriptionComponent implements OnInit, OnDestroy {
this.route.params.subscribe(params => {
this.id = params['id'];
if (this.sub_interval) { clearInterval(this.sub_interval); }
this.postsService.service_initialized.subscribe(init => {
if (init) {
this.getConfig();

View File

@@ -36,9 +36,6 @@
<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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
{
"17f0ea5d2d7a262b0e875acc70475f102aee84e6": "Opprett en spilleliste",
"cff1428d10d59d14e45edec3c735a27b5482db59": "Navn",
"f0baeb8b69d120073b6d60d34785889b0c3232c8": "Lyd",
"2d1ea268a6a9f483dbc2cbfe19bf4256a57a6af4": "Video",
"f61c6867295f3b53d23557021f2f4e0aa1d0b8fc": "Type",
"f47e2d56dd8a145b2e9599da9730c049d52962a2": "Lydfiler",
"a52dae09be10ca3a65da918533ced3d3f4992238": "Videoer",
"d9e83ac17026e70ef6e9c0f3240a3b2450367f40": "Endre youtube-dl-argumenter",
"7fc1946abe2b40f60059c6cd19975d677095fd19": "Simulerte nye argumenter",
"0b71824ae71972f236039bed43f8d2323e8fd570": "Legg til argument",
"c8b0e59eb491f2ac7505f0fbab747062e6b32b23": "Søk etter kategori",
"9eeb91caef5a50256dd87e1c4b7b3e8216479377": "Bruk argument-verdi",
"25d8ad5eba2ec24e68295a27d6a4bb9b49e3dacd": "Argument-verdi",
"7de2451ed3fb8d8b847979bd3f0c740b970f167b": "Legg til argument",
"d7b35c384aecd25a516200d6921836374613dfe7": "Avbryt",
"b2623aee44b70c9a4ba1fce16c8a593b0a4c7974": "Endre",
"a38ae1082fec79ba1f379978337385a539a28e73": "Kvalitet",
"4be966a9dcfbc9b54dfcc604b831c0289f847fa4": "Bruk nettadresse",
"d3f02f845e62cebd75fde451ab8479d2a8ad784d": "Vis",
"4a9889d36910edc8323d7bab60858ab3da6d91df": "Kun lyd",
"96a01fafe135afc58b0f8071a4ab00234495ce18": "Multi-nedlastingsmodus",
"6a21ba5fb0ac804a525bf9ab168038c3ee88e661": "Last ned",
"6a3777f913cf3f288664f0632b9f24794fdcc24e": "Avbryt",
"322ed150e02666fe2259c5b4614eac7066f4ffa0": "Avansert",
"b7ffe7c6586d6f3f18a9246806a7c7d5538ab43e": "Simulert kommando:",
"4e4c721129466be9c3862294dc40241b64045998": "Bruk egendefinerte argumenter:",
"ad2f8ac8b7de7945b80c8e424484da94e597125f": "Egendefinerte argumenter",
"a6911c2157f1b775284bbe9654ce5eb30cf45d7f": "Du trenger ikke å inkludere nettadressen, kun alt etter. Argumenter skilles ved bruk av to komma, slik: ,,",
"3a92a3443c65a52f37ca7efb8f453b35dbefbf29": "Bruk defendefinert utdata",
"d9c02face477f2f9cdaae318ccee5f89856851fb": "Egendefinert utdata",
"fcfd4675b4c90f08d18d3abede9a9a4dff4cfdc7": "Dokumentasjon",
"19d1ae64d94d28a29b2c57ae8671aace906b5401": "Sti er relativ til oppsettsnedlastingsstien. Ikke inkluder utvidelse.",
"8fad10737d3e3735a6699a4d89cbf6c20f6bb55f": "Bruk identitetsbekreftelse",
"08c74dc9762957593b91f6eb5d65efdfc975bf48": "Brukernavn",
"c32ef07f8803a223a83ed17024b38e8d82292407": "Passord",
"616e206cb4f25bd5885fc35925365e43cf5fb929": "Navn:",
"c52db455cca9109ee47e1a612c3f4117c09eb71b": "Nettadresse:",
"c6eb45d085384903e53ab001a3513d1de6a1dbac": "Opplaster:",
"109c6f4a5e46efb933612ededfaf52a13178b7e0": "Filstørrelse:",
"bd630d8669b16e5f264ec4649d9b469fe03e5ff4": "Sti:",
"a67e7d843cef735c79d5ef1c8ba4af3e758912bb": "Opplastingsdato:",
"f4e529ae5ffd73001d1ff4bbdeeb0a72e342e5c8": "Lukk",
"4f389e41e4592f7f9bb76abdd8af4afdfb13f4f1": "Endre spilleliste",
"511b600ae4cf037e4eb3b7a58410842cd5727490": "Legg til mer innhold",
"52c9a103b812f258bcddc3d90a6e3f46871d25fe": "Lagre",
"ca3dbbc7f3e011bffe32a10a3ea45cc84f30ecf1": "ID:",
"e684046d73bcee88e82f7ff01e2852789a05fc32": "Antall:",
"28f86ffd419b869711aa13f5e5ff54be6d70731c": "Rediger",
"826b25211922a1b46436589233cb6f1a163d89b7": "Slett",
"321e4419a943044e674beb55b8039f42a9761ca5": "Info",
"34504b488c24c27e68089be549f0eeae6ebaf30b": "Slett og svartelist",
"ebadf946ae90f13ecd0c70f09edbc0f983af8a0f": "Last opp nye kaker",
"98a8a42e5efffe17ab786636ed0139b4c7032d0e": "Dra og slipp",
"a8b7b9c168fd936a75e500806a8c0d7755ef1198": "Merk: Oppasting av nye kaker overskriver tidligere. Merk deg også at kaker gjelder for hele instansen, ikke per bruker.",
"121cc5391cd2a5115bc2b3160379ee5b36cd7716": "Innstillinger",
"801b98c6f02fe3b32f6afa3ee854c99ed83474e6": "Nettadresse",
"54c512cca1923ab72faf1a0bd98d3d172469629a": "Nettadressen dette programmet nås fra, uten porten.",
"cb2741a46e3560f6bc6dfd99d385e86b08b26d72": "Port",
"22e8f1d0423a3b784fe40fab187b92c06541b577": "Ønsket port. Forvalet er 17442.",
"d4477669a560750d2064051a510ef4d7679e2f3e": "Multi-brukermodus",
"2eb03565fcdce7a7a67abc277a936a32fcf51557": "Bruker-basissti",
"a64505c41150663968e277ec9b3ddaa5f4838798": "Basissti for brukere og deres nedlastede videoer.",
"4e3120311801c4acd18de7146add2ee4a4417773": "Tillat abonnementer",
"4bee2a4bef2d26d37c9b353c278e24e5cd309ce3": "Abonnements-basissti",
"bc9892814ee2d119ae94378c905ea440a249b84a": "Basissti for videoer fra dine abonnementskanaler og spillelister. Den er relativ til YTDL-Material sin rotmappe.",
"5bef4b25ba680da7fff06b86a91b1fc7e6a926e3": "Sjekkintervall",
"0f56a7449b77630c114615395bbda4cab398efd8": "I sekunder, kun tall.",
"27a56aad79d8b61269ed303f11664cc78bcc2522": "Drakt",
"ff7cee38a2259526c519f878e71b964f41db4348": "Forvalg",
"adb4562d2dbd3584370e44496969d58c511ecb63": "Mørk",
"7a6bacee4c31cb5c0ac2d24274fb4610d8858602": "Tillat draktendring",
"fe46ccaae902ce974e2441abe752399288298619": "Språk",
"82421c3e46a0453a70c42900eab51d58d79e6599": "Generelt",
"ab2756805742e84ad0cc0468f4be2d8aa9f855a5": "Lydmappe",
"c2c89cdf45d46ea64d2ed2f9ac15dfa4d77e26ca": "Sti for lydbaserte nedlastinger. Den er relativ til YTDL-Material sin rotmappe.",
"46826331da1949bd6fb74624447057099c9d20cd": "Videomappe",
"17c92e6d47a213fa95b5aa344b3f258147123f93": "Sti for videonedlastinger. Den er relativ til YTDL-Material sin rotmappe.",
"6b995e7130b4d667eaab6c5f61b362ace486d26d": "Egendefinerte argumenter for nedlastninger på hjemmesiden for hele programmet. Argumenter skilles med to komma, slik: ,,",
"78e49b7339b4fa7184dd21bcaae107ce9b7076f6": "Bruk youtube-dl-arktivet",
"ffc19f32b1cba0daefc0e5668f89346db1db83ad": "Inkluder miniatyrbilde",
"384de8f8f112c9e6092eb2698706d391553f3e8d": "Inkluder metadata",
"fb35145bfb84521e21b6385363d59221f436a573": "Drep alle nedlastinger",
"0ba25ad86a240576c4f20a2fada4722ebba77b1e": "Nedlaster",
"61f8fd90b5f8cb20c70371feb2ee5e1fac5a9095": "Topptittel",
"78d3531417c0d4ba4c90f0d4ae741edc261ec8df": "Filbehandler påskrudd",
"a5a1be0a5df07de9eec57f5d2a86ed0204b2e75a": "Nedlastingsbehandler påskrudd",
"c33bd5392b39dbed36b8e5a1145163a15d45835f": "Tillat kvalitetsvalg",
"bda5508e24e0d77debb28bcd9194d8fefb1cfb92": "Modus kun for nedlasting",
"09d31c803a7252658694e1e3176b97f5655a3fe3": "Tillat multi-nedlastingsmodus",
"1c4dbce56d96b8974aac24a02f7ab2ee81415014": "Skru på offentlig API",
"23bd81dcc30b74d06279a26d7a42e8901c1b124e": "Offentlig API-nøkkel",
"41016a73d8ad85e6cb26dffa0a8fab9fe8f60d8e": "Vis dokumentasjon",
"1b258b258b4cc475ceb2871305b61756b0134f4a": "Generer",
"00a94f58d9eb2e3aa561440eabea616d0c937fa2": "Dette vil slette din gamle API-nøkkel!",
"d5d7c61349f3b0859336066e6d453fc35d334fe5": "Bruk YouTube-API",
"ce10d31febb3d9d60c160750570310f303a22c22": "YouTube-API-nøkkel",
"8602e313cdfa7c4cc475ccbe86459fce3c3fd986": "Å generere en nøkkel er lett!",
"9b3cedfa83c6d7acb3210953289d1be4aab115c7": "Klikk her",
"7f09776373995003161235c0c8d02b7f91dbc4df": "for å laste ned den offisielle Chrome-utvidelsen for YouTubeDL-Material selv.",
"5b5296423906ab3371fdb2b5a5aaa83acaa2ee52": "Du må manuelt laste ned utvidelsen og endre dens innstillinger for å sette skjermflate-nettadresse.",
"9a2ec6da48771128384887525bdcac992632c863": "for å installere den offisielle Firefox-utvidelsen for YouTubeDL-Material rett fra Firefox sin utvidelsesside.",
"eb81be6b49e195e5307811d1d08a19259d411f37": "Detaljert oppsettsinstruks",
"cb17ff8fe3961cf90f44bee97c88a3f3347a7e55": "Ikke mye kreves annet enn å endre utvidelses innstillinger for å sette skjermflate-nettadresse.",
"61b81b11aad0b9d970ece2fce18405f07eac69c2": "Dra lenken nedenfor til bokmerker. Naviger til YouTube-videoen du ønsker å laste ned og klikk på bokmerket.",
"c505d6c5de63cc700f0aaf8a4b31fae9e18024e5": "Genrer \"kun lyd\"-bookmerke",
"d5f69691f9f05711633128b5a3db696783266b58": "Ekstra",
"5fab47f146b0a4b809dcebf3db9da94df6299ea1": "Bruk forvalgt nedlastingsagent",
"ec71e08aee647ea4a71fd6b7510c54d84a797ca6": "Velg en nedlaster",
"0c43af932e6a4ee85500e28f01b3538b4eb27bc4": "Loggingsnivå",
"db6c192032f4cab809aad35215f0aa4765761897": "Innloggingsutløp",
"dc3d990391c944d1fbfc7cfb402f7b5e112fb3a8": "Tillat avansert nedlasting",
"431e5f3a0dde88768d1074baedd65266412b3f02": "Bruk kaker",
"80651a7ad1229ea6613557d3559f702cfa5aecf5": "Sett kaker",
"bc2e854e111ecf2bd7db170da5e3c2ed08181d88": "Avansert",
"37224420db54d4bc7696f157b779a7225f03ca9d": "Tillat brukerregistrering",
"4f56ced9d6b85aeb1d4346433361d47ea72dac1a": "Intern",
"e3d7c5f019e79a3235a28ba24df24f11712c7627": "LDAP",
"fa548cee6ea11c160a416cac3e6bdec0363883dc": "Autentiseringsmetode",
"1db9789b93069861019bd0ccaa5d4706b00afc61": "LDAP-nettadresse",
"f50fa6c09c8944aed504f6325f2913ee6c7a296a": "BIND-DN",
"080cc6abcba236390fc22e79792d0d3443a3bd2a": "BIND-identitetsdetaljer",
"cfa67d14d84fe0e9fadf251dc51ffc181173b662": "Søkebase",
"e01d54ecc1a0fcf9525a3c100ed8b83d94e61c23": "Søkefilter",
"4d13a9cd5ed3dcee0eab22cb25198d43886942be": "Brukere",
"eb3d5aefff38a814b76da74371cbf02c0789a1ef": "Logger",
"fe8fd36dbf5deee1d56564965787a782a66eba44": "{VAR_SELECT, select, true {Close} false {Cancel} other {otha} }",
"cec82c0a545f37420d55a9b6c45c20546e82f94e": "Om YouTubeDL-Material",
"199c17e5d6a419313af3c325f06dcbb9645ca618": "er en fri YouTube-nedlaster bygd i henhold til Google sine Materielle spesifikasjoner. Du kan sømløst laste ned dine favorittvideoer som video- eller lydfiler, og tilogmed abonnere på dine favorittkanaler og spillelister for å holde deg oppdatert med nye videoer.",
"bc0ad0ee6630acb7fcb7802ec79f5a0ee943c1a7": "har noen flotte funksjoner inkludert. Et vidtfavnende API, Docker-støtte, og lokalisering (oversettelser)-støtte. Les om alle støttede funksjoner ved å klikke på GitHub-ikonet ovenfor.",
"a45e3b05f0529dc5246d70ef62304c94426d4c81": "Installert versjon:",
"e22f3a5351944f3a1a10cfc7da6f65dfbe0037fe": "Ser etter oppdateringer …",
"a16e92385b4fd9677bb830a4b796b8b79c113290": "Oppdatering tilgjengelig",
"189b28aaa19b3c51c6111ad039c4fd5e2a22e370": "Du kan oppdatere fra innstillingsmenyen.",
"b33536f59b94ec935a16bd6869d836895dc5300c": "Funnet en feil eller har et forslag å komme med?",
"e1f398f38ff1534303d4bb80bd6cece245f24016": "for å opprette en feilrapport.",
"42ff677ec14f111e88bd6cdd30145378e994d1bf": "Din profil",
"ac9d09de42edca1296371e4d801349c9096ac8de": "UID:",
"a5ed099ffc9e96f6970df843289ade8a7d20ab9f": "Opprettet:",
"fa96f2137af0a24e6d6d54c598c0af7d5d5ad344": "Du er ikke innlogget.",
"6765b4c916060f6bc42d9bb69e80377dbcb5e4e9": "Logg inn",
"bb694b49d408265c91c62799c2b3a7e3151c824d": "Logg ut",
"a1dbca87b9f36d2b06a5cbcffb5814c4ae9b798a": "Opprett administratorkonto",
"2d2adf3ca26a676bca2269295b7455a26fd26980": "Fant ingen administratorkonto. Dette vil opprette og sette passord for en slik konto med brukernavn som «admin».",
"70a67e04629f6d412db0a12d51820b480788d795": "Opprett",
"994363f08f9fbfa3b3994ff7b35c6904fdff18d8": "Profil",
"004b222ff9ef9dd4771b777950ca1d0e4cd4348a": "Om",
"92eee6be6de0b11c924e3ab27db30257159c0a7c": "Hjem",
"357064ca9d9ac859eb618e28e8126fa32be049e2": "Abonnementer",
"822fab38216f64e8166d368b59fe756ca39d301b": "Nedlastinger",
"a249a5ae13e0835383885aaf697d2890cc3e53e9": "Del spilleliste",
"15da89490e04496ca9ea1e1b3d44fb5efd4a75d9": "Del video",
"1d540dcd271b316545d070f9d182c372d923aadd": "Del lyd",
"1f6d14a780a37a97899dc611881e6bc971268285": "Skru på deling",
"6580b6a950d952df847cb3d8e7176720a740adc8": "Bruk tidsstempel",
"4f2ed9e71a7c981db3e50ae2fedb28aff2ec4e6c": "Sekunder",
"3a6e5a6aa78ca864f6542410c5dafb6334538106": "Kopier til utklippstavle",
"5b3075e8dc3f3921ec316b0bd83b6d14a06c1a4f": "Lagre endringer",
"4d8a18b04a1f785ecd8021ac824e0dfd5881dbfc": "Nedlastet",
"348cc5d553b18e862eb1c1770e5636f6b05ba130": "En feil inntraff",
"4f8b2bb476981727ab34ed40fde1218361f92c45": "Detaljer",
"e9aff8e6df2e2bf6299ea27bb2894c70bc48bd4d": "En feil har inntruffet:",
"77b0c73840665945b25bd128709aa64c8f017e1c": "Nedlastingsstart:",
"08ff9375ec078065bcdd7637b7ea65fce2979266": "Nedlastingsslutt:",
"ad127117f9471612f47d01eae09709da444a36a4": "Filsti(er):",
"a9806cf78ce00eb2613eeca11354a97e033377b8": "Abonner på en spilleliste eller kanal",
"93efc99ae087fc116de708ecd3ace86ca237cf30": "Spilleliste- eller kanal-nettadressen",
"08f5d0ef937ae17feb1b04aff15ad88911e87baf": "Egendefinert navn",
"ea30873bd3f0d5e4fb2378eec3f0a1db77634a28": "Last ned alle opplastinger",
"28a678e9cabf86e44c32594c43fa0e890135c20f": "Last ned videoer oppdatert siste",
"c76a955642714b8949ff3e4b4990864a2e2cac95": "Kun lyd-modus",
"408ca4911457e84a348cecf214f02c69289aa8f1": "Kun strømming-modus",
"f432e1a8d6adb12e612127978ce2e0ced933959c": "Disse legges til etter standard-argumentene.",
"98b6ec9ec138186d663e64770267b67334353d63": "Egendefinert filutdata",
"d0336848b0c375a1c25ba369b3481ee383217a4f": "Abonner",
"e78c0d60ac39787f62c9159646fe0b3c1ed55a1d": "Type:",
"a44d86aa1e6c20ced07aca3a7c081d8db9ded1c6": "Arkiv:",
"8efc77bf327659c0fec1f518cf48a98cdcd9dddf": "Eksporter arkiv",
"3042bd3ad8dffcfeca5fd1ae6159fd1047434e95": "Opphev abonnement",
"e2319dec5b4ccfb6ed9f55ccabd63650a8fdf547": "Dine abonnementer",
"807cf11e6ac1cde912496f764c176bdfdd6b7e19": "Kanaler",
"29b89f751593e1b347eef103891b7a1ff36ec03f": "Navn ikke tilgjengelig. Henter kanal …",
"4636cd4a1379c50d471e98786098c4d39e1e82ad": "Du har ingen kanalabonnementer.",
"47546e45bbb476baaaad38244db444c427ddc502": "Spillelister",
"2e0a410652cb07d069f576b61eab32586a18320d": "Navn ikke tilgjengelig. Henter spilleliste …",
"587b57ced54965d8874c3fd0e9dfedb987e5df04": "Du har ingen spillelisteabonnement.",
"3697f8583ea42868aa269489ad366103d94aece7": "Redigering",
"7e892ba15f2c6c17e83510e273b3e10fc32ea016": "Søk",
"2054791b822475aeaea95c0119113de3200f5e1c": "Lengde:",
"94e01842dcee90531caa52e4147f70679bac87fe": "Slett og last ned igjen",
"2031adb51e07a41844e8ba7704b054e98345c9c1": "Slett for alltid",
"91ecce65f1d23f9419d1c953cd6b7bc7f91c110e": "Oppdaterer",
"1372e61c5bd06100844bd43b98b016aabc468f62": "Velg en versjon:",
"cfc2f436ec2beffb042e7511a73c89c372e86a6c": "Regustrer",
"a1ad8b1be9be43b5183bd2c3186d4e19496f2a0b": "Økt-ID:",
"eb98135e35af26a9a326ee69bd8ff104d36dd8ec": "(nåværende)",
"b6c453e0e61faea184bbaf5c5b0a1e164f4de2a2": "Tøm alle nedlastinger",
"7117fc42f860e86d983bfccfcf2654e5750f3406": "Ingen nedlastninger tilgjengelige!",
"b7ff2e2b909c53abe088fe60b9f4b6ac7757247f": "Registrer en bruker",
"024886ca34a6f309e3e51c2ed849320592c3faaa": "Brukernavn",
"2bd201aea09e43fbfd3cd15ec0499b6755302329": "Håndter bruker",
"29c97c8e76763bb15b6d515648fa5bd1eb0f7510": "Bruker-UID:",
"e70e209561583f360b1e9cefd2cbb1fe434b6229": "Nytt passord",
"6498fa1b8f563988f769654a75411bb8060134b9": "Sett nytt passord",
"544e09cdc99a8978f48521d45f62db0da6dcf742": "Bruk rolle-forvalg",
"4f20f2d5a6882190892e58b85f6ccbedfa737952": "Ja",
"3d3ae7deebc5949b0c1c78b9847886a94321d9fd": "Nei",
"57c6c05d8ebf4ef1180c2705033c044f655bb2c4": "Håndter rolle",
"746f64ddd9001ac456327cd9a3d5152203a4b93c": "Brukernavn",
"52c1447c1ec9570a2a3025c7e566557b8d19ed92": "Rolle",
"59a8c38db3091a63ac1cb9590188dc3a972acfb3": "Handlinger",
"632e8b20c98e8eec4059a605a4b011bb476137af": "Rediger bruker",
"95b95a9c79e4fd9ed41f6855e37b3b06af25bcab": "Slett bruker",
"4d92a0395dd66778a931460118626c5794a3fc7a": "Legg til brukere",
"b0d7dd8a1b0349622d6e0c6e643e24a9ea0efa1d": "Rediger rolle",
"5009630cdf32ab4f1c78737b9617b8773512c05a": "Linjer:",
"8a0bda4c47f10b2423ff183acefbf70d4ab52ea2": "Tøm logger",
"ccf5ea825526ac490974336cb5c24352886abc07": "Åpne fil",
"5656a06f17c24b2d7eae9c221567b209743829a9": "Åpne fil i ny fane",
"a0720c36ee1057e5c54a86591b722485c62d7b1a": "Gå til abonnement",
"d02888c485d3aeab6de628508f4a00312a722894": "Mine videoer"
}

View File

@@ -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. (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>
<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>
<context-group purpose="location">
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
<context context-type="linenumber">134</context>

View File

@@ -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>
@@ -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. (Set args for subscriptions for each subscriptions separately!) Args are delimited using two commas like so: ,,</source>
<target>开始页面上用于下载的全局自定义参数。(单独为每个订阅设置订阅参数!) 参数由两个逗号分隔:,,</target>
<source>Global custom args for downloads on the home page. 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>

View File

@@ -33,18 +33,7 @@ async function createLocalizationJSON() {
for (let i = 0; i < files.length; i++) {
const file = path.basename(files[i]);
const file_parts = file.split('.');
if (file_parts.length !== 3 || file_parts[1] === 'en') continue;
try {
const locale_json = fs.readJSONSync(files[i]);
const locale_json_keys = Object.keys(locale_json);
let has_defined_keys = false;
for (let i = 0; i < locale_json_keys.length; i++) {
if (locale_json[locale_json_keys[i]] !== '') has_defined_keys = true;
}
if (has_defined_keys) locales.push(file_parts[1]);
} catch (err) {
console.error(err);
}
locales.push(file_parts[1]);
}
fs.unlinkSync('src/assets/i18n/messages.en.json');