mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-09 22:31:14 +03:00
Compare commits
63 Commits
bug-fixes
...
angular-17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2baa30d9a | ||
|
|
a74bca05cc | ||
|
|
7d3458ea41 | ||
|
|
6a7c1c9d0b | ||
|
|
e2e3dd280a | ||
|
|
25bf7a6fdd | ||
|
|
c56987ddd5 | ||
|
|
72399b09e4 | ||
|
|
4258b82040 | ||
|
|
7ac6a50b41 | ||
|
|
fb92975b73 | ||
|
|
b4cf1e39b9 | ||
|
|
026f24a327 | ||
|
|
1bf348f481 | ||
|
|
eb8cd3fd06 | ||
|
|
f96ffab530 | ||
|
|
dcb53691e3 | ||
|
|
2cf21541bb | ||
|
|
13e46397e9 | ||
|
|
7f079c56d0 | ||
|
|
e082919cd0 | ||
|
|
a89378b99f | ||
|
|
4dc899439e | ||
|
|
9b38c56528 | ||
|
|
0644b194d0 | ||
|
|
344d959c05 | ||
|
|
3912655912 | ||
|
|
cdf82abf3f | ||
|
|
84464db0e0 | ||
|
|
4bf03bfd1a | ||
|
|
75cbe4d5d0 | ||
|
|
9556f9c94f | ||
|
|
4a97fa4ef5 | ||
|
|
2c155b74a9 | ||
|
|
25e4c114e8 | ||
|
|
6152df3486 | ||
|
|
7cf5d86fc3 | ||
|
|
f57e0ab187 | ||
|
|
517c9e169d | ||
|
|
69d8751484 | ||
|
|
c3c8f50a92 | ||
|
|
caadf4f9d2 | ||
|
|
d10401cead | ||
|
|
d02d100001 | ||
|
|
6b59446a37 | ||
|
|
d30c338189 | ||
|
|
509e996107 | ||
|
|
353c35cd8d | ||
|
|
169a057c37 | ||
|
|
ab6d0f199e | ||
|
|
ae48a4c195 | ||
|
|
241473b99d | ||
|
|
ba98548662 | ||
|
|
72419d7be9 | ||
|
|
cc0fa03aca | ||
|
|
477cba93cd | ||
|
|
eda3dfcac7 | ||
|
|
188876e383 | ||
|
|
2c70e1367d | ||
|
|
7012524c61 | ||
|
|
cc6dfbf928 | ||
|
|
6ebda81225 | ||
|
|
a50476ac58 |
39
.devcontainer/devcontainer.json
Normal file
39
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
||||||
|
{
|
||||||
|
"name": "Node.js",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers-contrib/features/jshint:2": {},
|
||||||
|
"ghcr.io/devcontainers-contrib/features/angular-cli:2": {},
|
||||||
|
"ghcr.io/devcontainers/features/github-cli:1": {}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
"forwardPorts": [4200, 17442],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "npm install && cd backend && npm install",
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
"customizations": {
|
||||||
|
// Configure properties specific to VS Code.
|
||||||
|
"vscode": {
|
||||||
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python",
|
||||||
|
"Angular.ng-template",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"waderyan.gitblame",
|
||||||
|
"42Crunch.vscode-openapi",
|
||||||
|
"christian-kohler.npm-intellisense",
|
||||||
|
"redhat.vscode-yaml",
|
||||||
|
"hbenl.vscode-mocha-test-adapter",
|
||||||
|
"DavidAnson.vscode-markdownlint"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
||||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -13,11 +13,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: setup node
|
- name: setup node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '18'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- name: install dependencies
|
- name: install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
if: contains(github.ref, '/tags/v')
|
if: contains(github.ref, '/tags/v')
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: create release
|
- name: create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
|
|||||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
|
|||||||
4
.github/workflows/docker-pr.yml
vendored
4
.github/workflows/docker-pr.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Set hash
|
- name: Set hash
|
||||||
id: vars
|
id: vars
|
||||||
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- name: setup multi-arch docker build
|
- name: setup multi-arch docker build
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: build & push images
|
- name: build & push images
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
10
.github/workflows/docker-release.yml
vendored
10
.github/workflows/docker-release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set hash
|
- name: Set hash
|
||||||
id: vars
|
id: vars
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate Docker image metadata
|
- name: Generate Docker image metadata
|
||||||
id: docker-meta
|
id: docker-meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
|
${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
|
||||||
@@ -63,20 +63,20 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: build & push images
|
- name: build & push images
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set hash
|
- name: Set hash
|
||||||
id: vars
|
id: vars
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate Docker image metadata
|
- name: Generate Docker image metadata
|
||||||
id: docker-meta
|
id: docker-meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
# Defaults:
|
# Defaults:
|
||||||
# DOCKERHUB_USERNAME : tzahi12345
|
# DOCKERHUB_USERNAME : tzahi12345
|
||||||
# DOCKERHUB_REPO : youtubedl-material
|
# DOCKERHUB_REPO : youtubedl-material
|
||||||
@@ -63,20 +63,20 @@ jobs:
|
|||||||
type=sha,prefix=sha-,format=short
|
type=sha,prefix=sha-,format=short
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: build & push images
|
- name: build & push images
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
6
.github/workflows/mocha.yml
vendored
6
.github/workflows/mocha.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node:
|
node:
|
||||||
- 16
|
- 18
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '${{ matrix.node }}'
|
node-version: '${{ matrix.node }}'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: 'Cache node_modules'
|
- name: 'Cache node_modules'
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
- uses: FedericoCarboni/setup-ffmpeg@v2
|
- uses: FedericoCarboni/setup-ffmpeg@v2
|
||||||
id: setup-ffmpeg
|
id: setup-ffmpeg
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: npm install
|
run: npm install --dev
|
||||||
working-directory: ./backend
|
working-directory: ./backend
|
||||||
- name: Run All Node.js Tests
|
- name: Run All Node.js Tests
|
||||||
run: npm run test
|
run: npm run test
|
||||||
|
|||||||
28
Dockerfile
28
Dockerfile
@@ -1,5 +1,5 @@
|
|||||||
# Fetching our utils
|
# Fetching our utils
|
||||||
FROM ubuntu:22.04 AS utils
|
FROM ubuntu:23.04 AS utils
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
# Use script due local build compability
|
# Use script due local build compability
|
||||||
COPY docker-utils/*.sh .
|
COPY docker-utils/*.sh .
|
||||||
@@ -8,23 +8,23 @@ RUN sh ./ffmpeg-fetch.sh
|
|||||||
RUN sh ./fetch-twitchdownloader.sh
|
RUN sh ./fetch-twitchdownloader.sh
|
||||||
|
|
||||||
|
|
||||||
# Create our Ubuntu 22.04 with node 16.14.2 (that specific version is required as per: https://stackoverflow.com/a/72855258/8088021)
|
# Create our Ubuntu 22.04 with node 18.19.0
|
||||||
# Go to 20.04
|
FROM ubuntu:23.04 AS base
|
||||||
FROM ubuntu:22.04 AS base
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV UID=1000
|
ENV UID=1001
|
||||||
ENV GID=1000
|
ENV GID=1001
|
||||||
ENV USER=youtube
|
ENV USER=youtube
|
||||||
ENV NO_UPDATE_NOTIFIER=true
|
ENV NO_UPDATE_NOTIFIER=true
|
||||||
ENV PM2_HOME=/app/pm2
|
ENV PM2_HOME=/app/pm2
|
||||||
ENV ALLOW_CONFIG_MUTATIONS=true
|
ENV ALLOW_CONFIG_MUTATIONS=true
|
||||||
|
ENV npm_config_cache=/app/.npm
|
||||||
|
|
||||||
# Use NVM to get specific node version
|
# Use NVM to get specific node version
|
||||||
ENV NODE_VERSION=16.14.2
|
ENV NODE_VERSION=18.19.0
|
||||||
RUN groupadd -g $GID $USER && useradd --system -m -g $USER --uid $UID $USER && \
|
RUN groupadd -g $GID $USER && useradd --system -m -g $USER --uid $UID $USER && \
|
||||||
apt update && \
|
apt update && \
|
||||||
apt install -y --no-install-recommends curl ca-certificates tzdata libicu70 libatomic1 && \
|
apt install -y --no-install-recommends curl ca-certificates tzdata libatomic1 && \
|
||||||
apt clean && \
|
apt clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@@ -36,9 +36,11 @@ RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION}
|
|||||||
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION}
|
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION}
|
||||||
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
|
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
|
||||||
|
|
||||||
|
RUN npm install -g npm
|
||||||
|
|
||||||
# Build frontend
|
# Build frontend
|
||||||
ARG BUILDPLATFORM
|
ARG BUILDPLATFORM
|
||||||
FROM --platform=${BUILDPLATFORM} node:16 as frontend
|
FROM --platform=${BUILDPLATFORM} node:18 as frontend
|
||||||
RUN npm install -g @angular/cli
|
RUN npm install -g @angular/cli
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY [ "package.json", "package-lock.json", "angular.json", "tsconfig.json", "/build/" ]
|
COPY [ "package.json", "package-lock.json", "angular.json", "tsconfig.json", "/build/" ]
|
||||||
@@ -55,6 +57,8 @@ FROM base as backend
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY [ "backend/","/app/" ]
|
COPY [ "backend/","/app/" ]
|
||||||
RUN npm config set strict-ssl false && \
|
RUN npm config set strict-ssl false && \
|
||||||
|
npm config set registry https://registry.npm.taobao.org && \
|
||||||
|
npm config set fetch-retry-maxtimeout 60000 && \
|
||||||
npm install --prod && \
|
npm install --prod && \
|
||||||
ls -al
|
ls -al
|
||||||
|
|
||||||
@@ -71,10 +75,10 @@ RUN npm config set strict-ssl false && \
|
|||||||
|
|
||||||
# Final image
|
# Final image
|
||||||
FROM base
|
FROM base
|
||||||
RUN npm install -g pm2 && \
|
RUN apt update && \
|
||||||
apt update && \
|
curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh | bash && \
|
||||||
apt install -y --no-install-recommends gosu python3-minimal python-is-python3 python3-pip atomicparsley build-essential && \
|
apt install -y --no-install-recommends gosu python3-minimal python-is-python3 python3-pip atomicparsley build-essential && \
|
||||||
pip install pycryptodomex && \
|
pip install pycryptodomex --break-system-packages && \
|
||||||
apt remove -y --purge build-essential && \
|
apt remove -y --purge build-essential && \
|
||||||
apt autoremove -y --purge && \
|
apt autoremove -y --purge && \
|
||||||
apt clean && \
|
apt clean && \
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[](https://github.com/Tzahi12345/YoutubeDL-Material/issues)
|
[](https://github.com/Tzahi12345/YoutubeDL-Material/issues)
|
||||||
[](https://github.com/Tzahi12345/YoutubeDL-Material/blob/master/LICENSE.md)
|
[](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 15](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 17](https://angular.io/) for the frontend, and [Node.js](https://nodejs.org/) on the backend.
|
||||||
|
|
||||||
Now with [Docker](#Docker) support!
|
Now with [Docker](#Docker) support!
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ NOTE: If you would like to use Docker, you can skip down to the [Docker](#Docker
|
|||||||
|
|
||||||
Required dependencies:
|
Required dependencies:
|
||||||
|
|
||||||
* Node.js 16
|
* Node.js 18
|
||||||
* Python
|
* Python
|
||||||
|
|
||||||
Optional dependencies:
|
Optional dependencies:
|
||||||
@@ -42,7 +42,7 @@ Optional dependencies:
|
|||||||
<summary>Debian/Ubuntu</summary>
|
<summary>Debian/Ubuntu</summary>
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
|
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||||
sudo apt-get install nodejs youtube-dl ffmpeg unzip python npm
|
sudo apt-get install nodejs youtube-dl ffmpeg unzip python npm
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ sudo yum localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfu
|
|||||||
sudo yum install centos-release-scl-rh
|
sudo yum install centos-release-scl-rh
|
||||||
sudo yum install rh-nodejs12
|
sudo yum install rh-nodejs12
|
||||||
scl enable rh-nodejs12 bash
|
scl enable rh-nodejs12 bash
|
||||||
curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash -
|
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
|
||||||
sudo yum install nodejs youtube-dl ffmpeg ffmpeg-devel
|
sudo yum install nodejs youtube-dl ffmpeg ffmpeg-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
19
angular.json
19
angular.json
@@ -66,6 +66,14 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"codespaces": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.codespaces.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"es": {
|
"es": {
|
||||||
"localize": ["es"]
|
"localize": ["es"]
|
||||||
}
|
}
|
||||||
@@ -75,21 +83,24 @@
|
|||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "youtube-dl-material:build"
|
"buildTarget": "youtube-dl-material:build"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "youtube-dl-material:build:production"
|
"buildTarget": "youtube-dl-material:build:production"
|
||||||
},
|
},
|
||||||
"es": {
|
"es": {
|
||||||
"browserTarget": "youtube-dl-material:build:es"
|
"buildTarget": "youtube-dl-material:build:es"
|
||||||
|
},
|
||||||
|
"codespaces": {
|
||||||
|
"buildTarget": "youtube-dl-material:build:codespaces"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extract-i18n": {
|
"extract-i18n": {
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "youtube-dl-material:build"
|
"buildTarget": "youtube-dl-material:build"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"serve-electron": {
|
"serve-electron": {
|
||||||
|
|||||||
@@ -565,6 +565,7 @@ function loadConfigValues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getOrigin() {
|
function getOrigin() {
|
||||||
|
if (process.env.CODESPACES) return `https://${process.env.CODESPACE_NAME}-4200.${process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}`;
|
||||||
return url_domain.origin;
|
return url_domain.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,17 +590,6 @@ function generateEnvVarConfigItem(key) {
|
|||||||
return {key: key, value: process['env'][key]};
|
return {key: key, value: process['env'][key]};
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently only works for single urls
|
|
||||||
async function getUrlInfos(url) {
|
|
||||||
const {parsed_output, err} = await youtubedl_api.runYoutubeDL(url, ['--dump-json']);
|
|
||||||
if (!parsed_output || parsed_output.length !== 1) {
|
|
||||||
logger.error(`Failed to retrieve available formats for url: ${url}`);
|
|
||||||
if (err) logger.error(err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return parsed_output[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// youtube-dl functions
|
// youtube-dl functions
|
||||||
|
|
||||||
async function startYoutubeDL() {
|
async function startYoutubeDL() {
|
||||||
@@ -1870,11 +1860,11 @@ app.post('/api/clearAllLogs', optionalJwt, async function(req, res) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/getFileFormats', optionalJwt, async (req, res) => {
|
app.post('/api/getFileFormats', optionalJwt, async (req, res) => {
|
||||||
let url = req.body.url;
|
const url = req.body.url;
|
||||||
let result = await getUrlInfos(url);
|
const result = await downloader_api.getVideoInfoByURL(url);
|
||||||
res.send({
|
res.send({
|
||||||
result: result,
|
result: result && result.length === 1 ? result[0] : null,
|
||||||
success: !!result
|
success: result && result.length === 0
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -521,6 +521,8 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f
|
|||||||
downloadConfig.push('--write-thumbnail');
|
downloadConfig.push('--write-thumbnail');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadConfig.push('-i');
|
||||||
|
|
||||||
if (globalArgs && globalArgs !== '') {
|
if (globalArgs && globalArgs !== '') {
|
||||||
// adds global args
|
// adds global args
|
||||||
if (downloadConfig.indexOf('-o') !== -1 && globalArgs.split(',,').indexOf('-o') !== -1) {
|
if (downloadConfig.indexOf('-o') !== -1 && globalArgs.split(',,').indexOf('-o') !== -1) {
|
||||||
@@ -571,8 +573,8 @@ exports.getVideoInfoByURL = async (url, args = [], download_uid = null) => {
|
|||||||
let {callback} = await youtubedl_api.runYoutubeDL(url, new_args);
|
let {callback} = await youtubedl_api.runYoutubeDL(url, new_args);
|
||||||
const {parsed_output, err} = await callback;
|
const {parsed_output, err} = await callback;
|
||||||
if (!parsed_output || parsed_output.length === 0) {
|
if (!parsed_output || parsed_output.length === 0) {
|
||||||
let error_message = `Error while retrieving info on video with URL ${url} with the following message: ${err}`;
|
let error_message = `Error while retrieving info on video with URL ${url}`;
|
||||||
if (err.stderr) error_message += `\n\n${err.stderr}`;
|
if (err.stderr) error_message += ` with the following message: \n${err.stderr}`;
|
||||||
logger.error(error_message);
|
logger.error(error_message);
|
||||||
if (download_uid) {
|
if (download_uid) {
|
||||||
await handleDownloadError(download_uid, error_message, 'info_retrieve_failed');
|
await handleDownloadError(download_uid, error_message, 'info_retrieve_failed');
|
||||||
|
|||||||
154
backend/package-lock.json
generated
154
backend/package-lock.json
generated
@@ -30,7 +30,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
"mocha": "^9.2.2",
|
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"mongodb": "^3.6.9",
|
"mongodb": "^3.6.9",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
@@ -54,6 +53,9 @@
|
|||||||
"winston": "^3.7.2",
|
"winston": "^3.7.2",
|
||||||
"xmlbuilder2": "^3.0.2"
|
"xmlbuilder2": "^3.0.2"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "^10.2.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16",
|
"node": "^16",
|
||||||
"npm": "6.14.4"
|
"npm": "6.14.4"
|
||||||
@@ -363,11 +365,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ungap/promise-all-settled": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
|
|
||||||
},
|
|
||||||
"node_modules/@vladfrangu/async_event_emitter": {
|
"node_modules/@vladfrangu/async_event_emitter": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.1.tgz",
|
||||||
@@ -413,6 +410,7 @@
|
|||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||||
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
|
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -421,6 +419,7 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -429,6 +428,7 @@
|
|||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -443,6 +443,7 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-name": "~1.1.4"
|
"color-name": "~1.1.4"
|
||||||
},
|
},
|
||||||
@@ -453,7 +454,8 @@
|
|||||||
"node_modules/ansi-styles/node_modules/color-name": {
|
"node_modules/ansi-styles/node_modules/color-name": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/any-promise": {
|
"node_modules/any-promise": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
@@ -464,6 +466,7 @@
|
|||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
@@ -531,7 +534,8 @@
|
|||||||
"node_modules/argparse": {
|
"node_modules/argparse": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/array-buffer-byte-length": {
|
"node_modules/array-buffer-byte-length": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -707,6 +711,7 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -770,6 +775,7 @@
|
|||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.0.1"
|
||||||
},
|
},
|
||||||
@@ -780,7 +786,8 @@
|
|||||||
"node_modules/browser-stdout": {
|
"node_modules/browser-stdout": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
||||||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
|
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/bson": {
|
"node_modules/bson": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
@@ -935,6 +942,7 @@
|
|||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"strip-ansi": "^6.0.0",
|
"strip-ansi": "^6.0.0",
|
||||||
@@ -945,6 +953,7 @@
|
|||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1"
|
"ansi-regex": "^5.0.1"
|
||||||
},
|
},
|
||||||
@@ -1253,6 +1262,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
|
||||||
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
|
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -1331,6 +1341,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
||||||
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
|
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
@@ -1524,6 +1535,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -1537,6 +1549,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -1797,6 +1810,7 @@
|
|||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
},
|
},
|
||||||
@@ -1825,6 +1839,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"locate-path": "^6.0.0",
|
"locate-path": "^6.0.0",
|
||||||
"path-exists": "^4.0.0"
|
"path-exists": "^4.0.0"
|
||||||
@@ -1840,6 +1855,7 @@
|
|||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
|
||||||
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
|
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"flat": "cli.js"
|
"flat": "cli.js"
|
||||||
}
|
}
|
||||||
@@ -1964,6 +1980,7 @@
|
|||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -2021,6 +2038,7 @@
|
|||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "6.* || 8.* || >= 10.*"
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
}
|
}
|
||||||
@@ -2095,6 +2113,7 @@
|
|||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
},
|
},
|
||||||
@@ -2181,14 +2200,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
|
||||||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
|
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
|
||||||
},
|
},
|
||||||
"node_modules/growl": {
|
|
||||||
"version": "1.10.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
|
|
||||||
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/har-schema": {
|
"node_modules/har-schema": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||||
@@ -2280,6 +2291,7 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"he": "bin/he"
|
"he": "bin/he"
|
||||||
}
|
}
|
||||||
@@ -2450,6 +2462,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"binary-extensions": "^2.0.0"
|
"binary-extensions": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -2506,6 +2519,7 @@
|
|||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -2514,6 +2528,7 @@
|
|||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
},
|
},
|
||||||
@@ -2551,6 +2566,7 @@
|
|||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12.0"
|
"node": ">=0.12.0"
|
||||||
}
|
}
|
||||||
@@ -2573,6 +2589,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -2671,6 +2688,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
||||||
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
|
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -2708,6 +2726,7 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -2905,6 +2924,7 @@
|
|||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"p-locate": "^5.0.0"
|
"p-locate": "^5.0.0"
|
||||||
},
|
},
|
||||||
@@ -2949,6 +2969,7 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||||
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
|
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"is-unicode-supported": "^0.1.0"
|
"is-unicode-supported": "^0.1.0"
|
||||||
@@ -2964,6 +2985,7 @@
|
|||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": "^4.1.0",
|
"ansi-styles": "^4.1.0",
|
||||||
"supports-color": "^7.1.0"
|
"supports-color": "^7.1.0"
|
||||||
@@ -2979,6 +3001,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -2987,6 +3010,7 @@
|
|||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -3178,41 +3202,39 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mocha": {
|
"node_modules/mocha": {
|
||||||
"version": "9.2.2",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
|
||||||
"integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
|
"integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ungap/promise-all-settled": "1.1.2",
|
|
||||||
"ansi-colors": "4.1.1",
|
"ansi-colors": "4.1.1",
|
||||||
"browser-stdout": "1.3.1",
|
"browser-stdout": "1.3.1",
|
||||||
"chokidar": "3.5.3",
|
"chokidar": "3.5.3",
|
||||||
"debug": "4.3.3",
|
"debug": "4.3.4",
|
||||||
"diff": "5.0.0",
|
"diff": "5.0.0",
|
||||||
"escape-string-regexp": "4.0.0",
|
"escape-string-regexp": "4.0.0",
|
||||||
"find-up": "5.0.0",
|
"find-up": "5.0.0",
|
||||||
"glob": "7.2.0",
|
"glob": "7.2.0",
|
||||||
"growl": "1.10.5",
|
|
||||||
"he": "1.2.0",
|
"he": "1.2.0",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"log-symbols": "4.1.0",
|
"log-symbols": "4.1.0",
|
||||||
"minimatch": "4.2.1",
|
"minimatch": "5.0.1",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
"nanoid": "3.3.1",
|
"nanoid": "3.3.3",
|
||||||
"serialize-javascript": "6.0.0",
|
"serialize-javascript": "6.0.0",
|
||||||
"strip-json-comments": "3.1.1",
|
"strip-json-comments": "3.1.1",
|
||||||
"supports-color": "8.1.1",
|
"supports-color": "8.1.1",
|
||||||
"which": "2.0.2",
|
"workerpool": "6.2.1",
|
||||||
"workerpool": "6.2.0",
|
|
||||||
"yargs": "16.2.0",
|
"yargs": "16.2.0",
|
||||||
"yargs-parser": "20.2.4",
|
"yargs-parser": "20.2.4",
|
||||||
"yargs-unparser": "2.0.0"
|
"yargs-unparser": "2.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"_mocha": "bin/_mocha",
|
"_mocha": "bin/_mocha",
|
||||||
"mocha": "bin/mocha"
|
"mocha": "bin/mocha.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 14.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -3223,6 +3245,7 @@
|
|||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -3246,9 +3269,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mocha/node_modules/debug": {
|
"node_modules/mocha/node_modules/debug": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@@ -3264,12 +3288,14 @@
|
|||||||
"node_modules/mocha/node_modules/debug/node_modules/ms": {
|
"node_modules/mocha/node_modules/debug/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/mocha/node_modules/glob": {
|
"node_modules/mocha/node_modules/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
@@ -3289,6 +3315,7 @@
|
|||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
},
|
},
|
||||||
@@ -3300,30 +3327,43 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mocha/node_modules/minimatch": {
|
"node_modules/mocha/node_modules/minimatch": {
|
||||||
"version": "4.2.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||||
"integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
|
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^2.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mocha/node_modules/ms": {
|
"node_modules/mocha/node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/mocha/node_modules/nanoid": {
|
"node_modules/mocha/node_modules/nanoid": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
|
||||||
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
|
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
@@ -3335,6 +3375,7 @@
|
|||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
},
|
},
|
||||||
@@ -3346,6 +3387,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
},
|
},
|
||||||
@@ -3357,6 +3399,7 @@
|
|||||||
"version": "8.1.1",
|
"version": "8.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -3761,6 +3804,7 @@
|
|||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yocto-queue": "^0.1.0"
|
"yocto-queue": "^0.1.0"
|
||||||
},
|
},
|
||||||
@@ -3775,6 +3819,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"p-limit": "^3.0.2"
|
"p-limit": "^3.0.2"
|
||||||
},
|
},
|
||||||
@@ -3884,6 +3929,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -3935,6 +3981,7 @@
|
|||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
},
|
},
|
||||||
@@ -4039,6 +4086,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
@@ -4245,6 +4293,7 @@
|
|||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -4391,6 +4440,7 @@
|
|||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
|
||||||
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
|
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"randombytes": "^2.1.0"
|
"randombytes": "^2.1.0"
|
||||||
}
|
}
|
||||||
@@ -4568,6 +4618,7 @@
|
|||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"is-fullwidth-code-point": "^3.0.0",
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
@@ -4580,12 +4631,14 @@
|
|||||||
"node_modules/string-width/node_modules/emoji-regex": {
|
"node_modules/string-width/node_modules/emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/string-width/node_modules/is-fullwidth-code-point": {
|
"node_modules/string-width/node_modules/is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -4594,6 +4647,7 @@
|
|||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.0"
|
"ansi-regex": "^5.0.0"
|
||||||
},
|
},
|
||||||
@@ -4726,6 +4780,7 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
},
|
},
|
||||||
@@ -5106,14 +5161,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/workerpool": {
|
"node_modules/workerpool": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
|
||||||
"integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A=="
|
"integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/wrap-ansi": {
|
"node_modules/wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": "^4.0.0",
|
"ansi-styles": "^4.0.0",
|
||||||
"string-width": "^4.1.0",
|
"string-width": "^4.1.0",
|
||||||
@@ -5130,6 +5187,7 @@
|
|||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1"
|
"ansi-regex": "^5.0.1"
|
||||||
},
|
},
|
||||||
@@ -5220,6 +5278,7 @@
|
|||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
@@ -5233,6 +5292,7 @@
|
|||||||
"version": "16.2.0",
|
"version": "16.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cliui": "^7.0.2",
|
"cliui": "^7.0.2",
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
@@ -5250,6 +5310,7 @@
|
|||||||
"version": "20.2.4",
|
"version": "20.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
||||||
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
|
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
@@ -5258,6 +5319,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
|
||||||
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
|
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"camelcase": "^6.0.0",
|
"camelcase": "^6.0.0",
|
||||||
"decamelize": "^4.0.0",
|
"decamelize": "^4.0.0",
|
||||||
@@ -5272,6 +5334,7 @@
|
|||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -5283,6 +5346,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,7 +44,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
"mocha": "^9.2.2",
|
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"mongodb": "^3.6.9",
|
"mongodb": "^3.6.9",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
@@ -67,5 +66,8 @@
|
|||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"winston": "^3.7.2",
|
"winston": "^3.7.2",
|
||||||
"xmlbuilder2": "^3.0.2"
|
"xmlbuilder2": "^3.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "^10.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -529,7 +529,9 @@ exports.parseOutputJSON = (output, err) => {
|
|||||||
let split_output = [];
|
let split_output = [];
|
||||||
// const output_jsons = [];
|
// const output_jsons = [];
|
||||||
if (err && !output) {
|
if (err && !output) {
|
||||||
if (!err.stderr.includes('This video is unavailable') && !err.stderr.includes('Private video')) {
|
const attempt_backup_errs = ['This video is unavailable', 'Private video', 'unavailable video'];
|
||||||
|
const attempt_backup = err.stderr ? attempt_backup_errs.some(err_msg => err.stderr.includes(err_msg)) : false;
|
||||||
|
if (!attempt_backup) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
logger.info('An error was encountered with at least one video, backup method will be used.')
|
logger.info('An error was encountered with at least one video, backup method will be used.')
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ const runYoutubeDLProcess = async (url, args, youtubedl_fork = config_api.getCon
|
|||||||
const parsed_output = utils.parseOutputJSON(stdout.trim().split(/\r?\n/), stderr);
|
const parsed_output = utils.parseOutputJSON(stdout.trim().split(/\r?\n/), stderr);
|
||||||
resolve({parsed_output, err: stderr});
|
resolve({parsed_output, err: stderr});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
resolve({parsed_output: null, err: e})
|
// Attempt to not fail
|
||||||
|
const parsed_output = utils.parseOutputJSON(e && e.stdout && e.stdout.trim().split(/\r?\n/), e && e.stderr);
|
||||||
|
resolve({parsed_output: parsed_output, err: parsed_output ? null : e});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {child_process, callback}
|
return {child_process, callback}
|
||||||
@@ -118,10 +120,16 @@ async function downloadLatestYoutubeDLBinaryGeneric(youtubedl_fork, new_version,
|
|||||||
const download_url = `${exports.youtubedl_forks[youtubedl_fork]['download_url']}${file_ext}`;
|
const download_url = `${exports.youtubedl_forks[youtubedl_fork]['download_url']}${file_ext}`;
|
||||||
const output_path = custom_output_path || getYoutubeDLPath(youtubedl_fork);
|
const output_path = custom_output_path || getYoutubeDLPath(youtubedl_fork);
|
||||||
|
|
||||||
await utils.fetchFile(download_url, output_path, `${youtubedl_fork} ${new_version}`);
|
try {
|
||||||
fs.chmod(output_path, 0o777);
|
await utils.fetchFile(download_url, output_path, `${youtubedl_fork} ${new_version}`);
|
||||||
|
fs.chmod(output_path, 0o777);
|
||||||
|
|
||||||
updateDetailsJSON(new_version, youtubedl_fork, output_path);
|
updateDetailsJSON(new_version, youtubedl_fork, output_path);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to download new ${youtubedl_fork} version: ${new_version}`);
|
||||||
|
logger.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getLatestUpdateVersion = async (youtubedl_fork) => {
|
exports.getLatestUpdateVersion = async (youtubedl_fork) => {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ esac
|
|||||||
|
|
||||||
echo "(INFO) Architecture detected: $ARCH"
|
echo "(INFO) Architecture detected: $ARCH"
|
||||||
echo "(1/5) READY - Install unzip"
|
echo "(1/5) READY - Install unzip"
|
||||||
apt-get update && apt-get -y install unzip curl jq libicu70
|
apt-get update && apt-get -y install unzip curl jq
|
||||||
VERSION=$(curl --silent "https://api.github.com/repos/lay295/TwitchDownloader/releases" | jq -r --arg arch "$ARCH" '[.[] | select(.assets | length > 0) | select(.assets[].name | contains("CLI") and contains($arch))] | max_by(.published_at) | .tag_name')
|
VERSION=$(curl --silent "https://api.github.com/repos/lay295/TwitchDownloader/releases" | jq -r --arg arch "$ARCH" '[.[] | select(.assets | length > 0) | select(.assets[].name | contains("CLI") and contains($arch))] | max_by(.published_at) | .tag_name')
|
||||||
echo "(2/5) DOWNLOAD - Acquire twitchdownloader"
|
echo "(2/5) DOWNLOAD - Acquire twitchdownloader"
|
||||||
curl -o twitchdownloader.zip \
|
curl -o twitchdownloader.zip \
|
||||||
|
|||||||
13591
package-lock.json
generated
13591
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
53
package.json
53
package.json
@@ -5,6 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
|
"codespaces": "ng serve --configuration=codespaces",
|
||||||
"build": "ng build --configuration production",
|
"build": "ng build --configuration production",
|
||||||
"prebuild": "node src/postbuild.mjs",
|
"prebuild": "node src/postbuild.mjs",
|
||||||
"heroku-postbuild": "npm install --prefix backend",
|
"heroku-postbuild": "npm install --prefix backend",
|
||||||
@@ -16,23 +17,23 @@
|
|||||||
"i18n-source": "ng extract-i18n --output-path=src/assets/i18n --out-file=messages.en.xlf"
|
"i18n-source": "ng extract-i18n --output-path=src/assets/i18n --out-file=messages.en.xlf"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "12.3.1",
|
"node": "18.19.0",
|
||||||
"npm": "6.10.3"
|
"npm": "10.2.3"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-devkit/core": "^15.0.1",
|
"@angular-devkit/core": "^17.0.5",
|
||||||
"@angular/animations": "^15.0.1",
|
"@angular/animations": "^17.0.5",
|
||||||
"@angular/cdk": "^15.0.0",
|
"@angular/cdk": "^17.0.2",
|
||||||
"@angular/common": "^15.0.1",
|
"@angular/common": "^17.0.5",
|
||||||
"@angular/compiler": "^15.0.1",
|
"@angular/compiler": "^17.0.5",
|
||||||
"@angular/core": "^15.0.1",
|
"@angular/core": "^17.0.5",
|
||||||
"@angular/forms": "^15.0.1",
|
"@angular/forms": "^17.0.5",
|
||||||
"@angular/localize": "^15.0.1",
|
"@angular/localize": "^17.0.5",
|
||||||
"@angular/material": "^15.0.0",
|
"@angular/material": "^17.0.2",
|
||||||
"@angular/platform-browser": "^15.0.1",
|
"@angular/platform-browser": "^17.0.5",
|
||||||
"@angular/platform-browser-dynamic": "^15.0.1",
|
"@angular/platform-browser-dynamic": "^17.0.5",
|
||||||
"@angular/router": "^15.0.1",
|
"@angular/router": "^17.0.5",
|
||||||
"@fontsource/material-icons": "^4.5.4",
|
"@fontsource/material-icons": "^4.5.4",
|
||||||
"@ngneat/content-loader": "^7.0.0",
|
"@ngneat/content-loader": "^7.0.0",
|
||||||
"@videogular/ngx-videogular": "^6.0.0",
|
"@videogular/ngx-videogular": "^6.0.0",
|
||||||
@@ -43,20 +44,19 @@
|
|||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"material-icons": "^1.10.8",
|
"material-icons": "^1.10.8",
|
||||||
"nan": "^2.14.1",
|
"nan": "^2.14.1",
|
||||||
"ngx-avatars": "^1.4.1",
|
"ngx-avatars": "^1.10.0",
|
||||||
"ngx-file-drop": "^15.0.0",
|
"ngx-file-drop": "^15.0.0",
|
||||||
"rxjs": "^6.6.3",
|
"rxjs": "^6.6.3",
|
||||||
"rxjs-compat": "^6.6.7",
|
"rxjs-compat": "^6.6.7",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"typescript": "~4.8.4",
|
|
||||||
"xliff-to-json": "^1.0.4",
|
"xliff-to-json": "^1.0.4",
|
||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.14.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^15.0.1",
|
"@angular-devkit/build-angular": "^17.0.5",
|
||||||
"@angular/cli": "^15.0.1",
|
"@angular/cli": "^17.0.5",
|
||||||
"@angular/compiler-cli": "^15.0.1",
|
"@angular/compiler-cli": "^17.0.5",
|
||||||
"@angular/language-service": "^15.0.1",
|
"@angular/language-service": "^17.0.5",
|
||||||
"@types/core-js": "^2.5.2",
|
"@types/core-js": "^2.5.2",
|
||||||
"@types/file-saver": "^2.0.1",
|
"@types/file-saver": "^2.0.1",
|
||||||
"@types/jasmine": "^4.3.1",
|
"@types/jasmine": "^4.3.1",
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
"ajv": "^7.2.4",
|
"ajv": "^7.2.4",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.8.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
"karma": "~6.4.2",
|
"karma": "~6.4.2",
|
||||||
"karma-chrome-launcher": "~3.1.0",
|
"karma-chrome-launcher": "~3.1.0",
|
||||||
@@ -77,12 +77,13 @@
|
|||||||
"openapi-typescript-codegen": "^0.23.0",
|
"openapi-typescript-codegen": "^0.23.0",
|
||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"ts-node": "~3.0.4",
|
"ts-node": "~3.0.4",
|
||||||
"tslint": "~6.1.0"
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~5.2.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"ngx-avatars": {
|
"ngx-avatars": {
|
||||||
"@angular/common": "15.0.1",
|
"@angular/common": "^17.0.0",
|
||||||
"@angular/core": "15.0.1"
|
"@angular/core": "^17.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,95 @@
|
|||||||
<div [style.background]="postsService.theme ? postsService.theme.background_color : null" style="width: 100%; height: 100%;">
|
<div [style.background]="postsService.theme ? postsService.theme.background_color : null" style="width: 100%; height: 100%;">
|
||||||
<div class="mat-elevation-z3" style="position: relative; z-index: 10;">
|
<div class="mat-elevation-z3" style="position: relative; z-index: 10;">
|
||||||
<mat-toolbar class="sticky-toolbar top-toolbar">
|
<mat-toolbar class="sticky-toolbar top-toolbar">
|
||||||
<div class="container-fluid" style="padding-left: 0px; padding-right: 0px">
|
<div class="container-fluid" style="padding-left: 0px; padding-right: 0px">
|
||||||
<div class="row" width="100%" height="100%">
|
<div class="row" width="100%" height="100%">
|
||||||
<div class="col-6" style="text-align: left; margin-top: 1px;">
|
<div class="col-6" style="text-align: left; margin-top: 1px;">
|
||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
<button #hamburgerMenu style="outline: none" *ngIf="router.url.split(';')[0] !== '/player'" mat-icon-button aria-label="Toggle side navigation" (click)="toggleSidenav()"><mat-icon>menu</mat-icon></button>
|
@if (router.url.split(';')[0] !== '/player') {
|
||||||
<button (click)="goBack()" *ngIf="router.url.split(';')[0] === '/player'" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
|
<button #hamburgerMenu style="outline: none" mat-icon-button aria-label="Toggle side navigation" (click)="toggleSidenav()"><mat-icon>menu</mat-icon></button>
|
||||||
<div style="margin-left: 8px; display: inline-block;"><button mat-icon-button routerLink='/home'><img style="width: 32px;" src="assets/images/logo_128px.png"></button></div>
|
} @else {
|
||||||
</div>
|
<button (click)="goBack()" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
|
||||||
</div>
|
}
|
||||||
<div class="col-6" style="text-align: right; align-items: flex-end; display: inline-block">
|
<div style="margin-left: 8px; display: inline-block;"><button mat-icon-button routerLink='/home'><img style="width: 32px;" src="assets/images/logo_128px.png"></button></div>
|
||||||
<button *ngIf="postsService.config?.Extra.enable_notifications" [matMenuTriggerFor]="notificationsMenu" (menuOpened)="notificationMenuOpened()" mat-icon-button><mat-icon [matBadge]="notification_count" matBadgeColor="warn" matBadgeSize="small" *ngIf="notification_count > 0">notifications</mat-icon><mat-icon *ngIf="notification_count === 0">notifications_none</mat-icon></button>
|
|
||||||
<mat-menu [classList]="'notifications-menu'" (close)="notificationMenuClosed()" #notificationsMenu="matMenu">
|
|
||||||
<app-notifications #notifications (notificationCount)="notificationCountUpdate($event)" (click)="$event.stopPropagation()"></app-notifications>
|
|
||||||
</mat-menu>
|
|
||||||
<button [matMenuTriggerFor]="menuSettings" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
|
||||||
<mat-menu #menuSettings="matMenu">
|
|
||||||
<button class="top-menu-button" (click)="openProfileDialog()" mat-menu-item>
|
|
||||||
<mat-icon>person</mat-icon>
|
|
||||||
<span i18n="Profile menu label">Profile</span>
|
|
||||||
</button>
|
|
||||||
<button *ngIf="!postsService.config?.Advanced.multi_user_mode || postsService.isLoggedIn" class="top-menu-button" (click)="openArchivesDialog()" mat-menu-item>
|
|
||||||
<mat-icon>topic</mat-icon>
|
|
||||||
<span i18n="Archives menu label">Archives</span>
|
|
||||||
</button>
|
|
||||||
<button class="top-menu-button" (click)="themeMenuItemClicked($event)" *ngIf="allowThemeChange" mat-menu-item>
|
|
||||||
<mat-icon>{{(postsService.theme.key === 'default') ? 'brightness_5' : 'brightness_2'}}</mat-icon>
|
|
||||||
<span i18n="Dark mode toggle label">Dark</span>
|
|
||||||
<mat-slide-toggle class="theme-slide-toggle" [checked]="postsService.theme.key === 'dark'"></mat-slide-toggle>
|
|
||||||
</button>
|
|
||||||
<button class="top-menu-button" (click)="openAboutDialog()" mat-menu-item>
|
|
||||||
<mat-icon>info</mat-icon>
|
|
||||||
<span i18n="About menu label">About</span>
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-toolbar>
|
</div>
|
||||||
</div>
|
<div class="col-6" style="text-align: right; align-items: flex-end; display: inline-block">
|
||||||
<div class="sidenav-container" style="height: calc(100% - 64px)">
|
@if (postsService.config?.Extra.enable_notifications) {
|
||||||
<mat-sidenav-container style="height: 100%">
|
<button [matMenuTriggerFor]="notificationsMenu" (menuOpened)="notificationMenuOpened()" mat-icon-button>
|
||||||
<mat-sidenav [opened]="postsService.sidepanel_mode === 'side' && !window.location.href.includes('/player')" [mode]="postsService.sidepanel_mode" #sidenav>
|
@if (notification_count > 0) {
|
||||||
<mat-nav-list>
|
<mat-icon [matBadge]="notification_count" matBadgeColor="warn" matBadgeSize="small">notifications</mat-icon>
|
||||||
<a *ngIf="postsService.config && (!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn)" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/home'><ng-container i18n="Navigation menu Home Page title">Home</ng-container></a>
|
} @else {
|
||||||
<a *ngIf="postsService.config && postsService.config.Advanced.multi_user_mode && !postsService.isLoggedIn" mat-list-item (click)="sidenav.close()" routerLink='/login'><ng-container i18n="Navigation menu Login Page title">Login</ng-container></a>
|
<mat-icon>notifications_none</mat-icon>
|
||||||
<a *ngIf="postsService.config && allowSubscriptions && postsService.hasPermission('subscriptions')" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/subscriptions'><ng-container i18n="Navigation menu Subscriptions Page title">Subscriptions</ng-container></a>
|
}</button>
|
||||||
<a *ngIf="postsService.config && enableDownloadsManager && postsService.hasPermission('downloads_manager')" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/downloads'><ng-container i18n="Navigation menu Downloads Page title">Downloads</ng-container></a>
|
}
|
||||||
<a *ngIf="postsService.config && postsService.hasPermission('tasks_manager')" mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/tasks'><ng-container i18n="Navigation menu Tasks Page title">Tasks</ng-container></a>
|
<mat-menu [classList]="'notifications-menu'" (close)="notificationMenuClosed()" #notificationsMenu="matMenu">
|
||||||
<ng-container *ngIf="postsService.config && postsService.hasPermission('settings')">
|
<app-notifications #notifications (notificationCount)="notificationCountUpdate($event)" (click)="$event.stopPropagation()"></app-notifications>
|
||||||
<mat-divider></mat-divider>
|
</mat-menu>
|
||||||
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/settings'><ng-container i18n="Settings menu label">Settings</ng-container></a>
|
<button [matMenuTriggerFor]="menuSettings" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||||
</ng-container>
|
<mat-menu #menuSettings="matMenu">
|
||||||
<ng-container *ngIf="postsService.config && allowSubscriptions && postsService.subscriptions && postsService.hasPermission('subscriptions')">
|
<button class="top-menu-button" (click)="openProfileDialog()" mat-menu-item>
|
||||||
<mat-divider *ngIf="postsService.subscriptions.length > 0"></mat-divider>
|
<mat-icon>person</mat-icon>
|
||||||
<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.display]="'inline-block'" [style.margin-right]="'10px'" size="32" [name]="subscription.name"></ngx-avatars>{{subscription.name}}</a>
|
<span i18n="Profile menu label">Profile</span>
|
||||||
</ng-container>
|
</button>
|
||||||
</mat-nav-list>
|
@if (!postsService.config?.Advanced.multi_user_mode || postsService.isLoggedIn) {
|
||||||
</mat-sidenav>
|
<button class="top-menu-button" (click)="openArchivesDialog()" mat-menu-item>
|
||||||
<mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null">
|
<mat-icon>topic</mat-icon>
|
||||||
<router-outlet></router-outlet>
|
<span i18n="Archives menu label">Archives</span>
|
||||||
</mat-sidenav-content>
|
</button>
|
||||||
</mat-sidenav-container>
|
}
|
||||||
</div>
|
@if (allowThemeChange) {
|
||||||
|
<button class="top-menu-button" (click)="themeMenuItemClicked($event)" mat-menu-item>
|
||||||
|
<mat-icon>{{(postsService.theme.key === 'default') ? 'brightness_5' : 'brightness_2'}}</mat-icon>
|
||||||
|
<span i18n="Dark mode toggle label">Dark</span>
|
||||||
|
<mat-slide-toggle class="theme-slide-toggle" [checked]="postsService.theme.key === 'dark'"></mat-slide-toggle>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
<button class="top-menu-button" (click)="openAboutDialog()" mat-menu-item>
|
||||||
|
<mat-icon>info</mat-icon>
|
||||||
|
<span i18n="About menu label">About</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-toolbar>
|
||||||
|
</div>
|
||||||
|
<div class="sidenav-container" style="height: calc(100% - 64px)">
|
||||||
|
<mat-sidenav-container style="height: 100%">
|
||||||
|
<mat-sidenav [opened]="postsService.sidepanel_mode === 'side' && !window.location.href.includes('/player')" [mode]="postsService.sidepanel_mode" #sidenav>
|
||||||
|
<mat-nav-list>
|
||||||
|
@if (postsService.config && (!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn)) {
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/home'><ng-container i18n="Navigation menu Home Page title">Home</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && postsService.config.Advanced.multi_user_mode && !postsService.isLoggedIn) {
|
||||||
|
<a mat-list-item (click)="sidenav.close()" routerLink='/login'><ng-container i18n="Navigation menu Login Page title">Login</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && allowSubscriptions && postsService.hasPermission('subscriptions')) {
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/subscriptions'><ng-container i18n="Navigation menu Subscriptions Page title">Subscriptions</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && enableDownloadsManager && postsService.hasPermission('downloads_manager')) {
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/downloads'><ng-container i18n="Navigation menu Downloads Page title">Downloads</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && postsService.hasPermission('tasks_manager')) {
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/tasks'><ng-container i18n="Navigation menu Tasks Page title">Tasks</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && postsService.hasPermission('settings')) {
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" routerLink='/settings'><ng-container i18n="Settings menu label">Settings</ng-container></a>
|
||||||
|
}
|
||||||
|
@if (postsService.config && allowSubscriptions && postsService.subscriptions && postsService.hasPermission('subscriptions')) {
|
||||||
|
@if (postsService.subscriptions.length > 0) {
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
}
|
||||||
|
@for (subscription of postsService.subscriptions; track subscription) {
|
||||||
|
<a mat-list-item (click)="postsService.sidepanel_mode === 'over' ? sidenav.close() : null" [routerLink]="['/subscription', { id: subscription.id }]"><ngx-avatars [style.display]="'inline-block'" [style.margin-right]="'10px'" size="32" [name]="subscription.name"></ngx-avatars>{{subscription.name}}</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</mat-nav-list>
|
||||||
|
</mat-sidenav>
|
||||||
|
<mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</mat-sidenav-content>
|
||||||
|
</mat-sidenav-container>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -3,75 +3,68 @@
|
|||||||
<mat-label i18n="Filter">Filter</mat-label>
|
<mat-label i18n="Filter">Filter</mat-label>
|
||||||
<input matInput [(ngModel)]="text_filter" (keyup)="applyFilter($event)" #input>
|
<input matInput [(ngModel)]="text_filter" (keyup)="applyFilter($event)" #input>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div [hidden]="!(archives && archives.length > 0)">
|
<div [hidden]="!(archives && archives.length > 0)">
|
||||||
<div class="mat-elevation-z8">
|
<div class="mat-elevation-z8">
|
||||||
<mat-table matSort [dataSource]="dataSource">
|
<mat-table matSort [dataSource]="dataSource">
|
||||||
|
<!-- Select Column -->
|
||||||
<!-- Select Column -->
|
<!-- Checkbox Column -->
|
||||||
<!-- Checkbox Column -->
|
<ng-container matColumnDef="select">
|
||||||
<ng-container matColumnDef="select">
|
<mat-header-cell *matHeaderCellDef>
|
||||||
<mat-header-cell *matHeaderCellDef>
|
<mat-checkbox (change)="$event ? toggleAllRows() : null"
|
||||||
<mat-checkbox (change)="$event ? toggleAllRows() : null"
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
</mat-checkbox>
|
||||||
</mat-checkbox>
|
</mat-header-cell>
|
||||||
</mat-header-cell>
|
<mat-cell *matCellDef="let row">
|
||||||
<mat-cell *matCellDef="let row">
|
<mat-checkbox (click)="$event.stopPropagation()"
|
||||||
<mat-checkbox (click)="$event.stopPropagation()"
|
(change)="$event ? selection.toggle(row) : null"
|
||||||
(change)="$event ? selection.toggle(row) : null"
|
[checked]="selection.isSelected(row)">
|
||||||
[checked]="selection.isSelected(row)">
|
</mat-checkbox>
|
||||||
</mat-checkbox>
|
<mat-icon class="audio-video-icon">{{(row.type === 'audio') ? 'audiotrack' : 'movie'}}</mat-icon>
|
||||||
<mat-icon class="audio-video-icon">{{(row.type === 'audio') ? 'audiotrack' : 'movie'}}</mat-icon>
|
</mat-cell>
|
||||||
</mat-cell>
|
</ng-container>
|
||||||
</ng-container>
|
<!-- Date Column -->
|
||||||
|
<ng-container matColumnDef="timestamp">
|
||||||
<!-- Date Column -->
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Date">Date</ng-container> </mat-header-cell>
|
||||||
<ng-container matColumnDef="timestamp">
|
<mat-cell *matCellDef="let element"> {{element.timestamp*1000 | date: 'short'}} </mat-cell>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Date">Date</ng-container> </mat-header-cell>
|
</ng-container>
|
||||||
<mat-cell *matCellDef="let element"> {{element.timestamp*1000 | date: 'short'}} </mat-cell>
|
<!-- Title Column -->
|
||||||
</ng-container>
|
<ng-container matColumnDef="title">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
||||||
<!-- Title Column -->
|
<mat-cell *matCellDef="let element">
|
||||||
<ng-container matColumnDef="title">
|
<span class="max-two-lines" [matTooltip]="element.title ? element.title : null">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
{{element.title}}
|
||||||
<mat-cell *matCellDef="let element">
|
</span>
|
||||||
<span class="max-two-lines" [matTooltip]="element.title ? element.title : null">
|
</mat-cell>
|
||||||
{{element.title}}
|
</ng-container>
|
||||||
</span>
|
<!-- ID Column -->
|
||||||
</mat-cell>
|
<ng-container matColumnDef="id">
|
||||||
</ng-container>
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="ID">ID</ng-container> </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let element">
|
||||||
<!-- ID Column -->
|
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
||||||
<ng-container matColumnDef="id">
|
{{element.id}}
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="ID">ID</ng-container> </mat-header-cell>
|
</span>
|
||||||
<mat-cell *matCellDef="let element">
|
</mat-cell>
|
||||||
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
</ng-container>
|
||||||
{{element.id}}
|
<!-- Extractor Column -->
|
||||||
</span>
|
<ng-container matColumnDef="extractor">
|
||||||
</mat-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Extractor">Extractor</ng-container> </mat-header-cell>
|
||||||
</ng-container>
|
<mat-cell *matCellDef="let element">
|
||||||
|
<span class="one-line" [matTooltip]="element.extractor? element.extractor : null">
|
||||||
<!-- Extractor Column -->
|
{{element.extractor}}
|
||||||
<ng-container matColumnDef="extractor">
|
</span>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Extractor">Extractor</ng-container> </mat-header-cell>
|
</mat-cell>
|
||||||
<mat-cell *matCellDef="let element">
|
</ng-container>
|
||||||
<span class="one-line" [matTooltip]="element.extractor? element.extractor : null">
|
<mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
|
||||||
{{element.extractor}}
|
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||||
</span>
|
</mat-table>
|
||||||
</mat-cell>
|
</div>
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
|
|
||||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
|
||||||
</mat-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@if ((!archives || archives.length === 0)) {
|
||||||
<div *ngIf="(!archives || archives.length === 0)">
|
<div>
|
||||||
<h4 style="text-align: center; margin-top: 10px;" i18n="Archives empty">Archives empty</h4>
|
<h4 style="text-align: center; margin-top: 10px;" i18n="Archives empty">Archives empty</h4>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<div style="margin: 10px 10px 10px 0px; display: flex;">
|
<div style="margin: 10px 10px 10px 0px; display: flex;">
|
||||||
<span style="flex-grow: 1;" class="flex-items">
|
<span style="flex-grow: 1;" class="flex-items">
|
||||||
<button [disabled]="selection.selected.length === 0" color="warn" style="margin: 10px;" mat-stroked-button i18n="Delete selected" (click)="openDeleteSelectedArchivesDialog()">Delete selected</button>
|
<button [disabled]="selection.selected.length === 0" color="warn" style="margin: 10px;" mat-stroked-button i18n="Delete selected" (click)="openDeleteSelectedArchivesDialog()">Delete selected</button>
|
||||||
@@ -82,7 +75,9 @@
|
|||||||
<mat-label i18n="Subscription">Subscription</mat-label>
|
<mat-label i18n="Subscription">Subscription</mat-label>
|
||||||
<mat-select [ngModel]="sub_id" (ngModelChange)="subFilterSelectionChanged($event)">
|
<mat-select [ngModel]="sub_id" (ngModelChange)="subFilterSelectionChanged($event)">
|
||||||
<mat-option [value]="'none'" i18n="None">None</mat-option>
|
<mat-option [value]="'none'" i18n="None">None</mat-option>
|
||||||
<mat-option *ngFor="let sub of postsService.subscriptions" [value]="sub.id">{{sub.name}}</mat-option>
|
@for (sub of postsService.subscriptions; track sub) {
|
||||||
|
<mat-option [value]="sub.id">{{sub.name}}</mat-option>
|
||||||
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field style="width: 100px; margin-bottom: -1.25em; margin-left: 10px;">
|
<mat-form-field style="width: 100px; margin-bottom: -1.25em; margin-left: 10px;">
|
||||||
@@ -95,49 +90,55 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="file-drop-parent">
|
<div class="file-drop-parent">
|
||||||
<ngx-file-drop [multiple]="false" accept=".txt" dropZoneLabel="Drop file here" (onFileDrop)="dropped($event)">
|
<ngx-file-drop [multiple]="false" accept=".txt" dropZoneLabel="Drop file here" (onFileDrop)="dropped($event)">
|
||||||
<ng-template class="file-drop" ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
|
<ng-template class="file-drop" ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
<div>
|
<div>
|
||||||
<ng-container i18n="Drag and Drop">Drag and Drop</ng-container>
|
<ng-container i18n="Drag and Drop">Drag and Drop</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 6px;">
|
<div style="margin-top: 6px;">
|
||||||
<button mat-stroked-button (click)="openFileSelector()">Browse Files</button>
|
<button mat-stroked-button (click)="openFileSelector()">Browse Files</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngx-file-drop>
|
</ngx-file-drop>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 10px; color: white">
|
<div style="margin-top: 10px; color: white">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody class="upload-name-style">
|
<tbody class="upload-name-style">
|
||||||
<tr *ngFor="let item of files; let i=index">
|
@for (item of files; track item; let i = $index) {
|
||||||
<td style="vertical-align: middle; border-top: unset">
|
<tr>
|
||||||
<strong>{{ item.relativePath }}</strong>
|
<td style="vertical-align: middle; border-top: unset">
|
||||||
</td>
|
<strong>{{ item.relativePath }}</strong>
|
||||||
<td style="border-top: unset">
|
</td>
|
||||||
<div style="float: right">
|
<td style="border-top: unset">
|
||||||
<mat-form-field style="width: 150px;">
|
<div style="float: right">
|
||||||
<mat-label i18n="Subscription">Subscription</mat-label>
|
<mat-form-field style="width: 150px;">
|
||||||
<mat-select [ngModel]="upload_sub_id" (ngModelChange)="subUploadFilterSelectionChanged($event)">
|
<mat-label i18n="Subscription">Subscription</mat-label>
|
||||||
<mat-option [value]="'none'" i18n="None">None</mat-option>
|
<mat-select [ngModel]="upload_sub_id" (ngModelChange)="subUploadFilterSelectionChanged($event)">
|
||||||
<mat-option *ngFor="let sub of postsService.subscriptions" [value]="sub.id">{{sub.name}}</mat-option>
|
<mat-option [value]="'none'" i18n="None">None</mat-option>
|
||||||
</mat-select>
|
@for (sub of postsService.subscriptions; track sub) {
|
||||||
</mat-form-field>
|
<mat-option [value]="sub.id">{{sub.name}}</mat-option>
|
||||||
<mat-form-field style="width: 100px; margin-left: 10px">
|
}
|
||||||
<mat-label i18n="File type">File type</mat-label>
|
</mat-select>
|
||||||
<mat-select [(ngModel)]="upload_type" [value]="upload_type" [disabled]="upload_sub_id !== 'none'">
|
</mat-form-field>
|
||||||
<mat-option [value]="'video'" i18n="Video">Video</mat-option>
|
<mat-form-field style="width: 100px; margin-left: 10px">
|
||||||
<mat-option [value]="'audio'" i18n="Audio">Audio</mat-option>
|
<mat-label i18n="File type">File type</mat-label>
|
||||||
</mat-select>
|
<mat-select [(ngModel)]="upload_type" [value]="upload_type" [disabled]="upload_sub_id !== 'none'">
|
||||||
</mat-form-field>
|
<mat-option [value]="'video'" i18n="Video">Video</mat-option>
|
||||||
<button style="margin-left: 10px" [disabled]="uploading_archive || uploaded_archive" (click)="importArchive()" matTooltip="Upload" i18n-matTooltip="Upload" mat-mini-fab><mat-icon>publish</mat-icon><mat-spinner *ngIf="uploading_archive" class="spinner" [diameter]="38"></mat-spinner></button>
|
<mat-option [value]="'audio'" i18n="Audio">Audio</mat-option>
|
||||||
</div>
|
</mat-select>
|
||||||
</td>
|
</mat-form-field>
|
||||||
</tr>
|
<button style="margin-left: 10px" [disabled]="uploading_archive || uploaded_archive" (click)="importArchive()" matTooltip="Upload" i18n-matTooltip="Upload" mat-mini-fab><mat-icon>publish</mat-icon>
|
||||||
</tbody>
|
@if (uploading_archive) {
|
||||||
</table>
|
<mat-spinner class="spinner" [diameter]="38"></mat-spinner>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Archive } from 'api-types/models/Archive';
|
|||||||
import { ConfirmDialogComponent } from 'app/dialogs/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from 'app/dialogs/confirm-dialog/confirm-dialog.component';
|
||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { NgxFileDropEntry } from 'ngx-file-drop';
|
import { NgxFileDropEntry } from 'ngx-file-drop';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-archive-viewer',
|
selector: 'app-archive-viewer',
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
<div class="buttons-container">
|
<div class="buttons-container">
|
||||||
<button (click)="startWatching()" *ngIf="!watch_together_clicked" mat-flat-button>Watch together</button>
|
@if (!watch_together_clicked) {
|
||||||
<button (click)="startServer()" *ngIf="watch_together_clicked && !started && server_mode && server_already_exists === false" mat-flat-button>Start stream</button>
|
<button (click)="startWatching()" mat-flat-button>Watch together</button>
|
||||||
<button (click)="startClient()" *ngIf="watch_together_clicked && !started && server_already_exists === true" mat-flat-button>Join stream</button>
|
} @else {
|
||||||
<button style="margin-left: 10px;" (click)="stop()" *ngIf="watch_together_clicked" mat-flat-button>Stop</button>
|
@if (!started) {
|
||||||
|
@if (server_already_exists) {
|
||||||
|
<button (click)="startClient()" mat-flat-button>Join stream</button>
|
||||||
|
} @else if (server_mode) {
|
||||||
|
<button (click)="startServer()" mat-flat-button>Start stream</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<button style="margin-left: 10px;" (click)="stop()" mat-flat-button>Stop</button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
<div *ngIf="playlists && playlists.length > 0">
|
@if (playlists) {
|
||||||
|
<div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div *ngFor="let playlist of playlists; let i = index" class="mb-2 mt-2" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
@for (playlist of playlists; track playlist; let i = $index) {
|
||||||
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToPlaylist($event)" [file_obj]="playlist" [is_playlist]="true" (editPlaylist)="editPlaylistDialog($event)" (deleteFile)="deletePlaylist($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''" [loading]="false"></app-unified-file-card>
|
<div class="mb-2 mt-2" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
||||||
</div>
|
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToPlaylist($event)" [file_obj]="playlist" [is_playlist]="true" (editPlaylist)="editPlaylistDialog($event)" (deleteFile)="deletePlaylist($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''" [loading]="false"></app-unified-file-card>
|
||||||
</div>
|
</div>
|
||||||
|
} @empty {
|
||||||
|
<div style="text-align: center;">
|
||||||
|
No playlists available. Create one from your downloading files by clicking the blue plus button.
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="playlists && playlists.length === 0" style="text-align: center;">
|
}
|
||||||
No playlists available. Create one from your downloading files by clicking the blue plus button.
|
|
||||||
</div>
|
|
||||||
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog()" mat-fab><mat-icon>add</mat-icon></button></div>
|
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog()" mat-fab><mat-icon>add</mat-icon></button></div>
|
||||||
@@ -4,6 +4,7 @@ import { Router } from '@angular/router';
|
|||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { CreatePlaylistComponent } from 'app/create-playlist/create-playlist.component';
|
import { CreatePlaylistComponent } from 'app/create-playlist/create-playlist.component';
|
||||||
import { Playlist } from 'api-types';
|
import { Playlist } from 'api-types';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-custom-playlists',
|
selector: 'app-custom-playlists',
|
||||||
|
|||||||
@@ -1,97 +1,102 @@
|
|||||||
<div [hidden]="!(downloads && downloads.length > 0)">
|
<div [hidden]="!(downloads && downloads.length > 0)">
|
||||||
<div style="overflow: hidden;" [ngClass]="uids ? 'rounded mat-elevation-z2' : 'mat-elevation-z8'">
|
<div style="overflow: hidden;" [ngClass]="uids ? 'rounded mat-elevation-z2' : 'mat-elevation-z8'">
|
||||||
<mat-table style="overflow: hidden" [ngClass]="uids ? 'rounded-top' : null" matSort [dataSource]="dataSource">
|
<mat-table style="overflow: hidden" [ngClass]="uids ? 'rounded-top' : null" matSort [dataSource]="dataSource">
|
||||||
|
<!-- Date Column -->
|
||||||
<!-- Date Column -->
|
<ng-container matColumnDef="timestamp_start">
|
||||||
<ng-container matColumnDef="timestamp_start">
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Date">Date</ng-container> </mat-header-cell>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Date">Date</ng-container> </mat-header-cell>
|
<mat-cell *matCellDef="let element"> {{element.timestamp_start | date: 'short'}} </mat-cell>
|
||||||
<mat-cell *matCellDef="let element"> {{element.timestamp_start | date: 'short'}} </mat-cell>
|
</ng-container>
|
||||||
</ng-container>
|
<!-- Title Column -->
|
||||||
|
<ng-container matColumnDef="title">
|
||||||
<!-- Title Column -->
|
<mat-header-cell *matHeaderCellDef mat-sort-header style="flex: 2"> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
||||||
<ng-container matColumnDef="title">
|
<mat-cell *matCellDef="let element" style="flex: 2">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header style="flex: 2"> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
||||||
<mat-cell *matCellDef="let element" style="flex: 2">
|
{{element.title}}
|
||||||
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
</span>
|
||||||
{{element.title}}
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Subscription Column -->
|
||||||
|
<ng-container matColumnDef="sub_name">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Subscription">Subscription</ng-container> </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let element">
|
||||||
|
@if (element.sub_name) {
|
||||||
|
{{element.sub_name}}
|
||||||
|
} @else {
|
||||||
|
<ng-container i18n="N/A">N/A</ng-container>
|
||||||
|
}
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Progress Column -->
|
||||||
|
<ng-container matColumnDef="percent_complete">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Progress">Progress</ng-container> </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let element">
|
||||||
|
@if (!element.error) {
|
||||||
|
@if (element.step_index !== 2) {
|
||||||
|
{{STEP_INDEX_TO_LABEL[element.step_index]}}
|
||||||
|
} @else {
|
||||||
|
@if (element.percent_complete) {
|
||||||
|
{{+(element.percent_complete) > 100 ? '100' : element.percent_complete}}%
|
||||||
|
} @else {
|
||||||
|
<ng-container i18n="N/A">N/A</ng-container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
<ng-container i18n="Error">Error</ng-container>
|
||||||
|
}
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Actions Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<mat-header-cell *matHeaderCellDef [ngStyle]="{flex: actionsFlex}"> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let element" [ngStyle]="{flex: actionsFlex}">
|
||||||
|
@if (!minimizeButtons) {
|
||||||
|
<div>
|
||||||
|
@for (downloadAction of downloadActions; track downloadAction) {
|
||||||
|
<span class="button-span">
|
||||||
|
@if (downloadAction.loading && downloadAction.loading(element)) {
|
||||||
|
<mat-spinner [diameter]="28" class="icon-button-spinner"></mat-spinner>
|
||||||
|
}
|
||||||
|
@if (downloadAction.show(element)) {
|
||||||
|
<button (click)="downloadAction.action(element)" [disabled]="downloadAction.loading && downloadAction.loading(element)" [matTooltip]="downloadAction.tooltip" mat-icon-button><mat-icon>{{downloadAction.icon}}</mat-icon></button>
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</mat-cell>
|
}
|
||||||
</ng-container>
|
</div>
|
||||||
|
} @else {
|
||||||
<!-- Subscription Column -->
|
<div>
|
||||||
<ng-container matColumnDef="sub_name">
|
<button [matMenuTriggerFor]="download_actions" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Subscription">Subscription</ng-container> </mat-header-cell>
|
<mat-menu #download_actions="matMenu">
|
||||||
<mat-cell *matCellDef="let element">
|
@for (downloadAction of downloadActions; track downloadAction) {
|
||||||
<ng-container *ngIf="element.sub_name">
|
@if (downloadAction.show(element)) {
|
||||||
{{element.sub_name}}
|
<button (click)="downloadAction.action(element)" [disabled]="downloadAction.loading && downloadAction.loading(element)" mat-menu-item>
|
||||||
</ng-container>
|
<mat-icon>{{downloadAction.icon}}</mat-icon>
|
||||||
<ng-container *ngIf="!element.sub_name">
|
<span>{{downloadAction.tooltip}}</span>
|
||||||
N/A
|
</button>
|
||||||
</ng-container>
|
}
|
||||||
</mat-cell>
|
}
|
||||||
</ng-container>
|
</mat-menu>
|
||||||
|
</div>
|
||||||
<!-- Progress Column -->
|
}
|
||||||
<ng-container matColumnDef="percent_complete">
|
</mat-cell>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Progress">Progress</ng-container> </mat-header-cell>
|
</ng-container>
|
||||||
<mat-cell *matCellDef="let element">
|
<mat-header-row [ngClass]="uids ? 'rounded-top' : null" *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
<ng-container *ngIf="!element.error && element.step_index !== 2">
|
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||||
{{STEP_INDEX_TO_LABEL[element.step_index]}}
|
</mat-table>
|
||||||
</ng-container>
|
<mat-paginator [ngClass]="uids ? 'rounded-bottom' : null" [pageSizeOptions]="[5, 10, 20]"
|
||||||
<ng-container *ngIf="!element.error && element.step_index === 2">
|
showFirstLastButtons
|
||||||
<ng-container *ngIf="element.percent_complete">
|
aria-label="Select page of downloads">
|
||||||
{{+(element.percent_complete) > 100 ? '100' : element.percent_complete}}%
|
</mat-paginator>
|
||||||
</ng-container>
|
</div>
|
||||||
<ng-container *ngIf="!element.percent_complete">
|
@if (!uids) {
|
||||||
N/A
|
<div class="downloads-action-button-div">
|
||||||
</ng-container>
|
<button class="downloads-action-button" [disabled]="!running_download_exists" mat-stroked-button (click)="pauseAllDownloads()"><ng-container i18n="Pause all downloads">Pause all downloads</ng-container></button>
|
||||||
</ng-container>
|
<button class="downloads-action-button" [disabled]="!paused_download_exists" mat-stroked-button (click)="resumeAllDownloads()"><ng-container i18n="Resume all downloads">Resume all downloads</ng-container></button>
|
||||||
<ng-container *ngIf="element.error" i18n="Error">Error</ng-container>
|
<button class="downloads-action-button" color="warn" mat-stroked-button (click)="clearDownloadsByType()"><ng-container i18n="Clear downloads">Clear downloads</ng-container></button>
|
||||||
</mat-cell>
|
</div>
|
||||||
</ng-container>
|
}
|
||||||
|
|
||||||
<!-- Actions Column -->
|
|
||||||
<ng-container matColumnDef="actions">
|
|
||||||
<mat-header-cell *matHeaderCellDef [ngStyle]="{flex: actionsFlex}"> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let element" [ngStyle]="{flex: actionsFlex}">
|
|
||||||
<div *ngIf="!minimizeButtons">
|
|
||||||
<ng-container *ngFor="let downloadAction of downloadActions">
|
|
||||||
<span class="button-span">
|
|
||||||
<mat-spinner [diameter]="28" *ngIf="downloadAction.loading && downloadAction.loading(element)" class="icon-button-spinner"></mat-spinner>
|
|
||||||
<button *ngIf="downloadAction.show(element)" (click)="downloadAction.action(element)" [disabled]="downloadAction.loading && downloadAction.loading(element)" [matTooltip]="downloadAction.tooltip" mat-icon-button><mat-icon>{{downloadAction.icon}}</mat-icon></button>
|
|
||||||
</span>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="minimizeButtons">
|
|
||||||
<button [matMenuTriggerFor]="download_actions" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
|
||||||
<mat-menu #download_actions="matMenu">
|
|
||||||
<ng-container *ngFor="let downloadAction of downloadActions">
|
|
||||||
<button *ngIf="downloadAction.show(element)" (click)="downloadAction.action(element)" [disabled]="downloadAction.loading && downloadAction.loading(element)" mat-menu-item>
|
|
||||||
<mat-icon>{{downloadAction.icon}}</mat-icon>
|
|
||||||
<span>{{downloadAction.tooltip}}</span>
|
|
||||||
</button>
|
|
||||||
</ng-container>
|
|
||||||
</mat-menu>
|
|
||||||
</div>
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<mat-header-row [ngClass]="uids ? 'rounded-top' : null" *matHeaderRowDef="displayedColumns"></mat-header-row>
|
|
||||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
|
||||||
</mat-table>
|
|
||||||
|
|
||||||
<mat-paginator [ngClass]="uids ? 'rounded-bottom' : null" [pageSizeOptions]="[5, 10, 20]"
|
|
||||||
showFirstLastButtons
|
|
||||||
aria-label="Select page of downloads">
|
|
||||||
</mat-paginator>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="!uids" class="downloads-action-button-div">
|
|
||||||
<button class="downloads-action-button" [disabled]="!running_download_exists" mat-stroked-button (click)="pauseAllDownloads()"><ng-container i18n="Pause all downloads">Pause all downloads</ng-container></button>
|
|
||||||
<button class="downloads-action-button" [disabled]="!paused_download_exists" mat-stroked-button (click)="resumeAllDownloads()"><ng-container i18n="Resume all downloads">Resume all downloads</ng-container></button>
|
|
||||||
<button class="downloads-action-button" color="warn" mat-stroked-button (click)="clearDownloadsByType()"><ng-container i18n="Clear downloads">Clear downloads</ng-container></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@if ((!downloads || downloads.length === 0) && downloads_retrieved && !uids) {
|
||||||
<div *ngIf="(!downloads || downloads.length === 0) && downloads_retrieved && !uids">
|
<div>
|
||||||
<h4 style="text-align: center; margin-top: 10px;" i18n="No downloads label">No downloads available!</h4>
|
<h4 style="text-align: center; margin-top: 10px;" i18n="No downloads label">No downloads available!</h4>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
@@ -1,46 +1,55 @@
|
|||||||
<mat-card class="login-card">
|
<mat-card class="login-card">
|
||||||
<mat-tab-group mat-stretch-tabs style="margin-bottom: 20px" [(selectedIndex)]="selectedTabIndex">
|
<mat-tab-group mat-stretch-tabs style="margin-bottom: 20px" [(selectedIndex)]="selectedTabIndex">
|
||||||
<mat-tab label="Login" i18n-label="Login">
|
<mat-tab label="Login" i18n-label="Login">
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 10px;">
|
||||||
<mat-form-field style="width: 100%">
|
<mat-form-field style="width: 100%">
|
||||||
<mat-label i18n="User name">User name</mat-label>
|
<mat-label i18n="User name">User name</mat-label>
|
||||||
<input [(ngModel)]="loginUsernameInput" matInput>
|
<input [(ngModel)]="loginUsernameInput" matInput>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field style="width: 100%">
|
<mat-form-field style="width: 100%">
|
||||||
<mat-label i18n="Password">Password</mat-label>
|
<mat-label i18n="Password">Password</mat-label>
|
||||||
<input [(ngModel)]="loginPasswordInput" (keyup.enter)="login()" type="password" matInput>
|
<input [(ngModel)]="loginPasswordInput" (keyup.enter)="login()" type="password" matInput>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab *ngIf="registrationEnabled" label="Register" i18n-label="Register">
|
@if (registrationEnabled) {
|
||||||
<div style="margin-top: 10px;">
|
<mat-tab label="Register" i18n-label="Register">
|
||||||
<mat-form-field style="width: 100%">
|
<div style="margin-top: 10px;">
|
||||||
<mat-label i18n="User name">User name</mat-label>
|
<mat-form-field style="width: 100%">
|
||||||
<input [(ngModel)]="registrationUsernameInput" matInput>
|
<mat-label i18n="User name">User name</mat-label>
|
||||||
</mat-form-field>
|
<input [(ngModel)]="registrationUsernameInput" matInput>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<div>
|
</div>
|
||||||
<mat-form-field style="width: 100%">
|
<div>
|
||||||
<mat-label i18n="Password">Password</mat-label>
|
<mat-form-field style="width: 100%">
|
||||||
<input [(ngModel)]="registrationPasswordInput" (click)="register()" type="password" matInput>
|
<mat-label i18n="Password">Password</mat-label>
|
||||||
</mat-form-field>
|
<input [(ngModel)]="registrationPasswordInput" (click)="register()" type="password" matInput>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<div>
|
</div>
|
||||||
<mat-form-field style="width: 100%">
|
<div>
|
||||||
<mat-label i18n="Confirm Password">Confirm Password</mat-label>
|
<mat-form-field style="width: 100%">
|
||||||
<input [(ngModel)]="registrationPasswordConfirmationInput" (click)="register()" type="password" matInput>
|
<mat-label i18n="Confirm Password">Confirm Password</mat-label>
|
||||||
</mat-form-field>
|
<input [(ngModel)]="registrationPasswordConfirmationInput" (click)="register()" type="password" matInput>
|
||||||
</div>
|
</mat-form-field>
|
||||||
</mat-tab>
|
</div>
|
||||||
</mat-tab-group>
|
</mat-tab>
|
||||||
<div *ngIf="selectedTabIndex === 0" class="login-button-div">
|
}
|
||||||
<button [disabled]="loggingIn" color="primary" (click)="login()" mat-raised-button><ng-container i18n="Login">Login</ng-container></button>
|
</mat-tab-group>
|
||||||
<mat-progress-bar *ngIf="loggingIn" class="login-progress-bar" mode="indeterminate"></mat-progress-bar>
|
@if (selectedTabIndex === 0) {
|
||||||
|
<div class="login-button-div">
|
||||||
|
<button [disabled]="loggingIn" color="primary" (click)="login()" mat-raised-button><ng-container i18n="Login">Login</ng-container></button>
|
||||||
|
@if (loggingIn) {
|
||||||
|
<mat-progress-bar class="login-progress-bar" mode="indeterminate"></mat-progress-bar>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="selectedTabIndex === 1" class="login-button-div">
|
} @else {
|
||||||
<button [disabled]="registering" color="primary" (click)="register()" mat-raised-button><ng-container i18n="Register">Register</ng-container></button>
|
<div class="login-button-div">
|
||||||
<mat-progress-bar *ngIf="registering" class="login-progress-bar" mode="indeterminate"></mat-progress-bar>
|
<button [disabled]="registering" color="primary" (click)="register()" mat-raised-button><ng-container i18n="Register">Register</ng-container></button>
|
||||||
|
@if (registering) {
|
||||||
|
<mat-progress-bar class="login-progress-bar" mode="indeterminate"></mat-progress-bar>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</mat-card>
|
</mat-card>
|
||||||
@@ -1,37 +1,38 @@
|
|||||||
<div style="height: 100%;">
|
<div style="height: 100%;">
|
||||||
<div *ngIf="logs_loading" style="z-index: 999; position: absolute; top: 40%; left: 50%">
|
@if (logs_loading) {
|
||||||
<mat-spinner [diameter]="32"></mat-spinner>
|
<div style="z-index: 999; position: absolute; top: 40%; left: 50%">
|
||||||
|
<mat-spinner [diameter]="32"></mat-spinner>
|
||||||
</div>
|
</div>
|
||||||
<!-- Virtual mode (fast, select text buggy) -->
|
}
|
||||||
<!--<cdk-virtual-scroll-viewport style="height: 274px;" itemSize="50" class="example-viewport">
|
<!-- Virtual mode (fast, select text buggy) -->
|
||||||
<div *cdkVirtualFor="let log of logs; let i = index" class="example-item">
|
<!--<cdk-virtual-scroll-viewport style="height: 274px;" itemSize="50" class="example-viewport">
|
||||||
<span [ngStyle]="{'color':log.color}">{{log.text}}</span>
|
<div *cdkVirtualFor="let log of logs; let i = index" class="example-item">
|
||||||
</div>
|
<span [ngStyle]="{'color':log.color}">{{log.text}}</span>
|
||||||
</cdk-virtual-scroll-viewport>-->
|
</div>
|
||||||
|
</cdk-virtual-scroll-viewport>-->
|
||||||
<!-- Non-virtual mode (slow, bug-free) -->
|
<!-- Non-virtual mode (slow, bug-free) -->
|
||||||
<div style="height: 100%; overflow-y: auto">
|
<div style="height: 100%; overflow-y: auto">
|
||||||
<div *ngFor="let log of logs; let i = index" class="example-item">
|
@for (log of logs; track log) {
|
||||||
<span [ngStyle]="{'color':log.color}">{{log.text}}</span>
|
<div class="example-item">
|
||||||
</div>
|
<span [ngStyle]="{'color':log.color}">{{log.text}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<div>
|
</div>
|
||||||
<button style="position: absolute; right: 0px; top: 12px;" [cdkCopyToClipboard]="logs_text" (click)="copiedLogsToClipboard()" mat-mini-fab color="primary"><mat-icon style="font-size: 22px !important;">content_copy</mat-icon></button>
|
<div>
|
||||||
<div style="display: inline-block;">
|
<button style="position: absolute; right: 0px; top: 12px;" [cdkCopyToClipboard]="logs_text" (click)="copiedLogsToClipboard()" mat-mini-fab color="primary"><mat-icon style="font-size: 22px !important;">content_copy</mat-icon></button>
|
||||||
<ng-container i18n="Label for lines select in logger view">Lines:</ng-container>
|
<div style="display: inline-block;">
|
||||||
<mat-form-field style="width: 75px;">
|
<ng-container i18n="Label for lines select in logger view">Lines:</ng-container>
|
||||||
<mat-select (selectionChange)="getLogs()" [(ngModel)]="requested_lines">
|
<mat-form-field style="width: 75px;">
|
||||||
<mat-option [value]="10">10</mat-option>
|
<mat-select (selectionChange)="getLogs()" [(ngModel)]="requested_lines">
|
||||||
<mat-option [value]="25">25</mat-option>
|
<mat-option [value]="10">10</mat-option>
|
||||||
<mat-option [value]="50">50</mat-option>
|
<mat-option [value]="25">25</mat-option>
|
||||||
<mat-option [value]="100">100</mat-option>
|
<mat-option [value]="50">50</mat-option>
|
||||||
<mat-option [value]="0">All</mat-option>
|
<mat-option [value]="100">100</mat-option>
|
||||||
</mat-select>
|
<mat-option [value]="0">All</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<span class="spacer"></span>
|
</div>
|
||||||
<button style="float: right; margin-top: 12px;" (click)="clearLogs()" mat-stroked-button color="warn"><ng-container i18n="Clear logs button">Clear logs</ng-container></button>
|
<span class="spacer"></span>
|
||||||
</div>
|
<button style="float: right; margin-top: 12px;" (click)="clearLogs()" mat-stroked-button color="warn"><ng-container i18n="Clear logs button">Clear logs</ng-container></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,17 +1,19 @@
|
|||||||
<h4 *ngIf="role" mat-dialog-title><ng-container i18n="Manage role dialog title">Manage role</ng-container> - {{role.key}}</h4>
|
@if (role) {
|
||||||
|
<h4 mat-dialog-title><ng-container i18n="Manage role dialog title">Manage role</ng-container> - {{role.key}}</h4>
|
||||||
<mat-dialog-content *ngIf="role">
|
<mat-dialog-content>
|
||||||
<div *ngFor="let permission of available_permissions">
|
@for (permission of available_permissions; track permission) {
|
||||||
|
<div>
|
||||||
<div matListItemTitle>{{permissionToLabel[permission] ? permissionToLabel[permission] : permission}}</div>
|
<div matListItemTitle>{{permissionToLabel[permission] ? permissionToLabel[permission] : permission}}</div>
|
||||||
<div matListItemLine>
|
<div matListItemLine>
|
||||||
<mat-radio-group [disabled]="permission === 'settings' && role.key === 'admin'" (change)="changeRolePermissions($event, permission)" [(ngModel)]="permissions[permission]" [attr.aria-label]="'Give role permission for ' + permission">
|
<mat-radio-group [disabled]="permission === 'settings' && role.key === 'admin'" (change)="changeRolePermissions($event, permission)" [(ngModel)]="permissions[permission]" [attr.aria-label]="'Give role permission for ' + permission">
|
||||||
<mat-radio-button value="yes"><ng-container i18n="Yes">Yes</ng-container></mat-radio-button>
|
<mat-radio-button value="yes"><ng-container i18n="Yes">Yes</ng-container></mat-radio-button>
|
||||||
<mat-radio-button value="no"><ng-container i18n="No">No</ng-container></mat-radio-button>
|
<mat-radio-button value="no"><ng-container i18n="No">No</ng-container></mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
}
|
||||||
|
</mat-dialog-content>
|
||||||
|
}
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,30 +1,30 @@
|
|||||||
<h4 *ngIf="user" mat-dialog-title><ng-container i18n="Manage user dialog title">Manage user</ng-container> - {{user.name}}</h4>
|
@if (user) {
|
||||||
|
<h4 mat-dialog-title><ng-container i18n="Manage user dialog title">Manage user</ng-container> - {{user.name}}</h4>
|
||||||
<mat-dialog-content *ngIf="user">
|
<mat-dialog-content>
|
||||||
<p><ng-container i18n="User UID">User UID:</ng-container> {{user.uid}}</p>
|
<p><ng-container i18n="User UID">User UID:</ng-container> {{user.uid}}</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field style="margin-right: 15px;">
|
<mat-form-field style="margin-right: 15px;">
|
||||||
<mat-label i18n="New password">New password</mat-label>
|
<mat-label i18n="New password">New password</mat-label>
|
||||||
<input matInput [(ngModel)]="newPasswordInput" type="password">
|
<input matInput [(ngModel)]="newPasswordInput" type="password">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="accent" (click)="setNewPassword()" [disabled]="newPasswordInput.length === 0"><ng-container i18n="Set new password">Set new password</ng-container></button>
|
<button mat-raised-button color="accent" (click)="setNewPassword()" [disabled]="newPasswordInput.length === 0"><ng-container i18n="Set new password">Set new password</ng-container></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div *ngFor="let permission of available_permissions">
|
@for (permission of available_permissions; track permission) {
|
||||||
<div matListItemTitle>{{permissionToLabel[permission] ? permissionToLabel[permission] : permission}}</div>
|
<div>
|
||||||
<div matListItemLine>
|
<div matListItemTitle>{{permissionToLabel[permission] ? permissionToLabel[permission] : permission}}</div>
|
||||||
<mat-radio-group [disabled]="permission === 'settings' && postsService.user.uid === user.uid" (change)="changeUserPermissions($event, permission)" [(ngModel)]="permissions[permission]" [attr.aria-label]="'Give user permission for ' + permission">
|
<div matListItemLine>
|
||||||
<mat-radio-button value="default"><ng-container i18n="Use role default">Use role default</ng-container></mat-radio-button>
|
<mat-radio-group [disabled]="permission === 'settings' && postsService.user.uid === user.uid" (change)="changeUserPermissions($event, permission)" [(ngModel)]="permissions[permission]" [attr.aria-label]="'Give user permission for ' + permission">
|
||||||
<mat-radio-button value="yes"><ng-container i18n="Yes">Yes</ng-container></mat-radio-button>
|
<mat-radio-button value="default"><ng-container i18n="Use role default">Use role default</ng-container></mat-radio-button>
|
||||||
<mat-radio-button value="no"><ng-container i18n="No">No</ng-container></mat-radio-button>
|
<mat-radio-button value="yes"><ng-container i18n="Yes">Yes</ng-container></mat-radio-button>
|
||||||
</mat-radio-group>
|
<mat-radio-button value="no"><ng-container i18n="No">No</ng-container></mat-radio-button>
|
||||||
</div>
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
}
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button style="margin-bottom: 5px;" mat-stroked-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
<button style="margin-bottom: 5px;" mat-stroked-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,108 +1,103 @@
|
|||||||
<div *ngIf="dataSource; else loading">
|
@if (dataSource) {
|
||||||
|
<div>
|
||||||
<div style="padding: 15px">
|
<div style="padding: 15px">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="table table-responsive pb-4 pt-4">
|
<div class="table table-responsive pb-4 pt-4">
|
||||||
<div class="example-header">
|
<div class="example-header">
|
||||||
<mat-form-field appearance="outline">
|
<mat-form-field appearance="outline">
|
||||||
<mat-label i18n="Search">Search</mat-label>
|
<mat-label i18n="Search">Search</mat-label>
|
||||||
<input matInput (keyup)="applyFilter($event)">
|
<input matInput (keyup)="applyFilter($event)">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mat-elevation-z8" style="margin-right: 15px;">
|
||||||
<div class="mat-elevation-z8" style="margin-right: 15px;">
|
|
||||||
|
|
||||||
<mat-table #table [dataSource]="dataSource" matSort>
|
<mat-table #table [dataSource]="dataSource" matSort>
|
||||||
|
<!-- Name Column -->
|
||||||
<!-- Name Column -->
|
<ng-container matColumnDef="name">
|
||||||
<ng-container matColumnDef="name">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Username users table header"> User name </ng-container></mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Username users table header"> User name </ng-container></mat-header-cell>
|
||||||
|
|
||||||
<mat-cell *matCellDef="let row">
|
<mat-cell *matCellDef="let row">
|
||||||
<span *ngIf="editObject && editObject.uid === row.uid; else noteditingname">
|
@if (editObject && editObject.uid === row.uid) {
|
||||||
<span style="width: 80%;">
|
<span>
|
||||||
<mat-form-field>
|
<span style="width: 80%;">
|
||||||
<input matInput [(ngModel)]="constructedObject['name']" type="text" style="font-size: 12px">
|
<mat-form-field>
|
||||||
</mat-form-field>
|
<input matInput [(ngModel)]="constructedObject['name']" type="text" style="font-size: 12px">
|
||||||
|
</mat-form-field>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
} @else {
|
||||||
<ng-template #noteditingname>
|
{{row.name}}
|
||||||
{{row.name}}
|
}
|
||||||
</ng-template>
|
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<!-- Email Column -->
|
||||||
<!-- Email Column -->
|
<ng-container matColumnDef="role">
|
||||||
<ng-container matColumnDef="role">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Role users table header"> Role </ng-container></mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Role users table header"> Role </ng-container></mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row">
|
<mat-cell *matCellDef="let row">
|
||||||
<span *ngIf="editObject && editObject.uid === row.uid; else noteditingemail">
|
@if (editObject && editObject.uid === row.uid) {
|
||||||
<span style="width: 80%;">
|
<span>
|
||||||
|
<span style="width: 80%;">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select [(ngModel)]="constructedObject['role']">
|
<mat-select [(ngModel)]="constructedObject['role']">
|
||||||
<mat-option value="admin">Admin</mat-option>
|
<mat-option value="admin">Admin</mat-option>
|
||||||
<mat-option value="user">User</mat-option>
|
<mat-option value="user">User</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
} @else {
|
||||||
<ng-template #noteditingemail>
|
{{row.role}}
|
||||||
{{row.role}}
|
}
|
||||||
</ng-template>
|
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<!-- Actions Column -->
|
||||||
<!-- Actions Column -->
|
<ng-container matColumnDef="actions">
|
||||||
<ng-container matColumnDef="actions">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Actions users table header"> Actions </ng-container></mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header><ng-container i18n="Actions users table header"> Actions </ng-container></mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row">
|
<mat-cell *matCellDef="let row">
|
||||||
<span *ngIf="editObject && editObject.uid === row.uid; else notediting">
|
@if (editObject && editObject.uid === row.uid) {
|
||||||
<button mat-icon-button color="primary" (click)="finishEditing(row.uid)" matTooltip="Save" i18n-matTooltip="save user edit action button tooltip">
|
<span>
|
||||||
<mat-icon>done</mat-icon>
|
<button mat-icon-button color="primary" (click)="finishEditing(row.uid)" matTooltip="Save" i18n-matTooltip="save user edit action button tooltip">
|
||||||
</button>
|
<mat-icon>done</mat-icon>
|
||||||
<button mat-icon-button (click)="disableEditMode()" matTooltip="Cancel" i18n-matTooltip="cancel user edit action button tooltip">
|
</button>
|
||||||
<mat-icon>cancel</mat-icon>
|
<button mat-icon-button (click)="disableEditMode()" matTooltip="Cancel" i18n-matTooltip="cancel user edit action button tooltip">
|
||||||
</button>
|
<mat-icon>cancel</mat-icon>
|
||||||
</span>
|
</button>
|
||||||
<ng-template #notediting>
|
</span>
|
||||||
|
} @else {
|
||||||
<button mat-icon-button (click)="enableEditMode(row.uid)" matTooltip="Edit user" i18n-matTooltip="edit user action button tooltip">
|
<button mat-icon-button (click)="enableEditMode(row.uid)" matTooltip="Edit user" i18n-matTooltip="edit user action button tooltip">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
}
|
||||||
<button (click)="manageUser(row.uid)" mat-icon-button [disabled]="editObject && editObject.uid === row.uid" matTooltip="Manage user" i18n-matTooltip="manage user action button tooltip">
|
<button (click)="manageUser(row.uid)" mat-icon-button [disabled]="editObject && editObject.uid === row.uid" matTooltip="Manage user" i18n-matTooltip="manage user action button tooltip">
|
||||||
<mat-icon>settings</mat-icon>
|
<mat-icon>settings</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button [disabled]="editObject && editObject.uid === row.uid || row.uid === postsService.user.uid" (click)="removeUser(row.uid)" matTooltip="Delete user" i18n-matTooltip="delete user action button tooltip">
|
<button mat-icon-button [disabled]="editObject && editObject.uid === row.uid || row.uid === postsService.user.uid" (click)="removeUser(row.uid)" matTooltip="Delete user" i18n-matTooltip="delete user action button tooltip">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
<mat-row *matRowDef="let row; columns: displayedColumns;">
|
||||||
<mat-row *matRowDef="let row; columns: displayedColumns;">
|
</mat-row>
|
||||||
</mat-row>
|
|
||||||
</mat-table>
|
</mat-table>
|
||||||
|
|
||||||
<mat-paginator #paginator [length]="length"
|
<mat-paginator #paginator [length]="length"
|
||||||
[pageSize]="pageSize"
|
[pageSize]="pageSize"
|
||||||
[pageSizeOptions]="pageSizeOptions">
|
[pageSizeOptions]="pageSizeOptions">
|
||||||
</mat-paginator>
|
</mat-paginator>
|
||||||
|
|
||||||
<button color="primary" [disabled]="!this.users" mat-raised-button (click)="openAddUserDialog()" style="float: left; top: -45px; left: 15px">
|
<button color="primary" [disabled]="!this.users" mat-raised-button (click)="openAddUserDialog()" style="float: left; top: -45px; left: 15px">
|
||||||
<ng-container i18n="Add users button">Add Users</ng-container>
|
<ng-container i18n="Add users button">Add Users</ng-container>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button color="primary" [matMenuTriggerFor]="edit_roles_menu" class="edit-role" mat-raised-button><ng-container i18n="Edit role">Edit Role</ng-container></button>
|
||||||
|
<mat-menu #edit_roles_menu="matMenu">
|
||||||
|
@for (role of roles; track role) {
|
||||||
|
<button (click)="openModifyRole(role)" mat-menu-item>{{role.key}}</button>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
</div>
|
</div>
|
||||||
<button color="primary" [matMenuTriggerFor]="edit_roles_menu" class="edit-role" mat-raised-button><ng-container i18n="Edit role">Edit Role</ng-container></button>
|
|
||||||
<mat-menu #edit_roles_menu="matMenu">
|
|
||||||
<button (click)="openModifyRole(role)" mat-menu-item *ngFor="let role of roles">{{role.key}}</button>
|
|
||||||
</mat-menu>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
} @else {
|
||||||
<div style="position: absolute" class="centered">
|
<div style="position: absolute" class="centered">
|
||||||
<ng-template #loading>
|
<mat-spinner></mat-spinner>
|
||||||
<mat-spinner></mat-spinner>
|
</div>
|
||||||
</ng-template>
|
}
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,32 +1,38 @@
|
|||||||
<cdk-virtual-scroll-viewport itemSize="50" class="viewport" minBufferPx="1200" maxBufferPx="1200">
|
<cdk-virtual-scroll-viewport itemSize="50" class="viewport" minBufferPx="1200" maxBufferPx="1200">
|
||||||
<div #notification_parent class="notification-card-parent card-radius mat-elevation-z2" *cdkVirtualFor="let notification of notifications; let i = index;">
|
<div #notification_parent class="notification-card-parent card-radius mat-elevation-z2" *cdkVirtualFor="let notification of notifications; let i = index;">
|
||||||
<mat-card class="notification-card card-radius">
|
<mat-card class="notification-card card-radius">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
<div>
|
<div>
|
||||||
<span class="notification-timestamp">{{notification.timestamp * 1000 | date:'short'}}</span>
|
<span class="notification-timestamp">{{notification.timestamp * 1000 | date:'short'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-title>
|
<mat-card-title>
|
||||||
<ng-container *ngIf="NOTIFICATION_PREFIX[notification.type]">
|
@if (NOTIFICATION_PREFIX[notification.type]) {
|
||||||
{{NOTIFICATION_PREFIX[notification.type]}}
|
{{NOTIFICATION_PREFIX[notification.type]}}
|
||||||
</ng-container>
|
}
|
||||||
</mat-card-title>
|
</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<ng-container *ngIf="NOTIFICATION_SUFFIX_KEY[notification.type]">
|
@if (NOTIFICATION_SUFFIX_KEY[notification.type]) {
|
||||||
<div style="word-break: break-word">
|
<div style="word-break: break-word">
|
||||||
{{notification['data'][NOTIFICATION_SUFFIX_KEY[notification.type]]}}
|
{{notification['data'][NOTIFICATION_SUFFIX_KEY[notification.type]]}}
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
}
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions class="notification-actions" *ngIf="notification.actions?.length > 0">
|
@if (notification.actions?.length > 0) {
|
||||||
<button matTooltip="Remove" i18n-matTooltip="Remove" (click)="emitDeleteNotification(notification.uid)" mat-icon-button><mat-icon>close</mat-icon></button>
|
<mat-card-actions class="notification-actions">
|
||||||
<span *ngFor="let action of notification.actions">
|
<button matTooltip="Remove" i18n-matTooltip="Remove" (click)="emitDeleteNotification(notification.uid)" mat-icon-button><mat-icon>close</mat-icon></button>
|
||||||
<button [matTooltip]="NOTIFICATION_ACTION_TO_STRING[action]" (click)="emitNotificationAction(notification, action)" mat-icon-button><mat-icon>{{NOTIFICATION_ICON[action]}}</mat-icon></button>
|
@for (action of notification.actions; track action) {
|
||||||
</span>
|
<span>
|
||||||
</mat-card-actions>
|
<button [matTooltip]="NOTIFICATION_ACTION_TO_STRING[action]" (click)="emitNotificationAction(notification, action)" mat-icon-button><mat-icon>{{NOTIFICATION_ICON[action]}}</mat-icon></button>
|
||||||
<span *ngIf="!notification.read" class="dot"></span>
|
</span>
|
||||||
</mat-card>
|
}
|
||||||
</div>
|
</mat-card-actions>
|
||||||
|
}
|
||||||
|
@if (!notification.read) {
|
||||||
|
<span class="dot"></span>
|
||||||
|
}
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
</cdk-virtual-scroll-viewport>
|
</cdk-virtual-scroll-viewport>
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
<div *ngIf="notifications !== null && notifications.length === 0" style="text-align: center; margin: 10px;" i18n="No notifications available">No notifications available</div>
|
@if (notifications !== null && notifications.length === 0) {
|
||||||
<div *ngIf="notifications?.length > 0">
|
<div style="text-align: center; margin: 10px;" i18n="No notifications available">No notifications available</div>
|
||||||
|
}
|
||||||
|
@if (notifications?.length > 0) {
|
||||||
|
<div>
|
||||||
<div class="notifications-list-parent">
|
<div class="notifications-list-parent">
|
||||||
<mat-chip-listbox [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
|
<mat-chip-listbox [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
|
||||||
<mat-chip-option *ngFor="let filter of notificationFilters | keyvalue: originalOrder" [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
|
@for (filter of notificationFilters | keyvalue: originalOrder; track filter) {
|
||||||
</mat-chip-listbox>
|
<mat-chip-option [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
|
||||||
<app-notifications-list class="notifications-list" [style.height]="list_height" (notificationAction)="notificationAction($event)" (deleteNotification)="deleteNotification($event)" [notifications]="filtered_notifications"></app-notifications-list>
|
}
|
||||||
|
</mat-chip-listbox>
|
||||||
|
<app-notifications-list class="notifications-list" [style.height]="list_height" (notificationAction)="notificationAction($event)" (deleteNotification)="deleteNotification($event)" [notifications]="filtered_notifications"></app-notifications-list>
|
||||||
</div>
|
</div>
|
||||||
<button style="margin: 10px 0px 2px 10px;" *ngIf="notifications?.length > 0" color="warn" (click)="deleteAllNotifications()" mat-stroked-button>Remove all</button>
|
<button style="margin: 10px 0px 2px 10px;" color="warn" (click)="deleteAllNotifications()" mat-stroked-button>Remove all</button>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,105 +1,134 @@
|
|||||||
<div class="container-fluid" style="max-width: 941px;">
|
<div class="container-fluid" style="max-width: 941px;">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Sorting -->
|
<!-- Sorting -->
|
||||||
<div class="col-12 order-2 col-sm-4 order-sm-1 d-flex justify-content-center">
|
<div class="col-12 order-2 col-sm-4 order-sm-1 d-flex justify-content-center">
|
||||||
<app-sort-property [(sortProperty)]="sortProperty" [(descendingMode)]="descendingMode" (sortOptionChanged)="sortOptionChanged($event)"></app-sort-property>
|
<app-sort-property [(sortProperty)]="sortProperty" [(descendingMode)]="descendingMode" (sortOptionChanged)="sortOptionChanged($event)"></app-sort-property>
|
||||||
</div>
|
|
||||||
<!-- Files title -->
|
|
||||||
<div class="col-12 order-1 col-sm-4 order-sm-2 d-flex justify-content-center">
|
|
||||||
<h4 *ngIf="!customHeader" class="my-videos-title" i18n="My files title">My files</h4>
|
|
||||||
<h4 *ngIf="customHeader" class="my-videos-title">{{customHeader}}</h4>
|
|
||||||
</div>
|
|
||||||
<!-- Search -->
|
|
||||||
<div class="col-12 order-3 col-sm-4 order-sm-3 d-flex justify-content-center">
|
|
||||||
<mat-form-field appearance="outline" [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
|
|
||||||
<mat-label i18n="Search">Search</mat-label>
|
|
||||||
<input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput>
|
|
||||||
<mat-icon matSuffix>search</mat-icon>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Filters -->
|
<!-- Files title -->
|
||||||
<div class="row justify-content-center">
|
<div class="col-12 order-1 col-sm-4 order-sm-2 d-flex justify-content-center">
|
||||||
<mat-chip-listbox class="filter-list" [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
|
@if (!customHeader) {
|
||||||
<mat-chip-option *ngFor="let filter of fileFilters | keyvalue: originalOrder" [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
|
<h4 class="my-videos-title" i18n="My files title">My files</h4>
|
||||||
</mat-chip-listbox>
|
} @else {
|
||||||
|
<h4 class="my-videos-title">{{customHeader}}</h4>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="col-12 order-3 col-sm-4 order-sm-3 d-flex justify-content-center">
|
||||||
|
<mat-form-field appearance="outline" [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
|
||||||
|
<mat-label i18n="Search">Search</mat-label>
|
||||||
|
<input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput>
|
||||||
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Filters -->
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<mat-chip-listbox class="filter-list" [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
|
||||||
|
@for (filter of fileFilters | keyvalue: originalOrder; track filter) {
|
||||||
|
<mat-chip-option [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
|
||||||
|
}
|
||||||
|
</mat-chip-listbox>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<!-- Files -->
|
<!-- Files -->
|
||||||
<div *ngIf="!selectMode" class="container" style="margin-bottom: 16px">
|
@if (!selectMode) {
|
||||||
<div class="row justify-content-center">
|
<div class="container" style="margin-bottom: 16px">
|
||||||
<!-- Real cards -->
|
<div class="row justify-content-center">
|
||||||
<ng-container *ngIf="normal_files_received && paged_data">
|
<!-- Real cards -->
|
||||||
<div style="display: flex; align-items: center;" *ngFor="let file of paged_data; let i = index" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
@if (normal_files_received && paged_data) {
|
||||||
<app-unified-file-card [ngClass]="downloading_content[file.uid] ? 'blurred' : ''" [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToFile($event)" (goToSubscription)="goToSubscription($event)" (toggleFavorite)="toggleFavorite($event)" [file_obj]="file" [use_youtubedl_archive]="postsService.config['Downloader']['use_youtubedl_archive']" [availablePlaylists]="playlists" (addFileToPlaylist)="addFileToPlaylist($event)" [loading]="false" (deleteFile)="deleteFile($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''"></app-unified-file-card>
|
@for (file of paged_data; track file; let i = $index) {
|
||||||
<mat-spinner *ngIf="downloading_content[file.uid]" class="downloading-spinner" [diameter]="32"></mat-spinner>
|
<div style="display: flex; align-items: center;" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
||||||
</div>
|
<app-unified-file-card [ngClass]="downloading_content[file.uid] ? 'blurred' : ''" [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToFile($event)" (goToSubscription)="goToSubscription($event)" (toggleFavorite)="toggleFavorite($event)" [file_obj]="file" [use_youtubedl_archive]="postsService.config['Downloader']['use_youtubedl_archive']" [availablePlaylists]="playlists" (addFileToPlaylist)="addFileToPlaylist($event)" [loading]="false" (deleteFile)="deleteFile($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''"></app-unified-file-card>
|
||||||
<div *ngIf="paged_data.length === 0">
|
@if (downloading_content[file.uid]) {
|
||||||
<ng-container i18n="No files found">No files found.</ng-container>
|
<mat-spinner class="downloading-spinner" [diameter]="32"></mat-spinner>
|
||||||
</div>
|
}
|
||||||
</ng-container>
|
</div>
|
||||||
<!-- Fake cards -->
|
} @empty {
|
||||||
<ng-container>
|
<div>
|
||||||
<div *ngFor="let file of loading_files; let i = index" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[normal_files_received ? 'hide' : '', postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
<ng-container i18n="No files found">No files found.</ng-container>
|
||||||
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" [loading]="true" [theme]="postsService.theme"></app-unified-file-card>
|
</div>
|
||||||
</div>
|
}
|
||||||
</ng-container>
|
}
|
||||||
</div>
|
<!-- Fake cards -->
|
||||||
|
<ng-container>
|
||||||
|
@for (file of loading_files; track file; let i = $index) {
|
||||||
|
<div class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[normal_files_received ? 'hide' : '', postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
||||||
|
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" [loading]="true" [theme]="postsService.theme"></app-unified-file-card>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
} @else {
|
||||||
<div *ngIf="selectMode">
|
<div>
|
||||||
<!-- If selected files e.g. for creating a playlist -->
|
<!-- If selected files e.g. for creating a playlist -->
|
||||||
<mat-tab-group [(selectedIndex)]="selectedIndex">
|
<mat-tab-group [(selectedIndex)]="selectedIndex">
|
||||||
<mat-tab label="Order" i18n-label="Order">
|
<mat-tab label="Order" i18n-label="Order">
|
||||||
<div *ngIf="selected_data.length">
|
@if (selected_data.length) {
|
||||||
<span *ngIf="reverse_order === false" i18n="Normal order">Normal order </span>
|
<div>
|
||||||
<span *ngIf="reverse_order === true" i18n="Reverse order">Reverse order </span>
|
@if (reverse_order === false) {
|
||||||
<button (click)="toggleSelectionOrder()" mat-icon-button><mat-icon>{{!reverse_order ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
|
<span i18n="Normal order">Normal order </span>
|
||||||
</div>
|
}
|
||||||
|
@if (reverse_order === true) {
|
||||||
<!-- Selection order -->
|
<span i18n="Reverse order">Reverse order </span>
|
||||||
<mat-button-toggle-group *ngIf="selected_data.length" class="media-list" cdkDropList (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical #group="matButtonToggleGroup">
|
}
|
||||||
<!-- The following for loop can be optimized but it requires a pipe https://stackoverflow.com/a/35703364/8088021 -->
|
<button (click)="toggleSelectionOrder()" mat-icon-button><mat-icon>{{!reverse_order ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
|
||||||
<mat-button-toggle class="media-box" cdkDrag *ngFor="let file of (reverse_order ? selected_data_objs.slice().reverse() : selected_data_objs); let i = index" [checked]="false"><div><div class="playlist-item-text">{{file.title}}</div> <button (click)="removeSelectedFile(i)" class="remove-item-button" mat-icon-button><mat-icon>cancel</mat-icon></button></div></mat-button-toggle>
|
</div>
|
||||||
</mat-button-toggle-group>
|
}
|
||||||
|
<!-- Selection order -->
|
||||||
<div style="margin-top: 20px;" *ngIf="!selected_data.length">
|
@if (selected_data.length) {
|
||||||
<h4 style="text-align: center;">No files selected!</h4>
|
<mat-button-toggle-group class="media-list" cdkDropList (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical #group="matButtonToggleGroup">
|
||||||
</div>
|
<!-- The following for loop can be optimized but it requires a pipe https://stackoverflow.com/a/35703364/8088021 -->
|
||||||
|
@for (file of (reverse_order ? selected_data_objs.slice().reverse() : selected_data_objs); track file; let i = $index) {
|
||||||
</mat-tab>
|
<mat-button-toggle class="media-box" cdkDrag [checked]="false"><div><div class="playlist-item-text">{{file.title}}</div> <button (click)="removeSelectedFile(i)" class="remove-item-button" mat-icon-button><mat-icon>cancel</mat-icon></button></div></mat-button-toggle>
|
||||||
<mat-tab label="Select files" i18n-label="Select files">
|
}
|
||||||
<mat-selection-list *ngIf="normal_files_received" (selectionChange)="fileSelectionChanged($event)">
|
</mat-button-toggle-group>
|
||||||
<mat-list-option [selected]="selected_data.includes(file.uid)" *ngFor="let file of paged_data" [value]="file">
|
} @else {
|
||||||
<div class="container">
|
<div style="margin-top: 20px;">
|
||||||
<div class="row justify-content-center">
|
<h4 style="text-align: center;">No files selected!</h4>
|
||||||
<div class="col-10 select-file-title">
|
</div>
|
||||||
<mat-icon class="audio-video-icon">{{file.isAudio ? 'audiotrack' : 'movie'}}</mat-icon>
|
}
|
||||||
{{file.title}}
|
</mat-tab>
|
||||||
</div>
|
<mat-tab label="Select files" i18n-label="Select files">
|
||||||
<div class="col-2">{{file.registered | date:'shortDate'}}</div>
|
@if (normal_files_received) {
|
||||||
</div>
|
<mat-selection-list (selectionChange)="fileSelectionChanged($event)">
|
||||||
</div>
|
@for (file of paged_data; track file) {
|
||||||
|
<mat-list-option [selected]="selected_data.includes(file.uid)" [value]="file">
|
||||||
</mat-list-option>
|
<div class="container">
|
||||||
</mat-selection-list>
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-10 select-file-title">
|
||||||
<ng-container *ngIf="!normal_files_received && loading_files && loading_files.length > 0">
|
<mat-icon class="audio-video-icon">{{file.isAudio ? 'audiotrack' : 'movie'}}</mat-icon>
|
||||||
<mat-selection-list *ngIf="!normal_files_received">
|
{{file.title}}
|
||||||
<mat-list-option *ngFor="let file of paged_data">
|
</div>
|
||||||
<content-loader class="list-ghosts" [backgroundColor]="postsService.theme.ghost_primary" [foregroundColor]="postsService.theme.ghost_secondary" viewBox="0 0 250 8"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="8" /></content-loader>
|
<div class="col-2">{{file.registered | date:'shortDate'}}</div>
|
||||||
</mat-list-option>
|
</div>
|
||||||
</mat-selection-list>
|
</div>
|
||||||
</ng-container>
|
</mat-list-option>
|
||||||
</mat-tab>
|
}
|
||||||
</mat-tab-group>
|
</mat-selection-list>
|
||||||
|
}
|
||||||
|
@if (!normal_files_received && loading_files && loading_files.length > 0) {
|
||||||
|
@if (!normal_files_received) {
|
||||||
|
<mat-selection-list>
|
||||||
|
@for (file of paged_data; track file) {
|
||||||
|
<mat-list-option>
|
||||||
|
<content-loader class="list-ghosts" [backgroundColor]="postsService.theme.ghost_primary" [foregroundColor]="postsService.theme.ghost_secondary" viewBox="0 0 250 8"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="8" /></content-loader>
|
||||||
|
</mat-list-option>
|
||||||
|
}
|
||||||
|
</mat-selection-list>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<div style="position: relative;" *ngIf="usePaginator && selectedIndex > 0">
|
@if (usePaginator && selectedIndex > 0) {
|
||||||
<mat-paginator class="paginator" #paginator (page)="pageChangeEvent($event)" [length]="file_count"
|
<div style="position: relative;">
|
||||||
[pageSize]="pageSize"
|
<mat-paginator class="paginator" #paginator (page)="pageChangeEvent($event)" [length]="file_count"
|
||||||
[pageSizeOptions]="[5, 10, 25, 100, this.paged_data && this.paged_data.length > 100 ? this.paged_data.length : 250]">
|
[pageSize]="pageSize"
|
||||||
</mat-paginator>
|
[pageSizeOptions]="[5, 10, 25, 100, this.paged_data && this.paged_data.length > 100 ? this.paged_data.length : 250]">
|
||||||
|
</mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { distinctUntilChanged } from 'rxjs/operators';
|
|||||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||||
import { MatChipListboxChange } from '@angular/material/chips';
|
import { MatChipListboxChange } from '@angular/material/chips';
|
||||||
import { MatSelectionListChange } from '@angular/material/list';
|
import { MatSelectionListChange } from '@angular/material/list';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recent-videos',
|
selector: 'app-recent-videos',
|
||||||
@@ -380,8 +381,8 @@ export class RecentVideosComponent implements OnInit {
|
|||||||
|
|
||||||
fileSelectionChanged(event: MatSelectionListChange): void {
|
fileSelectionChanged(event: MatSelectionListChange): void {
|
||||||
// TODO: make sure below line is possible (_selected is private)
|
// TODO: make sure below line is possible (_selected is private)
|
||||||
const adding = event.option['_selected'];
|
const adding = event.options['_selected'];
|
||||||
const value = event.option.value;
|
const value = adding.value;
|
||||||
if (adding) {
|
if (adding) {
|
||||||
this.selected_data.push(value.uid);
|
this.selected_data.push(value.uid);
|
||||||
this.selected_data_objs.push(value);
|
this.selected_data_objs.push(value);
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
<span class="text" [ngStyle]="{'-webkit-line-clamp': !see_more_active ? line_limit : null}" [innerHTML]="text | linkify"></span>
|
<span class="text" [ngStyle]="{'-webkit-line-clamp': !see_more_active ? line_limit : null}" [innerHTML]="text | linkify"></span>
|
||||||
<span>
|
<span>
|
||||||
<a [routerLink]="[]" (click)="toggleSeeMore()">
|
<a [routerLink]="[]" (click)="toggleSeeMore()">
|
||||||
<ng-container *ngIf="!see_more_active" i18n="See more">
|
@if (!see_more_active) {
|
||||||
See more.
|
<ng-container i18n="See more">
|
||||||
</ng-container>
|
See more.
|
||||||
<ng-container *ngIf="see_more_active" i18n="See less">
|
</ng-container>
|
||||||
See less.
|
} @else {
|
||||||
</ng-container>
|
<ng-container i18n="See less">
|
||||||
</a>
|
See less.
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@@ -1 +1,3 @@
|
|||||||
<button *ngIf="show_skip_ad_button" (click)="skipAdButtonClicked()" mat-flat-button><ng-container i18n="Skip ad button">Skip ad</ng-container></button>
|
@if (show_skip_ad_button) {
|
||||||
|
<button (click)="skipAdButtonClicked()" mat-flat-button><ng-container i18n="Skip ad button">Skip ad</ng-container></button>
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
<div>
|
<div>
|
||||||
<div style="display: inline-block;">
|
<div style="display: inline-block;">
|
||||||
<mat-form-field appearance="outline" style="width: 165px;">
|
<mat-form-field appearance="outline" style="width: 165px;">
|
||||||
<mat-select [(ngModel)]="this.sortProperty" (selectionChange)="emitSortOptionChanged()">
|
<mat-select [(ngModel)]="this.sortProperty" (selectionChange)="emitSortOptionChanged()">
|
||||||
<mat-option *ngFor="let sortOption of sortProperties | keyvalue" [value]="sortOption.key">
|
@for (sortOption of sortProperties | keyvalue; track sortOption) {
|
||||||
{{sortOption['value']['label']}}
|
<mat-option [value]="sortOption.key">
|
||||||
</mat-option>
|
{{sortOption['value']['label']}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
}
|
||||||
</div>
|
</mat-select>
|
||||||
<div class="sort-dir-div">
|
</mat-form-field>
|
||||||
<button (click)="toggleModeChange()" mat-icon-button><mat-icon>{{descendingMode ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
|
</div>
|
||||||
</div>
|
<div class="sort-dir-div">
|
||||||
|
<button (click)="toggleModeChange()" mat-icon-button><mat-icon>{{descendingMode ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Task settings">Task settings - {{task.title}}</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Task settings">Task settings - {{task.title}}</ng-container></h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div *ngIf="task_key === 'delete_old_files'">
|
@if (task_key === 'delete_old_files') {
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Delete files older than">Delete files older than</mat-label>
|
|
||||||
<input [(ngModel)]="new_options['threshold_days']" matInput onlyNumber required>
|
|
||||||
<span matTextSuffix>days</span>
|
|
||||||
</mat-form-field>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox [(ngModel)]="new_options['blacklist_files']" i18n="Blacklist deleted files" placeholder="Archive mode must be enabled" placeholder-i18n>Blacklist all files</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox [disabled]="new_options['blacklist_files']" [(ngModel)]="new_options['blacklist_subscription_files']" i18n="Blacklist deleted subscription files" placeholder="Archive mode must be enabled" placeholder-i18n>Blacklist deleted subscription files</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-checkbox [(ngModel)]="new_options['auto_confirm']" i18n="Do not ask for confirmation">Do not ask for confirmation</mat-checkbox>
|
<mat-form-field color="accent">
|
||||||
|
<mat-label i18n="Delete files older than">Delete files older than</mat-label>
|
||||||
|
<input [(ngModel)]="new_options['threshold_days']" matInput onlyNumber required>
|
||||||
|
<span matTextSuffix>days</span>
|
||||||
|
</mat-form-field>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox [(ngModel)]="new_options['blacklist_files']" i18n="Blacklist deleted files" placeholder="Archive mode must be enabled" placeholder-i18n>Blacklist all files</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox [disabled]="new_options['blacklist_files']" [(ngModel)]="new_options['blacklist_subscription_files']" i18n="Blacklist deleted subscription files" placeholder="Archive mode must be enabled" placeholder-i18n>Blacklist deleted subscription files</mat-checkbox>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
<div>
|
||||||
|
<mat-checkbox [(ngModel)]="new_options['auto_confirm']" i18n="Do not ask for confirmation">Do not ask for confirmation</mat-checkbox>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close>
|
<button mat-button mat-dialog-close>
|
||||||
<ng-container *ngIf="optionsChanged()" i18n="Task settings cancel button">Cancel</ng-container>
|
@if (optionsChanged()) {
|
||||||
<ng-container *ngIf="!optionsChanged()" i18n="Task settings close button">Close</ng-container>
|
<ng-container i18n="Task settings cancel button">Cancel</ng-container>
|
||||||
</button>
|
} @else {
|
||||||
<button mat-button [disabled]="!optionsChanged()" (click)="saveSettings()"><ng-container i18n="Save button">Save</ng-container></button>
|
<ng-container i18n="Task settings close button">Close</ng-container>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
<button mat-button [disabled]="!optionsChanged()" (click)="saveSettings()"><ng-container i18n="Save button">Save</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,104 +1,114 @@
|
|||||||
<div [hidden]="!(tasks && tasks.length > 0)">
|
<div [hidden]="!(tasks && tasks.length > 0)">
|
||||||
<div style="overflow: hidden;" [ngClass]="'mat-elevation-z8'">
|
<div style="overflow: hidden;" [ngClass]="'mat-elevation-z8'">
|
||||||
<mat-table style="overflow: hidden" matSort [dataSource]="dataSource">
|
<mat-table style="overflow: hidden" matSort [dataSource]="dataSource">
|
||||||
<!-- Title Column -->
|
<!-- Title Column -->
|
||||||
<ng-container matColumnDef="title">
|
<ng-container matColumnDef="title">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Title">Title</ng-container> </mat-header-cell>
|
||||||
<mat-cell *matCellDef="let element">
|
<mat-cell *matCellDef="let element">
|
||||||
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
<span class="one-line" [matTooltip]="element.title ? element.title : null">
|
||||||
{{element.title}}
|
{{element.title}}
|
||||||
</span>
|
</span>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<!-- Last Ran Column -->
|
||||||
<!-- Last Ran Column -->
|
<ng-container matColumnDef="last_ran">
|
||||||
<ng-container matColumnDef="last_ran">
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Last ran">Last ran</ng-container> </mat-header-cell>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Last ran">Last ran</ng-container> </mat-header-cell>
|
<mat-cell *matCellDef="let element">
|
||||||
<mat-cell *matCellDef="let element">
|
@if (element.last_ran) {
|
||||||
<ng-container *ngIf="element.last_ran">{{element.last_ran*1000 | date: 'short'}}</ng-container>
|
{{element.last_ran*1000 | date: 'short'}}
|
||||||
<ng-container i18n="N/A" *ngIf="!element.last_ran">N/A</ng-container>
|
} @else {
|
||||||
</mat-cell>
|
<ng-container i18n="N/A">N/A</ng-container>
|
||||||
</ng-container>
|
}
|
||||||
|
</mat-cell>
|
||||||
<!-- Last Confirmed Column -->
|
</ng-container>
|
||||||
<ng-container matColumnDef="last_confirmed">
|
<!-- Last Confirmed Column -->
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Last confirmed">Last confirmed</ng-container> </mat-header-cell>
|
<ng-container matColumnDef="last_confirmed">
|
||||||
<mat-cell *matCellDef="let element">
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Last confirmed">Last confirmed</ng-container> </mat-header-cell>
|
||||||
<ng-container *ngIf="element.last_confirmed">{{element.last_confirmed*1000 | date: 'short'}}</ng-container>
|
<mat-cell *matCellDef="let element">
|
||||||
<ng-container i18n="N/A" *ngIf="!element.last_confirmed">N/A</ng-container>
|
@if (element.last_confirmed) {
|
||||||
</mat-cell>
|
{{element.last_confirmed*1000 | date: 'short'}}
|
||||||
</ng-container>
|
} @else {
|
||||||
|
<ng-container i18n="N/A">N/A</ng-container>
|
||||||
<!-- Status Column -->
|
}
|
||||||
<ng-container matColumnDef="status">
|
</mat-cell>
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Status">Status</ng-container> </mat-header-cell>
|
</ng-container>
|
||||||
<mat-cell *matCellDef="let element">
|
<!-- Status Column -->
|
||||||
<span *ngIf="element.running || element.confirming"><mat-spinner matTooltip="Busy" i18n-matTooltip="Busy" [diameter]="25"></mat-spinner></span>
|
<ng-container matColumnDef="status">
|
||||||
<span *ngIf="!(element.running || element.confirming) && element.schedule" style="display: flex">
|
<mat-header-cell *matHeaderCellDef mat-sort-header> <ng-container i18n="Status">Status</ng-container> </mat-header-cell>
|
||||||
<ng-container i18n="Scheduled">Scheduled for</ng-container>
|
<mat-cell *matCellDef="let element">
|
||||||
{{element.next_invocation | date: 'short'}}<mat-icon style="font-size: 16px; display: inline-flex; align-items: center; padding-left: 5px; padding-bottom: 6px;" *ngIf="element.schedule.type === 'recurring'">repeat</mat-icon>
|
@if (element.running || element.confirming) {
|
||||||
</span>
|
<span><mat-spinner matTooltip="Busy" i18n-matTooltip="Busy" [diameter]="25"></mat-spinner></span>
|
||||||
<span *ngIf="!(element.running || element.confirming) && !element.schedule">
|
} @else if (element.schedule) {
|
||||||
<ng-container i18n="Not scheduled">Not scheduled</ng-container>
|
<span style="display: flex">
|
||||||
</span>
|
<ng-container i18n="Scheduled">Scheduled for</ng-container>
|
||||||
</mat-cell>
|
{{element.next_invocation | date: 'short'}}
|
||||||
</ng-container>
|
@if (element.schedule.type === 'recurring') {
|
||||||
|
<mat-icon style="font-size: 16px; display: inline-flex; align-items: center; padding-left: 5px; padding-bottom: 6px;">repeat</mat-icon>
|
||||||
<!-- Actions Column -->
|
}
|
||||||
<ng-container matColumnDef="actions">
|
</span>
|
||||||
<mat-header-cell *matHeaderCellDef> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
|
} @else {
|
||||||
<mat-cell *matCellDef="let element">
|
<span>
|
||||||
<div class="container">
|
<ng-container i18n="Not scheduled">Not scheduled</ng-container>
|
||||||
<div class="row justify-content-start">
|
</span>
|
||||||
<div *ngIf="element.data?.uids?.length > 0 || (!element.data?.uids && element.data)" class="col-12 mt-2" style="display: flex; justify-content: center;">
|
}
|
||||||
<ng-container>
|
</mat-cell>
|
||||||
<button (click)="confirmTask(element.key)" [disabled]="element.running || element.confirming" mat-stroked-button>
|
</ng-container>
|
||||||
<ng-container *ngIf="element.key == 'missing_files_check'">
|
<!-- Actions Column -->
|
||||||
<ng-container i18n="Clear missing files from DB">Clear missing files from DB:</ng-container>{{element.data.uids.length}}
|
<ng-container matColumnDef="actions">
|
||||||
</ng-container>
|
<mat-header-cell *matHeaderCellDef> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
|
||||||
<ng-container *ngIf="element.key == 'duplicate_files_check'">
|
<mat-cell *matCellDef="let element">
|
||||||
<ng-container i18n="Clear duplicate files from DB">Clear duplicate files from DB:</ng-container> {{element.data.uids.length}}
|
<div class="container">
|
||||||
</ng-container>
|
<div class="row justify-content-start">
|
||||||
<ng-container *ngIf="element.key == 'youtubedl_update_check'">
|
@if (element.data?.uids?.length > 0 || (!element.data?.uids && element.data)) {
|
||||||
<ng-container i18n="Update binary to">Update binary to:</ng-container> {{element.data}}
|
<div class="col-12 mt-2" style="display: flex; justify-content: center;">
|
||||||
</ng-container>
|
<ng-container>
|
||||||
<ng-container *ngIf="element.key == 'delete_old_files'">
|
<button (click)="confirmTask(element.key)" [disabled]="element.running || element.confirming" mat-stroked-button>
|
||||||
<ng-container i18n="Delete old files">Delete old files:</ng-container> {{element.data.files_to_remove.length}}
|
@switch(element.key) {
|
||||||
</ng-container>
|
@case ('missing_files_check') {
|
||||||
</button>
|
<ng-container i18n="Clear missing files from DB">Clear missing files from DB:</ng-container>{{element.data.uids.length}}
|
||||||
</ng-container>
|
} @case ('duplicate_files_check') {
|
||||||
</div>
|
<ng-container i18n="Clear duplicate files from DB">Clear duplicate files from DB:</ng-container> {{element.data.uids.length}}
|
||||||
<div class="col-3">
|
} @case ('youtubedl_update_check') {
|
||||||
<button (click)="runTask(element.key)" [disabled]="element.running || element.confirming" mat-icon-button matTooltip="Run" i18n-matTooltip="Run"><mat-icon>play_arrow</mat-icon></button>
|
<ng-container i18n="Update binary to">Update binary to:</ng-container> {{element.data}}
|
||||||
</div>
|
} @case ('delete_old_files') {
|
||||||
<div class="col-3">
|
<ng-container i18n="Delete old files">Delete old files:</ng-container> {{element.data.files_to_remove.length}}
|
||||||
<button (click)="scheduleTask(element)" mat-icon-button matTooltip="Schedule" i18n-matTooltip="Schedule"><mat-icon>schedule</mat-icon></button>
|
}
|
||||||
</div>
|
}
|
||||||
<div class="col-3">
|
</button>
|
||||||
<button (click)="openTaskSettings(element)" mat-icon-button matTooltip="Settings" i18n-matTooltip="Settings"><mat-icon>settings</mat-icon></button>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="element.error" class="col-3">
|
}
|
||||||
<button (click)="showError(element)" mat-icon-button matTooltip="Show error" i18n-matTooltip="Show error"><mat-icon>warning</mat-icon></button>
|
<div class="col-3">
|
||||||
</div>
|
<button (click)="runTask(element.key)" [disabled]="element.running || element.confirming" mat-icon-button matTooltip="Run" i18n-matTooltip="Run"><mat-icon>play_arrow</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-3">
|
||||||
</mat-cell>
|
<button (click)="scheduleTask(element)" mat-icon-button matTooltip="Schedule" i18n-matTooltip="Schedule"><mat-icon>schedule</mat-icon></button>
|
||||||
</ng-container>
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
<button (click)="openTaskSettings(element)" mat-icon-button matTooltip="Settings" i18n-matTooltip="Settings"><mat-icon>settings</mat-icon></button>
|
||||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
</div>
|
||||||
</mat-table>
|
@if (element.error) {
|
||||||
|
<div class="col-3">
|
||||||
<mat-paginator [pageSizeOptions]="[10, 20]"
|
<button (click)="showError(element)" mat-icon-button matTooltip="Show error" i18n-matTooltip="Show error"><mat-icon>warning</mat-icon></button>
|
||||||
showFirstLastButtons
|
</div>
|
||||||
aria-label="Select page of tasks">
|
}
|
||||||
</mat-paginator>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</mat-cell>
|
||||||
<button style="margin-top: 10px; margin-left: 5px;" mat-stroked-button (click)="openRestoreDBBackupDialog()" i18n="Restore DB from backup button">Restore DB from backup</button>
|
</ng-container>
|
||||||
<button style="margin-top: 10px; margin-left: 5px;" mat-stroked-button (click)="resetTasks()" color="warn" i18n="Reset tasks button">Reset tasks</button>
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
|
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||||
|
</mat-table>
|
||||||
|
<mat-paginator [pageSizeOptions]="[10, 20]"
|
||||||
|
showFirstLastButtons
|
||||||
|
aria-label="Select page of tasks">
|
||||||
|
</mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
<button style="margin-top: 10px; margin-left: 5px;" mat-stroked-button (click)="openRestoreDBBackupDialog()" i18n="Restore DB from backup button">Restore DB from backup</button>
|
||||||
<div *ngIf="(!tasks || tasks.length === 0) && tasks_retrieved">
|
<button style="margin-top: 10px; margin-left: 5px;" mat-stroked-button (click)="resetTasks()" color="warn" i18n="Reset tasks button">Reset tasks</button>
|
||||||
<h4 style="text-align: center; margin-top: 10px;" i18n="No tasks label">No tasks available!</h4>
|
</div>
|
||||||
</div>
|
@if ((!tasks || tasks.length === 0) && tasks_retrieved) {
|
||||||
|
<div>
|
||||||
|
<h4 style="text-align: center; margin-top: 10px;" i18n="No tasks label">No tasks available!</h4>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
<div class="chat-container" #scrollContainer *ngIf="visible_chat">
|
@if (visible_chat) {
|
||||||
|
<div class="chat-container" #scrollContainer>
|
||||||
<div style="width: 250px; text-align: center;"><strong>Twitch Chat</strong></div>
|
<div style="width: 250px; text-align: center;"><strong>Twitch Chat</strong></div>
|
||||||
<div #chat style="max-width: 250px" *ngFor="let chat of visible_chat; let last = last">
|
@for (chat of visible_chat; track chat; let last = $last) {
|
||||||
|
<div #chat style="max-width: 250px">
|
||||||
{{chat.timestamp_str}} - <strong [style.color]="chat.user_color ? chat.user_color : null">{{chat.name}}</strong>: {{chat.message}}
|
{{chat.timestamp_str}} - <strong [style.color]="chat.user_color ? chat.user_color : null">{{chat.name}}</strong>: {{chat.message}}
|
||||||
{{last ? scrollToBottom() : ''}}
|
{{last ? scrollToBottom() : ''}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
</div>
|
||||||
<ng-container *ngIf="chat_response_received && !full_chat">
|
}
|
||||||
<button [disabled]="downloading_chat" (click)="downloadTwitchChat()" class="download-button" mat-raised-button color="accent"><ng-container i18n="Download Twitch Chat button">Download Twitch Chat</ng-container></button>
|
@if (chat_response_received && !full_chat) {
|
||||||
<mat-spinner *ngIf="downloading_chat" class="downloading-spinner" [diameter]="30"></mat-spinner>
|
<button [disabled]="downloading_chat" (click)="downloadTwitchChat()" class="download-button" mat-raised-button color="accent"><ng-container i18n="Download Twitch Chat button">Download Twitch Chat</ng-container></button>
|
||||||
</ng-container>
|
@if (downloading_chat) {
|
||||||
|
<mat-spinner class="downloading-spinner" [diameter]="30"></mat-spinner>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,73 +1,103 @@
|
|||||||
<div (mouseenter)="onMouseOver()" (mouseleave)="onMouseOut()" (contextmenu)="onRightClick($event)" style="position: relative; width: fit-content;">
|
<div (mouseenter)="onMouseOver()" (mouseleave)="onMouseOut()" (contextmenu)="onRightClick($event)" style="position: relative; width: fit-content;">
|
||||||
<div *ngIf="!loading" class="download-time">
|
@if (!loading) {
|
||||||
<mat-icon class="audio-video-icon">{{(file_obj.type === 'audio' || file_obj.isAudio) ? 'audiotrack' : 'movie'}}</mat-icon>
|
<div class="download-time">
|
||||||
|
<mat-icon class="audio-video-icon">{{(file_obj.type === 'audio' || file_obj.isAudio) ? 'audiotrack' : 'movie'}}</mat-icon>
|
||||||
<ng-container i18n="Auto-generated label" *ngIf="file_obj.auto">Auto-generated</ng-container>
|
|
||||||
<ng-container *ngIf="!file_obj.auto">{{file_obj.registered | date:'shortDate' : undefined : locale.ngID}}</ng-container>
|
@if (file_obj.auto) {
|
||||||
|
<ng-container i18n="Auto-generated label">Auto-generated</ng-container>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
{{file_obj.registered | date:'shortDate' : undefined : locale.ngID}}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="loading" class="download-time" style="width: 75%; margin-top: 5px;"><content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 250 30"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="30" /></content-loader></div>
|
}
|
||||||
<!-- The context menu trigger must be kept above the "more info" menu -->
|
@else {
|
||||||
<div style="visibility: hidden; position: fixed"
|
<div class="download-time" style="width: 75%; margin-top: 5px;"><content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 250 30"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="30" /></content-loader></div>
|
||||||
[style.left]="contextMenuPosition.x"
|
}
|
||||||
[style.top]="contextMenuPosition.y"
|
<!-- The context menu trigger must be kept above the "more info" menu -->
|
||||||
[matMenuTriggerFor]="context_menu">
|
<div style="visibility: hidden; position: fixed"
|
||||||
</div>
|
[style.left]="contextMenuPosition.x"
|
||||||
<button *ngIf="!file_obj || !file_obj.auto" [disabled]="loading" [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
[style.top]="contextMenuPosition.y"
|
||||||
<mat-menu #context_menu>
|
[matMenuTriggerFor]="context_menu">
|
||||||
<ng-container *ngIf="!loading">
|
</div>
|
||||||
<button (click)="navigateToFile($event)" mat-menu-item><mat-icon>open_in_browser</mat-icon><ng-container i18n="Open file button">Open file</ng-container></button>
|
@if (!file_obj || !file_obj.auto) {
|
||||||
<button (click)="navigateToFile({ctrlKey: true})" mat-menu-item><mat-icon>open_in_new</mat-icon><ng-container i18n="Open file in new tab">Open file in new tab</ng-container></button>
|
<button [disabled]="loading" [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||||
</ng-container>
|
}
|
||||||
</mat-menu>
|
<mat-menu #context_menu>
|
||||||
<mat-menu #action_menu="matMenu">
|
@if (!loading) {
|
||||||
<ng-container *ngIf="!is_playlist && !loading">
|
<button (click)="navigateToFile($event)" mat-menu-item><mat-icon>open_in_browser</mat-icon><ng-container i18n="Open file button">Open file</ng-container></button>
|
||||||
<button (click)="emitToggleFavorite()" mat-menu-item>
|
<button (click)="navigateToFile({ctrlKey: true})" mat-menu-item><mat-icon>open_in_new</mat-icon><ng-container i18n="Open file in new tab">Open file in new tab</ng-container></button>
|
||||||
<mat-icon>{{file_obj.favorite ? 'favorite_filled' : 'favorite_outline'}}</mat-icon>
|
}
|
||||||
<ng-container *ngIf="!file_obj.favorite" i18n="Favorite button">Favorite</ng-container>
|
</mat-menu>
|
||||||
<ng-container *ngIf="file_obj.favorite" i18n="Unfavorite button">Unfavorite</ng-container>
|
<mat-menu #action_menu="matMenu">
|
||||||
</button>
|
@if (!is_playlist && !loading) {
|
||||||
<button (click)="openFileInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
|
<button (click)="emitToggleFavorite()" mat-menu-item>
|
||||||
<button (click)="navigateToSubscription()" mat-menu-item *ngIf="file_obj.sub_id"><mat-icon>{{file_obj.isAudio ? 'library_music' : 'video_library'}}</mat-icon> <ng-container i18n="Go to subscription menu item">Go to subscription</ng-container></button>
|
<mat-icon>{{file_obj.favorite ? 'favorite_filled' : 'favorite_outline'}}</mat-icon>
|
||||||
<button [disabled]="!availablePlaylists || availablePlaylists.length === 0" [matMenuTriggerFor]="addtoplaylist" mat-menu-item><mat-icon>playlist_add</mat-icon> <ng-container i18n="Add to playlist menu item">Add to playlist</ng-container></button>
|
@if (!file_obj.favorite) {
|
||||||
<mat-menu #addtoplaylist="matMenu">
|
<ng-container i18n="Favorite button">Favorite</ng-container>
|
||||||
<ng-container *ngFor="let playlist of availablePlaylists">
|
}
|
||||||
<button *ngIf="(playlist.type === 'audio') === file_obj.isAudio" [disabled]="playlist.uids?.includes(file_obj.uid)" (click)="emitAddFileToPlaylist(playlist.id)" mat-menu-item>{{playlist.name}}</button>
|
@else {
|
||||||
</ng-container>
|
<ng-container i18n="Unfavorite button">Unfavorite</ng-container>
|
||||||
</mat-menu>
|
}
|
||||||
<mat-divider></mat-divider>
|
</button>
|
||||||
<button *ngIf="file_obj.sub_id" (click)="emitDeleteFile()" mat-menu-item><mat-icon>restore</mat-icon><ng-container i18n="Delete and redownload subscription video button">Delete and redownload</ng-container></button>
|
<button (click)="openFileInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
|
||||||
<button *ngIf="!file_obj.sub_id" (click)="emitDeleteFile()" mat-menu-item><mat-icon>delete</mat-icon><ng-container i18n="Delete video button">Delete</ng-container></button>
|
@if (file_obj.sub_id) {
|
||||||
<button *ngIf="file_obj.sub_id || use_youtubedl_archive" (click)="emitDeleteFile(true)" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete and don't download again">Delete and don't download again</ng-container></button>
|
<button (click)="navigateToSubscription()" mat-menu-item><mat-icon>{{file_obj.isAudio ? 'library_music' : 'video_library'}}</mat-icon> <ng-container i18n="Go to subscription menu item">Go to subscription</ng-container></button>
|
||||||
</ng-container>
|
}
|
||||||
<ng-container *ngIf="is_playlist && !loading">
|
<button [disabled]="!availablePlaylists || availablePlaylists.length === 0" [matMenuTriggerFor]="addtoplaylist" mat-menu-item><mat-icon>playlist_add</mat-icon> <ng-container i18n="Add to playlist menu item">Add to playlist</ng-container></button>
|
||||||
<button (click)="emitEditPlaylist()" mat-menu-item><mat-icon>edit</mat-icon><ng-container i18n="Playlist edit button">Edit</ng-container></button>
|
<mat-menu #addtoplaylist="matMenu">
|
||||||
<mat-divider></mat-divider>
|
@for (playlist of availablePlaylists; track playlist) {
|
||||||
<button (click)="emitDeleteFile()" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete playlist">Delete</ng-container></button>
|
@if ((playlist.type === 'audio') === file_obj.isAudio) {
|
||||||
</ng-container>
|
<button [disabled]="playlist.uids?.includes(file_obj.uid)" (click)="emitAddFileToPlaylist(playlist.id)" mat-menu-item>{{playlist.name}}</button>
|
||||||
<ng-container *ngIf="loading">
|
}
|
||||||
<button mat-menu-item>Placeholder</button>
|
}
|
||||||
</ng-container>
|
</mat-menu>
|
||||||
</mat-menu>
|
<mat-divider></mat-divider>
|
||||||
<mat-card [matTooltip]="null" (click)="navigateToFile($event)" matRipple class="file-mat-card" [ngClass]="{'small-mat-card': card_size === 'small', 'file-mat-card': card_size === 'medium', 'large-mat-card': card_size === 'large', 'mat-elevation-z4': !elevated, 'mat-elevation-z8': elevated}">
|
@if (file_obj.sub_id) {
|
||||||
<div style="padding:5px">
|
<button (click)="emitDeleteFile()" mat-menu-item><mat-icon>restore</mat-icon><ng-container i18n="Delete and redownload subscription video button">Delete and redownload</ng-container></button>
|
||||||
<div *ngIf="!loading && file_obj.thumbnailURL" class="img-div">
|
} @else {
|
||||||
<div [ngClass]="{'image-small': card_size === 'small', 'image': card_size === 'medium', 'image-large': card_size === 'large'}" style="position: relative">
|
<button (click)="emitDeleteFile()" mat-menu-item><mat-icon>delete</mat-icon><ng-container i18n="Delete video button">Delete</ng-container></button>
|
||||||
<img *ngIf="!hide_image || is_playlist || (file_obj.type === 'audio' || file_obj.isAudio)" [ngClass]="{'image-small': card_size === 'small', 'image': card_size === 'medium', 'image-large': card_size === 'large'}" [src]="file_obj.thumbnailPath ? thumbnailBlobURL : file_obj.thumbnailURL" alt="Thumbnail">
|
}
|
||||||
<video *ngIf="elevated && !is_playlist && !(file_obj.type === 'audio' || file_obj.isAudio)" autoplay loop muted [muted]="true" [ngClass]="{'video-small': card_size === 'small', 'video': card_size === 'medium', 'video-large': card_size === 'large'}" [src]="streamURL">
|
@if (file_obj.sub_id || use_youtubedl_archive) {
|
||||||
</video>
|
<button (click)="emitDeleteFile(true)" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete and don't download again">Delete and don't download again</ng-container></button>
|
||||||
<div class="duration-time">
|
}
|
||||||
{{file_length}}
|
}
|
||||||
</div>
|
@if (is_playlist && !loading) {
|
||||||
</div>
|
<button (click)="emitEditPlaylist()" mat-menu-item><mat-icon>edit</mat-icon><ng-container i18n="Playlist edit button">Edit</ng-container></button>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<button (click)="emitDeleteFile()" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete playlist">Delete</ng-container></button>
|
||||||
|
} @else if (loading) {
|
||||||
|
<button mat-menu-item>Placeholder</button>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
|
<mat-card [matTooltip]="null" (click)="navigateToFile($event)" matRipple class="file-mat-card" [ngClass]="{'small-mat-card': card_size === 'small', 'file-mat-card': card_size === 'medium', 'large-mat-card': card_size === 'large', 'mat-elevation-z4': !elevated, 'mat-elevation-z8': elevated}">
|
||||||
|
<div style="padding:5px">
|
||||||
|
@if (!loading && file_obj.thumbnailURL) {
|
||||||
|
<div class="img-div">
|
||||||
|
<div [ngClass]="{'image-small': card_size === 'small', 'image': card_size === 'medium', 'image-large': card_size === 'large'}" style="position: relative">
|
||||||
|
@if (!hide_image || is_playlist || (file_obj.type === 'audio' || file_obj.isAudio)) {
|
||||||
|
<img [ngClass]="{'image-small': card_size === 'small', 'image': card_size === 'medium', 'image-large': card_size === 'large'}" [src]="file_obj.thumbnailPath ? thumbnailBlobURL : file_obj.thumbnailURL" alt="Thumbnail">
|
||||||
|
}
|
||||||
|
@if (elevated && !is_playlist && !(file_obj.type === 'audio' || file_obj.isAudio)) {
|
||||||
|
<video autoplay loop muted [muted]="true" [ngClass]="{'video-small': card_size === 'small', 'video': card_size === 'medium', 'video-large': card_size === 'large'}" [src]="streamURL">
|
||||||
|
</video>
|
||||||
|
}
|
||||||
|
<div class="duration-time">
|
||||||
|
{{file_length}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div *ngIf="loading" class="img-div">
|
|
||||||
<content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 100 55"><svg:rect x="0" y="0" rx="0" ry="0" width="100" height="55" /></content-loader>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span *ngIf="!loading" [ngClass]="{'max-two-lines': card_size !== 'small', 'max-one-line': card_size === 'small' }">{{card_size === 'large' && file_obj.uploader ? file_obj.uploader + ' - ' : ''}}<strong>{{!is_playlist ? file_obj.title : file_obj.name}}</strong></span>
|
|
||||||
<span *ngIf="loading" class="title-loading"><content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 250 30"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="30" /></content-loader></span>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-card>
|
}
|
||||||
|
@if (loading) {
|
||||||
|
<div class="img-div">
|
||||||
|
<content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 100 55"><svg:rect x="0" y="0" rx="0" ry="0" width="100" height="55" /></content-loader>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<span [ngClass]="{'max-two-lines': card_size !== 'small', 'max-one-line': card_size === 'small' }">{{card_size === 'large' && file_obj.uploader ? file_obj.uploader + ' - ' : ''}}<strong>{{!is_playlist ? file_obj.title : file_obj.name}}</strong></span>
|
||||||
|
}
|
||||||
|
@if (loading) {
|
||||||
|
<span class="title-loading"><content-loader [backgroundColor]="theme.ghost_primary" [foregroundColor]="theme.ghost_secondary" viewBox="0 0 250 30"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="30" /></content-loader></span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,28 +1,35 @@
|
|||||||
<h4 mat-dialog-title *ngIf="create_mode" ><ng-container i18n="Create a playlist dialog title">Create a playlist</ng-container></h4>
|
@if (create_mode) {
|
||||||
<h4 mat-dialog-title *ngIf="!create_mode"><ng-container i18n="Modify playlist dialog title">Modify playlist</ng-container></h4>
|
<h4 mat-dialog-title ><ng-container i18n="Create a playlist dialog title">Create a playlist</ng-container></h4>
|
||||||
|
} @else {
|
||||||
|
<h4 mat-dialog-title><ng-container i18n="Modify playlist dialog title">Modify playlist</ng-container></h4>
|
||||||
|
}
|
||||||
<mat-dialog-content style="max-height: 85vh;">
|
<mat-dialog-content style="max-height: 85vh;">
|
||||||
<form>
|
<form>
|
||||||
<div *ngIf="create_mode || playlist">
|
@if (create_mode || playlist) {
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field color="accent">
|
<div>
|
||||||
<mat-label i18n="Playlist name">Name</mat-label>
|
<mat-form-field color="accent">
|
||||||
<input [(ngModel)]="name" matInput type="text" required aria-required [ngModelOptions]="{standalone: true}">
|
<mat-label i18n="Playlist name">Name</mat-label>
|
||||||
</mat-form-field>
|
<input [(ngModel)]="name" matInput type="text" required aria-required [ngModelOptions]="{standalone: true}">
|
||||||
</div>
|
</mat-form-field>
|
||||||
<app-recent-videos [selectMode]="true" [defaultSelected]="preselected_files" [customHeader]="'Select files'" (fileSelectionEmitter)="fileSelectionChanged($event)" [selectedIndex]="create_mode ? 1 : 0"></app-recent-videos>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<app-recent-videos [selectMode]="true" [defaultSelected]="preselected_files" [customHeader]="'Select files'" (fileSelectionEmitter)="fileSelectionChanged($event)" [selectedIndex]="create_mode ? 1 : 0"></app-recent-videos>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button *ngIf="create_mode" (click)="createPlaylist()" [disabled]="!name || !filesSelect.value || filesSelect.value.length === 0" color="primary" style="float: right" mat-button>
|
@if (create_mode) {
|
||||||
<ng-container i18n="Create button">Create</ng-container>
|
<button (click)="createPlaylist()" [disabled]="!name || !filesSelect.value || filesSelect.value.length === 0" color="primary" style="float: right" mat-button>
|
||||||
|
<ng-container i18n="Create button">Create</ng-container>
|
||||||
</button>
|
</button>
|
||||||
<button *ngIf="!create_mode" (click)="updatePlaylist()" [disabled]="!name || !playlistChanged()" color="primary" style="float: right" mat-button>
|
} @else {
|
||||||
<ng-container i18n="Save button">Save</ng-container>
|
<button (click)="updatePlaylist()" [disabled]="!name || !playlistChanged()" color="primary" style="float: right" mat-button>
|
||||||
|
<ng-container i18n="Save button">Save</ng-container>
|
||||||
</button>
|
</button>
|
||||||
<div *ngIf="create_in_progress" style="margin-left: 10px"><mat-spinner [diameter]="25"></mat-spinner></div>
|
}
|
||||||
|
@if (create_in_progress) {
|
||||||
|
<div style="margin-left: 10px"><mat-spinner [diameter]="25"></mat-spinner></div>
|
||||||
|
}
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -1,43 +1,51 @@
|
|||||||
<h4 style="position: relative" mat-dialog-title><ng-container i18n="About dialog title">About YoutubeDL-Material</ng-container>
|
<h4 style="position: relative" mat-dialog-title><ng-container i18n="About dialog title">About YoutubeDL-Material</ng-container>
|
||||||
<span class="logo-image">
|
<span class="logo-image">
|
||||||
<a [href]="projectLink" target="_blank">
|
<a [href]="projectLink" target="_blank">
|
||||||
<img style="width: 32px;" src="assets/images/GitHub-64px.png">
|
<img style="width: 32px;" src="assets/images/GitHub-64px.png">
|
||||||
</a>
|
</a>
|
||||||
<img style="width: 32px; margin-left: 15px;" src="assets/images/logo_128px.png">
|
<img style="width: 32px; margin-left: 15px;" src="assets/images/logo_128px.png">
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div style="margin-bottom: 5px;">
|
<div style="margin-bottom: 5px;">
|
||||||
<p>
|
<p>
|
||||||
<i>YoutubeDL-Material</i> <ng-container i18n="About first paragraph">is an open-source YouTube downloader built under Google's Material Design specifications. You can seamlessly download your favorite videos as video or audio files, and even subscribe to your favorite channels and playlists to keep updated with their new videos.</ng-container>
|
<i>YoutubeDL-Material</i> <ng-container i18n="About first paragraph">is an open-source YouTube downloader built under Google's Material Design specifications. You can seamlessly download your favorite videos as video or audio files, and even subscribe to your favorite channels and playlists to keep updated with their new videos.</ng-container>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i>YoutubeDL-Material</i> <ng-container i18n="About second paragraph">has some awesome features included! An extensive API, Docker support, and localization (translation) support. Read up on all the supported features by clicking on the GitHub icon above.</ng-container>
|
||||||
|
</p>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<h5 style="margin-top: 10px;">Installation details:</h5>
|
||||||
|
<p>
|
||||||
|
<ng-container i18n="Version label">Installed version:</ng-container> {{current_version_tag}} -
|
||||||
|
@if (checking_for_updates) {
|
||||||
|
<span style="display: inline-block"><mat-spinner class="version-spinner" [diameter]="22"></mat-spinner> <ng-container i18n="Checking for updates text">Checking for updates...</ng-container></span>
|
||||||
|
} @else {
|
||||||
|
<mat-icon class="version-checked-icon">done</mat-icon>
|
||||||
|
@if (latestGithubRelease['tag_name'] !== current_version_tag) {
|
||||||
|
<a [href]="latestUpdateLink" target="_blank"><ng-container i18n="View latest update">Update available</ng-container> - {{latestGithubRelease['tag_name']}}</a>. <ng-container i18n="Update through settings menu hint">You can update from the settings menu.</ng-container>
|
||||||
|
} @else {
|
||||||
|
<span>You are up to date.</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<ng-container i18n="Installation type">Installation type:</ng-container> {{postsService.version_info.type}}
|
||||||
|
<br>
|
||||||
|
@if (postsService.version_info.type === 'docker') {
|
||||||
|
<ng-container i18n="Docker tag">Docker tag:</ng-container> {{postsService.version_info.tag}}
|
||||||
|
<br>
|
||||||
|
}
|
||||||
|
<ng-container i18n="Commit hash">Commit hash:</ng-container> {{postsService.version_info.commit}}
|
||||||
|
<br>
|
||||||
|
<ng-container i18n="Build date">Build date:</ng-container> {{postsService.version_info.date}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<i>YoutubeDL-Material</i> <ng-container i18n="About second paragraph">has some awesome features included! An extensive API, Docker support, and localization (translation) support. Read up on all the supported features by clicking on the GitHub icon above.</ng-container>
|
<ng-container i18n="About bug prefix">Found a bug or have a suggestion?</ng-container> <a [href]="issuesLink" target="_blank"><ng-container i18n="About bug click here">Click here</ng-container></a> <ng-container i18n="About bug suffix">to create an issue!</ng-container>
|
||||||
</p>
|
</p>
|
||||||
<mat-divider></mat-divider>
|
</div>
|
||||||
<h5 style="margin-top: 10px;">Installation details:</h5>
|
</mat-dialog-content>
|
||||||
<p>
|
<mat-dialog-actions>
|
||||||
<ng-container i18n="Version label">Installed version:</ng-container> {{current_version_tag}} - <span style="display: inline-block" *ngIf="checking_for_updates"><mat-spinner class="version-spinner" [diameter]="22"></mat-spinner> <ng-container i18n="Checking for updates text">Checking for updates...</ng-container></span>
|
<button style="margin-bottom: 5px;" mat-stroked-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
||||||
<mat-icon *ngIf="!checking_for_updates" class="version-checked-icon">done</mat-icon> <ng-container *ngIf="!checking_for_updates && latestGithubRelease['tag_name'] !== current_version_tag"><a [href]="latestUpdateLink" target="_blank"><ng-container i18n="View latest update">Update available</ng-container> - {{latestGithubRelease['tag_name']}}</a>. <ng-container i18n="Update through settings menu hint">You can update from the settings menu.</ng-container></ng-container>
|
</mat-dialog-actions>
|
||||||
<span *ngIf="!checking_for_updates && latestGithubRelease['tag_name'] === current_version_tag">You are up to date.</span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<ng-container i18n="Installation type">Installation type:</ng-container> {{postsService.version_info.type}}
|
|
||||||
<br>
|
|
||||||
<ng-container *ngIf="postsService.version_info.type === 'docker'">
|
|
||||||
<ng-container i18n="Docker tag">Docker tag:</ng-container> {{postsService.version_info.tag}}
|
|
||||||
<br>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container i18n="Commit hash">Commit hash:</ng-container> {{postsService.version_info.commit}}
|
|
||||||
<br>
|
|
||||||
<ng-container i18n="Build date">Build date:</ng-container> {{postsService.version_info.date}}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<ng-container i18n="About bug prefix">Found a bug or have a suggestion?</ng-container> <a [href]="issuesLink" target="_blank"><ng-container i18n="About bug click here">Click here</ng-container></a> <ng-container i18n="About bug suffix">to create an issue!</ng-container>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</mat-dialog-content>
|
|
||||||
|
|
||||||
<mat-dialog-actions>
|
|
||||||
<button style="margin-bottom: 5px;" mat-stroked-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
|
||||||
</mat-dialog-actions>
|
|
||||||
@@ -1,92 +1,94 @@
|
|||||||
<h4 i18n="Modify args title" mat-dialog-title>Modify youtube-dl args</h4>
|
<h4 i18n="Modify args title" mat-dialog-title>Modify youtube-dl args</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<mat-card class="mat-elevation-z6">
|
<mat-card class="mat-elevation-z6">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<h6 i18n="Simulated args title">Simulated new args</h6>
|
<h6 i18n="Simulated args title">Simulated new args</h6>
|
||||||
<mat-chip-grid class="example-chip" #chipList aria-label="Args array" cdkDropList cdkDropListDisabled
|
<mat-chip-grid class="example-chip" #chipList aria-label="Args array" cdkDropList cdkDropListDisabled
|
||||||
cdkDropListOrientation="horizontal"
|
cdkDropListOrientation="horizontal"
|
||||||
(cdkDropListDropped)="drop($event)">
|
(cdkDropListDropped)="drop($event)">
|
||||||
<mat-chip-row [matTooltip]="argsByKey[arg] ? argsByKey[arg]['description'] : null" *ngFor="let arg of args_array; let i = index;" [removable]="removable" (removed)="remove(i)" cdkDrag>
|
@for (arg of args_array; track arg; let i = $index) {
|
||||||
{{arg}}
|
<mat-chip-row [matTooltip]="argsByKey[arg] ? argsByKey[arg]['description'] : null" [removable]="removable" (removed)="remove(i)" cdkDrag>
|
||||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
{{arg}}
|
||||||
</mat-chip-row>
|
@if (removable) {
|
||||||
</mat-chip-grid>
|
<mat-icon matChipRemove>cancel</mat-icon>
|
||||||
<mat-form-field style="width: 100%" color="accent">
|
}
|
||||||
|
</mat-chip-row>
|
||||||
<input #chipper style="width: 100%;" [formControl]="chipCtrl" matInput [matAutocomplete]="autochip" [matChipInputFor]="chipList"
|
}
|
||||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
</mat-chip-grid>
|
||||||
[matChipInputAddOnBlur]="addOnBlur"
|
<mat-form-field style="width: 100%" color="accent">
|
||||||
(matChipInputTokenEnd)="add($event)">
|
<input #chipper style="width: 100%;" [formControl]="chipCtrl" matInput [matAutocomplete]="autochip" [matChipInputFor]="chipList"
|
||||||
</mat-form-field>
|
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||||
<mat-autocomplete #autochip="matAutocomplete">
|
[matChipInputAddOnBlur]="addOnBlur"
|
||||||
<mat-option *ngFor="let arg of filteredChipOptions | async" [value]="arg.key">
|
(matChipInputTokenEnd)="add($event)">
|
||||||
<span [innerHTML]="arg.key | highlight : chipCtrl.value"></span>
|
</mat-form-field>
|
||||||
<button class="info-autocomplete-icon" [matTooltip]="arg.description" mat-icon-button><mat-icon>info</mat-icon></button>
|
<mat-autocomplete #autochip="matAutocomplete">
|
||||||
</mat-option>
|
@for (arg of filteredChipOptions | async; track arg) {
|
||||||
</mat-autocomplete>
|
<mat-option [value]="arg.key">
|
||||||
</mat-card-content>
|
<span [innerHTML]="arg.key | highlight : chipCtrl.value"></span>
|
||||||
</mat-card>
|
<button class="info-autocomplete-icon" [matTooltip]="arg.description" mat-icon-button><mat-icon>info</mat-icon></button>
|
||||||
</div>
|
</mat-option>
|
||||||
<div class="col-12">
|
}
|
||||||
<mat-card class="mat-elevation-z6 my-2">
|
</mat-autocomplete>
|
||||||
<mat-card-content>
|
</mat-card-content>
|
||||||
<h6 i18n="Add arg card title">Add an arg</h6>
|
</mat-card>
|
||||||
<form >
|
|
||||||
<div>
|
|
||||||
<mat-form-field style="width: 75%" color="accent">
|
|
||||||
<mat-label i18n="Arg">Arg</mat-label>
|
|
||||||
<input matInput [matAutocomplete]="auto" [formControl]="stateCtrl">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-autocomplete #auto="matAutocomplete">
|
|
||||||
<mat-option *ngFor="let arg of filteredOptions | async" [value]="arg.key">
|
|
||||||
<span [innerHTML]="arg.key | highlight : stateCtrl.value"></span>
|
|
||||||
<button class="info-autocomplete-icon" [matTooltip]="arg.description" mat-icon-button><mat-icon>info</mat-icon></button>
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<mat-menu #argsByCategoryMenu="matMenu">
|
|
||||||
<ng-container *ngFor="let argsInCategory of argsByCategory | keyvalue">
|
|
||||||
<button mat-menu-item [matMenuTriggerFor]="subMenu">{{argsInfo[argsInCategory.key].label}}</button>
|
|
||||||
<mat-menu #subMenu="matMenu">
|
|
||||||
<button mat-menu-item *ngFor="let arg of argsInCategory.value" (click)="setFirstArg(arg.key)"><div style="display: inline-block;">{{arg.key}}</div> <div class="info-menu-icon"><mat-icon [matTooltip]="arg.description">info</mat-icon></div></button>
|
|
||||||
</mat-menu>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
</mat-menu>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<button style="margin-bottom: 15px" mat-stroked-button [matMenuTriggerFor]="argsByCategoryMenu"><ng-container i18n="Search args by category button">Search by category</ng-container></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox color="accent" [ngModelOptions]="{standalone: true}" [(ngModel)]="secondArgEnabled"><ng-container i18n="Use arg value checkbox">Use arg value</ng-container></mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="secondArgEnabled">
|
|
||||||
<mat-form-field style="width: 75%" color="accent">
|
|
||||||
<mat-label i18n="Arg value">Arg value</mat-label>
|
|
||||||
<input [ngModelOptions]="{standalone: true}" matInput [disabled]="!secondArgEnabled" [(ngModel)]="secondArg">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div>
|
|
||||||
<button (click)="addArg()" [disabled]="!canAddArg()" mat-stroked-button color="accent"><ng-container i18n="Search args by category button">Add arg</ng-container></button>
|
|
||||||
</div>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<mat-card class="mat-elevation-z6 my-2">
|
||||||
|
<mat-card-content>
|
||||||
|
<h6 i18n="Add arg card title">Add an arg</h6>
|
||||||
|
<form >
|
||||||
|
<div>
|
||||||
|
<mat-form-field style="width: 75%" color="accent">
|
||||||
|
<mat-label i18n="Arg">Arg</mat-label>
|
||||||
|
<input matInput [matAutocomplete]="auto" [formControl]="stateCtrl">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-autocomplete #auto="matAutocomplete">
|
||||||
|
@for (arg of filteredOptions | async; track arg) {
|
||||||
|
<mat-option [value]="arg.key">
|
||||||
|
<span [innerHTML]="arg.key | highlight : stateCtrl.value"></span>
|
||||||
|
<button class="info-autocomplete-icon" [matTooltip]="arg.description" mat-icon-button><mat-icon>info</mat-icon></button>
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-autocomplete>
|
||||||
|
<div>
|
||||||
|
<mat-menu #argsByCategoryMenu="matMenu">
|
||||||
|
@for (argsInCategory of argsByCategory | keyvalue; track argsInCategory) {
|
||||||
|
<button mat-menu-item [matMenuTriggerFor]="subMenu">{{argsInfo[argsInCategory.key].label}}</button>
|
||||||
|
<mat-menu #subMenu="matMenu">
|
||||||
|
@for (arg of argsInCategory.value; track arg) {
|
||||||
|
<button mat-menu-item (click)="setFirstArg(arg.key)"><div style="display: inline-block;">{{arg.key}}</div> <div class="info-menu-icon"><mat-icon [matTooltip]="arg.description">info</mat-icon></div></button>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
|
<button style="margin-bottom: 15px" mat-stroked-button [matMenuTriggerFor]="argsByCategoryMenu"><ng-container i18n="Search args by category button">Search by category</ng-container></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox color="accent" [ngModelOptions]="{standalone: true}" [(ngModel)]="secondArgEnabled"><ng-container i18n="Use arg value checkbox">Use arg value</ng-container></mat-checkbox>
|
||||||
|
</div>
|
||||||
|
@if (secondArgEnabled) {
|
||||||
|
<div>
|
||||||
|
<mat-form-field style="width: 75%" color="accent">
|
||||||
|
<mat-label i18n="Arg value">Arg value</mat-label>
|
||||||
|
<input [ngModelOptions]="{standalone: true}" matInput [disabled]="!secondArgEnabled" [(ngModel)]="secondArg">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
|
<button (click)="addArg()" [disabled]="!canAddArg()" mat-stroked-button color="accent"><ng-container i18n="Search args by category button">Add arg</ng-container></button>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
</mat-dialog-content>
|
|
||||||
|
|
||||||
<mat-dialog-actions>
|
|
||||||
<button mat-button [mat-dialog-close]="null"><ng-container i18n="Arg modifier cancel button">Cancel</ng-container></button>
|
<button mat-button [mat-dialog-close]="null"><ng-container i18n="Arg modifier cancel button">Cancel</ng-container></button>
|
||||||
<button mat-button color="accent" [mat-dialog-close]="modified_args"><ng-container i18n="Arg modifier modify button">Modify</ng-container></button>
|
<button mat-button color="accent" [mat-dialog-close]="modified_args"><ng-container i18n="Arg modifier modify button">Modify</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -2,24 +2,27 @@
|
|||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div style="margin-bottom: 10px;">
|
<div style="margin-bottom: 10px;">
|
||||||
<!-- We can support text dialogs or dialogs where users must select items from a list -->
|
<!-- We can support text dialogs or dialogs where users must select items from a list -->
|
||||||
<ng-container *ngIf="dialogType === 'text'">
|
@if (dialogType === 'text') {
|
||||||
{{dialogText}}
|
{{dialogText}}
|
||||||
</ng-container>
|
} @else if (dialogType === 'selection_list') {
|
||||||
<ng-container *ngIf="dialogType === 'selection_list'">
|
|
||||||
<mat-selection-list [(ngModel)]="selected_items">
|
<mat-selection-list [(ngModel)]="selected_items">
|
||||||
<mat-list-option *ngFor="let item of list" [value]="item.key">
|
@for (item of list; track item) {
|
||||||
{{item.title}}
|
<mat-list-option [value]="item.key">
|
||||||
</mat-list-option>
|
{{item.title}}
|
||||||
|
</mat-list-option>
|
||||||
|
}
|
||||||
</mat-selection-list>
|
</mat-selection-list>
|
||||||
</ng-container>
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
||||||
<button [disabled]="dialogType === 'selection_list' && selected_items.length === 0" [color]="warnSubmitColor ? 'warn' : 'primary'" mat-flat-button type="submit" (click)="confirmClicked()">{{submitText}}</button>
|
<button [disabled]="dialogType === 'selection_list' && selected_items.length === 0" [color]="warnSubmitColor ? 'warn' : 'primary'" mat-flat-button type="submit" (click)="confirmClicked()">{{submitText}}</button>
|
||||||
<div class="mat-spinner" *ngIf="submitClicked">
|
@if (submitClicked) {
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<div class="mat-spinner">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<button style="float: right;" mat-stroked-button mat-dialog-close>
|
<button style="float: right;" mat-stroked-button mat-dialog-close>
|
||||||
{{cancelText}}
|
{{cancelText}}
|
||||||
|
|||||||
@@ -1,40 +1,44 @@
|
|||||||
<h4 mat-dialog-title i18n="Cookies uploader dialog title">Upload new cookies</h4>
|
<h4 mat-dialog-title i18n="Cookies uploader dialog title">Upload new cookies</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div>
|
<div>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<ngx-file-drop [multiple]="false" accept=".txt" dropZoneLabel="Drop files here" (onFileDrop)="dropped($event)"
|
<ngx-file-drop [multiple]="false" accept=".txt" dropZoneLabel="Drop files here" (onFileDrop)="dropped($event)"
|
||||||
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)">
|
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)">
|
||||||
<ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
|
<ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<ng-container i18n="Drag and Drop">Drag and Drop</ng-container>
|
<ng-container i18n="Drag and Drop">Drag and Drop</ng-container>
|
||||||
</div>
|
|
||||||
<div style="margin-top: 6px;">
|
|
||||||
<button mat-stroked-button (click)="openFileSelector()">Browse Files</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</ngx-file-drop>
|
|
||||||
<div style="margin-top: 15px;">
|
|
||||||
<p style="font-size: 14px;" i18n="Cookies upload warning">NOTE: Uploading new cookies will override your previous cookies. Also note that cookies are instance-wide, not per-user.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 6px;">
|
||||||
<table class="table">
|
<button mat-stroked-button (click)="openFileSelector()">Browse Files</button>
|
||||||
<tbody class="upload-name-style">
|
|
||||||
<tr *ngFor="let item of files; let i=index">
|
|
||||||
<td style="vertical-align: middle;">
|
|
||||||
<strong>{{ item.relativePath }}</strong>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button [disabled]="uploading || uploaded" (click)="uploadFile()" style="float: right" matTooltip="Upload" i18n-matTooltip="Upload" mat-mini-fab><mat-icon>publish</mat-icon><mat-spinner *ngIf="uploading" class="spinner" [diameter]="38"></mat-spinner></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngx-file-drop>
|
||||||
|
<div style="margin-top: 15px;">
|
||||||
|
<p style="font-size: 14px;" i18n="Cookies upload warning">NOTE: Uploading new cookies will override your previous cookies. Also note that cookies are instance-wide, not per-user.</p>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<table class="table">
|
||||||
|
<tbody class="upload-name-style">
|
||||||
|
@for (item of files; track item; let i = $index) {
|
||||||
|
<tr>
|
||||||
|
<td style="vertical-align: middle;">
|
||||||
|
<strong>{{ item.relativePath }}</strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button [disabled]="uploading || uploaded" (click)="uploadFile()" style="float: right" matTooltip="Upload" i18n-matTooltip="Upload" mat-mini-fab><mat-icon>publish</mat-icon>
|
||||||
|
@if (uploading) {
|
||||||
|
<mat-spinner class="spinner" [diameter]="38"></mat-spinner>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions><button style="margin-bottom: 5px;" mat-dialog-close mat-stroked-button><ng-container i18n="Close">Close</ng-container></button></mat-dialog-actions>
|
<mat-dialog-actions><button style="margin-bottom: 5px;" mat-dialog-close mat-stroked-button><ng-container i18n="Close">Close</ng-container></button></mat-dialog-actions>
|
||||||
@@ -1,64 +1,63 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Editing category dialog title">Editing category</ng-container> {{category['name']}}</h4>
|
<h4 mat-dialog-title><ng-container i18n="Editing category dialog title">Editing category</ng-container> {{category['name']}}</h4>
|
||||||
|
|
||||||
<mat-dialog-content style="max-height: 50vh">
|
<mat-dialog-content style="max-height: 50vh">
|
||||||
<mat-form-field style="width: 250px; margin-bottom: 5px;">
|
<mat-form-field style="width: 250px; margin-bottom: 5px;">
|
||||||
<mat-label i18n="Category name">Name</mat-label>
|
<mat-label i18n="Category name">Name</mat-label>
|
||||||
<input matInput [(ngModel)]="category['name']" required>
|
<input matInput [(ngModel)]="category['name']" required>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<h6 style="margin-top: 20px;" i18n="Rules">Rules</h6>
|
||||||
|
<mat-list>
|
||||||
|
@for (rule of category['rules']; track rule) {
|
||||||
|
<mat-list-item>
|
||||||
|
<mat-form-field [style.visibility]="$index === 0 ? 'hidden' : null" class="operator-select">
|
||||||
|
<mat-select [disabled]="$index === 0" [(ngModel)]="rule['preceding_operator']">
|
||||||
|
<mat-option value="or">OR</mat-option>
|
||||||
|
<mat-option value="and">AND</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="property-select">
|
||||||
|
<mat-select [(ngModel)]="rule['property']">
|
||||||
|
@for (propertyOption of propertyOptions; track propertyOption) {
|
||||||
|
<mat-option [value]="propertyOption.value">{{propertyOption.label}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="comparator-select">
|
||||||
|
<mat-select [(ngModel)]="rule['comparator']">
|
||||||
|
@for (comparatorOption of comparatorOptions; track comparatorOption) {
|
||||||
|
<mat-option [value]="comparatorOption.value">{{comparatorOption.label}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="value-input">
|
||||||
|
<input matInput [(ngModel)]="rule['value']">
|
||||||
|
</mat-form-field>
|
||||||
|
<span class="rule-buttons">
|
||||||
|
<button [disabled]="$index === category['rules'].length-1" (click)="swapRules($index, $index+1)" mat-icon-button><mat-icon>arrow_downward</mat-icon></button>
|
||||||
|
<button [disabled]="$index === 0" (click)="swapRules($index, $index-1)" mat-icon-button><mat-icon>arrow_upward</mat-icon></button>
|
||||||
|
<button (click)="removeRule($index)" mat-icon-button><mat-icon>cancel</mat-icon></button>
|
||||||
|
</span>
|
||||||
|
</mat-list-item>
|
||||||
|
}
|
||||||
|
</mat-list>
|
||||||
|
<button style="margin-bottom: 8px;" mat-icon-button (click)="addNewRule()" matTooltip="Add new rule" i18n-matTooltip="Add new rule tooltip"><mat-icon>add</mat-icon></button>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<mat-form-field style="width: 250px; margin-top: 10px;">
|
||||||
|
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
||||||
|
<input matInput [(ngModel)]="category['custom_output']">
|
||||||
|
<mat-hint>
|
||||||
|
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
||||||
|
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
||||||
|
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
<mat-divider></mat-divider>
|
<mat-dialog-actions>
|
||||||
|
|
||||||
<h6 style="margin-top: 20px;" i18n="Rules">Rules</h6>
|
|
||||||
|
|
||||||
<mat-list>
|
|
||||||
<mat-list-item *ngFor="let rule of category['rules']; let i = index">
|
|
||||||
<mat-form-field [style.visibility]="i === 0 ? 'hidden' : null" class="operator-select">
|
|
||||||
<mat-select [disabled]="i === 0" [(ngModel)]="rule['preceding_operator']">
|
|
||||||
<mat-option value="or">OR</mat-option>
|
|
||||||
<mat-option value="and">AND</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="property-select">
|
|
||||||
<mat-select [(ngModel)]="rule['property']">
|
|
||||||
<mat-option *ngFor="let propertyOption of propertyOptions" [value]="propertyOption.value">{{propertyOption.label}}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="comparator-select">
|
|
||||||
<mat-select [(ngModel)]="rule['comparator']">
|
|
||||||
<mat-option *ngFor="let comparatorOption of comparatorOptions" [value]="comparatorOption.value">{{comparatorOption.label}}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="value-input">
|
|
||||||
<input matInput [(ngModel)]="rule['value']">
|
|
||||||
</mat-form-field>
|
|
||||||
<span class="rule-buttons">
|
|
||||||
<button [disabled]="i === category['rules'].length-1" (click)="swapRules(i, i+1)" mat-icon-button><mat-icon>arrow_downward</mat-icon></button>
|
|
||||||
<button [disabled]="i === 0" (click)="swapRules(i, i-1)" mat-icon-button><mat-icon>arrow_upward</mat-icon></button>
|
|
||||||
<button (click)="removeRule(i)" mat-icon-button><mat-icon>cancel</mat-icon></button>
|
|
||||||
</span>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
|
|
||||||
<button style="margin-bottom: 8px;" mat-icon-button (click)="addNewRule()" matTooltip="Add new rule" i18n-matTooltip="Add new rule tooltip"><mat-icon>add</mat-icon></button>
|
|
||||||
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
|
|
||||||
<mat-form-field style="width: 250px; margin-top: 10px;">
|
|
||||||
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
|
||||||
<input matInput [(ngModel)]="category['custom_output']">
|
|
||||||
<mat-hint>
|
|
||||||
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
|
||||||
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
|
||||||
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-dialog-content>
|
|
||||||
|
|
||||||
<mat-dialog-actions>
|
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Cancel">Cancel</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Cancel">Cancel</ng-container></button>
|
||||||
|
|
||||||
<button mat-button [disabled]="categoryChanged()" type="submit" (click)="saveClicked()"><ng-container i18n="Save button">Save</ng-container></button>
|
<button mat-button [disabled]="categoryChanged()" type="submit" (click)="saveClicked()"><ng-container i18n="Save button">Save</ng-container></button>
|
||||||
<div class="mat-spinner" *ngIf="updating">
|
@if (updating) {
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<div class="mat-spinner">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
</mat-dialog-actions>
|
</div>
|
||||||
|
}
|
||||||
|
</mat-dialog-actions>
|
||||||
@@ -1,70 +1,80 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Edit subscription dialog title prefix">Editing</ng-container> {{sub.name}} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Edit subscription dialog title prefix">Editing</ng-container> {{sub.name}}
|
||||||
|
@if (sub.paused) {
|
||||||
|
<ng-container i18n="Paused suffix">(Paused)</ng-container>
|
||||||
|
}
|
||||||
|
</h4>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mt-3">
|
<div class="col-12 mt-3">
|
||||||
<mat-checkbox [(ngModel)]="new_sub.paused"><ng-container i18n="Paused subscription setting">Paused</ng-container></mat-checkbox>
|
<mat-checkbox [(ngModel)]="new_sub.paused"><ng-container i18n="Paused subscription setting">Paused</ng-container></mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 mt-3">
|
<div class="col-12 mt-3">
|
||||||
<mat-checkbox (change)="downloadAllToggled()" [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
|
<mat-checkbox (change)="downloadAllToggled()" [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12" *ngIf="editor_initialized">
|
@if (editor_initialized) {
|
||||||
<ng-container i18n="Download time range prefix">Download videos uploaded in the last</ng-container>
|
<div class="col-12">
|
||||||
<mat-form-field color="accent" class="amount-select">
|
<ng-container i18n="Download time range prefix">Download videos uploaded in the last</ng-container>
|
||||||
<input type="number" matInput [(ngModel)]="timerange_amount" (ngModelChange)="timerangeChanged($event, false)" [disabled]="download_all">
|
<mat-form-field color="accent" class="amount-select">
|
||||||
</mat-form-field>
|
<input type="number" matInput [(ngModel)]="timerange_amount" (ngModelChange)="timerangeChanged($event, false)" [disabled]="download_all">
|
||||||
<mat-form-field class="unit-select">
|
</mat-form-field>
|
||||||
<mat-select color="accent" [(ngModel)]="timerange_unit" (ngModelChange)="timerangeChanged($event, true)" [disabled]="download_all">
|
<mat-form-field class="unit-select">
|
||||||
<mat-option *ngFor="let time_unit of time_units" [value]="time_unit + (timerange_amount === 1 ? '' : 's')">
|
<mat-select color="accent" [(ngModel)]="timerange_unit" (ngModelChange)="timerangeChanged($event, true)" [disabled]="download_all">
|
||||||
{{time_unit + (timerange_amount === 1 ? '' : 's')}}
|
@for (time_unit of time_units; track time_unit) {
|
||||||
</mat-option>
|
<mat-option [value]="time_unit + (timerange_amount === 1 ? '' : 's')">
|
||||||
</mat-select>
|
{{time_unit + (timerange_amount === 1 ? '' : 's')}}
|
||||||
</mat-form-field>
|
</mat-option>
|
||||||
</div>
|
}
|
||||||
<div class="col-12">
|
</mat-select>
|
||||||
<div>
|
</mat-form-field>
|
||||||
<mat-checkbox [disabled]="true" [(ngModel)]="audioOnlyMode"><ng-container i18n="Streaming-only mode">Audio-only mode</ng-container></mat-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 mt-2">
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label i18n="Max quality">Max quality</mat-label>
|
|
||||||
<mat-select [disabled]="new_sub.type === 'audio'" [(ngModel)]="new_sub.maxQuality">
|
|
||||||
<mat-option *ngFor="let available_quality of available_qualities" [value]="available_quality['value']">{{available_quality['label']}}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 mb-3">
|
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Custom args">Custom args</mat-label>
|
|
||||||
<input [(ngModel)]="new_sub.custom_args" matInput>
|
|
||||||
<button class="args-edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
|
||||||
<mat-hint>
|
|
||||||
<ng-container i18n="Custom args hint">These are added after the standard args.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 mt-2">
|
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
|
||||||
<input [(ngModel)]="new_sub.custom_output" matInput>
|
|
||||||
<mat-hint>
|
|
||||||
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
|
||||||
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
|
||||||
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
<div class="col-12">
|
||||||
|
<div>
|
||||||
|
<mat-checkbox [disabled]="true" [(ngModel)]="audioOnlyMode"><ng-container i18n="Streaming-only mode">Audio-only mode</ng-container></mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label i18n="Max quality">Max quality</mat-label>
|
||||||
|
<mat-select [disabled]="new_sub.type === 'audio'" [(ngModel)]="new_sub.maxQuality">
|
||||||
|
@for (available_quality of available_qualities; track available_quality) {
|
||||||
|
<mat-option [value]="available_quality['value']">{{available_quality['label']}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mb-3">
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label i18n="Custom args">Custom args</mat-label>
|
||||||
|
<input [(ngModel)]="new_sub.custom_args" matInput>
|
||||||
|
<button class="args-edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
||||||
|
<mat-hint>
|
||||||
|
<ng-container i18n="Custom args hint">These are added after the standard args.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
||||||
|
<input [(ngModel)]="new_sub.custom_output" matInput>
|
||||||
|
<mat-hint>
|
||||||
|
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
||||||
|
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
||||||
|
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
<mat-dialog-actions>
|
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Subscribe cancel button">Cancel</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Subscribe cancel button">Cancel</ng-container></button>
|
||||||
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
||||||
<button mat-button [disabled]="updating || !subChanged()" type="submit" (click)="saveClicked()"><ng-container i18n="Save button">Save</ng-container></button>
|
<button mat-button [disabled]="updating || !subChanged()" type="submit" (click)="saveClicked()"><ng-container i18n="Save button">Save</ng-container></button>
|
||||||
<div class="mat-spinner" *ngIf="updating">
|
@if (updating) {
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<div class="mat-spinner">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
</mat-dialog-actions>
|
</div>
|
||||||
|
}
|
||||||
|
</mat-dialog-actions>
|
||||||
@@ -1,67 +1,68 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Generate RSS URL">Generate RSS URL</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Generate RSS URL">Generate RSS URL</ng-container></h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-md-6 mt-2">
|
<div class="col-12 col-md-6 mt-2">
|
||||||
<mat-form-field class="filter-field">
|
<mat-form-field class="filter-field">
|
||||||
<mat-label i18n="Title filter">Title filter</mat-label>
|
<mat-label i18n="Title filter">Title filter</mat-label>
|
||||||
<input [(ngModel)]="titleFilter" matInput (input)="rebuildURL()">
|
<input [(ngModel)]="titleFilter" matInput (input)="rebuildURL()">
|
||||||
<mat-hint i18n="Supports regex">Supports regex</mat-hint>
|
<mat-hint i18n="Supports regex">Supports regex</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-2">
|
<div class="col-12 col-md-6 mt-2">
|
||||||
<mat-form-field class="filter-field">
|
<mat-form-field class="filter-field">
|
||||||
<mat-label><ng-container i18n="File type">File type</ng-container></mat-label>
|
<mat-label><ng-container i18n="File type">File type</ng-container></mat-label>
|
||||||
<mat-select color="accent" [(ngModel)]="fileTypeFilter" (selectionChange)="rebuildURL()">
|
<mat-select color="accent" [(ngModel)]="fileTypeFilter" (selectionChange)="rebuildURL()">
|
||||||
<mat-option value="both"><ng-container i18n="Both">Both</ng-container></mat-option>
|
<mat-option value="both"><ng-container i18n="Both">Both</ng-container></mat-option>
|
||||||
<mat-option value="video_only"><ng-container i18n="Video only">Video only</ng-container></mat-option>
|
<mat-option value="video_only"><ng-container i18n="Video only">Video only</ng-container></mat-option>
|
||||||
<mat-option value="audio_only"><ng-container i18n="Audio only">Audio only</ng-container></mat-option>
|
<mat-option value="audio_only"><ng-container i18n="Audio only">Audio only</ng-container></mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-2">
|
<div class="col-12 col-md-6 mt-2">
|
||||||
<mat-form-field class="filter-field">
|
<mat-form-field class="filter-field">
|
||||||
<mat-label><ng-container i18n="User">User</ng-container></mat-label>
|
<mat-label><ng-container i18n="User">User</ng-container></mat-label>
|
||||||
<mat-select color="accent" [(ngModel)]="userFilter" (selectionChange)="rebuildURL()" [disabled]="!usersList">
|
<mat-select color="accent" [(ngModel)]="userFilter" (selectionChange)="rebuildURL()" [disabled]="!usersList">
|
||||||
<mat-option [value]="''"><ng-container i18n="None">None</ng-container></mat-option>
|
<mat-option [value]="''"><ng-container i18n="None">None</ng-container></mat-option>
|
||||||
<mat-option *ngFor="let user of usersList" [value]="user.uid"><ng-container>{{user.name}}</ng-container></mat-option>
|
@for (user of usersList; track user) {
|
||||||
</mat-select>
|
<mat-option [value]="user.uid"><ng-container>{{user.name}}</ng-container></mat-option>
|
||||||
</mat-form-field>
|
}
|
||||||
</div>
|
</mat-select>
|
||||||
<div class="col-12 col-md-6 mt-2">
|
</mat-form-field>
|
||||||
<mat-form-field class="filter-field">
|
</div>
|
||||||
<mat-label><ng-container i18n="Subscription">Subscription</ng-container></mat-label>
|
<div class="col-12 col-md-6 mt-2">
|
||||||
<mat-select color="accent" [(ngModel)]="subscriptionFilter" (selectionChange)="rebuildURL()">
|
<mat-form-field class="filter-field">
|
||||||
<mat-option [value]="''"><ng-container i18n="None">None</ng-container></mat-option>
|
<mat-label><ng-container i18n="Subscription">Subscription</ng-container></mat-label>
|
||||||
<mat-option *ngFor="let sub of postsService.subscriptions" [value]="sub.id"><ng-container>{{sub.name}}</ng-container></mat-option>
|
<mat-select color="accent" [(ngModel)]="subscriptionFilter" (selectionChange)="rebuildURL()">
|
||||||
</mat-select>
|
<mat-option [value]="''"><ng-container i18n="None">None</ng-container></mat-option>
|
||||||
</mat-form-field>
|
@for (sub of postsService.subscriptions; track sub) {
|
||||||
</div>
|
<mat-option [value]="sub.id"><ng-container>{{sub.name}}</ng-container></mat-option>
|
||||||
<div class="col-12 col-md-6 mt-2">
|
}
|
||||||
<app-sort-property (sortOptionChanged)="sortOptionChanged($event)"></app-sort-property>
|
</mat-select>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<div class="col-12 col-md-6 mt-2">
|
</div>
|
||||||
<mat-form-field class="filter-field">
|
<div class="col-12 col-md-6 mt-2">
|
||||||
<mat-label i18n="Item limit">Item limit</mat-label>
|
<app-sort-property (sortOptionChanged)="sortOptionChanged($event)"></app-sort-property>
|
||||||
<input type="number" [(ngModel)]="itemLimit" (input)="rebuildURL()" matInput>
|
</div>
|
||||||
</mat-form-field>
|
<div class="col-12 col-md-6 mt-2">
|
||||||
</div>
|
<mat-form-field class="filter-field">
|
||||||
<div class="col-12 mb-4">
|
<mat-label i18n="Item limit">Item limit</mat-label>
|
||||||
<mat-checkbox (change)="rebuildURL()" [(ngModel)]="favoriteFilter"><ng-container i18n="Favorited">Favorited</ng-container></mat-checkbox>
|
<input type="number" [(ngModel)]="itemLimit" (input)="rebuildURL()" matInput>
|
||||||
</div>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12 mb-4">
|
||||||
|
<mat-checkbox (change)="rebuildURL()" [(ngModel)]="favoriteFilter"><ng-container i18n="Favorited">Favorited</ng-container></mat-checkbox>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<mat-form-field style="width: 100%;">
|
<mat-form-field style="width: 100%;">
|
||||||
<mat-label i18n="URL">URL</mat-label>
|
<mat-label i18n="URL">URL</mat-label>
|
||||||
<input readonly [(ngModel)]="url" matInput>
|
<input readonly [(ngModel)]="url" matInput>
|
||||||
<button mat-icon-button matSuffix (click)="copyURL()">
|
<button mat-icon-button matSuffix (click)="copyURL()">
|
||||||
<mat-icon>content_copy</mat-icon>
|
<mat-icon>content_copy</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close">Close</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -1,29 +1,31 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Restore DB from backup">Restore DB from backup</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Restore DB from backup">Restore DB from backup</ng-container></h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<mat-selection-list [multiple]="false" [(ngModel)]="selected_backup">
|
<mat-selection-list [multiple]="false" [(ngModel)]="selected_backup">
|
||||||
<mat-list-option *ngFor="let db_backup of db_backups" [value]="db_backup.name" [matTooltip]="db_backup.name">
|
@for (db_backup of db_backups; track db_backup) {
|
||||||
<div class="container-fluid">
|
<mat-list-option [value]="db_backup.name" [matTooltip]="db_backup.name">
|
||||||
<div class="row">
|
<div class="container-fluid">
|
||||||
<div class="col-4">
|
<div class="row">
|
||||||
{{db_backup.timestamp*1000 | date: 'short'}}
|
<div class="col-4">
|
||||||
</div>
|
{{db_backup.timestamp*1000 | date: 'short'}}
|
||||||
<div class="col-4">
|
|
||||||
{{(db_backup.size/1000).toFixed(2)}} kB
|
|
||||||
</div>
|
|
||||||
<div class="col-4" style="text-transform: capitalize;">
|
|
||||||
{{db_backup.source}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-list-option>
|
<div class="col-4">
|
||||||
</mat-selection-list>
|
{{(db_backup.size/1000).toFixed(2)}} kB
|
||||||
|
</div>
|
||||||
|
<div class="col-4" style="text-transform: capitalize;">
|
||||||
|
{{db_backup.source}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-list-option>
|
||||||
|
}
|
||||||
|
</mat-selection-list>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Restore DB cancel button">Cancel</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Restore DB cancel button">Cancel</ng-container></button>
|
||||||
<button mat-button [disabled]="restoring" (click)="restoreClicked()" [disabled]="!selected_backup || selected_backup.length !== 1"><ng-container i18n="Restore button">Restore</ng-container></button>
|
<button mat-button [disabled]="restoring" (click)="restoreClicked()" [disabled]="!selected_backup || selected_backup.length !== 1"><ng-container i18n="Restore button">Restore</ng-container></button>
|
||||||
<div class="mat-spinner" *ngIf="restoring">
|
@if (restoring) {
|
||||||
|
<div class="mat-spinner">
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Create admin account dialog title">Create admin account</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Create admin account dialog title">Create admin account</ng-container></h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
<div>
|
||||||
|
<p i18n="No default admin detected explanation">No default admin account detected. This will create and set the password for an admin account with the user name as 'admin'.</p>
|
||||||
|
</div>
|
||||||
|
<div style="position: relative">
|
||||||
<div>
|
<div>
|
||||||
<p i18n="No default admin detected explanation">No default admin account detected. This will create and set the password for an admin account with the user name as 'admin'.</p>
|
<mat-form-field color="accent">
|
||||||
</div>
|
<mat-label i18n="Password">Password</mat-label>
|
||||||
<div style="position: relative">
|
<input type="password" (keyup.enter)="create()" matInput [(ngModel)]="input">
|
||||||
<div>
|
</mat-form-field>
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Password">Password</mat-label>
|
|
||||||
<input type="password" (keyup.enter)="create()" matInput [(ngModel)]="input">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button [disabled]="input.length === 0" color="accent" style="margin-bottom: 12px;" (click)="create()" mat-raised-button><ng-container i18n="Create">Create</ng-container></button>
|
<button [disabled]="input.length === 0" color="accent" style="margin-bottom: 12px;" (click)="create()" mat-raised-button><ng-container i18n="Create">Create</ng-container></button>
|
||||||
<div class="spinner-div"><mat-spinner [diameter]="25" *ngIf="creating"></mat-spinner></div>
|
<div class="spinner-div">
|
||||||
|
@if (creating) {
|
||||||
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,31 +1,32 @@
|
|||||||
<h4 mat-dialog-title>
|
<h4 mat-dialog-title>
|
||||||
<ng-container *ngIf="is_playlist" i18n="Share playlist dialog title">Share playlist</ng-container>
|
@if (is_playlist) {
|
||||||
<ng-container *ngIf="!is_playlist" i18n="Share video dialog title">Share file</ng-container>
|
<ng-container i18n="Share playlist dialog title">Share playlist</ng-container>
|
||||||
|
} @else {
|
||||||
|
<ng-container i18n="Share video dialog title">Share file</ng-container>
|
||||||
|
}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<mat-checkbox [checked]="sharing_enabled" (change)="sharingChanged($event)" [disabled]="uuid && (!postsService.isLoggedIn || postsService.user?.uid !== uuid)"><ng-container i18n="Enable sharing checkbox">Enable sharing</ng-container></mat-checkbox>
|
||||||
<mat-checkbox [checked]="sharing_enabled" (change)="sharingChanged($event)" [disabled]="uuid && (!postsService.isLoggedIn || postsService.user?.uid !== uuid)"><ng-container i18n="Enable sharing checkbox">Enable sharing</ng-container></mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox style="margin-right: 15px;" (change)="useTimestampChanged()" [(ngModel)]="timestamp_enabled"><ng-container i18n="Use timestamp">Use timestamp</ng-container></mat-checkbox>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label i18n="Seconds">Seconds</mat-label>
|
|
||||||
<input matInput type="number" [(ngModel)]="current_timestamp" [disabled]="!timestamp_enabled" (change)="timestampInputChanged($event)">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-form-field style="width: 100%">
|
|
||||||
<input matInput [disabled]="!sharing_enabled" [readonly]="true" [value]="share_url">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div style="margin-bottom: 10px;">
|
|
||||||
<button color="accent" (click)="copiedToClipboard()" [disabled]="!sharing_enabled" [cdkCopyToClipboard]="share_url" mat-raised-button><ng-container i18n="Copy to clipboard button">Copy to clipboard</ng-container></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox style="margin-right: 15px;" (change)="useTimestampChanged()" [(ngModel)]="timestamp_enabled"><ng-container i18n="Use timestamp">Use timestamp</ng-container></mat-checkbox>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label i18n="Seconds">Seconds</mat-label>
|
||||||
|
<input matInput type="number" [(ngModel)]="current_timestamp" [disabled]="!timestamp_enabled" (change)="timestampInputChanged($event)">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-form-field style="width: 100%">
|
||||||
|
<input matInput [disabled]="!sharing_enabled" [readonly]="true" [value]="share_url">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 10px;">
|
||||||
|
<button color="accent" (click)="copiedToClipboard()" [disabled]="!sharing_enabled" [cdkCopyToClipboard]="share_url" mat-raised-button><ng-container i18n="Copy to clipboard button">Copy to clipboard</ng-container></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close button">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close button">Close</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -1,87 +1,91 @@
|
|||||||
<h4 mat-dialog-title i18n="Subscribe dialog title">Subscribe to playlist or channel</h4>
|
<h4 mat-dialog-title i18n="Subscribe dialog title">Subscribe to playlist or channel</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<mat-form-field color="accent">
|
<mat-form-field color="accent">
|
||||||
<mat-label i18n="URL">URL</mat-label>
|
<mat-label i18n="URL">URL</mat-label>
|
||||||
<input [(ngModel)]="url" matInput required aria-required="true">
|
<input [(ngModel)]="url" matInput required aria-required="true">
|
||||||
<mat-hint><ng-container i18n="Subscription URL input hint">The playlist or channel URL</ng-container></mat-hint>
|
<mat-hint><ng-container i18n="Subscription URL input hint">The playlist or channel URL</ng-container></mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<mat-divider></mat-divider>
|
</div>
|
||||||
<div class="container-fluid">
|
<mat-divider></mat-divider>
|
||||||
<div class="row">
|
<div class="container-fluid">
|
||||||
<div class="col-12 mt-2">
|
<div class="row">
|
||||||
<mat-form-field color="accent">
|
<div class="col-12 mt-2">
|
||||||
<mat-label i18n="Custom name">Custom name</mat-label>
|
<mat-form-field color="accent">
|
||||||
<input [(ngModel)]="name" matInput>
|
<mat-label i18n="Custom name">Custom name</mat-label>
|
||||||
</mat-form-field>
|
<input [(ngModel)]="name" matInput>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<div class="col-12">
|
</div>
|
||||||
<mat-checkbox [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
|
<div class="col-12">
|
||||||
</div>
|
<mat-checkbox [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
|
||||||
<div class="col-12">
|
</div>
|
||||||
<span i18n="Download time range prefix">Download videos uploaded in the last</span>
|
<div class="col-12">
|
||||||
<div>
|
<span i18n="Download time range prefix">Download videos uploaded in the last</span>
|
||||||
<mat-form-field color="accent" style="width: 100px; text-align: center;">
|
<div>
|
||||||
<input type="number" matInput [(ngModel)]="timerange_amount" [disabled]="download_all">
|
<mat-form-field color="accent" style="width: 100px; text-align: center;">
|
||||||
</mat-form-field>
|
<input type="number" matInput [(ngModel)]="timerange_amount" [disabled]="download_all">
|
||||||
<mat-form-field class="unit-select">
|
</mat-form-field>
|
||||||
<mat-select color="accent" [(ngModel)]="timerange_unit" [disabled]="download_all">
|
<mat-form-field class="unit-select">
|
||||||
<mat-option *ngFor="let time_unit of time_units" [value]="time_unit + (timerange_amount === 1 ? '' : 's')">
|
<mat-select color="accent" [(ngModel)]="timerange_unit" [disabled]="download_all">
|
||||||
{{time_unit + (timerange_amount === 1 ? '' : 's')}}
|
@for (time_unit of time_units; track time_unit) {
|
||||||
</mat-option>
|
<mat-option [value]="time_unit + (timerange_amount === 1 ? '' : 's')">
|
||||||
</mat-select>
|
{{time_unit + (timerange_amount === 1 ? '' : 's')}}
|
||||||
</mat-form-field>
|
</mat-option>
|
||||||
</div>
|
}
|
||||||
</div>
|
</mat-select>
|
||||||
<div class="col-12 mt-2">
|
</mat-form-field>
|
||||||
<mat-form-field>
|
|
||||||
<mat-label i18n="Max quality">Max quality</mat-label>
|
|
||||||
<mat-select [disabled]="audioOnlyMode" [(ngModel)]="maxQuality">
|
|
||||||
<mat-option *ngFor="let available_quality of available_qualities" [value]="available_quality['value']">{{available_quality['label']}}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12">
|
|
||||||
<div>
|
|
||||||
<mat-checkbox [(ngModel)]="audioOnlyMode"><ng-container i18n="Streaming-only mode">Audio-only mode</ng-container></mat-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 mb-4">
|
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Custom args">Custom args</mat-label>
|
|
||||||
<input [(ngModel)]="customArgs" matInput>
|
|
||||||
<button class="args-edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
|
||||||
<mat-hint>
|
|
||||||
<ng-container i18n="Custom args hint">These are added after the standard args.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12">
|
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
|
||||||
<input [(ngModel)]="customFileOutput" matInput>
|
|
||||||
<mat-hint>
|
|
||||||
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
|
||||||
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
|
||||||
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label i18n="Max quality">Max quality</mat-label>
|
||||||
|
<mat-select [disabled]="audioOnlyMode" [(ngModel)]="maxQuality">
|
||||||
|
@for (available_quality of available_qualities; track available_quality) {
|
||||||
|
<mat-option [value]="available_quality['value']">{{available_quality['label']}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div>
|
||||||
|
<mat-checkbox [(ngModel)]="audioOnlyMode"><ng-container i18n="Streaming-only mode">Audio-only mode</ng-container></mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mb-4">
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label i18n="Custom args">Custom args</mat-label>
|
||||||
|
<input [(ngModel)]="customArgs" matInput>
|
||||||
|
<button class="args-edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
||||||
|
<mat-hint>
|
||||||
|
<ng-container i18n="Custom args hint">These are added after the standard args.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label i18n="Custom file output">Custom file output</mat-label>
|
||||||
|
<input [(ngModel)]="customFileOutput" matInput>
|
||||||
|
<mat-hint>
|
||||||
|
<a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
||||||
|
<ng-container i18n="Custom output template documentation link">Documentation</ng-container></a>.
|
||||||
|
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
<mat-dialog-actions>
|
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Subscribe cancel button">Cancel</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Subscribe cancel button">Cancel</ng-container></button>
|
||||||
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
||||||
<button mat-button [disabled]="!url" type="submit" (click)="subscribeClicked()"><ng-container i18n="Subscribe button">Subscribe</ng-container></button>
|
<button mat-button [disabled]="!url" type="submit" (click)="subscribeClicked()"><ng-container i18n="Subscribe button">Subscribe</ng-container></button>
|
||||||
<div class="mat-spinner" *ngIf="subscribing">
|
@if (subscribing) {
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<div class="mat-spinner">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
</mat-dialog-actions>
|
</div>
|
||||||
|
}
|
||||||
|
</mat-dialog-actions>
|
||||||
@@ -1,27 +1,31 @@
|
|||||||
<h4 mat-dialog-title>{{sub.name}} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></h4>
|
<h4 mat-dialog-title>{{sub.name}}
|
||||||
|
@if (sub.paused) {
|
||||||
|
<ng-container i18n="Paused suffix">(Paused)</ng-container>
|
||||||
|
}
|
||||||
|
</h4>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
<div class="info-item">
|
||||||
|
<strong><ng-container i18n="Subscription type property">Type:</ng-container> </strong>
|
||||||
|
<span class="info-item-value">{{(sub.isPlaylist ? 'Playlist' : 'Channel')}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<strong><ng-container i18n="Subscription URL property">URL:</ng-container> </strong>
|
||||||
|
<span class="info-item-value">{{sub.url}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<strong><ng-container i18n="Subscription ID property">ID:</ng-container> </strong>
|
||||||
|
<span class="info-item-value">{{sub.id}}</span>
|
||||||
|
</div>
|
||||||
|
@if (sub.archive) {
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<strong><ng-container i18n="Subscription type property">Type:</ng-container> </strong>
|
<strong><ng-container i18n="Subscription ID property">Archive:</ng-container> </strong>
|
||||||
<span class="info-item-value">{{(sub.isPlaylist ? 'Playlist' : 'Channel')}}</span>
|
<span class="info-item-value">{{sub.archive}}</span>
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<strong><ng-container i18n="Subscription URL property">URL:</ng-container> </strong>
|
|
||||||
<span class="info-item-value">{{sub.url}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<strong><ng-container i18n="Subscription ID property">ID:</ng-container> </strong>
|
|
||||||
<span class="info-item-value">{{sub.id}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item" *ngIf="sub.archive">
|
|
||||||
<strong><ng-container i18n="Subscription ID property">Archive:</ng-container> </strong>
|
|
||||||
<span class="info-item-value">{{sub.archive}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close subscription info button">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close subscription info button">Close</ng-container></button>
|
||||||
<button mat-stroked-button (click)="downloadArchive()" color="accent"><ng-container i18n="Export Archive button">Export Archive</ng-container></button>
|
<button mat-stroked-button (click)="downloadArchive()" color="accent"><ng-container i18n="Export Archive button">Export Archive</ng-container></button>
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<button mat-button (click)="confirmUnsubscribe()" color="warn"><ng-container i18n="Unsubscribe button">Unsubscribe</ng-container></button>
|
<button mat-button (click)="confirmUnsubscribe()" color="warn"><ng-container i18n="Unsubscribe button">Unsubscribe</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -3,6 +3,7 @@ import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dial
|
|||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
|
||||||
import { Subscription } from 'api-types';
|
import { Subscription } from 'api-types';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-subscription-info-dialog',
|
selector: 'app-subscription-info-dialog',
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
<h4 i18n="Update progress dialog title" mat-dialog-title>Updater</h4>
|
<h4 i18n="Update progress dialog title" mat-dialog-title>Updater</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div *ngIf="updateStatus">
|
@if (updateStatus) {
|
||||||
<div style="margin-bottom: 8px;">
|
<div>
|
||||||
<h6 *ngIf="updateStatus['updating']">Update in progress</h6>
|
<div style="margin-bottom: 8px;">
|
||||||
<h6 *ngIf="!updateStatus['updating'] && updateStatus['error']">Update failed</h6>
|
@if (updateStatus['updating']) {
|
||||||
<h6 *ngIf="!updateStatus['updating'] && !updateStatus['error']">Update succeeded!</h6>
|
<h6>Update in progress</h6>
|
||||||
</div>
|
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||||
<mat-progress-bar *ngIf="updateStatus['updating']" mode="indeterminate"></mat-progress-bar>
|
} @else {
|
||||||
<mat-progress-bar *ngIf="!updateStatus['updating']" mode="determinate" value="100"></mat-progress-bar>
|
@if (updateStatus['error']) {
|
||||||
<p style="margin-top: 4px; font-size: 13px;" *ngIf="updateStatus['details']">{{updateStatus['details']}}</p>
|
<h6>Update failed</h6>
|
||||||
|
} @else {
|
||||||
|
<h6>Update succeeded!</h6>
|
||||||
|
}
|
||||||
|
<mat-progress-bar mode="determinate" value="100"></mat-progress-bar>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (updateStatus['details']) {
|
||||||
|
<p style="margin-top: 4px; font-size: 13px;">{{updateStatus['details']}}</p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close update progress dialog">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close update progress dialog">Close</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,54 +1,59 @@
|
|||||||
<h4 mat-dialog-title><ng-container i18n="Update task schedule">Update task schedule</ng-container></h4>
|
<h4 mat-dialog-title><ng-container i18n="Update task schedule">Update task schedule</ng-container></h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mt-3">
|
<div class="col-12 mt-3">
|
||||||
<mat-checkbox [(ngModel)]="enabled"><ng-container i18n="Enabled">Enabled</ng-container></mat-checkbox>
|
<mat-checkbox [(ngModel)]="enabled"><ng-container i18n="Enabled">Enabled</ng-container></mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 mt-2">
|
<div class="col-12 mt-2">
|
||||||
<mat-checkbox [(ngModel)]="recurring" [disabled]="!enabled"><ng-container i18n="Recurring">Recurring</ng-container></mat-checkbox>
|
<mat-checkbox [(ngModel)]="recurring" [disabled]="!enabled"><ng-container i18n="Recurring">Recurring</ng-container></mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 mt-2" *ngIf="recurring">
|
@if (recurring) {
|
||||||
<mat-form-field>
|
<div class="col-12 mt-2">
|
||||||
<mat-select placeholder="Interval" [(ngModel)]="interval" [disabled]="!enabled">
|
<mat-form-field>
|
||||||
<mat-option value="weekly">Weekly</mat-option>
|
<mat-select placeholder="Interval" [(ngModel)]="interval" [disabled]="!enabled">
|
||||||
<mat-option value="daily">Daily</mat-option>
|
<mat-option value="weekly">Weekly</mat-option>
|
||||||
</mat-select>
|
<mat-option value="daily">Daily</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
</div>
|
</mat-form-field>
|
||||||
<div *ngIf="!recurring" class="col-12 mt-2">
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label i18n="Choose a date">Choose a date</mat-label>
|
|
||||||
<input [(ngModel)]="date" [min]="today" matInput [matDatepicker]="picker" [disabled]="!enabled">
|
|
||||||
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="recurring && interval === 'weekly'" class="col-12 mt-2">
|
|
||||||
<mat-button-toggle-group [(ngModel)]="days_of_week" [multiple]="true" [disabled]="!enabled" aria-label="Week day">
|
|
||||||
<!-- TODO: support translation -->
|
|
||||||
<mat-button-toggle [value]="0">M</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="1">T</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="2">W</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="3">T</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="4">F</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="5">S</mat-button-toggle>
|
|
||||||
<mat-button-toggle [value]="6">S</mat-button-toggle>
|
|
||||||
</mat-button-toggle-group>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 mt-2">
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Time</mat-label>
|
|
||||||
<input type="time" matInput [(ngModel)]="time" [disabled]="!enabled">
|
|
||||||
<mat-hint *ngIf="Intl?.DateTimeFormat().resolvedOptions().timeZone">{{Intl.DateTimeFormat().resolvedOptions().timeZone}}</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@if (interval === 'weekly') {
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-button-toggle-group [(ngModel)]="days_of_week" [multiple]="true" [disabled]="!enabled" aria-label="Week day">
|
||||||
|
<!-- TODO: support translation -->
|
||||||
|
<mat-button-toggle [value]="0">M</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="1">T</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="2">W</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="3">T</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="4">F</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="5">S</mat-button-toggle>
|
||||||
|
<mat-button-toggle [value]="6">S</mat-button-toggle>
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label i18n="Choose a date">Choose a date</mat-label>
|
||||||
|
<input [(ngModel)]="date" [min]="today" matInput [matDatepicker]="picker" [disabled]="!enabled">
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="col-12 mt-2">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Time</mat-label>
|
||||||
|
<input type="time" matInput [(ngModel)]="time" [disabled]="!enabled">
|
||||||
|
@if (Intl?.DateTimeFormat().resolvedOptions().timeZone) {
|
||||||
|
<mat-hint>{{Intl.DateTimeFormat().resolvedOptions().timeZone}}</mat-hint>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Update task schedule cancel button">Cancel</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Update task schedule cancel button">Cancel</ng-container></button>
|
||||||
<button mat-button (click)="updateTaskSchedule()"><ng-container i18n="Update button">Update</ng-container></button>
|
<button mat-button (click)="updateTaskSchedule()"><ng-container i18n="Update button">Update</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,64 +1,68 @@
|
|||||||
<h4 mat-dialog-title i18n="User profile dialog title">Your Profile</h4>
|
<h4 mat-dialog-title i18n="User profile dialog title">Your Profile</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div *ngIf="postsService.isLoggedIn && postsService.user">
|
@if (postsService.isLoggedIn && postsService.user) {
|
||||||
<div>
|
<div>
|
||||||
<strong><ng-container i18n="Name">Name:</ng-container></strong> {{postsService.user.name}}
|
<div>
|
||||||
</div>
|
<strong><ng-container i18n="Name">Name:</ng-container></strong> {{postsService.user.name}}
|
||||||
<div>
|
</div>
|
||||||
<strong><ng-container i18n="UID">UID:</ng-container></strong> {{postsService.user.uid}}
|
<div>
|
||||||
</div>
|
<strong><ng-container i18n="UID">UID:</ng-container></strong> {{postsService.user.uid}}
|
||||||
<div>
|
</div>
|
||||||
<strong><ng-container i18n="Created">Created:</ng-container></strong> {{postsService.user.created ? (postsService.user.created | date) : 'N/A'}}
|
<div>
|
||||||
</div>
|
<strong><ng-container i18n="Created">Created:</ng-container></strong> {{postsService.user.created ? (postsService.user.created | date) : 'N/A'}}
|
||||||
<div style="margin-top: 20px;">
|
</div>
|
||||||
</div>
|
<div style="margin-top: 20px;">
|
||||||
<mat-divider style="margin-bottom: 20px"></mat-divider>
|
</div>
|
||||||
|
<mat-divider style="margin-bottom: 20px"></mat-divider>
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field color="accent">
|
}
|
||||||
<mat-label><ng-container i18n="Language select label">Language</ng-container></mat-label>
|
<mat-form-field color="accent">
|
||||||
<mat-select (selectionChange)="localeSelectChanged($event.value)" [(value)]="initialLocale">
|
<mat-label><ng-container i18n="Language select label">Language</ng-container></mat-label>
|
||||||
<mat-option *ngFor="let locale of supported_locales" [value]="locale">
|
<mat-select (selectionChange)="localeSelectChanged($event.value)" [(value)]="initialLocale">
|
||||||
<ng-container *ngIf="all_locales[locale]">
|
@for (locale of supported_locales; track locale) {
|
||||||
{{all_locales[locale]['nativeName']}}
|
<mat-option [value]="locale">
|
||||||
</ng-container>
|
@if (all_locales[locale]) {
|
||||||
</mat-option>
|
{{all_locales[locale]['nativeName']}}
|
||||||
</mat-select>
|
}
|
||||||
</mat-form-field>
|
</mat-option>
|
||||||
<br/>
|
}
|
||||||
<mat-form-field>
|
</mat-select>
|
||||||
<mat-label i18n="Sidepanel mode">Sidepanel mode</mat-label>
|
</mat-form-field>
|
||||||
<mat-select [(ngModel)]="sidepanel_mode" (selectionChange)="sidePanelModeChanged($event.value)">
|
<br/>
|
||||||
<mat-option i18n="Over" value="over">
|
<mat-form-field>
|
||||||
Over
|
<mat-label i18n="Sidepanel mode">Sidepanel mode</mat-label>
|
||||||
</mat-option>
|
<mat-select [(ngModel)]="sidepanel_mode" (selectionChange)="sidePanelModeChanged($event.value)">
|
||||||
<mat-option i18n="Side" value="side">
|
<mat-option i18n="Over" value="over">
|
||||||
Side
|
Over
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
<mat-option i18n="Side" value="side">
|
||||||
</mat-form-field>
|
Side
|
||||||
<br/>
|
</mat-option>
|
||||||
<mat-form-field>
|
</mat-select>
|
||||||
<mat-label i18n="File card size">File card size</mat-label>
|
</mat-form-field>
|
||||||
<mat-select [(ngModel)]="card_size" (selectionChange)="cardSizeOptionChanged($event.value)">
|
<br/>
|
||||||
<mat-option i18n="Large" value="large">
|
<mat-form-field>
|
||||||
Large
|
<mat-label i18n="File card size">File card size</mat-label>
|
||||||
</mat-option>
|
<mat-select [(ngModel)]="card_size" (selectionChange)="cardSizeOptionChanged($event.value)">
|
||||||
<mat-option i18n="Medium" value="medium">
|
<mat-option i18n="Large" value="large">
|
||||||
Medium
|
Large
|
||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-option i18n="Small" value="small">
|
<mat-option i18n="Medium" value="medium">
|
||||||
Small
|
Medium
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
<mat-option i18n="Small" value="small">
|
||||||
</mat-form-field>
|
Small
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<div style="width: 100%">
|
<div style="width: 100%">
|
||||||
<div style="position: relative">
|
<div style="position: relative">
|
||||||
<button mat-stroked-button mat-dialog-close color="primary"><ng-container i18n="Close">Close</ng-container></button>
|
<button mat-stroked-button mat-dialog-close color="primary"><ng-container i18n="Close">Close</ng-container></button>
|
||||||
<button *ngIf="postsService.isLoggedIn" style="position: absolute; right: 0px;" (click)="logoutClicked()" mat-stroked-button color="warn"><ng-container i18n="Logout">Logout</ng-container></button>
|
@if (postsService.isLoggedIn) {
|
||||||
</div>
|
<button style="position: absolute; right: 0px;" (click)="logoutClicked()" mat-stroked-button color="warn"><ng-container i18n="Logout">Logout</ng-container></button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -1,83 +1,84 @@
|
|||||||
<h4 mat-dialog-title>
|
<h4 mat-dialog-title>
|
||||||
{{file.title}}
|
{{file.title}}
|
||||||
<div class="favorite-button">
|
<div class="favorite-button">
|
||||||
<button [disabled]="!initialized || retrieving_file || !write_access" mat-icon-button (click)="editing = !editing"><mat-icon>edit</mat-icon></button>
|
<button [disabled]="!initialized || retrieving_file || !write_access" mat-icon-button (click)="editing = !editing"><mat-icon>edit</mat-icon></button>
|
||||||
<button [disabled]="!initialized || retrieving_file || !write_access" (click)="toggleFavorite()" mat-icon-button ><mat-icon>{{file.favorite ? 'favorite_filled' : 'favorite_outline'}}</mat-icon></button>
|
<button [disabled]="!initialized || retrieving_file || !write_access" (click)="toggleFavorite()" mat-icon-button ><mat-icon>{{file.favorite ? 'favorite_filled' : 'favorite_outline'}}</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="Name">Name</mat-label>
|
||||||
|
<input [(ngModel)]="new_file.title" matInput [disabled]="!editing">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="URL">URL</mat-label>
|
||||||
|
<input [(ngModel)]="new_file.url" matInput [disabled]="!editing">
|
||||||
|
<button mat-icon-button matSuffix (click)="window.open(new_file.url, '_blank')">
|
||||||
|
<mat-icon>link</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="Uploader">Uploader</mat-label>
|
||||||
|
<input [(ngModel)]="new_file.uploader" matInput [disabled]="!editing">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="Upload date">Upload date</mat-label>
|
||||||
|
<input [value]="upload_date" matInput [matDatepicker]="picker" (dateChange)="uploadDateChanged($event)" [disabled]="!editing">
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="Thumbnail path">Thumbnail path</mat-label>
|
||||||
|
<input [(ngModel)]="new_file.thumbnailPath" matInput [disabled]="!editing">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="info-field">
|
||||||
|
<mat-label i18n="Thumbnail URL">Thumbnail URL</mat-label>
|
||||||
|
<input [(ngModel)]="new_file.thumbnailURL" matInput [disabled]="!editing || new_file.thumbnailPath">
|
||||||
|
</mat-form-field>
|
||||||
|
@if (initialized && postsService.categories) {
|
||||||
<mat-form-field class="info-field">
|
<mat-form-field class="info-field">
|
||||||
<mat-label i18n="Name">Name</mat-label>
|
<mat-label i18n="Category">Category</mat-label>
|
||||||
<input [(ngModel)]="new_file.title" matInput [disabled]="!editing">
|
<mat-select [value]="category" (selectionChange)="categoryChanged($event)" [compareWith]="categoryComparisonFunction" [disabled]="!editing">
|
||||||
|
<mat-option [value]="{}">
|
||||||
|
N/A
|
||||||
|
</mat-option>
|
||||||
|
@for (available_category of postsService.categories | keyvalue; track available_category) {
|
||||||
|
<mat-option [value]="available_category.value">
|
||||||
|
{{available_category.value['name']}}
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="info-field">
|
}
|
||||||
<mat-label i18n="URL">URL</mat-label>
|
<mat-form-field class="info-field">
|
||||||
<input [(ngModel)]="new_file.url" matInput [disabled]="!editing">
|
<mat-label i18n="View count">View count</mat-label>
|
||||||
<button mat-icon-button matSuffix (click)="window.open(new_file.url, '_blank')">
|
<input type="number" [(ngModel)]="new_file.view_count" matInput [disabled]="!editing">
|
||||||
<mat-icon>link</mat-icon>
|
</mat-form-field>
|
||||||
</button>
|
<mat-form-field class="info-field">
|
||||||
</mat-form-field>
|
<mat-label i18n="Local view count">Local view count</mat-label>
|
||||||
<mat-form-field class="info-field">
|
<input type="number" [(ngModel)]="new_file.local_view_count" matInput [disabled]="!editing">
|
||||||
<mat-label i18n="Uploader">Uploader</mat-label>
|
</mat-form-field>
|
||||||
<input [(ngModel)]="new_file.uploader" matInput [disabled]="!editing">
|
<mat-divider style="margin-bottom: 16px;"></mat-divider>
|
||||||
</mat-form-field>
|
@if (!new_file.isAudio) {
|
||||||
<mat-form-field class="info-field">
|
|
||||||
<mat-label i18n="Upload date">Upload date</mat-label>
|
|
||||||
<input [value]="upload_date" matInput [matDatepicker]="picker" (dateChange)="uploadDateChanged($event)" [disabled]="!editing">
|
|
||||||
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="info-field">
|
|
||||||
<mat-label i18n="Thumbnail path">Thumbnail path</mat-label>
|
|
||||||
<input [(ngModel)]="new_file.thumbnailPath" matInput [disabled]="!editing">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="info-field">
|
|
||||||
<mat-label i18n="Thumbnail URL">Thumbnail URL</mat-label>
|
|
||||||
<input [(ngModel)]="new_file.thumbnailURL" matInput [disabled]="!editing || new_file.thumbnailPath">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field *ngIf="initialized && postsService.categories" class="info-field">
|
|
||||||
<mat-label i18n="Category">Category</mat-label>
|
|
||||||
<mat-select [value]="category" (selectionChange)="categoryChanged($event)" [compareWith]="categoryComparisonFunction" [disabled]="!editing">
|
|
||||||
<mat-option [value]="{}">
|
|
||||||
N/A
|
|
||||||
</mat-option>
|
|
||||||
<mat-option *ngFor="let available_category of postsService.categories | keyvalue" [value]="available_category.value">
|
|
||||||
{{available_category.value['name']}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="info-field">
|
|
||||||
<mat-label i18n="View count">View count</mat-label>
|
|
||||||
<input type="number" [(ngModel)]="new_file.view_count" matInput [disabled]="!editing">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="info-field">
|
|
||||||
<mat-label i18n="Local view count">Local view count</mat-label>
|
|
||||||
<input type="number" [(ngModel)]="new_file.local_view_count" matInput [disabled]="!editing">
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-divider style="margin-bottom: 16px;"></mat-divider>
|
|
||||||
|
|
||||||
<div *ngIf="!new_file.isAudio" class="info-item">
|
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video resolution property">Resolution:</ng-container> </strong></div>
|
|
||||||
<div class="info-item-value">{{new_file.height ? new_file.height + 'p' : 'N/A'}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video audio bitrate property">Audio bitrate:</ng-container> </strong></div>
|
<div class="info-item-label"><strong><ng-container i18n="Video resolution property">Resolution:</ng-container> </strong></div>
|
||||||
<div class="info-item-value">{{new_file.abr ? new_file.abr + ' Kbps' : 'N/A'}}</div>
|
<div class="info-item-value">{{new_file.height ? new_file.height + 'p' : 'N/A'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
}
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video file size property">File size:</ng-container> </strong></div>
|
<div class="info-item">
|
||||||
<div class="info-item-value">{{new_file.size ? filesize(new_file.size) : 'N/A'}}</div>
|
<div class="info-item-label"><strong><ng-container i18n="Video audio bitrate property">Audio bitrate:</ng-container> </strong></div>
|
||||||
</div>
|
<div class="info-item-value">{{new_file.abr ? new_file.abr + ' Kbps' : 'N/A'}}</div>
|
||||||
<div class="info-item">
|
</div>
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video path property">Path:</ng-container> </strong></div>
|
<div class="info-item">
|
||||||
<div class="info-item-value">{{new_file.path ? new_file.path : 'N/A'}}</div>
|
<div class="info-item-label"><strong><ng-container i18n="Video file size property">File size:</ng-container> </strong></div>
|
||||||
</div>
|
<div class="info-item-value">{{new_file.size ? filesize(new_file.size) : 'N/A'}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-item-label"><strong><ng-container i18n="Video path property">Path:</ng-container> </strong></div>
|
||||||
|
<div class="info-item-value">{{new_file.path ? new_file.path : 'N/A'}}</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button mat-dialog-close><ng-container i18n="Close video info button">Close</ng-container></button>
|
<button mat-button mat-dialog-close><ng-container i18n="Close video info button">Close</ng-container></button>
|
||||||
<button mat-button [disabled]="!metadataChanged()" (click)="saveChanges()"><ng-container i18n="Save video info button">Save</ng-container></button>
|
<button mat-button [disabled]="!metadataChanged()" (click)="saveChanges()"><ng-container i18n="Save video info button">Save</ng-container></button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -11,7 +11,9 @@
|
|||||||
<button mat-button mat-dialog-close>Cancel</button>
|
<button mat-button mat-dialog-close>Cancel</button>
|
||||||
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
|
||||||
<button mat-button [disabled]="!inputText" type="submit" (click)="enterPressed()">{{submitText}}</button>
|
<button mat-button [disabled]="!inputText" type="submit" (click)="enterPressed()">{{submitText}}</button>
|
||||||
<div class="mat-spinner" *ngIf="inputSubmitted">
|
@if (inputSubmitted) {
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<div class="mat-spinner">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,216 +1,249 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<div class="big demo-basic">
|
<div class="big demo-basic">
|
||||||
<mat-card id="card" style="margin-right: 20px; margin-left: 20px;" [ngClass]="(allowAdvancedDownload) ? 'no-border-radius-bottom' : 'border-radius-both'">
|
<mat-card id="card" style="margin-right: 20px; margin-left: 20px;" [ngClass]="(allowAdvancedDownload) ? 'no-border-radius-bottom' : 'border-radius-both'">
|
||||||
<mat-card-content style="padding: 0px 8px 0px 8px;">
|
<mat-card-content style="padding: 0px 8px 0px 8px;">
|
||||||
<div style="position: relative; margin-right: 15px; margin-top: 20px;">
|
<div style="position: relative; margin-right: 15px; margin-top: 20px;">
|
||||||
<form class="example-form">
|
<form class="example-form">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div [ngClass]="allowQualitySelect ? 'col-sm-9' : null" class="col-12">
|
<div [ngClass]="allowQualitySelect ? 'col-sm-9' : null" class="col-12">
|
||||||
<mat-form-field color="accent" class="example-full-width">
|
<mat-form-field color="accent" class="example-full-width">
|
||||||
<textarea class="url-input" cdkTextareaAutosize cdkAutosizeMinRows="1" wrap="off" matInput (ngModelChange)="inputChanged($event)" [(ngModel)]="url" [placeholder]="'URL' + (youtubeSearchEnabled ? ' or search' : '')" type="url" name="url" #urlinput></textarea>
|
<textarea class="url-input" cdkTextareaAutosize cdkAutosizeMinRows="1" wrap="off" matInput (ngModelChange)="inputChanged($event)" [(ngModel)]="url" [placeholder]="'URL' + (youtubeSearchEnabled ? ' or search' : '')" type="url" name="url" #urlinput></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<!--<button type="button" class="input-clear-button" mat-icon-button (click)="clearInput()"><mat-icon>clear</mat-icon></button>-->
|
<!--<button type="button" class="input-clear-button" mat-icon-button (click)="clearInput()"><mat-icon>clear</mat-icon></button>-->
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="allowQualitySelect" class="col-7 col-sm-3">
|
@if (allowQualitySelect) {
|
||||||
<mat-form-field color="accent" style="display: inline-block; width: inherit; min-width: 120px;">
|
<div class="col-7 col-sm-3">
|
||||||
<mat-label>
|
<mat-form-field color="accent" style="display: inline-block; width: inherit; min-width: 120px;">
|
||||||
<ng-container i18n="Quality select label">
|
<mat-label>
|
||||||
Quality
|
<ng-container i18n="Quality select label">
|
||||||
</ng-container>
|
Quality
|
||||||
</mat-label>
|
</ng-container>
|
||||||
<mat-select [disabled]="url === '' || cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats_loading']" [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality" (ngModelChange)="argsChanged()">
|
</mat-label>
|
||||||
<mat-option i18n="Best" [value]="''">
|
<mat-select [disabled]="url === '' || cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats_loading']" [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality" (ngModelChange)="argsChanged()">
|
||||||
Best
|
<mat-option i18n="Best" [value]="''">
|
||||||
</mat-option>
|
Best
|
||||||
<ng-container *ngIf="url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats && !cachedAvailableFormats[url]?.formats_failed">
|
</mat-option>
|
||||||
<ng-container *ngFor="let option of cachedAvailableFormats[url]['formats'][audioOnly ? 'audio' : 'video']">
|
@if (url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats && !cachedAvailableFormats[url]?.formats_failed) {
|
||||||
<mat-option [matTooltip]="option.expected_filesize ? humanFileSize(option.expected_filesize) : null" *ngIf="option.key !== 'best_audio_format'" [value]="option">
|
@for (option of cachedAvailableFormats[url]['formats'][audioOnly ? 'audio' : 'video']; track option) {
|
||||||
{{option.key}}
|
@if (option.key !== 'best_audio_format') {
|
||||||
</mat-option>
|
<mat-option [matTooltip]="option.expected_filesize ? humanFileSize(option.expected_filesize) : null" [value]="option">
|
||||||
</ng-container>
|
{{option.key}}
|
||||||
</ng-container>
|
</mat-option>
|
||||||
<ng-container *ngIf="url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats_failed">
|
}
|
||||||
<ng-container *ngFor="let option of qualityOptions[audioOnly ? 'audio' : 'video']">
|
}
|
||||||
<mat-option [value]="option.value">
|
}
|
||||||
{{option.label}}
|
@if (url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats_failed) {
|
||||||
</mat-option>
|
@for (option of qualityOptions[audioOnly ? 'audio' : 'video']; track option) {
|
||||||
</ng-container>
|
<mat-option [value]="option.value">
|
||||||
</ng-container>
|
{{option.label}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
}
|
||||||
<div class="spinner-div" *ngIf="url !== '' && cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats_loading']">
|
}
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
</mat-select>
|
||||||
</div>
|
</mat-form-field>
|
||||||
</div>
|
@if (url !== '' && cachedAvailableFormats[url] && cachedAvailableFormats[url]['formats_loading']) {
|
||||||
</div>
|
<div class="spinner-div">
|
||||||
</div>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
<div class="results-div" *ngIf="results_showing">
|
|
||||||
<span *ngFor="let result of results; let i = index">
|
|
||||||
<mat-card appearance="outlined" class="result-card mat-elevation-z7" [ngClass]="[(i === 0 && results.length > 1) ? 'first-result-card' : '', ((i === results.length-1) && results.length > 1) ? 'last-result-card' : '', (results.length === 1) ? 'only-result-card' : '']">
|
|
||||||
<div class="search-card-title">
|
|
||||||
{{result.title}}
|
|
||||||
</div>
|
|
||||||
<div style="font-size: 12px; margin-bottom: 10px;">
|
|
||||||
{{result.uploaded}}
|
|
||||||
</div>
|
|
||||||
<button mat-flat-button color="primary" style="float: left;" (click)="useURL(result.videoUrl)">
|
|
||||||
<ng-container i18n="YT search Use URL button for searched video">Use URL</ng-container>
|
|
||||||
</button>
|
|
||||||
<button mat-stroked-button color="primary" (click)="visitURL(result.videoUrl)" style="float: right">
|
|
||||||
<ng-container i18n="YT search View button for searched video">
|
|
||||||
View
|
|
||||||
</ng-container>
|
|
||||||
</button>
|
|
||||||
</mat-card>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<br/>
|
|
||||||
<mat-checkbox [disabled]="autoplay && !!current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px; margin-left: 4px;">
|
|
||||||
<ng-container i18n="Only Audio checkbox">
|
|
||||||
Only Audio
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-checkbox *ngIf="!forceAutoplay" [disabled]="getURLArray(url).length > 1" (change)="autoplayChanged($event)" [(ngModel)]="autoplay" style="float: right; margin-top: -12px">
|
|
||||||
<ng-container i18n="Autoplay checkbox">
|
|
||||||
Autoplay
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</mat-card-content>
|
|
||||||
<mat-card-actions>
|
|
||||||
<button style="margin-left: 8px; margin-bottom: 8px" (click)="downloadClicked()" [disabled]="downloadingfile || url === ''" type="submit" mat-stroked-button color="accent">
|
|
||||||
<ng-container i18n="Main download button">
|
|
||||||
Download
|
|
||||||
</ng-container>
|
|
||||||
</button>
|
|
||||||
<button (click)="cancelDownload()" style="margin-left: 8px; margin-bottom: 8px" *ngIf="!!current_download" mat-stroked-button color="warn">
|
|
||||||
<ng-container i18n="Cancel download button">
|
|
||||||
Cancel
|
|
||||||
</ng-container>
|
|
||||||
</button>
|
|
||||||
</mat-card-actions>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="allowAdvancedDownload" class="big demo-basic">
|
|
||||||
<form style="margin-left: 20px; margin-right: 20px;">
|
|
||||||
<mat-expansion-panel class="big no-border-radius-top">
|
|
||||||
<mat-expansion-panel-header>
|
|
||||||
<mat-panel-title>
|
|
||||||
<ng-container i18n="Advanced download mode panel">
|
|
||||||
Advanced
|
|
||||||
</ng-container>
|
|
||||||
</mat-panel-title>
|
|
||||||
</mat-expansion-panel-header>
|
|
||||||
<p *ngIf="this.simulatedOutput">
|
|
||||||
<ng-container i18n="Simulated command label">
|
|
||||||
Simulated command:
|
|
||||||
</ng-container>
|
|
||||||
<i>{{this.simulatedOutput}}</i></p>
|
|
||||||
<div class="container" style="padding-bottom: 20px;">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 col-sm-6">
|
|
||||||
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="customArgsEnabledChanged($event)" [(ngModel)]="customArgsEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
|
||||||
<ng-container i18n="Use custom args checkbox">
|
|
||||||
Use custom args
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<button class="edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
|
||||||
<mat-checkbox color="accent" [disabled]="!customArgsEnabled || !!current_download" (change)="replaceArgsChanged($event)" [(ngModel)]="replaceArgs" style="z-index: 999; margin-left: 10px" [ngModelOptions]="{standalone: true}">
|
|
||||||
<ng-container i18n="Replace args">
|
|
||||||
Replace args
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input">
|
|
||||||
<mat-label i18n="Custom args">Custom args</mat-label>
|
|
||||||
<input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput (ngModelChange)="argsChanged()">
|
|
||||||
<mat-hint>
|
|
||||||
<ng-container i18n="Custom Args input hint">
|
|
||||||
No need to include URL, just everything after. Args are delimited using two commas like so: ,,
|
|
||||||
</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-sm-6">
|
|
||||||
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="customOutputEnabledChanged($event)" [(ngModel)]="customOutputEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
|
||||||
<ng-container i18n="Use custom output checkbox">
|
|
||||||
Use custom output
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input">
|
|
||||||
<mat-label i18n="Custom output">Custom output</mat-label>
|
|
||||||
<input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput (ngModelChange)="argsChanged()">
|
|
||||||
<mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
|
||||||
<ng-container i18n="Youtube-dl output template documentation link">Documentation</ng-container></a>.
|
|
||||||
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-3">
|
|
||||||
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="youtubeAuthEnabledChanged($event)" [(ngModel)]="youtubeAuthEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
|
||||||
<ng-container i18n="Use authentication checkbox">
|
|
||||||
Use authentication
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-form-field *ngIf="youtubeAuthEnabled" color="accent" class="advanced-input">
|
|
||||||
<mat-label i18n="Username">Username</mat-label>
|
|
||||||
<input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-3">
|
|
||||||
<mat-form-field *ngIf="youtubeAuthEnabled" style="margin-top: 40px;" color="accent" class="advanced-input">
|
|
||||||
<mat-label i18n="Password">Password</mat-label>
|
|
||||||
<input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()">
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-sm-6 mt-3">
|
|
||||||
<mat-checkbox color="accent" [disabled]="!!current_download" [(ngModel)]="cropFile" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
|
||||||
<ng-container i18n="Crop video checkbox">
|
|
||||||
Crop file
|
|
||||||
</ng-container>
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-form-field *ngIf="cropFile" color="accent" class="advanced-input">
|
|
||||||
<mat-label i18n="Crop from (seconds)">Crop from (seconds)</mat-label>
|
|
||||||
<input [(ngModel)]="cropFileStart" type="number" [ngModelOptions]="{standalone: true}" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-sm-6 mt-3">
|
|
||||||
<mat-form-field *ngIf="cropFile" style="margin-top: 40px;" color="accent" class="advanced-input">
|
|
||||||
<mat-label i18n="Crop to (seconds)">Crop to (seconds)</mat-label>
|
|
||||||
<input [(ngModel)]="cropFileEnd" type="number" [ngModelOptions]="{standalone: true}" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-expansion-panel>
|
</div>
|
||||||
</form>
|
@if (results_showing) {
|
||||||
|
<div class="results-div">
|
||||||
|
@for (result of results; track result; let i = $index) {
|
||||||
|
<span>
|
||||||
|
<mat-card appearance="outlined" class="result-card mat-elevation-z7" [ngClass]="[(i === 0 && results.length > 1) ? 'first-result-card' : '', ((i === results.length-1) && results.length > 1) ? 'last-result-card' : '', (results.length === 1) ? 'only-result-card' : '']">
|
||||||
|
<div class="search-card-title">
|
||||||
|
{{result.title}}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px; margin-bottom: 10px;">
|
||||||
|
{{result.uploaded}}
|
||||||
|
</div>
|
||||||
|
<button mat-flat-button color="primary" style="float: left;" (click)="useURL(result.videoUrl)">
|
||||||
|
<ng-container i18n="YT search Use URL button for searched video">Use URL</ng-container>
|
||||||
|
</button>
|
||||||
|
<button mat-stroked-button color="primary" (click)="visitURL(result.videoUrl)" style="float: right">
|
||||||
|
<ng-container i18n="YT search View button for searched video">
|
||||||
|
View
|
||||||
|
</ng-container>
|
||||||
|
</button>
|
||||||
|
</mat-card>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
<br/>
|
||||||
|
<mat-checkbox [disabled]="autoplay && !!current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px; margin-left: 4px;">
|
||||||
|
<ng-container i18n="Only Audio checkbox">
|
||||||
|
Only Audio
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
@if (!forceAutoplay) {
|
||||||
|
<mat-checkbox [disabled]="getURLArray(url).length > 1" (change)="autoplayChanged($event)" [(ngModel)]="autoplay" style="float: right; margin-top: -12px">
|
||||||
|
<ng-container i18n="Autoplay checkbox">
|
||||||
|
Autoplay
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button style="margin-left: 8px; margin-bottom: 8px" (click)="downloadClicked()" [disabled]="downloadingfile || url === ''" type="submit" mat-stroked-button color="accent">
|
||||||
|
<ng-container i18n="Main download button">
|
||||||
|
Download
|
||||||
|
</ng-container>
|
||||||
|
</button>
|
||||||
|
@if (!!current_download) {
|
||||||
|
<button (click)="cancelDownload()" style="margin-left: 8px; margin-bottom: 8px" mat-stroked-button color="warn">
|
||||||
|
<ng-container i18n="Cancel download button">
|
||||||
|
Cancel
|
||||||
|
</ng-container>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
@if (allowAdvancedDownload) {
|
||||||
<div class="centered big" id="bar_div" *ngIf="current_download && autoplay">
|
<div class="big demo-basic">
|
||||||
<div class="margined">
|
<form style="margin-left: 20px; margin-right: 20px;">
|
||||||
<div [ngClass]="(+percentDownloaded > 99)?'make-room-for-spinner':'equal-sizes'" style="display: inline-block; width: 100%; padding-left: 20px" *ngIf="current_download.percent_complete && current_download.percent_complete > 1;else indeterminateprogress">
|
<mat-expansion-panel class="big no-border-radius-top">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
<ng-container i18n="Advanced download mode panel">
|
||||||
|
Advanced
|
||||||
|
</ng-container>
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
@if (this.simulatedOutput) {
|
||||||
|
<p>
|
||||||
|
<ng-container i18n="Simulated command label">
|
||||||
|
Simulated command:
|
||||||
|
</ng-container>
|
||||||
|
<i>{{this.simulatedOutput}}</i></p>
|
||||||
|
}
|
||||||
|
<div class="container" style="padding-bottom: 20px;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-sm-6">
|
||||||
|
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="customArgsEnabledChanged($event)" [(ngModel)]="customArgsEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
||||||
|
<ng-container i18n="Use custom args checkbox">
|
||||||
|
Use custom args
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
<button class="edit-button" (click)="openArgsModifierDialog()" mat-icon-button><mat-icon>edit</mat-icon></button>
|
||||||
|
<mat-checkbox color="accent" [disabled]="!customArgsEnabled || !!current_download" (change)="replaceArgsChanged($event)" [(ngModel)]="replaceArgs" style="z-index: 999; margin-left: 10px" [ngModelOptions]="{standalone: true}">
|
||||||
|
<ng-container i18n="Replace args">
|
||||||
|
Replace args
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input">
|
||||||
|
<mat-label i18n="Custom args">Custom args</mat-label>
|
||||||
|
<input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput (ngModelChange)="argsChanged()">
|
||||||
|
<mat-hint>
|
||||||
|
<ng-container i18n="Custom Args input hint">
|
||||||
|
No need to include URL, just everything after. Args are delimited using two commas like so: ,,
|
||||||
|
</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-6">
|
||||||
|
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="customOutputEnabledChanged($event)" [(ngModel)]="customOutputEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
||||||
|
<ng-container i18n="Use custom output checkbox">
|
||||||
|
Use custom output
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input">
|
||||||
|
<mat-label i18n="Custom output">Custom output</mat-label>
|
||||||
|
<input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput (ngModelChange)="argsChanged()">
|
||||||
|
<mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
||||||
|
<ng-container i18n="Youtube-dl output template documentation link">Documentation</ng-container></a>.
|
||||||
|
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
@if (!youtubeAuthDisabledOverride) {
|
||||||
|
<div class="col-12 col-sm-6 mt-3">
|
||||||
|
<mat-checkbox color="accent" [disabled]="!!current_download" (change)="youtubeAuthEnabledChanged($event)" [(ngModel)]="youtubeAuthEnabled" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
||||||
|
<ng-container i18n="Use authentication checkbox">
|
||||||
|
Use authentication
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
@if (youtubeAuthEnabled) {
|
||||||
|
<mat-form-field color="accent" class="advanced-input">
|
||||||
|
<mat-label i18n="Username">Username</mat-label>
|
||||||
|
<input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()">
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-6 mt-3">
|
||||||
|
@if (youtubeAuthEnabled) {
|
||||||
|
<mat-form-field style="margin-top: 40px;" color="accent" class="advanced-input">
|
||||||
|
<mat-label i18n="Password">Password</mat-label>
|
||||||
|
<input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()">
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="col-12 col-sm-6 mt-3">
|
||||||
|
<mat-checkbox color="accent" [disabled]="!!current_download" [(ngModel)]="cropFile" style="z-index: 999" [ngModelOptions]="{standalone: true}">
|
||||||
|
<ng-container i18n="Crop video checkbox">
|
||||||
|
Crop file
|
||||||
|
</ng-container>
|
||||||
|
</mat-checkbox>
|
||||||
|
@if (cropFile) {
|
||||||
|
<mat-form-field color="accent" class="advanced-input">
|
||||||
|
<mat-label i18n="Crop from (seconds)">Crop from (seconds)</mat-label>
|
||||||
|
<input [(ngModel)]="cropFileStart" type="number" [ngModelOptions]="{standalone: true}" matInput>
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-6 mt-3">
|
||||||
|
@if (cropFile) {
|
||||||
|
<mat-form-field style="margin-top: 40px;" color="accent" class="advanced-input">
|
||||||
|
<mat-label i18n="Crop to (seconds)">Crop to (seconds)</mat-label>
|
||||||
|
<input [(ngModel)]="cropFileEnd" type="number" [ngModelOptions]="{standalone: true}" matInput>
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<br/>
|
||||||
|
@if (current_download && autoplay) {
|
||||||
|
<div class="centered big" id="bar_div">
|
||||||
|
<div class="margined">
|
||||||
|
@if (current_download.percent_complete && current_download.percent_complete > 1) {
|
||||||
|
<div [ngClass]="(+percentDownloaded > 99)?'make-room-for-spinner':'equal-sizes'" style="display: inline-block; width: 100%; padding-left: 20px">
|
||||||
<mat-progress-bar style="border-radius: 5px;" mode="determinate" value="{{percentDownloaded}}"></mat-progress-bar>
|
<mat-progress-bar style="border-radius: 5px;" mode="determinate" value="{{percentDownloaded}}"></mat-progress-bar>
|
||||||
<br/>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="+percentDownloaded > 99" class="spinner">
|
} @else {
|
||||||
|
<mat-progress-bar style="border-radius: 5px;" mode="indeterminate"></mat-progress-bar>
|
||||||
|
}
|
||||||
|
@if (+percentDownloaded > 99) {
|
||||||
|
<div class="spinner">
|
||||||
<mat-spinner [diameter]="25"></mat-spinner>
|
<mat-spinner [diameter]="25"></mat-spinner>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #indeterminateprogress>
|
}
|
||||||
<mat-progress-bar style="border-radius: 5px;" mode="indeterminate"></mat-progress-bar>
|
</div>
|
||||||
</ng-template>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
}
|
||||||
</div>
|
@if (downloads && downloads.length > 0 && !autoplay) {
|
||||||
|
<div style="display: flex; justify-content: center;">
|
||||||
<div style="display: flex; justify-content: center;" *ngIf="downloads && downloads.length > 0 && !autoplay">
|
<app-downloads style="width: 80%; min-width: 350px; margin-bottom: 10px" [uids]="download_uids"></app-downloads>
|
||||||
<app-downloads style="width: 80%; min-width: 350px; margin-bottom: 10px" [uids]="download_uids"></app-downloads>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
@if (cachedFileManagerEnabled || fileManagerEnabled) {
|
||||||
<ng-container *ngIf="cachedFileManagerEnabled || fileManagerEnabled">
|
|
||||||
<app-recent-videos #recentVideos></app-recent-videos>
|
<app-recent-videos #recentVideos></app-recent-videos>
|
||||||
<br/>
|
<br/>
|
||||||
<h4 style="text-align: center">Custom playlists</h4>
|
<h4 style="text-align: center">Custom playlists</h4>
|
||||||
<app-custom-playlists></app-custom-playlists>
|
<app-custom-playlists></app-custom-playlists>
|
||||||
</ng-container>
|
}
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
if (!(this.cachedAvailableFormats[url] && this.cachedAvailableFormats[url]['formats'])) {
|
if (!(this.cachedAvailableFormats[url] && this.cachedAvailableFormats[url]['formats'])) {
|
||||||
this.cachedAvailableFormats[url]['formats_loading'] = true;
|
this.cachedAvailableFormats[url]['formats_loading'] = true;
|
||||||
this.postsService.getFileFormats([url]).subscribe(res => {
|
this.postsService.getFileFormats(url).subscribe(res => {
|
||||||
this.cachedAvailableFormats[url]['formats_loading'] = false;
|
this.cachedAvailableFormats[url]['formats_loading'] = false;
|
||||||
const infos = res['result'];
|
const infos = res['result'];
|
||||||
if (!infos || !infos.formats) {
|
if (!infos || !infos.formats) {
|
||||||
|
|||||||
@@ -1,64 +1,86 @@
|
|||||||
<div style="height: 100%" *ngIf="playlist.length > 0 && show_player">
|
@if (playlist.length > 0 && show_player) {
|
||||||
|
<div style="height: 100%">
|
||||||
<div style="height: 100%" [ngClass]="(currentItem.type === 'audio/mp3') ? null : 'container-video'">
|
<div style="height: 100%" [ngClass]="(currentItem.type === 'audio/mp3') ? null : 'container-video'">
|
||||||
<div style="max-width: 100%; margin-left: 0px; height: 100%">
|
<div style="max-width: 100%; margin-left: 0px; height: 100%">
|
||||||
<mat-drawer-container style="height: 100%" class="example-container" autosize>
|
<mat-drawer-container style="height: 100%" class="example-container" autosize>
|
||||||
<div style="height: fit-content" [ngClass]="(currentItem.type === 'audio/mp3') ? 'audio-col' : 'video-col'">
|
<div style="height: fit-content" [ngClass]="(currentItem.type === 'audio/mp3') ? 'audio-col' : 'video-col'">
|
||||||
<vg-player style="height: fit-content; max-height: 75vh" (onPlayerReady)="onPlayerReady($event)" [style.background-color]="(currentItem.type === 'audio/mp3') ? postsService.theme.drawer_color : 'black'">
|
<vg-player style="height: fit-content; max-height: 75vh" (onPlayerReady)="onPlayerReady($event)" [style.background-color]="(currentItem.type === 'audio/mp3') ? postsService.theme.drawer_color : 'black'">
|
||||||
<video [ngClass]="(currentItem.type === 'audio/mp3') ? 'audio-styles' : 'video-styles'" #media class="video-player" [vgMedia]="$any(media)" [src]="currentItem.src" id="singleVideo" preload="auto" controls playsinline>
|
<video [ngClass]="(currentItem.type === 'audio/mp3') ? 'audio-styles' : 'video-styles'" #media class="video-player" [vgMedia]="$any(media)" [src]="currentItem.src" id="singleVideo" preload="auto" controls playsinline>
|
||||||
</video>
|
</video>
|
||||||
<app-skip-ad-button *ngIf="postsService['config']['API']['use_sponsorblock_API'] && api && playlist?.length > 0 && playlist[currentIndex]['type'] === 'video/mp4'" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [current_video]="playlist[currentIndex]" [playback_timestamp]="api.currentTime" class="skip-ad-button"></app-skip-ad-button>
|
@if (postsService['config']['API']['use_sponsorblock_API'] && api && playlist?.length > 0 && playlist[currentIndex]['type'] === 'video/mp4') {
|
||||||
</vg-player>
|
<app-skip-ad-button (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [current_video]="playlist[currentIndex]" [playback_timestamp]="api.currentTime" class="skip-ad-button"></app-skip-ad-button>
|
||||||
</div>
|
}
|
||||||
<div style="height: fit-content; width: 100%; margin-top: 10px;">
|
</vg-player>
|
||||||
<div class="container">
|
</div>
|
||||||
<div class="row">
|
<div style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||||
<div class="col-2 col-lg-1">
|
<div class="container">
|
||||||
<ng-container *ngIf="db_file">{{db_file['local_view_count'] ? db_file['local_view_count']+1 : 1}} <ng-container i18n="View count label">views</ng-container></ng-container>
|
<div class="row">
|
||||||
</div>
|
<div class="col-2 col-lg-1">
|
||||||
<div style="white-space: pre-line;" class="col-8 col-lg-9">
|
@if (db_file) {
|
||||||
<ng-container *ngIf="db_file && db_file['description']">
|
{{db_file['local_view_count'] ? db_file['local_view_count']+1 : 1}} <ng-container i18n="View count label">views</ng-container>
|
||||||
<p>
|
}
|
||||||
<app-see-more [text]="db_file['description']"></app-see-more>
|
</div>
|
||||||
</p>
|
<div style="white-space: pre-line;" class="col-8 col-lg-9">
|
||||||
</ng-container>
|
@if (db_file && db_file['description']) {
|
||||||
<ng-container *ngIf="!db_file || !db_file['description']">
|
<p>
|
||||||
<p i18n="No description" style="text-align: center;">
|
<app-see-more [text]="db_file['description']"></app-see-more>
|
||||||
No description available.
|
</p>
|
||||||
</p>
|
} @else {
|
||||||
</ng-container>
|
<p i18n="No description" style="text-align: center;">
|
||||||
</div>
|
No description available.
|
||||||
<div class="col-2">
|
</p>
|
||||||
<span class="buttons" *ngIf="db_playlist">
|
}
|
||||||
<button (click)="downloadContent()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon></button>
|
</div>
|
||||||
<mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner>
|
<div class="col-2">
|
||||||
<button *ngIf="(!postsService.isLoggedIn || postsService.permissions.includes('sharing')) && !auto" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
@if (db_playlist) {
|
||||||
</span>
|
<span class="buttons">
|
||||||
<span class="buttons" *ngIf="db_file">
|
<button (click)="downloadContent()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon></button>
|
||||||
<button (click)="downloadFile()" [disabled]="downloading" mat-icon-button><mat-icon>cloud_download</mat-icon></button>
|
@if (downloading) {
|
||||||
<mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner>
|
<mat-spinner class="spinner" [diameter]="35"></mat-spinner>
|
||||||
<button *ngIf="!postsService.isLoggedIn || postsService.permissions.includes('sharing')" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
}
|
||||||
</span>
|
@if ((!postsService.isLoggedIn || postsService.permissions.includes('sharing')) && !auto) {
|
||||||
<ng-container *ngIf="db_file || playlist[currentIndex]"></ng-container>
|
<button (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||||
<button (click)="openFileInfoDialog()" *ngIf="db_file || db_playlist" mat-icon-button><mat-icon>info</mat-icon></button>
|
}
|
||||||
<button *ngIf="db_file && db_file.url.includes('twitch.tv')" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
</span>
|
||||||
</div>
|
}
|
||||||
</div>
|
@if (db_file) {
|
||||||
</div>
|
<span class="buttons">
|
||||||
</div>
|
<button (click)="downloadFile()" [disabled]="downloading" mat-icon-button><mat-icon>cloud_download</mat-icon></button>
|
||||||
<div style="height: fit-content; width: 100%; margin-top: 10px;">
|
@if (downloading) {
|
||||||
<mat-button-toggle-group cdkDropList [cdkDropListSortingDisabled]="true" (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical name="videoSelect" aria-label="Video Select" #group="matButtonToggleGroup">
|
<mat-spinner class="spinner" [diameter]="35"></mat-spinner>
|
||||||
<mat-button-toggle cdkDrag *ngFor="let playlist_item of playlist; let i = index" [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
|
}
|
||||||
</mat-button-toggle-group>
|
@if (!postsService.isLoggedIn || postsService.permissions.includes('sharing')) {
|
||||||
</div>
|
<button (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||||
|
}
|
||||||
<app-concurrent-stream *ngIf="db_file && api && postsService.config" (setPlaybackRate)="setPlaybackRate($event)" (togglePlayback)="togglePlayback($event)" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [playing]="api.state === 'playing'" [uid]="uid" [playback_timestamp]="api.time.current/1000" [server_mode]="!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn"></app-concurrent-stream>
|
</span>
|
||||||
|
}
|
||||||
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
|
@if (db_file || db_playlist) {
|
||||||
<ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv')">
|
<button (click)="openFileInfoDialog()" mat-icon-button><mat-icon>info</mat-icon></button>
|
||||||
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
|
}
|
||||||
</ng-container>
|
@if (db_file && db_file.url.includes('twitch.tv')) {
|
||||||
</mat-drawer>
|
<button (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||||
</mat-drawer-container>
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||||
|
<mat-button-toggle-group cdkDropList [cdkDropListSortingDisabled]="true" (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical name="videoSelect" aria-label="Video Select" #group="matButtonToggleGroup">
|
||||||
|
@for (playlist_item of playlist; track playlist_item; let i = $index) {
|
||||||
|
<mat-button-toggle cdkDrag [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
|
||||||
|
}
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</div>
|
||||||
|
@if (db_file && api && postsService.config) {
|
||||||
|
<app-concurrent-stream (setPlaybackRate)="setPlaybackRate($event)" (togglePlayback)="togglePlayback($event)" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [playing]="api.state === 'playing'" [uid]="uid" [playback_timestamp]="api.time.current/1000" [server_mode]="!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn"></app-concurrent-stream>
|
||||||
|
}
|
||||||
|
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
|
||||||
|
@if (api_ready && db_file && db_file.url.includes('twitch.tv')) {
|
||||||
|
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
|
||||||
|
}
|
||||||
|
</mat-drawer>
|
||||||
|
</mat-drawer-container>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { ShareMediaDialogComponent } from '../dialogs/share-media-dialog/share-m
|
|||||||
import { DatabaseFile, FileType, Playlist } from '../../api-types';
|
import { DatabaseFile, FileType, Playlist } from '../../api-types';
|
||||||
import { TwitchChatComponent } from 'app/components/twitch-chat/twitch-chat.component';
|
import { TwitchChatComponent } from 'app/components/twitch-chat/twitch-chat.component';
|
||||||
import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component';
|
import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
export interface IMedia {
|
export interface IMedia {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'rxjs/add/operator/map';
|
|||||||
import 'rxjs/add/operator/catch';
|
import 'rxjs/add/operator/catch';
|
||||||
import 'rxjs/add/observable/throw';
|
import 'rxjs/add/observable/throw';
|
||||||
import { THEMES_CONFIG } from '../themes';
|
import { THEMES_CONFIG } from '../themes';
|
||||||
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
|
import { Router, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
@@ -119,9 +119,10 @@ import {
|
|||||||
import { isoLangs } from './dialogs/user-profile-dialog/locales_list';
|
import { isoLangs } from './dialogs/user-profile-dialog/locales_list';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { MatDrawerMode } from '@angular/material/sidenav';
|
import { MatDrawerMode } from '@angular/material/sidenav';
|
||||||
|
import { environment } from '../environments/environment';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PostsService implements CanActivate {
|
export class PostsService {
|
||||||
path = '';
|
path = '';
|
||||||
|
|
||||||
// local settings
|
// local settings
|
||||||
@@ -176,7 +177,7 @@ export class PostsService implements CanActivate {
|
|||||||
|
|
||||||
if (isDevMode()) {
|
if (isDevMode()) {
|
||||||
this.debugMode = true;
|
this.debugMode = true;
|
||||||
this.path = 'http://localhost:17442/api/';
|
this.path = !environment.codespaces ? 'http://localhost:17442/api/' : `${window.location.origin.replace('4200', '17442')}/api/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.http_params = `apiKey=${this.auth_token}`
|
this.http_params = `apiKey=${this.auth_token}`
|
||||||
@@ -459,7 +460,7 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post<SuccessObject>(this.path + 'deleteArchiveItems', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'deleteArchiveItems', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFileFormats(url) {
|
getFileFormats(url: string) {
|
||||||
const body: GetFileFormatsRequest = {url: url};
|
const body: GetFileFormatsRequest = {url: url};
|
||||||
return this.http.post<GetFileFormatsResponse>(this.path + 'getFileFormats', body, this.httpOptions);
|
return this.http.post<GetFileFormatsResponse>(this.path + 'getFileFormats', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,38 @@
|
|||||||
<div style="margin-top: 14px;">
|
<div style="margin-top: 14px;">
|
||||||
<button class="back-button" (click)="goBack()" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
|
<button class="back-button" (click)="goBack()" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
|
||||||
<div style="margin-bottom: 15px;">
|
<div style="margin-bottom: 15px;">
|
||||||
<h2 style="text-align: center;" *ngIf="subscription">
|
@if (subscription) {
|
||||||
{{subscription.name}} <ng-container *ngIf="subscription.paused" i18n="Paused suffix">(Paused)</ng-container>
|
<h2 style="text-align: center;">
|
||||||
<button class="edit-button" (click)="editSubscription()" [disabled]="downloading" matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button><mat-icon class="save-icon">edit</mat-icon></button>
|
{{subscription.name}}
|
||||||
</h2>
|
@if (subscription.paused) {
|
||||||
<mat-progress-bar style="width: 80%; margin: 0 auto; margin-top: 15px;" *ngIf="subscription && subscription.downloading" mode="indeterminate"></mat-progress-bar>
|
<ng-container i18n="Paused suffix">(Paused)</ng-container>
|
||||||
</div>
|
}
|
||||||
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
|
<button class="edit-button" (click)="editSubscription()" [disabled]="downloading" matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button><mat-icon class="save-icon">edit</mat-icon></button>
|
||||||
<br/>
|
</h2>
|
||||||
|
}
|
||||||
<!-- Extra margin added for floating buttons to have room -->
|
@if (subscription && subscription.downloading) {
|
||||||
<div style="margin-bottom: 100px;" *ngIf="subscription">
|
<mat-progress-bar style="width: 80%; margin: 0 auto; margin-top: 15px;" mode="indeterminate"></mat-progress-bar>
|
||||||
<app-recent-videos #recentVideos [sub_id]="subscription.id"></app-recent-videos>
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="check-button">
|
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
|
||||||
<ng-container *ngIf="subscription.downloading">
|
<br/>
|
||||||
<button color="primary" (click)="cancelCheckSubscription()" [disabled]="cancel_clicked" matTooltip="Cancel subscription check" i18n-matTooltip="Cancel subscription check" mat-fab><mat-icon class="save-icon">cancel</mat-icon></button>
|
<!-- Extra margin added for floating buttons to have room -->
|
||||||
</ng-container>
|
@if (subscription) {
|
||||||
<ng-container *ngIf="!subscription.downloading">
|
<div style="margin-bottom: 100px;">
|
||||||
<button color="primary" (click)="checkSubscription()" [disabled]="check_clicked" matTooltip="Check subscription" i18n-matTooltip="Check subscription" mat-fab><mat-icon class="save-icon">youtube_searched_for</mat-icon></button>
|
<app-recent-videos #recentVideos [sub_id]="subscription.id"></app-recent-videos>
|
||||||
</ng-container>
|
</div>
|
||||||
</div>
|
}
|
||||||
<button class="watch-button" color="primary" (click)="watchSubscription()" matTooltip="Play all" i18n-matTooltip="Play all" mat-fab><mat-icon class="save-icon">video_library</mat-icon></button>
|
<div class="check-button">
|
||||||
<button class="save-button" color="primary" (click)="downloadContent()" [disabled]="downloading" matTooltip="Download zip" i18n-matTooltip="Download zip" mat-fab><mat-icon class="save-icon">save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="50"></mat-spinner></button>
|
@if (subscription.downloading) {
|
||||||
|
<button color="primary" (click)="cancelCheckSubscription()" [disabled]="cancel_clicked" matTooltip="Cancel subscription check" i18n-matTooltip="Cancel subscription check" mat-fab><mat-icon class="save-icon">cancel</mat-icon></button>
|
||||||
|
} @else {
|
||||||
|
<button color="primary" (click)="checkSubscription()" [disabled]="check_clicked" matTooltip="Check subscription" i18n-matTooltip="Check subscription" mat-fab><mat-icon class="save-icon">youtube_searched_for</mat-icon></button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<button class="watch-button" color="primary" (click)="watchSubscription()" matTooltip="Play all" i18n-matTooltip="Play all" mat-fab><mat-icon class="save-icon">video_library</mat-icon></button>
|
||||||
|
<button class="save-button" color="primary" (click)="downloadContent()" [disabled]="downloading" matTooltip="Download zip" i18n-matTooltip="Download zip" mat-fab><mat-icon class="save-icon">save</mat-icon>
|
||||||
|
@if (downloading) {
|
||||||
|
<mat-spinner class="spinner" [diameter]="50"></mat-spinner>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router, ParamMap } from '@angular/router';
|
|||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { EditSubscriptionDialogComponent } from 'app/dialogs/edit-subscription-dialog/edit-subscription-dialog.component';
|
import { EditSubscriptionDialogComponent } from 'app/dialogs/edit-subscription-dialog/edit-subscription-dialog.component';
|
||||||
import { Subscription } from 'api-types';
|
import { Subscription } from 'api-types';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-subscription',
|
selector: 'app-subscription',
|
||||||
|
|||||||
@@ -1,60 +1,76 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<h2 i18n="Subscriptions title" style="text-align: center; margin-bottom: 15px;">Your subscriptions</h2>
|
<h2 i18n="Subscriptions title" style="text-align: center; margin-bottom: 15px;">Your subscriptions</h2>
|
||||||
|
|
||||||
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
|
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<h4 i18n="Subscriptions channels title" style="text-align: center;">Channels</h4>
|
<h4 i18n="Subscriptions channels title" style="text-align: center;">Channels</h4>
|
||||||
<mat-nav-list class="sub-nav-list">
|
<mat-nav-list class="sub-nav-list">
|
||||||
<mat-list-item *ngFor="let sub of channel_subscriptions" style="pointer-events: none">
|
@for (sub of channel_subscriptions; track sub) {
|
||||||
<a style="pointer-events: auto;" class="a-list-item" matListItemTitle (click)="goToSubscription(sub)">
|
<mat-list-item style="pointer-events: none">
|
||||||
<strong *ngIf="sub.name">{{ sub.name }} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></strong>
|
<a style="pointer-events: auto;" class="a-list-item" matListItemTitle (click)="goToSubscription(sub)">
|
||||||
<div *ngIf="!sub.name">
|
@if (sub.name) {
|
||||||
<ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
|
<strong>{{ sub.name }}
|
||||||
</div>
|
@if (sub.paused) {
|
||||||
</a>
|
<ng-container i18n="Paused suffix">(Paused)</ng-container>
|
||||||
<div style="pointer-events: auto; color: unset" matListItemMeta>
|
}
|
||||||
<button matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button (click)="editSubscription(sub)">
|
</strong>
|
||||||
<mat-icon>edit</mat-icon>
|
} @else {
|
||||||
</button>
|
<div>
|
||||||
<button matTooltip="Info" i18n-matTooltip="Info" mat-icon-button (click)="showSubInfo(sub)">
|
<ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
|
||||||
<mat-icon>info</mat-icon>
|
</div>
|
||||||
</button>
|
}
|
||||||
</div>
|
</a>
|
||||||
|
<div style="pointer-events: auto; color: unset" matListItemMeta>
|
||||||
|
<button matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button (click)="editSubscription(sub)">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button matTooltip="Info" i18n-matTooltip="Info" mat-icon-button (click)="showSubInfo(sub)">
|
||||||
|
<mat-icon>info</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-nav-list>
|
}
|
||||||
|
</mat-nav-list>
|
||||||
<div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="channel_subscriptions.length === 0 && subscriptions">
|
@if (channel_subscriptions.length === 0 && subscriptions) {
|
||||||
|
<div style="width: 80%; margin: 0 auto; padding-left: 15px;">
|
||||||
<p i18n="No channel subscriptions text">You have no channel subscriptions.</p>
|
<p i18n="No channel subscriptions text">You have no channel subscriptions.</p>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<h4 i18n="Subscriptions playlists title" style="text-align: center; margin-top: 10px;">Playlists</h4>
|
<h4 i18n="Subscriptions playlists title" style="text-align: center; margin-top: 10px;">Playlists</h4>
|
||||||
<mat-nav-list class="sub-nav-list">
|
<mat-nav-list class="sub-nav-list">
|
||||||
<mat-list-item *ngFor="let sub of playlist_subscriptions" style="pointer-events: none">
|
@for (sub of playlist_subscriptions; track sub) {
|
||||||
<a style="pointer-events: auto;" class="a-list-item" matListItemTitle (click)="goToSubscription(sub)">
|
<mat-list-item style="pointer-events: none">
|
||||||
<strong *ngIf="sub.name">{{ sub.name }} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></strong>
|
<a style="pointer-events: auto;" class="a-list-item" matListItemTitle (click)="goToSubscription(sub)">
|
||||||
<div *ngIf="!sub.name">
|
@if (sub.name) {
|
||||||
<ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
|
<strong>{{ sub.name }}
|
||||||
</div>
|
@if (sub.paused) {
|
||||||
</a>
|
<ng-container i18n="Paused suffix">(Paused)</ng-container>
|
||||||
<div style="pointer-events: auto; color: unset" matListItemMeta>
|
}
|
||||||
<button matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button (click)="editSubscription(sub)">
|
</strong>
|
||||||
<mat-icon>edit</mat-icon>
|
} @else {
|
||||||
</button>
|
<div>
|
||||||
<button matTooltip="Info" i18n-matTooltip="Info" mat-icon-button (click)="showSubInfo(sub)">
|
<ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
|
||||||
<mat-icon>info</mat-icon>
|
</div>
|
||||||
</button>
|
}
|
||||||
</div>
|
</a>
|
||||||
|
<div style="pointer-events: auto; color: unset" matListItemMeta>
|
||||||
|
<button matTooltip="Edit" i18n-matTooltip="Edit" mat-icon-button (click)="editSubscription(sub)">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button matTooltip="Info" i18n-matTooltip="Info" mat-icon-button (click)="showSubInfo(sub)">
|
||||||
|
<mat-icon>info</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
|
}
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
|
@if (playlist_subscriptions.length === 0 && subscriptions) {
|
||||||
<div style="width: 80%; margin: 0 auto; padding-left: 15px;" *ngIf="playlist_subscriptions.length === 0 && subscriptions">
|
<div style="width: 80%; margin: 0 auto; padding-left: 15px;">
|
||||||
<p i18n="No playlist subscriptions text">You have no playlist subscriptions.</p>
|
<p i18n="No playlist subscriptions text">You have no playlist subscriptions.</p>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<div style="margin: 0 auto; width: 80%" *ngIf="subscriptions_loading">
|
@if (subscriptions_loading) {
|
||||||
|
<div style="margin: 0 auto; width: 80%">
|
||||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<button class="add-subscription-button" (click)="openSubscribeDialog()" matTooltip="Add subscription" i18n-matTooltip="Add subscription" mat-fab><mat-icon>add</mat-icon></button>
|
<button class="add-subscription-button" (click)="openSubscribeDialog()" matTooltip="Add subscription" i18n-matTooltip="Add subscription" mat-fab><mat-icon>add</mat-icon></button>
|
||||||
@@ -1,18 +1,28 @@
|
|||||||
<div style="display: block">
|
<div style="display: block">
|
||||||
<div style="display: inline-block">
|
<div style="display: inline-block">
|
||||||
<ng-container i18n="Select a version">Select a version:</ng-container>
|
<ng-container i18n="Select a version">Select a version:</ng-container>
|
||||||
|
</div>
|
||||||
|
@if (availableVersions) {
|
||||||
|
<div style="display: inline-block; margin-left: 15px;">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-select [(ngModel)]="selectedVersion">
|
||||||
|
@for (version of availableVersionsFiltered; track version) {
|
||||||
|
<mat-option [value]="version['tag_name']">
|
||||||
|
{{version['tag_name'] + (version === latestStableRelease ? ' - Latest Stable' : '') + (version['tag_name'] === CURRENT_VERSION ? ' - Current Version' : '')}}
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="availableVersions" style="display: inline-block; margin-left: 15px;">
|
}
|
||||||
<mat-form-field>
|
@if (selectedVersion && selectedVersion !== CURRENT_VERSION) {
|
||||||
<mat-select [(ngModel)]="selectedVersion">
|
<div style="display: inline-block; margin-left: 15px;">
|
||||||
<mat-option *ngFor="let version of availableVersionsFiltered" [value]="version['tag_name']">
|
<button (click)="updateServer()" color="accent" mat-raised-button><mat-icon>update</mat-icon>
|
||||||
{{version['tag_name'] + (version === latestStableRelease ? ' - Latest Stable' : '') + (version['tag_name'] === CURRENT_VERSION ? ' - Current Version' : '')}}
|
@if (selectedVersion > CURRENT_VERSION) {
|
||||||
</mat-option>
|
<ng-container i18n="Upgrade to">Upgrade to</ng-container>
|
||||||
</mat-select>
|
} @else {
|
||||||
</mat-form-field>
|
<ng-container i18n="Downgrade to">Downgrade to</ng-container>
|
||||||
</div>
|
} {{selectedVersion}}</button>
|
||||||
<div *ngIf="selectedVersion && selectedVersion !== CURRENT_VERSION" style="display: inline-block; margin-left: 15px;">
|
|
||||||
<button (click)="updateServer()" color="accent" mat-raised-button><mat-icon>update</mat-icon>
|
|
||||||
<ng-container *ngIf="selectedVersion > CURRENT_VERSION">Upgrade to</ng-container><ng-container *ngIf="selectedVersion < CURRENT_VERSION">Downgrade to</ng-container> {{selectedVersion}}</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -4142,6 +4142,163 @@
|
|||||||
<context context-type="linenumber">363</context>
|
<context context-type="linenumber">363</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="6549265851868599441" datatype="html">
|
||||||
|
<source>Video</source>
|
||||||
|
<target state="translated">Vídeo</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">40</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="28da11220a3377ddce3c7948825d33101f142782" datatype="html">
|
||||||
|
<source>Extractor</source>
|
||||||
|
<target state="translated">Extractor</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">57</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Extractor</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c150a30bbbdb175b4d08820196a9acb66b167653" datatype="html">
|
||||||
|
<source>Archives empty</source>
|
||||||
|
<target state="translated">Arxius buits</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives empty</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="51a161ce175abcd44f6c6cbd0e996681bf553ac3" datatype="html">
|
||||||
|
<source>Delete selected</source>
|
||||||
|
<target state="translated">Elimina seleccionat</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">77</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete selected</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="a2f14a73f7a6e94479f67423cc51102da8d6f524" datatype="html">
|
||||||
|
<source>None</source>
|
||||||
|
<target state="translated">Cap</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">84</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">126</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">36</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">None</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c41475a25c9f9d9639db9efa56637603a77528b4" datatype="html">
|
||||||
|
<source>Download archive</source>
|
||||||
|
<target state="translated">Descarregar arxiu</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download archive</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8425787787095143143" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archive(s)?</source>
|
||||||
|
<target state="translated">T'agradaria eliminar <x id="selected archives amount" equiv-text="this.selection.selected.length"/> arxiu(s)?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">153</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2525880134753073592" datatype="html">
|
||||||
|
<source>Successfully deleted archive items!</source>
|
||||||
|
<target state="translated">Elements de l'arxiu eliminats amb èxit!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c748ac656af9f13998206ef2c52018dd418b0483" datatype="html">
|
||||||
|
<source>Archives</source>
|
||||||
|
<target state="translated">Arxius</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives menu label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4b3972c3e9485218508a95f7a4ce7758e3f09ced" datatype="html">
|
||||||
|
<source>Upload</source>
|
||||||
|
<target state="translated">Pujar</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">137</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/cookies-uploader-dialog/cookies-uploader-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Upload</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="347407180135731058" datatype="html">
|
||||||
|
<source>Audio</source>
|
||||||
|
<target state="translated">Àudio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">44</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7022070615528435141" datatype="html">
|
||||||
|
<source>Delete</source>
|
||||||
|
<target state="translated">Suprimir</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">154</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">160</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953483585652369683" datatype="html">
|
||||||
|
<source>Archive successfully imported!</source>
|
||||||
|
<target state="translated">Arxiu importat amb èxit!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">130</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="45cc8ca94b5a50842a9a8ef804a5ab089a38ae5c" datatype="html">
|
||||||
|
<source>ID</source>
|
||||||
|
<target state="translated">ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">47</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3159807825117518005" datatype="html">
|
||||||
|
<source>Delete archives</source>
|
||||||
|
<target state="translated">Elimina arxius</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">152</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ca707824ab93066c7d9b44e1b8bf216725c2c22" datatype="html">
|
||||||
|
<source>Filter</source>
|
||||||
|
<target state="translated">Filtres</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">3</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Filter</note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -1107,7 +1107,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="dc3d990391c944d1fbfc7cfb402f7b5e112fb3a8" datatype="html">
|
<trans-unit id="dc3d990391c944d1fbfc7cfb402f7b5e112fb3a8" datatype="html">
|
||||||
<source>Allow advanced download</source>
|
<source>Allow advanced download</source>
|
||||||
<target xml:lang="de-DE">Erweiterte Download-Optionen aktivieren</target>
|
<target xml:lang="de-DE" state="translated">Erweiterte Downloads erlauben</target>
|
||||||
<note from="description" priority="1">Allow advanced downloading setting</note>
|
<note from="description" priority="1">Allow advanced downloading setting</note>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
||||||
@@ -1525,7 +1525,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ea30873bd3f0d5e4fb2378eec3f0a1db77634a28" datatype="html">
|
<trans-unit id="ea30873bd3f0d5e4fb2378eec3f0a1db77634a28" datatype="html">
|
||||||
<source>Download all uploads</source>
|
<source>Download all uploads</source>
|
||||||
<target xml:lang="de-DE">Alle hochgeladene Videos herunterladen</target>
|
<target xml:lang="de-DE" state="translated">Alle hochgeladenen Videos herunterladen</target>
|
||||||
<note from="description" priority="1">Download all uploads subscription setting</note>
|
<note from="description" priority="1">Download all uploads subscription setting</note>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/dialogs/subscribe-dialog/subscribe-dialog.component.html</context>
|
<context context-type="sourcefile">app/dialogs/subscribe-dialog/subscribe-dialog.component.html</context>
|
||||||
@@ -1642,7 +1642,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="587b57ced54965d8874c3fd0e9dfedb987e5df04" datatype="html">
|
<trans-unit id="587b57ced54965d8874c3fd0e9dfedb987e5df04" datatype="html">
|
||||||
<source>You have no playlist subscriptions.</source>
|
<source>You have no playlist subscriptions.</source>
|
||||||
<target xml:lang="de-DE">Sie haben keine Wiedergabeliste abonniert.</target>
|
<target xml:lang="de-DE" state="translated">Du hast keine Wiedergabeliste abonniert.</target>
|
||||||
<note from="description" priority="1">No playlist subscriptions text</note>
|
<note from="description" priority="1">No playlist subscriptions text</note>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/subscriptions/subscriptions.component.html</context>
|
<context context-type="sourcefile">app/subscriptions/subscriptions.component.html</context>
|
||||||
@@ -2059,7 +2059,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="fb35145bfb84521e21b6385363d59221f436a573" datatype="html">
|
<trans-unit id="fb35145bfb84521e21b6385363d59221f436a573" datatype="html">
|
||||||
<source>Kill all downloads</source>
|
<source>Kill all downloads</source>
|
||||||
<target>Alle Herunterladen-Ereignisse abbrechen</target>
|
<target state="translated">Alle Downloads abbrechen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
<context context-type="sourcefile">app/settings/settings.component.html</context>
|
||||||
<context context-type="linenumber">139</context>
|
<context context-type="linenumber">139</context>
|
||||||
@@ -2221,7 +2221,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3697f8583ea42868aa269489ad366103d94aece7" datatype="html">
|
<trans-unit id="3697f8583ea42868aa269489ad366103d94aece7" datatype="html">
|
||||||
<source>Editing</source>
|
<source>Editing</source>
|
||||||
<target>Bearbeiten</target>
|
<target state="translated">In Bearbeitung</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/dialogs/edit-subscription-dialog/edit-subscription-dialog.component.html</context>
|
<context context-type="sourcefile">app/dialogs/edit-subscription-dialog/edit-subscription-dialog.component.html</context>
|
||||||
<context context-type="linenumber">1</context>
|
<context context-type="linenumber">1</context>
|
||||||
@@ -2592,7 +2592,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="d54142de169844b014ae913a4056c31495f4a305" datatype="html">
|
<trans-unit id="d54142de169844b014ae913a4056c31495f4a305" datatype="html">
|
||||||
<source>Test connection string</source>
|
<source>Test connection string</source>
|
||||||
<target>Verbindungstest-String</target>
|
<target state="translated">Verbindungsstring testen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
<context context-type="linenumber">304</context>
|
<context context-type="linenumber">304</context>
|
||||||
@@ -2717,7 +2717,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="49e09cce4426975ba06c1667063d2c1df9c94362" datatype="html">
|
<trans-unit id="49e09cce4426975ba06c1667063d2c1df9c94362" datatype="html">
|
||||||
<source>Autoplay</source>
|
<source>Autoplay</source>
|
||||||
<target>Automatisches abspielen</target>
|
<target state="translated">Automatisches Abspielen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/main/main.component.html</context>
|
<context context-type="sourcefile">src/app/main/main.component.html</context>
|
||||||
<context context-type="linenumber">70,71</context>
|
<context context-type="linenumber">70,71</context>
|
||||||
@@ -4309,7 +4309,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6219551536751479443" datatype="html">
|
<trans-unit id="6219551536751479443" datatype="html">
|
||||||
<source>Finished downloading</source>
|
<source>Finished downloading</source>
|
||||||
<target state="translated">Herunterladen abgeschlossen</target>
|
<target state="translated">Download abgeschlossen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
<context context-type="linenumber">17</context>
|
<context context-type="linenumber">17</context>
|
||||||
@@ -4317,7 +4317,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5947241266456580665" datatype="html">
|
<trans-unit id="5947241266456580665" datatype="html">
|
||||||
<source>Download failed</source>
|
<source>Download failed</source>
|
||||||
<target state="translated">Herunterladen fehlgeschlagen</target>
|
<target state="translated">Download fehlgeschlagen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
<context context-type="linenumber">18</context>
|
<context context-type="linenumber">18</context>
|
||||||
@@ -4358,7 +4358,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6876310993601590130" datatype="html">
|
<trans-unit id="6876310993601590130" datatype="html">
|
||||||
<source>Download completed</source>
|
<source>Download completed</source>
|
||||||
<target state="translated">Herunterladen abgeschlossen</target>
|
<target state="translated">Download abgeschlossen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
<context context-type="linenumber">23</context>
|
<context context-type="linenumber">23</context>
|
||||||
@@ -4523,7 +4523,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="c5dc5fbcce45e9b1530e2a5c2baa8ebe722aef4c" datatype="html">
|
<trans-unit id="c5dc5fbcce45e9b1530e2a5c2baa8ebe722aef4c" datatype="html">
|
||||||
<source>Download complete</source>
|
<source>Download complete</source>
|
||||||
<target state="translated">Herunterladen abgeschlossen</target>
|
<target state="translated">Download abgeschlossen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
<context context-type="linenumber">391</context>
|
<context context-type="linenumber">391</context>
|
||||||
@@ -4703,7 +4703,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8643601595923420698" datatype="html">
|
<trans-unit id="8643601595923420698" datatype="html">
|
||||||
<source>Retry download</source>
|
<source>Retry download</source>
|
||||||
<target state="translated">Herunterladen erneut versuchen</target>
|
<target state="translated">Download erneut versuchen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
<context context-type="linenumber">31</context>
|
<context context-type="linenumber">31</context>
|
||||||
@@ -4727,7 +4727,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5000203534763292992" datatype="html">
|
<trans-unit id="5000203534763292992" datatype="html">
|
||||||
<source>Download restarted!</source>
|
<source>Download restarted!</source>
|
||||||
<target state="translated">Herunterladen neu gestartet!</target>
|
<target state="translated">Download neu gestartet!</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
<context context-type="linenumber">72</context>
|
<context context-type="linenumber">72</context>
|
||||||
@@ -4783,7 +4783,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3ffd9490f3a4c0b24021d25e1dc71fcfe5d39cd6" datatype="html">
|
<trans-unit id="3ffd9490f3a4c0b24021d25e1dc71fcfe5d39cd6" datatype="html">
|
||||||
<source>Download error</source>
|
<source>Download error</source>
|
||||||
<target state="translated">Herunterladefehler</target>
|
<target state="translated">Downloadfehler</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
<context context-type="linenumber">392</context>
|
<context context-type="linenumber">392</context>
|
||||||
@@ -4941,6 +4941,206 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">No description</note>
|
<note priority="1" from="description">No description</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="4665451070906079743" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Favorisiert</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">65</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="56b1a3c93fb95fed1805005c561a5e431d57ffae" datatype="html">
|
||||||
|
<source>Blacklist all files</source>
|
||||||
|
<target state="translated">Alle Dateien blacklisten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">11</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa1b4779a515170b297d2c0507e6ff9d2e3e0e0" datatype="html">
|
||||||
|
<source>Blacklist deleted subscription files</source>
|
||||||
|
<target state="translated">Gelöschte Abo-Dateien blacklisten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">14</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted subscription files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c2faa86201eab08b5b39b5437f96ab9432e125e7" datatype="html">
|
||||||
|
<source>Item limit</source>
|
||||||
|
<target state="translated">Elementlimit</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Item limit</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="784837056777689544" datatype="html">
|
||||||
|
<source>Would you like to unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/>?</source>
|
||||||
|
<target state="translated">Möchtest Du dich von <x id="subscription name" equiv-text="this.sub['name']"/> abmelden?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d618f383a0ea2458eeb945a85190d4a002ea394b" datatype="html">
|
||||||
|
<source>Arg</source>
|
||||||
|
<target state="translated">Argument</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">41</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Arg</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0cfc9cfe7cd8ea14bc053693b28872da739af02c" datatype="html">
|
||||||
|
<source>See docs here.</source>
|
||||||
|
<target state="translated">Doku ansehen.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">375</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">382</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">392</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">402</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">409</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord API setting hint</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9e766e11a9de375907aaf566897ecc6dac393ebc" datatype="html">
|
||||||
|
<source>Webhook URL</source>
|
||||||
|
<target state="translated">Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">366</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b770c48628d98cb4633d6a17e3f0ba0265376af5" datatype="html">
|
||||||
|
<source>Gotify app token</source>
|
||||||
|
<target state="translated">Gotify app token</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">407</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify app token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3e420c675b8f3f3702576d52e8bb6e8e1d3feda0" datatype="html">
|
||||||
|
<source>How do I get the chat ID?</source>
|
||||||
|
<target state="translated">Wie bekomme ich die Chat ID?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">426</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID help</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="06f503e492d6dbcf59e7b9c412ca86913d718689" datatype="html">
|
||||||
|
<source>ntfy topic URL</source>
|
||||||
|
<target state="translated">ntfy Themen URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">390</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ntfy topic URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5827fde8fcafdd55ae80921ad3ad4aa01012e203" datatype="html">
|
||||||
|
<source>Use gotify API</source>
|
||||||
|
<target state="translated">gotify API verwenden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">396</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use gotify API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="55f559d6f666b945479f534b0c182f70cd0a8a69" datatype="html">
|
||||||
|
<source>Gotify server URL</source>
|
||||||
|
<target state="translated">Gotify Server URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">400</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify server URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="144e1a21ebe8fa238f88d2ac27515ed711cfc9a0" datatype="html">
|
||||||
|
<source>Telegram chat ID</source>
|
||||||
|
<target state="translated">Telegram chat ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">424</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2481374649045841364" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
||||||
|
<target state="translated">Möchtest du <x id="category name" equiv-text="category['name']"/> löschen?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">159</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3371159074051387771" datatype="html">
|
||||||
|
<source>Failed to delete <x id="category name" equiv-text="category['name']"/>!</source>
|
||||||
|
<target state="translated">Löschen von <x id="category name" equiv-text="category['name']"/> fehlgeschlagen!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8336047719608684263" datatype="html">
|
||||||
|
<source>Unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/></source>
|
||||||
|
<target state="translated">Von <x id="subscription name" equiv-text="this.sub['name']"/> abmelden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="37469c9f3e31d95087fa22b6c9c3bc64adf1692d" datatype="html">
|
||||||
|
<source>Enable RSS Feed</source>
|
||||||
|
<target state="translated">RSS Feed aktivieren</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">271</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable RSS Feed setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3264d82792954815be755b3da01e2625458711dc" datatype="html">
|
||||||
|
<source>Discord Webhook URL</source>
|
||||||
|
<target state="translated">Discord Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">373</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7cedb649779673568447b994463b2882c4e0436a" datatype="html">
|
||||||
|
<source>Slack Webhook URL</source>
|
||||||
|
<target state="translated">Slack Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">380</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Slack Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c1bf02206fbc371ff69ab1b7e35a17ba29d169d" datatype="html">
|
||||||
|
<source>Use ntfy API</source>
|
||||||
|
<target state="translated">ntfy API verwenden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">386</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use ntfy API setting</note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -4802,7 +4802,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2481374649045841364" datatype="html">
|
<trans-unit id="2481374649045841364" datatype="html">
|
||||||
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
||||||
<target state="needs-translation">Apakah Anda ingin menghapus <x id="category name" equiv-text="category['name']"/>?</target>
|
<target state="translated">Apakah Anda ingin menghapus <x id="category name" equiv-text="category['name']"/>?</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">159</context>
|
<context context-type="linenumber">159</context>
|
||||||
@@ -5026,6 +5026,70 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Telegram chat ID</note>
|
<note priority="1" from="description">Telegram chat ID</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="af30e51aa8b67e1133a341ec28359be05150e65c" datatype="html">
|
||||||
|
<source>No description available.</source>
|
||||||
|
<target state="translated">Tidak ada deskripsi.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/player/player.component.html</context>
|
||||||
|
<context context-type="linenumber">25,27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No description</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e0a11fbea353b1ce1131161774e4a3e10bcb99b1" datatype="html">
|
||||||
|
<source>Large</source>
|
||||||
|
<target state="translated">Besar</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">44,46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Large</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b6399391e706e2d7b7b7880eb5630e4e6f49728c" datatype="html">
|
||||||
|
<source>Side</source>
|
||||||
|
<target state="translated">Samping</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">35,37</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Side</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1236604279860679031" datatype="html">
|
||||||
|
<source>Restart</source>
|
||||||
|
<target state="translated">Mulai ulang</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9042260521669277115" datatype="html">
|
||||||
|
<source>Pause</source>
|
||||||
|
<target state="translated">Jeda</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">68</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7182974689040833178" datatype="html">
|
||||||
|
<source>Resume</source>
|
||||||
|
<target state="translated">Lanjutkan</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">74</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="338b44701a53ce3ef2f36abfb56f89c3edfa9eab" datatype="html">
|
||||||
|
<source>Over</source>
|
||||||
|
<target state="translated">Lebih</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">32,34</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Over</note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -4119,6 +4119,963 @@
|
|||||||
<context context-type="linenumber">58</context>
|
<context context-type="linenumber">58</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="ea2b65121b93921fe54692025da9b9e3ce779ad5" datatype="html">
|
||||||
|
<source>Task settings - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></source>
|
||||||
|
<target state="translated">Impostazioni attività - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Task settings</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3264d82792954815be755b3da01e2625458711dc" datatype="html">
|
||||||
|
<source>Discord Webhook URL</source>
|
||||||
|
<target state="translated">URL webhook Discord</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">373</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5827fde8fcafdd55ae80921ad3ad4aa01012e203" datatype="html">
|
||||||
|
<source>Use gotify API</source>
|
||||||
|
<target state="translated">Utilizza API gotify</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">396</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use gotify API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5000203534763292992" datatype="html">
|
||||||
|
<source>Download restarted!</source>
|
||||||
|
<target state="translated">Download riavviato!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8643601595923420698" datatype="html">
|
||||||
|
<source>Retry download</source>
|
||||||
|
<target state="translated">Riprova download</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6785427850041119037" datatype="html">
|
||||||
|
<source>Delete category</source>
|
||||||
|
<target state="translated">Elimina categoria</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">158</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3ffd9490f3a4c0b24021d25e1dc71fcfe5d39cd6" datatype="html">
|
||||||
|
<source>Download error</source>
|
||||||
|
<target state="translated">Errore nel download</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">359</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download error</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9176960997786930103" datatype="html">
|
||||||
|
<source>Error for: <x id="PH" equiv-text="task['title']"/></source>
|
||||||
|
<target state="translated">Errore per: <x id="PH" equiv-text="task['title']"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||||
|
<context context-type="linenumber">174</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="019d4bd6a5690f0cfa0ecf346a4e6bf7f0d8debb" datatype="html">
|
||||||
|
<source>Remove</source>
|
||||||
|
<target state="translated">Rimuovi</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.html</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Remove</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b770c48628d98cb4633d6a17e3f0ba0265376af5" datatype="html">
|
||||||
|
<source>Gotify app token</source>
|
||||||
|
<target state="translated">Token app Gotify</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">407</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify app token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="56b1a3c93fb95fed1805005c561a5e431d57ffae" datatype="html">
|
||||||
|
<source>Blacklist all files</source>
|
||||||
|
<target state="translated">Metti nella lista nera tutti i file</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">11</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6549265851868599441" datatype="html">
|
||||||
|
<source>Video</source>
|
||||||
|
<target state="translated">Video</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">40</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1d4fa01d25990f60abf21c3a451fa8ba262b7912" datatype="html">
|
||||||
|
<source>Unfavorite</source>
|
||||||
|
<target state="translated">Non preferito</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Unfavorite button</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1f2809e6a99d511fdb6eaf041d785fe54d0680cc" datatype="html">
|
||||||
|
<source>File card size</source>
|
||||||
|
<target state="translated">Dimensione carta file</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">42</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">File card size</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="28da11220a3377ddce3c7948825d33101f142782" datatype="html">
|
||||||
|
<source>Extractor</source>
|
||||||
|
<target state="translated">Estrattore</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">57</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Extractor</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="338b44701a53ce3ef2f36abfb56f89c3edfa9eab" datatype="html">
|
||||||
|
<source>Over</source>
|
||||||
|
<target state="translated">Sopra</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">32,34</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Over</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="378c072ce05889c9771718d05106e7685fcd3507" datatype="html">
|
||||||
|
<source>Medium</source>
|
||||||
|
<target state="translated">Media</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">47,49</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Medium</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9a865c2922f5c01899d06c472dba2e5bd63bcff9" datatype="html">
|
||||||
|
<source>Small</source>
|
||||||
|
<target state="translated">Piccola</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">50,52</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Small</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5a105e7bd7e7db6ea211fe950fc9f317379acceb" datatype="html">
|
||||||
|
<source>No notifications available</source>
|
||||||
|
<target state="translated">Nessuna notifica disponibile</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No notifications available</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0cfc9cfe7cd8ea14bc053693b28872da739af02c" datatype="html">
|
||||||
|
<source>See docs here.</source>
|
||||||
|
<target state="translated">Vedi la documentazione qui.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">375</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">382</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">392</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">402</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">409</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord API setting hint</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c1bf02206fbc371ff69ab1b7e35a17ba29d169d" datatype="html">
|
||||||
|
<source>Use ntfy API</source>
|
||||||
|
<target state="translated">Utilizza API ntfy</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">386</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use ntfy API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa62bf1a535a97a4d752bbc5cf1c31af0f0c1f7" datatype="html">
|
||||||
|
<source>Supports regex</source>
|
||||||
|
<target state="translated">Supporta espressioni regolari</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">10</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Supports regex</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4665451070906079743" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Preferito</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">65</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7cedb649779673568447b994463b2882c4e0436a" datatype="html">
|
||||||
|
<source>Slack Webhook URL</source>
|
||||||
|
<target state="translated">URL webhook Slack</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">380</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Slack Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b6399391e706e2d7b7b7880eb5630e4e6f49728c" datatype="html">
|
||||||
|
<source>Side</source>
|
||||||
|
<target state="translated">Laterale</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">35,37</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Side</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="144e1a21ebe8fa238f88d2ac27515ed711cfc9a0" datatype="html">
|
||||||
|
<source>Telegram chat ID</source>
|
||||||
|
<target state="translated">ID chat Telegram</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">424</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c150a30bbbdb175b4d08820196a9acb66b167653" datatype="html">
|
||||||
|
<source>Archives empty</source>
|
||||||
|
<target state="translated">Archivi vuoti</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives empty</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5947241266456580665" datatype="html">
|
||||||
|
<source>Download failed</source>
|
||||||
|
<target state="translated">Download non riuscito</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">18</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b78a98bc54259a29cf6250dbaeab5fe11fae91cf" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Preferito</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">51</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Favorited</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="51a161ce175abcd44f6c6cbd0e996681bf553ac3" datatype="html">
|
||||||
|
<source>Delete selected</source>
|
||||||
|
<target state="translated">Cancella selezionati</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">77</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete selected</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="35cf4cdcedc8ef3f94b6100e0d86836e31dbb908" datatype="html">
|
||||||
|
<source>Force autoplay</source>
|
||||||
|
<target state="translated">Forza l'auto-riproduzione</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">218</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Force autoplay setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3640026747176198246" datatype="html">
|
||||||
|
<source>Watch content</source>
|
||||||
|
<target state="translated">Guarda contenuto</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">50</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="a2f14a73f7a6e94479f67423cc51102da8d6f524" datatype="html">
|
||||||
|
<source>None</source>
|
||||||
|
<target state="translated">Nessuno</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">84</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">126</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">36</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">None</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="06f503e492d6dbcf59e7b9c412ca86913d718689" datatype="html">
|
||||||
|
<source>ntfy topic URL</source>
|
||||||
|
<target state="translated">URL argomento ntfy</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">390</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ntfy topic URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
|
||||||
|
<source>User</source>
|
||||||
|
<target state="translated">Utente</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">User</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c41475a25c9f9d9639db9efa56637603a77528b4" datatype="html">
|
||||||
|
<source>Download archive</source>
|
||||||
|
<target state="translated">Scarica archivio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download archive</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8224301330941792118" datatype="html">
|
||||||
|
<source>Failed to delete archive items!</source>
|
||||||
|
<target state="translated">Impossibile eliminare l'archivio/i!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">174</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="33a7c6d5ff3515fa237f1fd4e43df8b65373954d" datatype="html">
|
||||||
|
<source>Enable all notifications</source>
|
||||||
|
<target state="translated">Abilita tutte le notifiche</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">352</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable all notifications setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8425787787095143143" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archive(s)?</source>
|
||||||
|
<target state="translated">Desideri eliminare <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archivio/i?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">153</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="11a0771f88158a540a54e0e4ec5d25733d65fc0e" datatype="html">
|
||||||
|
<source>Favorite</source>
|
||||||
|
<target state="translated">Preferito</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Favorite button</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2525880134753073592" datatype="html">
|
||||||
|
<source>Successfully deleted archive items!</source>
|
||||||
|
<target state="translated">Archivio/i eliminato/i con successo!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c65dd978b3c7566551c0ebefb234c2d41942b847" datatype="html">
|
||||||
|
<source>Delete files older than</source>
|
||||||
|
<target state="translated">Elimina file più vecchi di</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">6</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete files older than</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1698114086921246480" datatype="html">
|
||||||
|
<source>Unsubscribe</source>
|
||||||
|
<target state="translated">Annulla iscrizione</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d57c023a4cf63b2f12c10328c15b636ff18929aa" datatype="html">
|
||||||
|
<source>Best</source>
|
||||||
|
<target state="translated">Migliore</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/main/main.component.html</context>
|
||||||
|
<context context-type="linenumber">24,25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Best</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c5dc5fbcce45e9b1530e2a5c2baa8ebe722aef4c" datatype="html">
|
||||||
|
<source>Download complete</source>
|
||||||
|
<target state="translated">Download completato</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">358</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download complete</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5709555629190115111" datatype="html">
|
||||||
|
<source>View task</source>
|
||||||
|
<target state="translated">Visualizza attività</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">33</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7410432243549869948" datatype="html">
|
||||||
|
<source>Duration</source>
|
||||||
|
<target state="translated">Durata</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">29</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7332320960988475089" datatype="html">
|
||||||
|
<source>Successfully deleted <x id="category name" equiv-text="category['name']"/>!</source>
|
||||||
|
<target state="translated">Categoria <x id="category name" equiv-text="category['name']"/> eliminata con successo!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">168</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8336047719608684263" datatype="html">
|
||||||
|
<source>Unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/></source>
|
||||||
|
<target state="translated">Annulla l'iscrizione da <x id="subscription name" equiv-text="this.sub['name']"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3371159074051387771" datatype="html">
|
||||||
|
<source>Failed to delete <x id="category name" equiv-text="category['name']"/>!</source>
|
||||||
|
<target state="translated">Impossibile eliminare la categoria <x id="category name" equiv-text="category['name']"/>!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c748ac656af9f13998206ef2c52018dd418b0483" datatype="html">
|
||||||
|
<source>Archives</source>
|
||||||
|
<target state="translated">Archivi</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives menu label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8443034725057696949" datatype="html">
|
||||||
|
<source>Task finished</source>
|
||||||
|
<target state="translated">Attività completata</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2361a4f76caaa4574803fbcdca8b0a47c91cc7ed" datatype="html">
|
||||||
|
<source>Task finished</source>
|
||||||
|
<target state="translated">Attività completata</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">360</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Task finished</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1a9b415816364f554ee411020e65219092655271" datatype="html">
|
||||||
|
<source>Title filter</source>
|
||||||
|
<target state="translated">Filtro titolo</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">8</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Title filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e0a11fbea353b1ce1131161774e4a3e10bcb99b1" datatype="html">
|
||||||
|
<source>Large</source>
|
||||||
|
<target state="translated">Grande</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">44,46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Large</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="674a999dd48d7da565ffdd105602261b8a4761ea" datatype="html">
|
||||||
|
<source>Download zip</source>
|
||||||
|
<target state="translated">Scarica zip</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscription/subscription/subscription.component.html</context>
|
||||||
|
<context context-type="linenumber">18</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download zip</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="55f559d6f666b945479f534b0c182f70cd0a8a69" datatype="html">
|
||||||
|
<source>Gotify server URL</source>
|
||||||
|
<target state="translated">URL server Gotify</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">400</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify server URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9c562d26e041390ecc3f49dabc51cc50ebba7469" datatype="html">
|
||||||
|
<source>Allowed notification types</source>
|
||||||
|
<target state="translated">Tipi di notifiche consentiti</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">356</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Allowed notification types</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7b4585a9072f3c1292972c14a3d0e14978fbfc9c" datatype="html">
|
||||||
|
<source>Delete old files:</source>
|
||||||
|
<target state="translated">Elimina vecchi file:</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||||
|
<context context-type="linenumber">66</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete old files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6219551536751479443" datatype="html">
|
||||||
|
<source>Finished downloading</source>
|
||||||
|
<target state="translated">Download completato</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6268070779441507380" datatype="html">
|
||||||
|
<source>Download Date</source>
|
||||||
|
<target state="translated">Data download</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">13</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2481374649045841364" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
||||||
|
<target state="translated">Desideri eliminare <x id="category name" equiv-text="category['name']"/>?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">159</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="eeb0ba2e4743901d8f5eebd9a3529aa1f236c608" datatype="html">
|
||||||
|
<source>Create bot here.</source>
|
||||||
|
<target state="translated">Crea il bot qui.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">419</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram bot create link</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6437411876967154040" datatype="html">
|
||||||
|
<source>Audio only</source>
|
||||||
|
<target state="translated">Solo audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6080b77234e92ad41bb52653b239c4c4f851317d" datatype="html">
|
||||||
|
<source>Error</source>
|
||||||
|
<target state="translated">Errore</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||||
|
<context context-type="linenumber">39</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Error</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8456659390937171831" datatype="html">
|
||||||
|
<source>Show error</source>
|
||||||
|
<target state="translated">Mostra errore</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">56</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4b3972c3e9485218508a95f7a4ce7758e3f09ced" datatype="html">
|
||||||
|
<source>Upload</source>
|
||||||
|
<target state="translated">Carica</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">137</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/cookies-uploader-dialog/cookies-uploader-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Upload</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="37469c9f3e31d95087fa22b6c9c3bc64adf1692d" datatype="html">
|
||||||
|
<source>Enable RSS Feed</source>
|
||||||
|
<target state="translated">Abilita feed RSS</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">271</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable RSS Feed setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1236604279860679031" datatype="html">
|
||||||
|
<source>Restart</source>
|
||||||
|
<target state="translated">Riavvia</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8bcabdf6b16cad0313a86c7e940c5e3ad7f9f8ab" datatype="html">
|
||||||
|
<source>Notifications</source>
|
||||||
|
<target state="translated">Notifiche</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">343</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Notifications settings label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="784837056777689544" datatype="html">
|
||||||
|
<source>Would you like to unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/>?</source>
|
||||||
|
<target state="translated">Desideri annullare l'iscrizione da <x id="subscription name" equiv-text="this.sub['name']"/>?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1091872159779006651" datatype="html">
|
||||||
|
<source>You must input a time!</source>
|
||||||
|
<target state="translated">Devi inserire un tempo!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">70</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0ed98b4c6ec1db6708a963e8a2699478ac97f55c" datatype="html">
|
||||||
|
<source>Add subscription</source>
|
||||||
|
<target state="translated">Aggiungi abbonamento</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscriptions/subscriptions.component.html</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Add subscription</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="61d6b5fa4311b1c617b66dad72496f9dd43b07b4" datatype="html">
|
||||||
|
<source>Be careful enabling this with multi-user mode! User data may be exposed.</source>
|
||||||
|
<target state="translated">Attenzione all'abilitazione in modalità multiutente! I dati dell'utente potrebbero essere esposti.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">272</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS Feed prefix</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3533826530554274875" datatype="html">
|
||||||
|
<source>Upload Date</source>
|
||||||
|
<target state="translated">Data upload</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="347407180135731058" datatype="html">
|
||||||
|
<source>Audio</source>
|
||||||
|
<target state="translated">Audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">44</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="cdf5297d8d080a78e8b10debc5c38b7845a3cbe7" datatype="html">
|
||||||
|
<source>Do not ask for confirmation</source>
|
||||||
|
<target state="translated">Non chiedere conferma</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Do not ask for confirmation</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c2faa86201eab08b5b39b5437f96ab9432e125e7" datatype="html">
|
||||||
|
<source>Item limit</source>
|
||||||
|
<target state="translated">Limite elementi</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Item limit</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7022070615528435141" datatype="html">
|
||||||
|
<source>Delete</source>
|
||||||
|
<target state="translated">Elimina</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">154</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">160</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9e766e11a9de375907aaf566897ecc6dac393ebc" datatype="html">
|
||||||
|
<source>Webhook URL</source>
|
||||||
|
<target state="translated">URL webhook</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">366</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2e076ff9866213d0815961c494aa48b177046b9d" datatype="html">
|
||||||
|
<source>Telegram bot token</source>
|
||||||
|
<target state="translated">Token bot Telegram</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">417</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram bot token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d618f383a0ea2458eeb945a85190d4a002ea394b" datatype="html">
|
||||||
|
<source>Arg</source>
|
||||||
|
<target state="translated">Argomento</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">41</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Arg</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1879058637439215882" datatype="html">
|
||||||
|
<source>Download error</source>
|
||||||
|
<target state="translated">Errore nel download</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953483585652369683" datatype="html">
|
||||||
|
<source>Archive successfully imported!</source>
|
||||||
|
<target state="translated">Archivio importato con successo!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">130</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7911845622864460134" datatype="html">
|
||||||
|
<source>Video only</source>
|
||||||
|
<target state="translated">Solo video</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">55</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="38992954440d6afb54aeb58af12ca0123ee5e26e" datatype="html">
|
||||||
|
<source>Use Telegram API</source>
|
||||||
|
<target state="translated">Utilizza API Telegram</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">413</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use Telegram API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6876310993601590130" datatype="html">
|
||||||
|
<source>Download completed</source>
|
||||||
|
<target state="translated">Download completato</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4578192247039196794" datatype="html">
|
||||||
|
<source>Task</source>
|
||||||
|
<target state="translated">Attività</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ac5a0e5ffe8e5623b40696f4c2403c17349271f" datatype="html">
|
||||||
|
<source>Sidepanel mode</source>
|
||||||
|
<target state="translated">Modalità pannello laterale</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Sidepanel mode</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8571838164752006148" datatype="html">
|
||||||
|
<source>View error</source>
|
||||||
|
<target state="translated">Visualizza errore</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa1b4779a515170b297d2c0507e6ff9d2e3e0e0" datatype="html">
|
||||||
|
<source>Blacklist deleted subscription files</source>
|
||||||
|
<target state="translated">Metti nella lista nera i file di abbonamenti eliminati</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">14</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted subscription files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9042260521669277115" datatype="html">
|
||||||
|
<source>Pause</source>
|
||||||
|
<target state="translated">Metti in pausa</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">68</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="45cc8ca94b5a50842a9a8ef804a5ab089a38ae5c" datatype="html">
|
||||||
|
<source>ID</source>
|
||||||
|
<target state="translated">ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">47</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c6e24eab969d9f63a8a0e9d617aee3b99e28ae6" datatype="html">
|
||||||
|
<source>Play all</source>
|
||||||
|
<target state="translated">Riproduci tutto</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscription/subscription/subscription.component.html</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Play all</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3e420c675b8f3f3702576d52e8bb6e8e1d3feda0" datatype="html">
|
||||||
|
<source>How do I get the chat ID?</source>
|
||||||
|
<target state="translated">Come posso ottenere l'ID chat?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">426</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID help</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7182974689040833178" datatype="html">
|
||||||
|
<source>Resume</source>
|
||||||
|
<target state="translated">Riprendi</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">74</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8564202903947049539" datatype="html">
|
||||||
|
<source>Play</source>
|
||||||
|
<target state="translated">Riproduci</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="a4ed8eba1e057e67d5c2d87b52230f182b3dae4e" datatype="html">
|
||||||
|
<source>Restart required.</source>
|
||||||
|
<target state="translated">Riavvio richiesto.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">446</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Restart required hint</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3159807825117518005" datatype="html">
|
||||||
|
<source>Delete archives</source>
|
||||||
|
<target state="translated">Elimina archivi</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">152</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c35ef0f03a863d33b04aae6807f140397a50f491" datatype="html">
|
||||||
|
<source>Generate RSS URL</source>
|
||||||
|
<target state="translated">Genera URL RSS</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">273</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Generate RSS URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953033926734869941" datatype="html">
|
||||||
|
<source>Name</source>
|
||||||
|
<target state="translated">Nome</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">21</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ca707824ab93066c7d9b44e1b8bf216725c2c22" datatype="html">
|
||||||
|
<source>Filter</source>
|
||||||
|
<target state="translated">Filtra</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">3</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c40370dc182b5e4333828b70f7478bde58bb5cfe" datatype="html">
|
||||||
|
<source>Enable notifications</source>
|
||||||
|
<target state="translated">Abilita notifiche</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">349</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable notifications setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2492098975665776610" datatype="html">
|
||||||
|
<source>File Size</source>
|
||||||
|
<target state="translated">Dimensione file</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="af30e51aa8b67e1133a341ec28359be05150e65c" datatype="html">
|
||||||
|
<source>No description available.</source>
|
||||||
|
<target state="translated">Nessuna descrizione disponibile.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/player/player.component.html</context>
|
||||||
|
<context context-type="linenumber">25,27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No description</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="fd467148a18f0921c10d116d4e0174fe29452be4" datatype="html">
|
||||||
|
<source>See documentation here.</source>
|
||||||
|
<target state="translated">Vedi la documentazione qui.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">274</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS feed documentation</note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4142,6 +4142,963 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Video resolution property</note>
|
<note priority="1" from="description">Video resolution property</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="a2f14a73f7a6e94479f67423cc51102da8d6f524" datatype="html">
|
||||||
|
<source>None</source>
|
||||||
|
<target state="translated">Geen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">84</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">126</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">36</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">None</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ca707824ab93066c7d9b44e1b8bf216725c2c22" datatype="html">
|
||||||
|
<source>Filter</source>
|
||||||
|
<target state="translated">Filter</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">3</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6080b77234e92ad41bb52653b239c4c4f851317d" datatype="html">
|
||||||
|
<source>Error</source>
|
||||||
|
<target state="translated">Fout</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||||
|
<context context-type="linenumber">39</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Error</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3640026747176198246" datatype="html">
|
||||||
|
<source>Watch content</source>
|
||||||
|
<target state="translated">Inhoud bekijken</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">50</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c150a30bbbdb175b4d08820196a9acb66b167653" datatype="html">
|
||||||
|
<source>Archives empty</source>
|
||||||
|
<target state="translated">Archieven leeg</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives empty</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8571838164752006148" datatype="html">
|
||||||
|
<source>View error</source>
|
||||||
|
<target state="translated">Toon foutmelding</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5709555629190115111" datatype="html">
|
||||||
|
<source>View task</source>
|
||||||
|
<target state="translated">Toon taak</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">33</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b78a98bc54259a29cf6250dbaeab5fe11fae91cf" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Favorieten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">51</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Favorited</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ac5a0e5ffe8e5623b40696f4c2403c17349271f" datatype="html">
|
||||||
|
<source>Sidepanel mode</source>
|
||||||
|
<target state="translated">Zijpaneel-modus</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Sidepanel mode</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c1bf02206fbc371ff69ab1b7e35a17ba29d169d" datatype="html">
|
||||||
|
<source>Use ntfy API</source>
|
||||||
|
<target state="translated">Gebruik ntfy API</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">386</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use ntfy API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0ed98b4c6ec1db6708a963e8a2699478ac97f55c" datatype="html">
|
||||||
|
<source>Add subscription</source>
|
||||||
|
<target state="translated">Abonnement toevoegen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscriptions/subscriptions.component.html</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Add subscription</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9a865c2922f5c01899d06c472dba2e5bd63bcff9" datatype="html">
|
||||||
|
<source>Small</source>
|
||||||
|
<target state="translated">Klein</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">50,52</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Small</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c748ac656af9f13998206ef2c52018dd418b0483" datatype="html">
|
||||||
|
<source>Archives</source>
|
||||||
|
<target state="translated">Archieven</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives menu label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="45cc8ca94b5a50842a9a8ef804a5ab089a38ae5c" datatype="html">
|
||||||
|
<source>ID</source>
|
||||||
|
<target state="translated">ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">47</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="28da11220a3377ddce3c7948825d33101f142782" datatype="html">
|
||||||
|
<source>Extractor</source>
|
||||||
|
<target state="translated">Extractor</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">57</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Extractor</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="51a161ce175abcd44f6c6cbd0e996681bf553ac3" datatype="html">
|
||||||
|
<source>Delete selected</source>
|
||||||
|
<target state="translated">Verwijder geselecteerde</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">77</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete selected</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c41475a25c9f9d9639db9efa56637603a77528b4" datatype="html">
|
||||||
|
<source>Download archive</source>
|
||||||
|
<target state="translated">Archief downloaden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download archive</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4b3972c3e9485218508a95f7a4ce7758e3f09ced" datatype="html">
|
||||||
|
<source>Upload</source>
|
||||||
|
<target state="translated">Uploaden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">137</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/cookies-uploader-dialog/cookies-uploader-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Upload</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6549265851868599441" datatype="html">
|
||||||
|
<source>Video</source>
|
||||||
|
<target state="translated">Video</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">40</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="347407180135731058" datatype="html">
|
||||||
|
<source>Audio</source>
|
||||||
|
<target state="translated">Audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">44</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953483585652369683" datatype="html">
|
||||||
|
<source>Archive successfully imported!</source>
|
||||||
|
<target state="translated">Archief succesvol geïmporteerd!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">130</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3159807825117518005" datatype="html">
|
||||||
|
<source>Delete archives</source>
|
||||||
|
<target state="translated">Archieven verwijderen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">152</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8425787787095143143" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archive(s)?</source>
|
||||||
|
<target state="translated">Wilt u <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archieven verwijderen?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">153</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7022070615528435141" datatype="html">
|
||||||
|
<source>Delete</source>
|
||||||
|
<target state="translated">Verwijderen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">154</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">160</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2525880134753073592" datatype="html">
|
||||||
|
<source>Successfully deleted archive items!</source>
|
||||||
|
<target state="translated">Archiefstukken succesvol verwijderd!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8224301330941792118" datatype="html">
|
||||||
|
<source>Failed to delete archive items!</source>
|
||||||
|
<target state="translated">Archiefstukken verwijderen mislukt!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">174</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8443034725057696949" datatype="html">
|
||||||
|
<source>Task finished</source>
|
||||||
|
<target state="translated">Taak voltooid</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6219551536751479443" datatype="html">
|
||||||
|
<source>Finished downloading</source>
|
||||||
|
<target state="translated">Downloaden voltooid</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5947241266456580665" datatype="html">
|
||||||
|
<source>Download failed</source>
|
||||||
|
<target state="translated">Download mislukt</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">18</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8564202903947049539" datatype="html">
|
||||||
|
<source>Play</source>
|
||||||
|
<target state="translated">Afspelen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8643601595923420698" datatype="html">
|
||||||
|
<source>Retry download</source>
|
||||||
|
<target state="translated">Download opnieuw proberen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1879058637439215882" datatype="html">
|
||||||
|
<source>Download error</source>
|
||||||
|
<target state="translated">Download fout</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4578192247039196794" datatype="html">
|
||||||
|
<source>Task</source>
|
||||||
|
<target state="translated">Taak</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5a105e7bd7e7db6ea211fe950fc9f317379acceb" datatype="html">
|
||||||
|
<source>No notifications available</source>
|
||||||
|
<target state="translated">Geen notificaties beschikbaar</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No notifications available</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6876310993601590130" datatype="html">
|
||||||
|
<source>Download completed</source>
|
||||||
|
<target state="translated">Download voltooid</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6437411876967154040" datatype="html">
|
||||||
|
<source>Audio only</source>
|
||||||
|
<target state="translated">Alleen audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7911845622864460134" datatype="html">
|
||||||
|
<source>Video only</source>
|
||||||
|
<target state="translated">Alleen video</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">55</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4665451070906079743" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Favoriet</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">65</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6268070779441507380" datatype="html">
|
||||||
|
<source>Download Date</source>
|
||||||
|
<target state="translated">Downloaddatum</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">13</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953033926734869941" datatype="html">
|
||||||
|
<source>Name</source>
|
||||||
|
<target state="translated">Naam</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">21</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2492098975665776610" datatype="html">
|
||||||
|
<source>File Size</source>
|
||||||
|
<target state="translated">Bestandsgrootte</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7410432243549869948" datatype="html">
|
||||||
|
<source>Duration</source>
|
||||||
|
<target state="translated">Duur</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">29</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c65dd978b3c7566551c0ebefb234c2d41942b847" datatype="html">
|
||||||
|
<source>Delete files older than</source>
|
||||||
|
<target state="translated">Verwijder bestanden ouder dan</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">6</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete files older than</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3533826530554274875" datatype="html">
|
||||||
|
<source>Upload Date</source>
|
||||||
|
<target state="translated">Uploaddatum</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa1b4779a515170b297d2c0507e6ff9d2e3e0e0" datatype="html">
|
||||||
|
<source>Blacklist deleted subscription files</source>
|
||||||
|
<target state="translated">Verwijderde abonnementsbestanden op de zwarte lijst zetten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">14</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted subscription files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="cdf5297d8d080a78e8b10debc5c38b7845a3cbe7" datatype="html">
|
||||||
|
<source>Do not ask for confirmation</source>
|
||||||
|
<target state="translated">Niet om bevestiging vragen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Do not ask for confirmation</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="56b1a3c93fb95fed1805005c561a5e431d57ffae" datatype="html">
|
||||||
|
<source>Blacklist all files</source>
|
||||||
|
<target state="translated">Alle bestanden op de zwarte lijst zetten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">11</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9176960997786930103" datatype="html">
|
||||||
|
<source>Error for: <x id="PH" equiv-text="task['title']"/></source>
|
||||||
|
<target state="translated">Fout voor: <x id="PH" equiv-text="task['title']"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||||
|
<context context-type="linenumber">174</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="11a0771f88158a540a54e0e4ec5d25733d65fc0e" datatype="html">
|
||||||
|
<source>Favorite</source>
|
||||||
|
<target state="translated">Favoriet</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Favorite button</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1d4fa01d25990f60abf21c3a451fa8ba262b7912" datatype="html">
|
||||||
|
<source>Unfavorite</source>
|
||||||
|
<target state="translated">Verwijder uit favorieten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Unfavorite button</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1f2809e6a99d511fdb6eaf041d785fe54d0680cc" datatype="html">
|
||||||
|
<source>File card size</source>
|
||||||
|
<target state="translated">Bestandskaart grootte</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">42</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">File card size</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d618f383a0ea2458eeb945a85190d4a002ea394b" datatype="html">
|
||||||
|
<source>Arg</source>
|
||||||
|
<target state="translated">Optie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">41</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Arg</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
|
||||||
|
<source>User</source>
|
||||||
|
<target state="translated">Gebruiker</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">User</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c35ef0f03a863d33b04aae6807f140397a50f491" datatype="html">
|
||||||
|
<source>Generate RSS URL</source>
|
||||||
|
<target state="translated">RSS-URL genereren</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">273</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Generate RSS URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="35cf4cdcedc8ef3f94b6100e0d86836e31dbb908" datatype="html">
|
||||||
|
<source>Force autoplay</source>
|
||||||
|
<target state="translated">Automatisch afspelen forceren</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">218</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Force autoplay setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="61d6b5fa4311b1c617b66dad72496f9dd43b07b4" datatype="html">
|
||||||
|
<source>Be careful enabling this with multi-user mode! User data may be exposed.</source>
|
||||||
|
<target state="translated">Wees voorzichtig als je dit aanzet samen met de modus voor meerdere gebruikers! Gebruikersdata kunnen blootgesteld worden.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">272</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS Feed prefix</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="fd467148a18f0921c10d116d4e0174fe29452be4" datatype="html">
|
||||||
|
<source>See documentation here.</source>
|
||||||
|
<target state="translated">Zie documentatie hier.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">274</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS feed documentation</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9c562d26e041390ecc3f49dabc51cc50ebba7469" datatype="html">
|
||||||
|
<source>Allowed notification types</source>
|
||||||
|
<target state="translated">Toegestane typen notificaties</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">356</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Allowed notification types</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="33a7c6d5ff3515fa237f1fd4e43df8b65373954d" datatype="html">
|
||||||
|
<source>Enable all notifications</source>
|
||||||
|
<target state="translated">Alle notificaties inschakelen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">352</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable all notifications setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9e766e11a9de375907aaf566897ecc6dac393ebc" datatype="html">
|
||||||
|
<source>Webhook URL</source>
|
||||||
|
<target state="translated">Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">366</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="55f559d6f666b945479f534b0c182f70cd0a8a69" datatype="html">
|
||||||
|
<source>Gotify server URL</source>
|
||||||
|
<target state="translated">Gotify server URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">400</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify server URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="eeb0ba2e4743901d8f5eebd9a3529aa1f236c608" datatype="html">
|
||||||
|
<source>Create bot here.</source>
|
||||||
|
<target state="translated">Bot hier maken.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">419</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram bot create link</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c6e24eab969d9f63a8a0e9d617aee3b99e28ae6" datatype="html">
|
||||||
|
<source>Play all</source>
|
||||||
|
<target state="translated">Alles afspelen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscription/subscription/subscription.component.html</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Play all</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7cedb649779673568447b994463b2882c4e0436a" datatype="html">
|
||||||
|
<source>Slack Webhook URL</source>
|
||||||
|
<target state="translated">Slack Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">380</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Slack Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="a4ed8eba1e057e67d5c2d87b52230f182b3dae4e" datatype="html">
|
||||||
|
<source>Restart required.</source>
|
||||||
|
<target state="translated">Opnieuw starten vereist.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">446</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Restart required hint</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3e420c675b8f3f3702576d52e8bb6e8e1d3feda0" datatype="html">
|
||||||
|
<source>How do I get the chat ID?</source>
|
||||||
|
<target state="translated">Hoe kan ik het chat ID krijgen?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">426</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID help</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8456659390937171831" datatype="html">
|
||||||
|
<source>Show error</source>
|
||||||
|
<target state="translated">Toon fout</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">56</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1236604279860679031" datatype="html">
|
||||||
|
<source>Restart</source>
|
||||||
|
<target state="translated">Herstarten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9042260521669277115" datatype="html">
|
||||||
|
<source>Pause</source>
|
||||||
|
<target state="translated">Pauzeren</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">68</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7182974689040833178" datatype="html">
|
||||||
|
<source>Resume</source>
|
||||||
|
<target state="translated">Hervatten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">74</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="019d4bd6a5690f0cfa0ecf346a4e6bf7f0d8debb" datatype="html">
|
||||||
|
<source>Remove</source>
|
||||||
|
<target state="translated">Verwijderen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.html</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Remove</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5000203534763292992" datatype="html">
|
||||||
|
<source>Download restarted!</source>
|
||||||
|
<target state="translated">Download herstart!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="ea2b65121b93921fe54692025da9b9e3ce779ad5" datatype="html">
|
||||||
|
<source>Task settings - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></source>
|
||||||
|
<target state="translated">Taakinstellingen - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Task settings</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7b4585a9072f3c1292972c14a3d0e14978fbfc9c" datatype="html">
|
||||||
|
<source>Delete old files:</source>
|
||||||
|
<target state="translated">Verwijder oude bestanden:</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||||
|
<context context-type="linenumber">66</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete old files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1a9b415816364f554ee411020e65219092655271" datatype="html">
|
||||||
|
<source>Title filter</source>
|
||||||
|
<target state="translated">Titelfilter</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">8</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Title filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa62bf1a535a97a4d752bbc5cf1c31af0f0c1f7" datatype="html">
|
||||||
|
<source>Supports regex</source>
|
||||||
|
<target state="translated">Ondersteunt regex</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">10</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Supports regex</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c2faa86201eab08b5b39b5437f96ab9432e125e7" datatype="html">
|
||||||
|
<source>Item limit</source>
|
||||||
|
<target state="translated">Item limiet</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Item limit</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8336047719608684263" datatype="html">
|
||||||
|
<source>Unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/></source>
|
||||||
|
<target state="translated">Afmelden van <x id="subscription name" equiv-text="this.sub['name']"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="784837056777689544" datatype="html">
|
||||||
|
<source>Would you like to unsubscribe from <x id="subscription name" equiv-text="this.sub['name']"/>?</source>
|
||||||
|
<target state="translated">Wil je afmelden van <x id="subscription name" equiv-text="this.sub['name']"/>?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1698114086921246480" datatype="html">
|
||||||
|
<source>Unsubscribe</source>
|
||||||
|
<target state="translated">Afmelden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1091872159779006651" datatype="html">
|
||||||
|
<source>You must input a time!</source>
|
||||||
|
<target state="translated">Je moet een tijd invoeren!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">70</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="338b44701a53ce3ef2f36abfb56f89c3edfa9eab" datatype="html">
|
||||||
|
<source>Over</source>
|
||||||
|
<target state="translated">Over</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">32,34</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Over</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b6399391e706e2d7b7b7880eb5630e4e6f49728c" datatype="html">
|
||||||
|
<source>Side</source>
|
||||||
|
<target state="translated">Zijkant</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">35,37</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Side</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e0a11fbea353b1ce1131161774e4a3e10bcb99b1" datatype="html">
|
||||||
|
<source>Large</source>
|
||||||
|
<target state="translated">Groot</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">44,46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Large</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d57c023a4cf63b2f12c10328c15b636ff18929aa" datatype="html">
|
||||||
|
<source>Best</source>
|
||||||
|
<target state="translated">Beste</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/main/main.component.html</context>
|
||||||
|
<context context-type="linenumber">24,25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Best</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="af30e51aa8b67e1133a341ec28359be05150e65c" datatype="html">
|
||||||
|
<source>No description available.</source>
|
||||||
|
<target state="translated">Geen beschrijving beschikbaar.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/player/player.component.html</context>
|
||||||
|
<context context-type="linenumber">25,27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No description</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c40370dc182b5e4333828b70f7478bde58bb5cfe" datatype="html">
|
||||||
|
<source>Enable notifications</source>
|
||||||
|
<target state="translated">Notificaties inschakelen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">349</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable notifications setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8bcabdf6b16cad0313a86c7e940c5e3ad7f9f8ab" datatype="html">
|
||||||
|
<source>Notifications</source>
|
||||||
|
<target state="translated">Notificaties</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">343</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Notifications settings label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c5dc5fbcce45e9b1530e2a5c2baa8ebe722aef4c" datatype="html">
|
||||||
|
<source>Download complete</source>
|
||||||
|
<target state="translated">Download voltooid</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">358</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download complete</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3ffd9490f3a4c0b24021d25e1dc71fcfe5d39cd6" datatype="html">
|
||||||
|
<source>Download error</source>
|
||||||
|
<target state="translated">Downloadfout</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">359</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download error</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2361a4f76caaa4574803fbcdca8b0a47c91cc7ed" datatype="html">
|
||||||
|
<source>Task finished</source>
|
||||||
|
<target state="translated">Taak voltooid</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">360</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Task finished</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3264d82792954815be755b3da01e2625458711dc" datatype="html">
|
||||||
|
<source>Discord Webhook URL</source>
|
||||||
|
<target state="translated">Discord Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">373</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0cfc9cfe7cd8ea14bc053693b28872da739af02c" datatype="html">
|
||||||
|
<source>See docs here.</source>
|
||||||
|
<target state="translated">Zie documentatie hier.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">375</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">382</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">392</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">402</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">409</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Discord API setting hint</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="06f503e492d6dbcf59e7b9c412ca86913d718689" datatype="html">
|
||||||
|
<source>ntfy topic URL</source>
|
||||||
|
<target state="translated">ntfy onderwerp URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">390</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ntfy topic URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5827fde8fcafdd55ae80921ad3ad4aa01012e203" datatype="html">
|
||||||
|
<source>Use gotify API</source>
|
||||||
|
<target state="translated">Gebruik gotify API</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">396</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use gotify API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b770c48628d98cb4633d6a17e3f0ba0265376af5" datatype="html">
|
||||||
|
<source>Gotify app token</source>
|
||||||
|
<target state="translated">Gotify app token</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">407</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify app token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="38992954440d6afb54aeb58af12ca0123ee5e26e" datatype="html">
|
||||||
|
<source>Use Telegram API</source>
|
||||||
|
<target state="translated">Telegram API gebruiken</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">413</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use Telegram API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2e076ff9866213d0815961c494aa48b177046b9d" datatype="html">
|
||||||
|
<source>Telegram bot token</source>
|
||||||
|
<target state="translated">Telegram bot token</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">417</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram bot token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="144e1a21ebe8fa238f88d2ac27515ed711cfc9a0" datatype="html">
|
||||||
|
<source>Telegram chat ID</source>
|
||||||
|
<target state="translated">Telegram chat ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">424</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6785427850041119037" datatype="html">
|
||||||
|
<source>Delete category</source>
|
||||||
|
<target state="translated">Categorie verwijderen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">158</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2481374649045841364" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
||||||
|
<target state="translated">Wil je <x id="category name" equiv-text="category['name']"/> verwijderen?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">159</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7332320960988475089" datatype="html">
|
||||||
|
<source>Successfully deleted <x id="category name" equiv-text="category['name']"/>!</source>
|
||||||
|
<target state="translated"><x id="category name" equiv-text="category['name']"/> is succesvol verwijderd!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">168</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3371159074051387771" datatype="html">
|
||||||
|
<source>Failed to delete <x id="category name" equiv-text="category['name']"/>!</source>
|
||||||
|
<target state="translated"><x id="category name" equiv-text="category['name']"/> verwijderen mislukt!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="674a999dd48d7da565ffdd105602261b8a4761ea" datatype="html">
|
||||||
|
<source>Download zip</source>
|
||||||
|
<target state="translated">Zip downloaden</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscription/subscription/subscription.component.html</context>
|
||||||
|
<context context-type="linenumber">18</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download zip</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="378c072ce05889c9771718d05106e7685fcd3507" datatype="html">
|
||||||
|
<source>Medium</source>
|
||||||
|
<target state="translated">Gemiddeld</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">47,49</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Medium</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="37469c9f3e31d95087fa22b6c9c3bc64adf1692d" datatype="html">
|
||||||
|
<source>Enable RSS Feed</source>
|
||||||
|
<target state="translated">RSS-feed aanzetten</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">271</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable RSS Feed setting</note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -3784,6 +3784,727 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Download error</note>
|
<note priority="1" from="description">Download error</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="51a161ce175abcd44f6c6cbd0e996681bf553ac3" datatype="html">
|
||||||
|
<source>Delete selected</source>
|
||||||
|
<target state="translated">Usuń wybrane</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">77</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete selected</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7022070615528435141" datatype="html">
|
||||||
|
<source>Delete</source>
|
||||||
|
<target state="translated">Usuń</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">154</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">160</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5709555629190115111" datatype="html">
|
||||||
|
<source>View task</source>
|
||||||
|
<target state="translated">Wyświetl zadanie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">33</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4578192247039196794" datatype="html">
|
||||||
|
<source>Task</source>
|
||||||
|
<target state="translated">Zadanie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9a865c2922f5c01899d06c472dba2e5bd63bcff9" datatype="html">
|
||||||
|
<source>Small</source>
|
||||||
|
<target state="translated">Mały</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">50,52</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Small</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9c562d26e041390ecc3f49dabc51cc50ebba7469" datatype="html">
|
||||||
|
<source>Allowed notification types</source>
|
||||||
|
<target state="translated">Dozwolone typy powiadomień</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">356</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Allowed notification types</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="33a7c6d5ff3515fa237f1fd4e43df8b65373954d" datatype="html">
|
||||||
|
<source>Enable all notifications</source>
|
||||||
|
<target state="translated">Włącz wszystkie powiadomienia</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">352</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable all notifications setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6268070779441507380" datatype="html">
|
||||||
|
<source>Download Date</source>
|
||||||
|
<target state="translated">Data pobrania</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">13</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa1b4779a515170b297d2c0507e6ff9d2e3e0e0" datatype="html">
|
||||||
|
<source>Blacklist deleted subscription files</source>
|
||||||
|
<target state="translated">Czarna lista usuniętych plików subskrypcji</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">14</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Blacklist deleted subscription files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c748ac656af9f13998206ef2c52018dd418b0483" datatype="html">
|
||||||
|
<source>Archives</source>
|
||||||
|
<target state="translated">Archiwum</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/app.component.html</context>
|
||||||
|
<context context-type="linenumber">26</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives menu label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5ca707824ab93066c7d9b44e1b8bf216725c2c22" datatype="html">
|
||||||
|
<source>Filter</source>
|
||||||
|
<target state="translated">Filtr</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">3</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="45cc8ca94b5a50842a9a8ef804a5ab089a38ae5c" datatype="html">
|
||||||
|
<source>ID</source>
|
||||||
|
<target state="translated">ID</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">47</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="28da11220a3377ddce3c7948825d33101f142782" datatype="html">
|
||||||
|
<source>Extractor</source>
|
||||||
|
<target state="translated">Ekstraktor</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">57</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Extractor</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c150a30bbbdb175b4d08820196a9acb66b167653" datatype="html">
|
||||||
|
<source>Archives empty</source>
|
||||||
|
<target state="translated">Archiwum puste</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">72</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Archives empty</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c41475a25c9f9d9639db9efa56637603a77528b4" datatype="html">
|
||||||
|
<source>Download archive</source>
|
||||||
|
<target state="translated">Pobierz archiwum</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Download archive</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="a2f14a73f7a6e94479f67423cc51102da8d6f524" datatype="html">
|
||||||
|
<source>None</source>
|
||||||
|
<target state="translated">Brak</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">84</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">126</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">36</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">None</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2d1ea268a6a9f483dbc2cbfe19bf4256a57a6af4" datatype="html">
|
||||||
|
<source>Video</source>
|
||||||
|
<target state="translated">Wideo</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">92</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">133</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Video</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="f0baeb8b69d120073b6d60d34785889b0c3232c8" datatype="html">
|
||||||
|
<source>Audio</source>
|
||||||
|
<target state="translated">Audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">93</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">134</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Audio</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4b3972c3e9485218508a95f7a4ce7758e3f09ced" datatype="html">
|
||||||
|
<source>Upload</source>
|
||||||
|
<target state="translated">Wyślij</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.html</context>
|
||||||
|
<context context-type="linenumber">137</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/cookies-uploader-dialog/cookies-uploader-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Upload</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6549265851868599441" datatype="html">
|
||||||
|
<source>Video</source>
|
||||||
|
<target state="translated">Wideo</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">40</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="347407180135731058" datatype="html">
|
||||||
|
<source>Audio</source>
|
||||||
|
<target state="translated">Audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">44</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8425787787095143143" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="selected archives amount" equiv-text="this.selection.selected.length"/> archive(s)?</source>
|
||||||
|
<target state="translated">Chcesz usunąć archiwum(a) <x id="selected archives amount" equiv-text="this.selection.selected.length"/>?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">153</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2525880134753073592" datatype="html">
|
||||||
|
<source>Successfully deleted archive items!</source>
|
||||||
|
<target state="translated">Pomyślnie usunięto elementy archiwum!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">172</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953483585652369683" datatype="html">
|
||||||
|
<source>Archive successfully imported!</source>
|
||||||
|
<target state="translated">Archiwum zostało pomyślnie zaimportowane!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/archive-viewer/archive-viewer.component.ts</context>
|
||||||
|
<context context-type="linenumber">130</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6876310993601590130" datatype="html">
|
||||||
|
<source>Download completed</source>
|
||||||
|
<target state="translated">Pobieranie zakończone</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7911845622864460134" datatype="html">
|
||||||
|
<source>Video only</source>
|
||||||
|
<target state="translated">Tylko wideo</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">55</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9176960997786930103" datatype="html">
|
||||||
|
<source>Error for: <x id="PH" equiv-text="task['title']"/></source>
|
||||||
|
<target state="translated">Błąd dla: <x id="PH" equiv-text="task['title']"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.ts</context>
|
||||||
|
<context context-type="linenumber">174</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1d4fa01d25990f60abf21c3a451fa8ba262b7912" datatype="html">
|
||||||
|
<source>Unfavorite</source>
|
||||||
|
<target state="translated">Nieulubione</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Unfavorite button</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1f2809e6a99d511fdb6eaf041d785fe54d0680cc" datatype="html">
|
||||||
|
<source>File card size</source>
|
||||||
|
<target state="translated">Rozmiar karty pliku</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">42</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">File card size</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d618f383a0ea2458eeb945a85190d4a002ea394b" datatype="html">
|
||||||
|
<source>Arg</source>
|
||||||
|
<target state="translated">Argument</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">41</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Arg</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1a9b415816364f554ee411020e65219092655271" datatype="html">
|
||||||
|
<source>Title filter</source>
|
||||||
|
<target state="translated">Filtr tytułu</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">8</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Title filter</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9aa62bf1a535a97a4d752bbc5cf1c31af0f0c1f7" datatype="html">
|
||||||
|
<source>Supports regex</source>
|
||||||
|
<target state="translated">Obsługa regex</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">10</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Supports regex</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1698114086921246480" datatype="html">
|
||||||
|
<source>Unsubscribe</source>
|
||||||
|
<target state="translated">Anuluj subskrypcję</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/subscription-info-dialog/subscription-info-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="35cf4cdcedc8ef3f94b6100e0d86836e31dbb908" datatype="html">
|
||||||
|
<source>Force autoplay</source>
|
||||||
|
<target state="translated">Wymuś autoodtwarzanie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">218</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Force autoplay setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="37469c9f3e31d95087fa22b6c9c3bc64adf1692d" datatype="html">
|
||||||
|
<source>Enable RSS Feed</source>
|
||||||
|
<target state="translated">Włącz kanał RSS</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">271</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Enable RSS Feed setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0ed98b4c6ec1db6708a963e8a2699478ac97f55c" datatype="html">
|
||||||
|
<source>Add subscription</source>
|
||||||
|
<target state="translated">Dodaj subskrypcję</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscriptions/subscriptions.component.html</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Add subscription</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8c6e24eab969d9f63a8a0e9d617aee3b99e28ae6" datatype="html">
|
||||||
|
<source>Play all</source>
|
||||||
|
<target state="translated">Odtwórz wszystko</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/subscription/subscription/subscription.component.html</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Play all</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6080b77234e92ad41bb52653b239c4c4f851317d" datatype="html">
|
||||||
|
<source>Error</source>
|
||||||
|
<target state="translated">Błąd</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.html</context>
|
||||||
|
<context context-type="linenumber">39</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Error</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3640026747176198246" datatype="html">
|
||||||
|
<source>Watch content</source>
|
||||||
|
<target state="translated">Oglądaj zawartość</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">50</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8456659390937171831" datatype="html">
|
||||||
|
<source>Show error</source>
|
||||||
|
<target state="translated">Pokaż błąd</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">56</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1236604279860679031" datatype="html">
|
||||||
|
<source>Restart</source>
|
||||||
|
<target state="translated">Uruchom ponownie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="9042260521669277115" datatype="html">
|
||||||
|
<source>Pause</source>
|
||||||
|
<target state="translated">Wstrzymaj</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">68</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7182974689040833178" datatype="html">
|
||||||
|
<source>Resume</source>
|
||||||
|
<target state="translated">Wznów</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">74</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/downloads/downloads.component.ts</context>
|
||||||
|
<context context-type="linenumber">80</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="019d4bd6a5690f0cfa0ecf346a4e6bf7f0d8debb" datatype="html">
|
||||||
|
<source>Remove</source>
|
||||||
|
<target state="translated">Usuń</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.html</context>
|
||||||
|
<context context-type="linenumber">23</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Remove</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8443034725057696949" datatype="html">
|
||||||
|
<source>Task finished</source>
|
||||||
|
<target state="translated">Zadanie zakończone</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8564202903947049539" datatype="html">
|
||||||
|
<source>Play</source>
|
||||||
|
<target state="translated">Odtwarzaj</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">30</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8643601595923420698" datatype="html">
|
||||||
|
<source>Retry download</source>
|
||||||
|
<target state="translated">Ponów próbę pobrania</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">31</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5a105e7bd7e7db6ea211fe950fc9f317379acceb" datatype="html">
|
||||||
|
<source>No notifications available</source>
|
||||||
|
<target state="translated">B</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No notifications available</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1879058637439215882" datatype="html">
|
||||||
|
<source>Download error</source>
|
||||||
|
<target state="translated">Błąd pobierania</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications/notifications.component.ts</context>
|
||||||
|
<context context-type="linenumber">27</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6437411876967154040" datatype="html">
|
||||||
|
<source>Audio only</source>
|
||||||
|
<target state="translated">Tylko audio</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">60</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3533826530554274875" datatype="html">
|
||||||
|
<source>Upload Date</source>
|
||||||
|
<target state="translated">Data przesłania</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8953033926734869941" datatype="html">
|
||||||
|
<source>Name</source>
|
||||||
|
<target state="translated">Nazwa</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">21</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2492098975665776610" datatype="html">
|
||||||
|
<source>File Size</source>
|
||||||
|
<target state="translated">Rozmiar pliku</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="ea2b65121b93921fe54692025da9b9e3ce779ad5" datatype="html">
|
||||||
|
<source>Task settings - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></source>
|
||||||
|
<target state="translated">Ustawienia zadania - <x id="INTERPOLATION" equiv-text="{{task.title}}"/></target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Task settings</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="cdf5297d8d080a78e8b10debc5c38b7845a3cbe7" datatype="html">
|
||||||
|
<source>Do not ask for confirmation</source>
|
||||||
|
<target state="translated">Nie pytaj o potwierdzenie</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">19</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Do not ask for confirmation</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8571838164752006148" datatype="html">
|
||||||
|
<source>View error</source>
|
||||||
|
<target state="translated">Wyświetl błąd</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/notifications-list/notifications-list.component.ts</context>
|
||||||
|
<context context-type="linenumber">32</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4665451070906079743" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Ulubione</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.ts</context>
|
||||||
|
<context context-type="linenumber">65</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7410432243549869948" datatype="html">
|
||||||
|
<source>Duration</source>
|
||||||
|
<target state="translated">Czas trwania</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/sort-property/sort-property.component.ts</context>
|
||||||
|
<context context-type="linenumber">29</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c65dd978b3c7566551c0ebefb234c2d41942b847" datatype="html">
|
||||||
|
<source>Delete files older than</source>
|
||||||
|
<target state="translated">Usuń pliki starsze niż</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/task-settings/task-settings.component.html</context>
|
||||||
|
<context context-type="linenumber">6</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete files older than</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7b4585a9072f3c1292972c14a3d0e14978fbfc9c" datatype="html">
|
||||||
|
<source>Delete old files:</source>
|
||||||
|
<target state="translated">Usuń stare pliki:</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/tasks/tasks.component.html</context>
|
||||||
|
<context context-type="linenumber">66</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Delete old files</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b78a98bc54259a29cf6250dbaeab5fe11fae91cf" datatype="html">
|
||||||
|
<source>Favorited</source>
|
||||||
|
<target state="translated">Ulubione</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">51</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Favorited</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
|
||||||
|
<source>User</source>
|
||||||
|
<target state="translated">Użytkownik</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/generate-rss-url/generate-rss-url.component.html</context>
|
||||||
|
<context context-type="linenumber">25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">User</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1091872159779006651" datatype="html">
|
||||||
|
<source>You must input a time!</source>
|
||||||
|
<target state="translated">Musisz wprowadzić czas!</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component.ts</context>
|
||||||
|
<context context-type="linenumber">70</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="338b44701a53ce3ef2f36abfb56f89c3edfa9eab" datatype="html">
|
||||||
|
<source>Over</source>
|
||||||
|
<target state="translated">Nad</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">32,34</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Over</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="e0a11fbea353b1ce1131161774e4a3e10bcb99b1" datatype="html">
|
||||||
|
<source>Large</source>
|
||||||
|
<target state="translated">Duży</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/dialogs/user-profile-dialog/user-profile-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">44,46</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Large</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="d57c023a4cf63b2f12c10328c15b636ff18929aa" datatype="html">
|
||||||
|
<source>Best</source>
|
||||||
|
<target state="translated">Najlepsze</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/main/main.component.html</context>
|
||||||
|
<context context-type="linenumber">24,25</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Best</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="af30e51aa8b67e1133a341ec28359be05150e65c" datatype="html">
|
||||||
|
<source>No description available.</source>
|
||||||
|
<target state="translated">Opis nie dostępny.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/player/player.component.html</context>
|
||||||
|
<context context-type="linenumber">25,27</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">No description</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="61d6b5fa4311b1c617b66dad72496f9dd43b07b4" datatype="html">
|
||||||
|
<source>Be careful enabling this with multi-user mode! User data may be exposed.</source>
|
||||||
|
<target state="translated">Uważaj, włączając to w trybie wielu użytkowników! Dane użytkownika mogą zostać ujawnione.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">272</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS Feed prefix</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="fd467148a18f0921c10d116d4e0174fe29452be4" datatype="html">
|
||||||
|
<source>See documentation here.</source>
|
||||||
|
<target state="translated">Zobacz dokumentację tutaj.</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">274</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">RSS feed documentation</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="06f503e492d6dbcf59e7b9c412ca86913d718689" datatype="html">
|
||||||
|
<source>ntfy topic URL</source>
|
||||||
|
<target state="translated">ntfy topic URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">390</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">ntfy topic URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5827fde8fcafdd55ae80921ad3ad4aa01012e203" datatype="html">
|
||||||
|
<source>Use gotify API</source>
|
||||||
|
<target state="translated">Użyj gotify API</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">396</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use gotify API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="55f559d6f666b945479f534b0c182f70cd0a8a69" datatype="html">
|
||||||
|
<source>Gotify server URL</source>
|
||||||
|
<target state="translated">Adres serwera Gotify</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">400</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify server URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b770c48628d98cb4633d6a17e3f0ba0265376af5" datatype="html">
|
||||||
|
<source>Gotify app token</source>
|
||||||
|
<target state="translated">Token aplikacji Gotify</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">407</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Gotify app token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="38992954440d6afb54aeb58af12ca0123ee5e26e" datatype="html">
|
||||||
|
<source>Use Telegram API</source>
|
||||||
|
<target state="translated">Użyj Telegram API</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">413</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Use Telegram API setting</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2e076ff9866213d0815961c494aa48b177046b9d" datatype="html">
|
||||||
|
<source>Telegram bot token</source>
|
||||||
|
<target state="translated">Token bota Telegramu</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">417</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram bot token</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="144e1a21ebe8fa238f88d2ac27515ed711cfc9a0" datatype="html">
|
||||||
|
<source>Telegram chat ID</source>
|
||||||
|
<target state="translated">ID czatu Telegram</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">424</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3e420c675b8f3f3702576d52e8bb6e8e1d3feda0" datatype="html">
|
||||||
|
<source>How do I get the chat ID?</source>
|
||||||
|
<target state="translated">Jak uzyskać ID czatu Telegram?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">426</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Telegram chat ID help</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8bcabdf6b16cad0313a86c7e940c5e3ad7f9f8ab" datatype="html">
|
||||||
|
<source>Notifications</source>
|
||||||
|
<target state="translated">Powiadomienia</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">343</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Notifications settings label</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7cedb649779673568447b994463b2882c4e0436a" datatype="html">
|
||||||
|
<source>Slack Webhook URL</source>
|
||||||
|
<target state="translated">Slack Webhook URL</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.html</context>
|
||||||
|
<context context-type="linenumber">380</context>
|
||||||
|
</context-group>
|
||||||
|
<note priority="1" from="description">Slack Webhook URL</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2481374649045841364" datatype="html">
|
||||||
|
<source>Would you like to delete <x id="category name" equiv-text="category['name']"/>?</source>
|
||||||
|
<target state="translated">Czy chcesz usunąć <x id="category name" equiv-text="category['name']"/>?</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/settings/settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">159</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
4277
src/assets/i18n/messages.vi.xlf
Normal file
4277
src/assets/i18n/messages.vi.xlf
Normal file
File diff suppressed because it is too large
Load Diff
9
src/environments/environment.codespaces.ts
Normal file
9
src/environments/environment.codespaces.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// The file contents for the current environment will overwrite these during build.
|
||||||
|
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||||
|
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||||
|
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false,
|
||||||
|
codespaces: true
|
||||||
|
};
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: true,
|
||||||
|
codespaces: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: false,
|
||||||
|
codespaces: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
@use '@angular/material' as mat;
|
||||||
|
|
||||||
@import '~material-icons/iconfont/material-icons.css';
|
@import '~material-icons/iconfont/material-icons.css';
|
||||||
|
|
||||||
@@ -12,7 +13,6 @@
|
|||||||
html, body { height: 100%; }
|
html, body { height: 100%; }
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||||
|
|
||||||
@import '@angular/material/theming';
|
|
||||||
// Plus imports for other components in your app.
|
// Plus imports for other components in your app.
|
||||||
|
|
||||||
/*// Typography
|
/*// Typography
|
||||||
@@ -24,22 +24,22 @@ $custom-typography: mat-typography-config(
|
|||||||
@include angular-material-typography($custom-typography);
|
@include angular-material-typography($custom-typography);
|
||||||
*/
|
*/
|
||||||
// Default colors
|
// Default colors
|
||||||
$my-app-primary: mat-palette($mat-light-blue, 700, 100, 800);
|
$my-app-primary: mat.define-palette(mat.$light-blue-palette, 700, 100, 800); // mat-palette($mat-light-blue, 700, 100, 800);
|
||||||
$my-app-accent: mat-palette($mat-blue, 700, 100, 800);
|
$my-app-accent: mat.define-palette(mat.$blue-palette, 700, 100, 800);
|
||||||
$my-app-warn: mat-palette($mat-red, 700, 100, 800);
|
$my-app-warn: mat.define-palette(mat.$red-palette, 700, 100, 800);
|
||||||
|
|
||||||
$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn);
|
$my-app-theme: mat.define-light-theme((color: (primary: $my-app-primary, accent: $my-app-accent, warn: $my-app-warn)));
|
||||||
@include angular-material-theme($my-app-theme);
|
@include mat.all-component-themes($my-app-theme);
|
||||||
|
|
||||||
// Dark theme
|
// Dark theme
|
||||||
$dark-primary: mat-palette($mat-light-blue, 700, 100, 800);
|
$dark-primary: mat.define-palette(mat.$light-blue-palette, 700, 100, 800);
|
||||||
$dark-accent: mat-palette($mat-blue);
|
$dark-accent: mat.define-palette(mat.$blue-palette);
|
||||||
$dark-warn: mat-palette($mat-deep-orange);
|
$dark-warn: mat.define-palette(mat.$deep-orange-palette);
|
||||||
|
|
||||||
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
|
$dark-theme: mat.define-dark-theme((color: (primary: $dark-primary, accent: $dark-accent, warn: $dark-warn)));
|
||||||
|
|
||||||
.dark-theme {
|
.dark-theme {
|
||||||
@include angular-material-theme($dark-theme);
|
@include mat.all-component-themes($dark-theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-mdc-outlined-button, .mat-mdc-raised-button, .mat-mdc-flat-button {
|
.mat-mdc-outlined-button, .mat-mdc-raised-button, .mat-mdc-flat-button {
|
||||||
@@ -47,14 +47,14 @@ $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Light theme
|
// Light theme
|
||||||
$light-primary: mat-palette($mat-grey, 200, 500, 300);
|
$light-primary: mat.define-palette(mat.$grey-palette, 200, 500, 300);
|
||||||
$light-accent: mat-palette($mat-brown, 200);
|
$light-accent: mat.define-palette(mat.$brown-palette, 200);
|
||||||
$light-warn: mat-palette($mat-deep-orange, 200);
|
$light-warn: mat.define-palette(mat.$deep-orange-palette, 200);
|
||||||
|
|
||||||
$light-theme: mat-light-theme($light-primary, $light-accent, $light-warn);
|
$light-theme: mat.define-light-theme((color: (primary: $light-primary, accent: $light-accent, warn: $light-warn)));
|
||||||
|
|
||||||
.light-theme {
|
.light-theme {
|
||||||
@include angular-material-theme($light-theme);
|
@include mat.all-component-themes($light-theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-outline {
|
.no-outline {
|
||||||
@@ -65,9 +65,7 @@ $light-theme: mat-light-theme($light-primary, $light-accent, $light-warn);
|
|||||||
// Include the common styles for Angular Material. We include this here so that you only
|
// Include the common styles for Angular Material. We include this here so that you only
|
||||||
// have to load a single css file for Angular Material in your app.
|
// have to load a single css file for Angular Material in your app.
|
||||||
// Be sure that you only ever include this mixin once!
|
// Be sure that you only ever include this mixin once!
|
||||||
@include mat-core();
|
@include mat.core();
|
||||||
|
|
||||||
// @import '../node_modules/@angular/material/theming';
|
|
||||||
|
|
||||||
.centered {
|
.centered {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
Reference in New Issue
Block a user