Compare commits

..

65 Commits

Author SHA1 Message Date
Isaac Abadi
b56c66f705 Refactored retrieval of categories and improved runtime search of files in category
Fixed issue with editing/saving categories

Database queries can now handle nested object paths

Code cleanup
2022-06-17 19:43:32 -04:00
Isaac Abadi
c810d4d878 Code cleanup 2022-06-17 15:35:06 -04:00
Isaac Abadi
9cf8b87c6e Added ability to modify file metadata 2022-06-17 15:34:12 -04:00
Isaac Abadi
53a181e04d Fixed several bugs with categories
Code cleanup
2022-06-16 23:42:47 -04:00
Isaac Abadi
eee8494c70 Updated local font/bootstrap setup to be more Angular compatible 2022-06-14 21:00:28 -04:00
Isaac Abadi
b50baf6fa7 Merge branch 'master' of https://github.com/Tzahi12345/YoutubeDL-Material into improved-downloads-management 2022-06-14 20:40:46 -04:00
Isaac Abadi
f905d3c321 Fixed a few broken tests 2022-06-14 20:33:01 -04:00
Glassed Silver
91f5de326d Merge pull request #649 from fpiesche/patch-4
Fix 403s when pushing to GHCR
2022-06-14 06:55:20 +02:00
Florian Piesche
dcbd8f0346 Fix secret name 2022-06-13 18:32:34 +01:00
Florian Piesche
8a6a578e60 Fix secret name 2022-06-13 18:31:24 +01:00
Florian Piesche
01114d9309 Fix 403 when pushing images to GHCR 2022-06-13 18:29:53 +01:00
Florian Piesche
7f387ce6aa Fix 403s when pushing images to GHCR 2022-06-13 18:28:45 +01:00
Glassed Silver
523d303766 Merge pull request #647 from weblate/weblate-youtubedl-material-ytdl-material
Translations update from Hosted Weblate
2022-06-12 03:09:39 +02:00
ㅤAbsurdUsername
6bd9ddd14c Translated using Weblate (Italian)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/it/
2022-06-11 13:17:31 +02:00
TyRoyal
f8d4e18fd4 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/zh_Hans/
2022-06-11 13:17:28 +02:00
TyRoyal
56facd320f Translated using Weblate (Chinese (Simplified))
Currently translated at 98.4% (319 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/zh_Hans/
2022-06-10 04:40:04 +02:00
Glassed Silver
14c9dc482b Merge pull request #628 from firstdorsal/master
add fonts and css local for better privacy
2022-06-09 14:34:09 +02:00
Glassed Silver
1f47f01fd5 Merge pull request #635 from weblate/weblate-youtubedl-material-ytdl-material
Translations update from Hosted Weblate
2022-06-09 14:30:27 +02:00
Glassed Silver
09957843ec Merge pull request #631 from fpiesche/patch-2
Automatically run docker release on releases
2022-06-09 14:27:31 +02:00
Glassed Silver
a6ae5d114e Merge pull request #633 from fpiesche/patch-4
Use docker/metadata-action
2022-06-09 14:26:19 +02:00
Glassed Silver
68c2bc9d3d Merge pull request #632 from fpiesche/patch-3
Add Dependabot configuration
2022-06-09 14:00:06 +02:00
Felipe
f9f35b27bd Translated using Weblate (Portuguese)
Currently translated at 89.8% (291 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/pt/
2022-06-08 09:16:19 +02:00
Felipe Nogueira
6a63f7ee1a Added translation using Weblate (Portuguese (Brazil)) 2022-06-07 08:52:10 +02:00
Maxime Leroy
11acd56e1e Translated using Weblate (French)
Currently translated at 99.3% (322 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/fr/
2022-06-03 07:14:29 +02:00
Florian Piesche
12dd9d45b5 Use docker/metadata-action
This simplifies specifying tags and will also generate metadata labels for the image as per [OpenContainers spec](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
2022-06-01 23:40:58 +01:00
Florian Piesche
d0171d719b Use docker/metadata-action
This will generate tags based on specific patterns, as well as add metadata labels to the images as per [the OpenContainers spec](https://github.com/opencontainers/image-spec/blob/main/annotations.md).
2022-06-01 23:25:05 +01:00
Florian Piesche
e298f19534 Fix Github workflows directory 2022-06-01 23:05:28 +01:00
Florian Piesche
6c875ba667 Add Dependabot configuration
With this set up, you'll automatically get PRs from [Dependabot](https://github.com/dependabot) for most of your dependencies - base images for your Dockerfiles, Github Actions in your workflows, and npm packages for the frontend and backend.
2022-06-01 23:03:48 +01:00
Florian Piesche
1b4caf4699 Automatically run docker release on releases
With this change, publishing a new release using the github web UI will automatically trigger the `docker-release.yml` workflow and build and push the image, publishing it under the `latest` tag as well as the repository tag name for the release. No more manually kicking off the release workflow!

I've also added publishing the image to ghcr.io because with Docker Hub pushing harder on subscriptions it might be nice to have a backup in place.
2022-06-01 22:55:56 +01:00
Paul Colin Hennig
ca9b1641d8 add fonts and css local for better privacy 2022-05-29 14:14:50 +02:00
Glassed Silver
050c40fc19 Merge pull request #616 from weblate/weblate-youtubedl-material-ytdl-material
Translations update from Hosted Weblate
2022-05-22 19:21:10 +02:00
AHOHNMYC
0945a0bbd1 Translated using Weblate (Russian)
Currently translated at 97.8% (317 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/ru/
2022-05-22 13:41:56 +02:00
S3aBreeze
9f91fdf221 Translated using Weblate (Russian)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/ru/
2022-05-22 13:41:56 +02:00
AHOHNMYC
4b89c58c84 Translated using Weblate (Russian)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/ru/
2022-05-22 13:41:56 +02:00
dejan995
d0876516a6 Translated using Weblate (Macedonian)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/mk/
2022-05-22 13:41:56 +02:00
Maite Guix
e8390e3d9d Translated using Weblate (Catalan)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/ca/
2022-05-22 13:41:56 +02:00
Isaac Abadi
306da4ea63 LDAP logins no longer show error resulting from the required internal login attempt 2022-05-21 22:59:39 -04:00
Glassed Silver
5c4c282718 Merge pull request #619 from Tzahi12345/GlassedSilver-REPO-improvement-no-response
Autoclose stale issues lacking requested response
2022-05-22 04:11:50 +02:00
Isaac Abadi
bf64d97b72 Fixed downloads not sorting properly
Confirm dialog can now be a selection list
2022-05-21 21:26:25 -04:00
Isaac Abadi
71d5a64272 Ported $ne to local DB and added tests for applyFilterToLocalDB 2022-05-11 23:56:49 -04:00
Isaac Abadi
a2db8ba0fe Further cleanup to API and models 2022-05-11 23:53:10 -04:00
Isaac Abadi
1514952fd1 Cleaned up dependencies, routes, and API models 2022-05-11 22:58:46 -04:00
Glassed Silver
9fc659dc0a Autoclose stale issues lacking requested response
fixes #618
2022-05-11 21:30:47 +02:00
Glassed Silver
8dac9d1806 Merge pull request #609 from martadinata666/docker-nodejs16-upgrade
Docker nodejs16 upgrade
2022-05-08 08:11:02 +02:00
Glassed Silver
0f6742f11b Merge pull request #611 from weblate/weblate-youtubedl-material-ytdl-material
Translations update from Hosted Weblate
2022-05-08 08:05:36 +02:00
Glassed Silver
d6aaca9233 Merge branch 'master' into docker-nodejs16-upgrade 2022-05-07 11:36:27 +02:00
Dedy Martadinata S
7333edf6c8 Update Dockerfile 2022-05-07 12:31:52 +07:00
Dedy Martadinata S
5d9cb19bde Update Dockerfile 2022-05-07 12:21:05 +07:00
Dedy Martadinata S
a21dc85d15 revert script 2022-05-07 12:10:23 +07:00
Dedy Martadinata S
a57a25133c go to 20.04 2022-05-07 10:57:47 +07:00
Dedy Martadinata S
d6f5b87d3f also correctly create user home 2022-05-07 10:41:53 +07:00
Dedy Martadinata S
2678215e08 fetch ffmpeg without script 2022-05-07 10:34:27 +07:00
Heimen Stoffels
95203a47d0 Translated using Weblate (Dutch)
Currently translated at 100.0% (324 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/nl/
2022-05-06 14:11:54 +02:00
Eric
7f4119febe Translated using Weblate (Chinese (Simplified))
Currently translated at 75.3% (244 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/zh_Hans/
2022-05-06 14:11:54 +02:00
Tzahi12345
02f758c33d Translated using Weblate (Spanish)
Currently translated at 81.4% (264 of 324 strings)

Translation: YoutubeDL-Material/ytdl-material
Translate-URL: https://hosted.weblate.org/projects/youtubedl-material/ytdl-material/es/
2022-05-06 14:11:54 +02:00
Glassed Silver
554f7c9787 Merge pull request #610 from Tzahi12345/docker-revert-ubuntu-version
Reverted ubuntu version to 20.04
2022-05-06 04:05:33 +02:00
Isaac Abadi
d37287541f Reverted ubuntu version to 20.04 2022-05-05 21:37:02 -04:00
Dedy Martadinata S
da226df72a move to ubuntu as requested
Use setup node 16, as LTS im afraid it will jump to node 18 few months later.
2022-05-06 08:16:48 +07:00
Dedy Martadinata S
6199157687 Update Dockerfile 2022-05-06 00:02:13 +07:00
Dedy Martadinata S
d2e1b04326 check again 2022-05-05 23:43:13 +07:00
Dedy Martadinata S
4bff50a5f0 copy all backend 2022-05-05 22:02:05 +07:00
Dedy Martadinata S
6ffa9d1ffd Some clean up and restructure 2022-05-05 21:42:52 +07:00
Dedy Martadinata S
5a80b7aafa rename to prevent confusion 2022-05-05 21:39:24 +07:00
Glassed Silver
4d00960fcf Merge pull request #607 from Tzahi12345/fix-603
Startup crash hotfix
2022-05-05 16:06:58 +02:00
Tzahi12345
6e8ca9d843 Fixed bug that caused verifyBinaryExistsLinux to crash the server on startup 2022-05-05 09:27:56 -04:00
167 changed files with 7326 additions and 884 deletions

18
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/.github/workflows"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/backend/"
schedule:
interval: "daily"

View File

@@ -0,0 +1,38 @@
name: No Response
# Both `issue_comment` and `scheduled` event types are required for this Action
# to work properly.
on:
issue_comment:
types: [created]
schedule:
# Schedule for five minutes after the hour, every hour
- cron: '5 * * * *'
# By specifying the access of one of the scopes, all of those that are not
# specified are set to 'none'.
permissions:
issues: write
jobs:
noResponse:
runs-on: ubuntu-latest
if: ${{ github.repository == 'Tzahi12345/YoutubeDL-Material' }}
steps:
- uses: lee-dohm/no-response@v0.5.0
with:
token: ${{ github.token }}
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further. We will re-open this issue if you provide us
with the requested information with a comment under this issue.
Thank you for your understanding and for trying to help make this application
a better one!
# Number of days of inactivity before an issue is closed for lack of response.
daysUntilClose: 21
# Label requiring a response.
responseRequiredLabel: "💬 response-needed"

View File

@@ -6,19 +6,25 @@ on:
tags:
description: 'Docker tags'
required: true
release:
types: [published]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v2
- name: Set hash
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Get current date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- name: create-json
id: create-json
uses: jsdaniell/create-json@1.1.2
@@ -26,15 +32,49 @@ jobs:
name: "version.json"
json: '{"type": "docker", "tag": "latest", "commit": "${{ steps.vars.outputs.sha_short }}", "date": "${{ steps.date.outputs.date }}"}'
dir: 'backend/'
- name: Set image tag
id: tags
run: |
if [ ${{ github.event.action }} == "workflow_dispatch" ]; then
echo "::set-output name=tags::${{ github.event.inputs.tags }}"
elif [ ${{ github.event.action }} == "release" ]; then
echo "::set-output name=tags::${{ github.event.release.tag_name }}"
else
echo "Unknown workflow trigger: ${{ github.event.action }}! Cannot determine default tag."
exit 1
fi
- name: Generate Docker image metadata
id: docker-meta
uses: docker/metadata-action@v4
with:
images: |
${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
ghcr.io/${{ github.repository_owner }}/${{ secrets.DOCKERHUB_REPO }}
tags: |
raw=${{ steps.tags.outputs.tags }}
raw=latest
- name: setup platform emulator
uses: docker/setup-qemu-action@v1
- name: setup multi-arch docker build
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build & push images
uses: docker/build-push-action@v2
with:
@@ -42,4 +82,5 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64,linux/arm,linux/arm64/v8
push: true
tags: ${{ github.event.inputs.tags }}
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}

View File

@@ -20,12 +20,15 @@ jobs:
steps:
- name: checkout code
uses: actions/checkout@v2
- name: Set hash
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Get current date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- name: create-json
id: create-json
uses: jsdaniell/create-json@1.1.2
@@ -33,15 +36,42 @@ jobs:
name: "version.json"
json: '{"type": "docker", "tag": "${{secrets.DOCKERHUB_MASTER_TAG}}", "commit": "${{ steps.vars.outputs.sha_short }}", "date": "${{ steps.date.outputs.date }}"}'
dir: 'backend/'
- name: setup platform emulator
uses: docker/setup-qemu-action@v1
- name: setup multi-arch docker build
uses: docker/setup-buildx-action@v1
- name: Generate Docker image metadata
id: docker-meta
uses: docker/metadata-action@v4
# Defaults:
# DOCKERHUB_USERNAME : tzahi12345
# DOCKERHUB_REPO : youtubedl-material
# DOCKERHUB_MASTER_TAG: nightly
with:
images: |
${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}
ghcr.io/${{ github.repository_owner }}/${{ secrets.DOCKERHUB_REPO }}
tags: |
type=raw,${{secrets.DOCKERHUB_MASTER_TAG}}-{{ date 'YYYY-MM-DD' }}
type=raw,${{secrets.DOCKERHUB_MASTER_TAG}}
type=sha,prefix=sha-,format=short
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build & push images
uses: docker/build-push-action@v2
with:
@@ -49,8 +79,5 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64,linux/arm,linux/arm64/v8
push: true
# Defaults:
# DOCKERHUB_USERNAME : tzahi12345
# DOCKERHUB_REPO : youtubedl-material
# DOCKERHUB_MASTER_TAG: nightly
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{secrets.DOCKERHUB_MASTER_TAG}}
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}

View File

@@ -1,77 +1,66 @@
# Fetching our ffmpeg
FROM ubuntu:22.04 AS ffmpeg
ENV DEBIAN_FRONTEND=noninteractive
# Use script due local build compability
COPY ffmpeg-fetch.sh .
RUN sh ./ffmpeg-fetch.sh
RUN apt-get update && apt-get install -y software-properties-common
RUN add-apt-repository ppa:savoury1/ffmpeg4
RUN add-apt-repository ppa:savoury1/ffmpeg5 && apt-get update && apt-get install -y ffmpeg
#--------------# Stage 2
FROM ubuntu:22.04 as frontend
# Create our Ubuntu 22.04 with node 16
# Go to 20.04
FROM ubuntu:20.04 AS base
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install \
curl \
gnupg \
# Ubuntu 22.04 ships Node.JS 12 by default :)
nodejs \
# needed on 21.10 and before, maybe not on 22.04 YARN: brings along npm, solves dependency conflicts,
# spares us this spaghetti approach: https://stackoverflow.com/a/60547197
npm && \
apt-get install -f && \
npm config set strict-ssl false && \
npm install -g @angular/cli
ENV UID=1000
ENV GID=1000
ENV USER=youtube
ENV NO_UPDATE_NOTIFIER=true
ENV PM2_HOME=/app/pm2
RUN groupadd -g $GID $USER && useradd --system -m -g $USER --uid $UID $USER && \
apt update && \
apt install -y --no-install-recommends curl ca-certificates && \
curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \
apt install -y --no-install-recommends nodejs && \
npm -g install npm && \
apt clean && \
rm -rf /var/lib/apt/lists/*
# Build frontend
FROM base as frontend
RUN npm install -g @angular/cli
WORKDIR /build
COPY [ "package.json", "package-lock.json", "/build/" ]
RUN npm install
COPY [ "angular.json", "tsconfig.json", "/build/" ]
COPY [ "package.json", "package-lock.json", "angular.json", "tsconfig.json", "/build/" ]
COPY [ "src/", "/build/src/" ]
RUN npm run build
RUN npm install && \
npm run build && \
ls -al /build/backend/public
#--------------# Final Stage
FROM ubuntu:22.04
ENV UID=1000 \
GID=1000 \
USER=youtube \
NO_UPDATE_NOTIFIER=true
ENV DEBIAN_FRONTEND=noninteractive
RUN groupadd -g $GID $USER && useradd --system -g $USER --uid $UID $USER
RUN apt-get update && apt-get -y install \
npm \
python2 \
python3 \
gosu \
atomicparsley \
--no-install-recommends && \
apt-get install -f && \
apt-get autoremove --purge && \
apt-get autoremove && \
apt-get clean && \
rm -rf /var/lib/apt
# Install backend deps
FROM base as backend
WORKDIR /app
COPY [ "backend/","/app/" ]
RUN npm config set strict-ssl false && \
npm install --prod && \
ls -al
# Final image
FROM base
RUN npm install -g pm2 && \
apt update && \
apt install -y --no-install-recommends gosu python3-minimal python-is-python3 atomicparsley && \
apt clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# User 1000 already exist from base image
COPY --chown=$UID:$GID --from=ffmpeg [ "/usr/local/bin/ffmpeg", "/usr/local/bin/ffmpeg" ]
COPY --chown=$UID:$GID --from=ffmpeg [ "/usr/local/bin/ffprobe", "/usr/local/bin/ffprobe" ]
COPY --chown=$UID:$GID [ "backend/package.json", "backend/package-lock.json", "/app/" ]
ENV PM2_HOME=/app/pm2
RUN npm config set strict-ssl false && \
npm install pm2 -g && \
npm install && chown -R $UID:$GID ./
# needed for ubuntu, see #596
RUN ln -s /usr/bin/python3 /usr/bin/python
COPY --chown=$UID:$GID --from=backend ["/app/","/app/"]
COPY --chown=$UID:$GID --from=frontend [ "/build/backend/public/", "/app/public/" ]
COPY --chown=$UID:$GID [ "/backend/", "/app/" ]
# Add some persistence data
#VOLUME ["/app/appdata"]
EXPOSE 17442
# ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD [ "pm2-runtime", "pm2.config.js" ]
ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD [ "pm2-runtime","--raw","pm2.config.js" ]

View File

@@ -129,6 +129,27 @@ paths:
description: User is not authorized to view the file.
security:
- Auth query parameter: []
/api/updateFile:
post:
tags:
- files
summary: Updates file database object
description: Updates a file db object using its uid and a change object.
operationId: post-updateFile
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateFileRequest'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessObject'
security:
- Auth query parameter: []
/api/enableSharing:
post:
tags:
@@ -841,17 +862,10 @@ paths:
- Auth query parameter: []
tags:
- downloader
/api/clearFinishedDownloads:
/api/clearDownloads:
post:
tags:
- downloader
summary: Clear finished downloads
operationId: post-api-clear-finished-downloads
requestBody:
content:
application/json:
schema:
type: object
summary: Clear multiple downloads
operationId: post-api-clear-downloads
responses:
'200':
description: OK
@@ -859,8 +873,17 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/SuccessObject'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ClearDownloadsRequest'
description: ''
description: "Clears multiple downloads based on a given filter."
security:
- Auth query parameter: []
tags:
- downloader
/api/getTask:
post:
summary: Get info for one task
@@ -1507,6 +1530,8 @@ components:
properties:
success:
type: boolean
error:
type: string
FileType:
type: string
enum:
@@ -1607,6 +1632,15 @@ components:
type: array
items:
$ref: '#/components/schemas/Download'
ClearDownloadsRequest:
type: object
properties:
clear_finished:
type: boolean
clear_paused:
type: boolean
clear_errors:
type: boolean
GetTaskRequest:
type: object
properties:
@@ -1727,6 +1761,18 @@ components:
type: boolean
file:
$ref: '#/components/schemas/DatabaseFile'
UpdateFileRequest:
required:
- uid
- change_obj
type: object
properties:
uid:
type: string
description: Video UID
change_obj:
type: object
description: Object with fields to update as keys and their new values
SharingToggle:
required:
- uid
@@ -2153,7 +2199,6 @@ components:
type: boolean
result:
allOf:
- $ref: '#/components/schemas/file'
- type: object
properties:
formats:
@@ -2311,6 +2356,9 @@ components:
type: string
thumbnailURL:
type: string
description: Backup if thumbnailPath is not defined
thumbnailPath:
type: string
isAudio:
type: boolean
duration:
@@ -2322,6 +2370,7 @@ components:
type: string
size:
type: number
description: In bytes
path:
type: string
upload_date:
@@ -2330,6 +2379,12 @@ components:
type: string
sharingEnabled:
type: boolean
category:
$ref: '#/components/schemas/Category'
view_count:
type: number
local_view_count:
type: number
Playlist:
required:
- uids
@@ -2359,6 +2414,8 @@ components:
type: number
user_uid:
type: string
auto:
type: boolean
Download:
required:
- url
@@ -2545,28 +2602,6 @@ components:
type: string
passhash:
type: string
files:
type: object
properties:
audio:
type: array
items:
$ref: '#/components/schemas/file'
video:
type: array
items:
$ref: '#/components/schemas/file'
playlists:
type: object
properties:
audio:
type: array
items:
$ref: '#/components/schemas/file'
video:
type: array
items:
$ref: '#/components/schemas/file'
subscriptions:
type: array
items:

View File

@@ -30,7 +30,8 @@
"src/backend"
],
"styles": [
"src/styles.scss"
"src/styles.scss",
"src/bootstrap.min.css"
],
"scripts": [],
"vendorChunk": true,
@@ -118,7 +119,8 @@
"src/backend"
],
"styles": [
"src/styles.scss"
"src/styles.scss",
"src/bootstrap.min.css"
],
"scripts": []
},
@@ -151,7 +153,8 @@
"tsConfig": "src/tsconfig.spec.json",
"scripts": [],
"styles": [
"src/styles.scss"
"src/styles.scss",
"src/bootstrap.min.css"
],
"assets": [
"src/assets",

View File

@@ -933,23 +933,34 @@ app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
else if (file_type_filter === 'video_only') filter_obj['isAudio'] = false;
files = await db_api.getRecords('files', filter_obj, false, sort, range, text_search);
let file_count = await db_api.getRecords('files', filter_obj, true);
playlists = await db_api.getRecords('playlists', {user_uid: uuid});
const categories = await categories_api.getCategoriesAsPlaylists(files);
if (categories) {
playlists = playlists.concat(categories);
}
const file_count = await db_api.getRecords('files', filter_obj, true);
files = JSON.parse(JSON.stringify(files));
res.send({
files: files,
file_count: file_count,
playlists: playlists
});
});
app.post('/api/updateFile', optionalJwt, async function (req, res) {
const uid = req.body.uid;
const change_obj = req.body.change_obj;
const file = await db_api.updateRecord('files', {uid: uid}, change_obj);
if (!file) {
res.send({
success: false,
error: 'File could not be found'
});
} else {
res.send({
success: true
});
}
});
app.post('/api/checkConcurrentStream', async (req, res) => {
const uid = req.body.uid;
@@ -1365,7 +1376,7 @@ app.post('/api/getPlaylists', optionalJwt, async (req, res) => {
let playlists = await db_api.getRecords('playlists', {user_uid: uuid});
if (include_categories) {
const categories = await categories_api.getCategoriesAsPlaylists(files);
const categories = await categories_api.getCategoriesAsPlaylists();
if (categories) {
playlists = playlists.concat(categories);
}
@@ -1669,9 +1680,15 @@ app.post('/api/download', optionalJwt, async (req, res) => {
}
});
app.post('/api/clearFinishedDownloads', optionalJwt, async (req, res) => {
app.post('/api/clearDownloads', optionalJwt, async (req, res) => {
const user_uid = req.isAuthenticated() ? req.user.uid : null;
const success = db_api.removeAllRecords('download_queue', {finished: true, user_uid: user_uid});
const clear_finished = req.body.clear_finished;
const clear_paused = req.body.clear_paused;
const clear_errors = req.body.clear_errors;
let success = true;
if (clear_finished) success &= await db_api.removeAllRecords('download_queue', {finished: true, user_uid: user_uid});
if (clear_paused) success &= await db_api.removeAllRecords('download_queue', {paused: true, user_uid: user_uid});
if (clear_errors) success &= await db_api.removeAllRecords('download_queue', {error: {$ne: null}, user_uid: user_uid});
res.send({success: success});
});

View File

@@ -171,8 +171,12 @@ exports.registerUser = async function(req, res) {
exports.login = async (username, password) => {
// even if we're using LDAP, we still want users to be able to login using internal credentials
const user = await db_api.getRecord('users', {name: username});
if (!user) { logger.error(`User ${username} not found`); return false }
if (!user) {
if (config_api.getConfigItem('ytdl_auth_method') === 'internal') logger.error(`User ${username} not found`);
return false;
}
if (user.auth_method && user.auth_method !== 'internal') { return false }
return await bcrypt.compare(password, user.passhash) ? user : false;
}

View File

@@ -55,17 +55,18 @@ async function getCategories() {
return categories ? categories : null;
}
async function getCategoriesAsPlaylists(files = null) {
async function getCategoriesAsPlaylists() {
const categories_as_playlists = [];
const available_categories = await getCategories();
if (available_categories && files) {
if (available_categories) {
for (let category of available_categories) {
const files_that_match = utils.addUIDsToCategory(category, files);
const files_that_match = await db_api.getRecords('files', {'category.uid': category['uid']});
if (files_that_match && files_that_match.length > 0) {
category['thumbnailURL'] = files_that_match[0].thumbnailURL;
category['thumbnailPath'] = files_that_match[0].thumbnailPath;
category['duration'] = files_that_match.reduce((a, b) => a + utils.durationStringToNumber(b.duration), 0);
category['id'] = category['uid'];
category['auto'] = true;
categories_as_playlists.push(category);
}
}

View File

@@ -127,7 +127,7 @@ function setConfigItem(key, value) {
success = setConfigFile(config_json);
return success;
};
}
function setConfigItems(items) {
let success = false;

View File

@@ -387,9 +387,9 @@ exports.getPlaylist = async (playlist_id, user_uid = null, require_sharing = fal
if (!playlist) {
playlist = await exports.getRecord('categories', {uid: playlist_id});
if (playlist) {
// category found
const files = await exports.getFiles(user_uid);
utils.addUIDsToCategory(playlist, files);
const uids = (await exports.getRecords('files', {'category.uid': playlist_id})).map(file => file.uid);
playlist['uids'] = uids;
playlist['auto'] = true;
}
}
@@ -629,7 +629,7 @@ exports.bulkInsertRecordsIntoTable = async (table, docs) => {
exports.getRecord = async (table, filter_obj) => {
// local db override
if (using_local_db) {
return applyFilterLocalDB(local_db.get(table), filter_obj, 'find').value();
return exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'find').value();
}
return await database.collection(table).findOne(filter_obj);
@@ -638,7 +638,7 @@ exports.getRecord = async (table, filter_obj) => {
exports.getRecords = async (table, filter_obj = null, return_count = false, sort = null, range = null) => {
// local db override
if (using_local_db) {
let cursor = filter_obj ? applyFilterLocalDB(local_db.get(table), filter_obj, 'filter').value() : local_db.get(table).value();
let cursor = filter_obj ? exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'filter').value() : local_db.get(table).value();
if (sort) {
cursor = cursor.sort((a, b) => (a[sort['by']] > b[sort['by']] ? sort['order'] : sort['order']*-1));
}
@@ -664,7 +664,7 @@ exports.getRecords = async (table, filter_obj = null, return_count = false, sort
exports.updateRecord = async (table, filter_obj, update_obj) => {
// local db override
if (using_local_db) {
applyFilterLocalDB(local_db.get(table), filter_obj, 'find').assign(update_obj).write();
exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'find').assign(update_obj).write();
return true;
}
@@ -677,7 +677,7 @@ exports.updateRecord = async (table, filter_obj, update_obj) => {
exports.updateRecords = async (table, filter_obj, update_obj) => {
// local db override
if (using_local_db) {
applyFilterLocalDB(local_db.get(table), filter_obj, 'filter').assign(update_obj).write();
exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'filter').assign(update_obj).write();
return true;
}
@@ -722,7 +722,7 @@ exports.bulkUpdateRecords = async (table, key_label, update_obj) => {
exports.pushToRecordsArray = async (table, filter_obj, key, value) => {
// local db override
if (using_local_db) {
applyFilterLocalDB(local_db.get(table), filter_obj, 'find').get(key).push(value).write();
exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'find').get(key).push(value).write();
return true;
}
@@ -733,7 +733,7 @@ exports.pushToRecordsArray = async (table, filter_obj, key, value) => {
exports.pullFromRecordsArray = async (table, filter_obj, key, value) => {
// local db override
if (using_local_db) {
applyFilterLocalDB(local_db.get(table), filter_obj, 'find').get(key).pull(value).write();
exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'find').get(key).pull(value).write();
return true;
}
@@ -746,7 +746,7 @@ exports.pullFromRecordsArray = async (table, filter_obj, key, value) => {
exports.removeRecord = async (table, filter_obj) => {
// local db override
if (using_local_db) {
applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
return true;
}
@@ -757,7 +757,7 @@ exports.removeRecord = async (table, filter_obj) => {
// exports.removeRecordsByUIDBulk = async (table, uids) => {
// // local db override
// if (using_local_db) {
// applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
// exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
// return true;
// }
@@ -821,7 +821,7 @@ exports.removeAllRecords = async (table = null, filter_obj = null) => {
if (using_local_db) {
for (let i = 0; i < tables_to_remove.length; i++) {
const table_to_remove = tables_to_remove[i];
if (filter_obj) applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
if (filter_obj) exports.applyFilterLocalDB(local_db.get(table), filter_obj, 'remove').write();
else local_db.assign({[table_to_remove]: []}).write();
logger.debug(`Successfully removed records from ${table_to_remove}`);
}
@@ -1075,8 +1075,13 @@ exports.transferDB = async (local_to_remote) => {
This function is necessary to emulate mongodb's ability to search for null or missing values.
A filter of null or undefined for a property will find docs that have that property missing, or have it
null or undefined. We want that same functionality for the local DB as well
error: {$ne: null}
^ ^
| |
filter_prop filter_prop_value
*/
const applyFilterLocalDB = (db_path, filter_obj, operation) => {
exports.applyFilterLocalDB = (db_path, filter_obj, operation) => {
const filter_props = Object.keys(filter_obj);
const return_val = db_path[operation](record => {
if (!filter_props) return true;
@@ -1085,14 +1090,20 @@ const applyFilterLocalDB = (db_path, filter_obj, operation) => {
const filter_prop = filter_props[i];
const filter_prop_value = filter_obj[filter_prop];
if (filter_prop_value === undefined || filter_prop_value === null) {
filtered &= record[filter_prop] === undefined || record[filter_prop] === null
filtered &= record[filter_prop] === undefined || record[filter_prop] === null;
} else {
if (typeof filter_prop_value === 'object') {
if (filter_prop_value['$regex']) {
if ('$regex' in filter_prop_value) {
filtered &= (record[filter_prop].search(new RegExp(filter_prop_value['$regex'], filter_prop_value['$options'])) !== -1);
} else if ('$ne' in filter_prop_value) {
filtered &= filter_prop in record && record[filter_prop] !== filter_prop_value['$ne'];
}
} else {
filtered &= record[filter_prop] === filter_prop_value;
// handle case of nested property check
if (filter_prop.includes('.'))
filtered &= utils.searchObjectByString(record, filter_prop) === filter_prop_value;
else
filtered &= record[filter_prop] === filter_prop_value;
}
}
}

View File

@@ -108,6 +108,7 @@ exports.clearDownload = async (download_uid) => {
}
async function handleDownloadError(download_uid, error_message) {
if (!download_uid) return;
await db_api.updateRecord('download_queue', {uid: download_uid}, {error: error_message, finished: true, running: false});
}
@@ -186,7 +187,7 @@ async function collectInfo(download_uid) {
let args = await exports.generateArgs(url, type, options, download['user_uid']);
// get video info prior to download
let info = await getVideoInfoByURL(url, args, download_uid);
let info = await exports.getVideoInfoByURL(url, args, download_uid);
if (!info) {
// info failed, error presumably already recorded
@@ -203,9 +204,11 @@ async function collectInfo(download_uid) {
options.customOutput = category['custom_output'];
options.noRelativePath = true;
args = await exports.generateArgs(url, type, options, download['user_uid']);
info = await getVideoInfoByURL(url, args, download_uid);
info = await exports.getVideoInfoByURL(url, args, download_uid);
}
download['category'] = category;
// setup info required to calculate download progress
const expected_file_size = utils.getExpectedFileSize(info);
@@ -507,7 +510,7 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f
return downloadConfig;
}
async function getVideoInfoByURL(url, args = [], download_uid = null) {
exports.getVideoInfoByURL = async (url, args = [], download_uid = null) => {
return new Promise(resolve => {
// remove bad args
const new_args = [...args];

View File

@@ -148,6 +148,7 @@ exports.updateTaskSchedule = async (task_key, schedule) => {
await db_api.updateRecord('tasks', {key: task_key}, {schedule: schedule});
if (TASKS[task_key]['job']) {
TASKS[task_key]['job'].cancel();
TASKS[task_key]['job'] = null;
}
if (schedule) {
TASKS[task_key]['job'] = scheduleJob(task_key, schedule);

View File

@@ -42,6 +42,25 @@ const { uuid } = require('uuidv4');
db_api.initialize(db, users_db);
const sample_video_json = {
id: "Sample Video",
title: "Sample Video",
thumbnailURL: "https://sampleurl.jpg",
isAudio: false,
duration: 177.413,
url: "sampleurl.com",
uploader: "Sample Uploader",
size: 2838445,
path: "users\\admin\\video\\Sample Video.mp4",
upload_date: "2017-07-28",
description: null,
view_count: 230,
abr: 128,
thumbnailPath: null,
user_uid: "admin",
uid: "1ada04ab-2773-4dd4-bbdd-3e2d40761c50",
registered: 1628469039377
}
describe('Database', async function() {
describe('Import', async function() {
@@ -214,7 +233,7 @@ describe('Database', async function() {
for (let i = 0; i < NUM_RECORDS_TO_ADD; i++) {
const uid = uuid();
if (i === NUM_RECORDS_TO_ADD/2) random_uid = uid;
test_records.push({"id":"A$AP Mob - Yamborghini High (Official Music Video) ft. Juicy J","title":"A$AP Mob - Yamborghini High (Official Music Video) ft. Juicy J","thumbnailURL":"https://i.ytimg.com/vi/tt7gP_IW-1w/maxresdefault.jpg","isAudio":true,"duration":312,"url":"https://www.youtube.com/watch?v=tt7gP_IW-1w","uploader":"asapmobVEVO","size":5060157,"path":"audio\\A$AP Mob - Yamborghini High (Official Music Video) ft. Juicy J.mp3","upload_date":"2016-05-11","description":"A$AP Mob ft. Juicy J - \"Yamborghini High\" Get it now on:\niTunes: http://smarturl.it/iYAMH?IQid=yt\nListen on Spotify: http://smarturl.it/sYAMH?IQid=yt\nGoogle Play: http://smarturl.it/gYAMH?IQid=yt\nAmazon: http://smarturl.it/aYAMH?IQid=yt\n\nFollow A$AP Mob:\nhttps://www.facebook.com/asapmobofficial\nhttps://twitter.com/ASAPMOB\nhttp://instagram.com/asapmob \nhttp://www.asapmob.com/\n\n#AsapMob #YamborghiniHigh #Vevo #HipHop #OfficialMusicVideo #JuicyJ","view_count":118689353,"height":null,"abr":160,"uid": uid,"registered":1626672120632});
test_records.push({"id":"RandomTextRandomText","title":"RandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomText","thumbnailURL":"https://i.ytimg.com/vi/randomurl/maxresdefault.jpg","isAudio":true,"duration":312,"url":"https://www.youtube.com/watch?v=randomvideo","uploader":"randomUploader","size":5060157,"path":"audio\\RandomTextRandomText.mp3","upload_date":"2016-05-11","description":"RandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomTextRandomText","view_count":118689353,"height":null,"abr":160,"uid": uid,"registered":1626672120632});
}
const insert_start = Date.now();
let success = await db_api.bulkInsertRecordsIntoTable('test', test_records);
@@ -235,6 +254,30 @@ describe('Database', async function() {
assert(success);
});
});
describe('Local DB Filters', async function() {
it('Basic', async function() {
const result = db_api.applyFilterLocalDB([{test: 'test'}, {test: 'test1'}], {test: 'test'}, 'find');
assert(result && result['test'] === 'test');
});
it('Regex', async function() {
const filter = {$regex: `\\w+\\d`, $options: 'i'};
const result = db_api.applyFilterLocalDB([{test: 'test'}, {test: 'test1'}], {test: filter}, 'find');
assert(result && result['test'] === 'test1');
});
it('Not equals', async function() {
const filter = {$ne: 'test'};
const result = db_api.applyFilterLocalDB([{test: 'test'}, {test: 'test1'}], {test: filter}, 'find');
assert(result && result['test'] === 'test1');
});
it('Nested', async function() {
const result = db_api.applyFilterLocalDB([{test1: {test2: 'test3'}}, {test4: 'test5'}], {'test1.test2': 'test3'}, 'find');
assert(result && result['test1']['test2'] === 'test3');
});
})
});
describe('Multi User', async function() {
@@ -253,10 +296,12 @@ describe('Multi User', async function() {
assert(user);
});
});
describe('Video player - normal', function() {
const video_to_test = 'ebbcfffb-d6f1-4510-ad25-d1ec82e0477e';
describe('Video player - normal', async function() {
await db_api.removeRecord('files', {uid: sample_video_json['uid']});
await db_api.insertRecordIntoTable('files', sample_video_json);
const video_to_test = sample_video_json['uid'];
it('Get video', async function() {
const video_obj = db_api.getVideo(video_to_test, 'admin');
const video_obj = await db_api.getVideo(video_to_test);
assert(video_obj);
});
@@ -341,7 +386,9 @@ describe('Downloader', function() {
});
it('Get file info', async function() {
this.timeout(300000);
const info = await downloader_api.getVideoInfoByURL(url);
assert(!!info);
});
it('Download file', async function() {
@@ -360,20 +407,23 @@ describe('Downloader', function() {
});
it('Pause file', async function() {
const returned_download = await downloader_api.createDownload(url, 'video', options);
await downloader_api.pauseDownload(returned_download['uid']);
const updated_download = await db_api.getRecord('download_queue', {uid: returned_download['uid']});
assert(updated_download['paused'] && !updated_download['running']);
});
it('Generate args', async function() {
const args = await downloader_api.generateArgs(url, 'video', options);
console.log(args);
assert(args.length > 0);
});
it('Generate args - subscription', async function() {
subscriptions_api.initialize(db_api, logger);
const sub = await subscriptions_api.getSubscription(sub_id);
const sub_options = subscriptions_api.generateOptionsForSubscriptionDownload(sub, 'admin');
const args = await downloader_api.generateArgs(url, 'video', sub_options, 'admin');
console.log(args);
const args_normal = await downloader_api.generateArgs(url, 'video', options);
const args_sub = await downloader_api.generateArgs(url, 'video', sub_options, 'admin');
console.log(JSON.stringify(args_normal) !== JSON.stringify(args_sub));
});
it('Generate kodi NFO file', async function() {
@@ -417,7 +467,7 @@ describe('Tasks', function() {
};
tasks_api.TASKS['dummy_task'] = dummy_task;
await tasks_api.initialize();
await tasks_api.setupTasks();
});
it('Backup db', async function() {
const backups_original = await utils.recFindByExt('appdata', 'bak');
@@ -429,12 +479,13 @@ describe('Tasks', function() {
});
it('Check for missing files', async function() {
this.timeout(300000);
await db_api.removeAllRecords('files', {uid: 'test'});
const test_missing_file = {uid: 'test', path: 'test/missing_file.mp4'};
await db_api.insertRecordIntoTable('files', test_missing_file);
await tasks_api.executeTask('missing_files_check');
const task_obj = await db_api.getRecord('tasks', {key: 'missing_files_check'});
assert(task_obj['data'] && task_obj['data']['uids'] && task_obj['data']['uids'].length >= 1, true);
const missing_file_db_record = await db_api.getRecord('files', {uid: 'test'});
assert(!missing_file_db_record, true);
});
it('Check for duplicate files', async function() {
@@ -447,10 +498,13 @@ describe('Tasks', function() {
await db_api.insertRecordIntoTable('files', test_duplicate_file1);
await db_api.insertRecordIntoTable('files', test_duplicate_file2);
await db_api.insertRecordIntoTable('files', test_duplicate_file3);
await tasks_api.executeTask('duplicate_files_check');
await tasks_api.executeRun('duplicate_files_check');
const task_obj = await db_api.getRecord('tasks', {key: 'duplicate_files_check'});
const duplicated_record_count = await db_api.getRecords('files', {path: 'test/missing_file.mp4'}, true);
assert(task_obj['data'] && task_obj['data']['uids'] && task_obj['data']['uids'].length >= 1, true);
await tasks_api.executeTask('duplicate_files_check');
const duplicated_record_count = await db_api.getRecords('files', {path: 'test/missing_file.mp4'}, true);
assert(duplicated_record_count == 1, true);
});
@@ -475,22 +529,36 @@ describe('Tasks', function() {
});
it('Schedule and cancel task', async function() {
const today_4_hours = new Date();
today_4_hours.setHours(today_4_hours.getHours() + 4);
await tasks_api.updateTaskSchedule('dummy_task', today_4_hours);
assert(!!tasks_api.TASKS['dummy_task']['job'], true);
this.timeout(5000);
const today_one_year = new Date();
today_one_year.setFullYear(today_one_year.getFullYear() + 1);
const schedule_obj = {
type: 'timestamp',
data: { timestamp: today_one_year.getTime() }
}
await tasks_api.updateTaskSchedule('dummy_task', schedule_obj);
const dummy_task = await db_api.getRecord('tasks', {key: 'dummy_task'});
assert(!!tasks_api.TASKS['dummy_task']['job']);
assert(!!dummy_task['schedule']);
await tasks_api.updateTaskSchedule('dummy_task', null);
assert(!!tasks_api.TASKS['dummy_task']['job'], false);
const dummy_task_updated = await db_api.getRecord('tasks', {key: 'dummy_task'});
assert(!tasks_api.TASKS['dummy_task']['job']);
assert(!dummy_task_updated['schedule']);
});
it('Schedule and run task', async function() {
this.timeout(5000);
const today_1_second = new Date();
today_1_second.setSeconds(today_1_second.getSeconds() + 1);
await tasks_api.updateTaskSchedule('dummy_task', today_1_second);
assert(!!tasks_api.TASKS['dummy_task']['job'], true);
const schedule_obj = {
type: 'timestamp',
data: { timestamp: today_1_second.getTime() }
}
await tasks_api.updateTaskSchedule('dummy_task', schedule_obj);
assert(!!tasks_api.TASKS['dummy_task']['job']);
await utils.wait(2000);
const dummy_task_obj = await db_api.getRecord('tasks', {key: 'dummy_task'});
assert(dummy_task_obj['data'], true);
assert(dummy_task_obj['data']);
});
});

View File

@@ -456,6 +456,21 @@ function injectArgs(original_args, new_args) {
return updated_args;
}
const searchObjectByString = function(o, s) {
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
s = s.replace(/^\./, ''); // strip a leading dot
var a = s.split('.');
for (var i = 0, n = a.length; i < n; ++i) {
var k = a[i];
if (k in o) {
o = o[k];
} else {
return;
}
}
return o;
}
// objects
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description, view_count, height, abr) {
@@ -489,7 +504,6 @@ module.exports = {
createContainerZipFile: createContainerZipFile,
durationStringToNumber: durationStringToNumber,
getMatchingCategoryFiles: getMatchingCategoryFiles,
addUIDsToCategory: addUIDsToCategory,
getCurrentDownloader: getCurrentDownloader,
recFindByExt: recFindByExt,
removeFileExtension: removeFileExtension,
@@ -501,5 +515,6 @@ module.exports = {
fetchFile: fetchFile,
restartServer: restartServer,
injectArgs: injectArgs,
searchObjectByString: searchObjectByString,
File: File
}

View File

@@ -90,7 +90,7 @@ exports.updateYoutubeDL = async (latest_update_version) => {
exports.verifyBinaryExistsLinux = () => {
const details_json = fs.readJSONSync(CONSTS.DETAILS_BIN_PATH);
if (!is_windows && details_json && details_json['path'].includes('.exe')) {
if (!is_windows && details_json && (details_json['path'].includes('.exe') || !details_json['path'])) {
details_json['path'] = 'node_modules/youtube-dl/bin/youtube-dl';
details_json['exec'] = 'youtube-dl';
details_json['version'] = OUTDATED_VERSION;

View File

@@ -40,4 +40,4 @@ echo "(4/5) PROVISION - Provide ffmpeg and ffprobe from ffmpeg obtain layer"
cp /tmp/ffmpeg/*/ffmpeg /usr/local/bin/ffmpeg
cp /tmp/ffmpeg/*/ffprobe /usr/local/bin/ffprobe
echo "(5/5) CLEANUP - Remove temporary downloads from ffmpeg obtain layer"
rm -rf /tmp/ffmpeg ffmpeg.txz
rm -rf /tmp/ffmpeg ffmpeg.txz

59
package-lock.json generated
View File

@@ -3295,65 +3295,12 @@
"safer-buffer": "~2.1.0"
}
},
"asn1.js": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
"dev": true,
"requires": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"safer-buffer": "^2.1.0"
},
"dependencies": {
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
"dev": true
}
}
},
"assert": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
"integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
"dev": true,
"requires": {
"object-assign": "^4.1.1",
"util": "0.10.3"
},
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
"dev": true
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"dev": true,
"requires": {
"inherits": "2.0.1"
}
}
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
},
"assign-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true
},
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
@@ -3367,9 +3314,9 @@
"dev": true
},
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true,
"requires": {
"lodash": "^4.17.14"

View File

@@ -6,7 +6,7 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build --configuration production",
"prebuild": "node src/postbuild.js",
"prebuild": "node src/postbuild.mjs",
"heroku-postbuild": "npm install --prefix backend",
"test": "ng test",
"lint": "ng lint",

View File

@@ -4,6 +4,7 @@
export type { AddFileToPlaylistRequest } from './models/AddFileToPlaylistRequest';
export type { BaseChangePermissionsRequest } from './models/BaseChangePermissionsRequest';
export type { binary } from './models/binary';
export type { body_19 } from './models/body_19';
export type { body_20 } from './models/body_20';
export type { Category } from './models/Category';
@@ -12,6 +13,7 @@ export type { ChangeRolePermissionsRequest } from './models/ChangeRolePermission
export type { ChangeUserPermissionsRequest } from './models/ChangeUserPermissionsRequest';
export type { CheckConcurrentStreamRequest } from './models/CheckConcurrentStreamRequest';
export type { CheckConcurrentStreamResponse } from './models/CheckConcurrentStreamResponse';
export type { ClearDownloadsRequest } from './models/ClearDownloadsRequest';
export type { ConcurrentStream } from './models/ConcurrentStream';
export type { Config } from './models/Config';
export type { ConfigResponse } from './models/ConfigResponse';
@@ -23,6 +25,7 @@ export type { CropFileSettings } from './models/CropFileSettings';
export type { DatabaseFile } from './models/DatabaseFile';
export { DBBackup } from './models/DBBackup';
export type { DBInfoResponse } from './models/DBInfoResponse';
export type { DeleteAllFilesResponse } from './models/DeleteAllFilesResponse';
export type { DeleteCategoryRequest } from './models/DeleteCategoryRequest';
export type { DeleteMp3Mp4Request } from './models/DeleteMp3Mp4Request';
export type { DeletePlaylistRequest } from './models/DeletePlaylistRequest';
@@ -36,7 +39,6 @@ export type { DownloadResponse } from './models/DownloadResponse';
export type { DownloadTwitchChatByVODIDRequest } from './models/DownloadTwitchChatByVODIDRequest';
export type { DownloadTwitchChatByVODIDResponse } from './models/DownloadTwitchChatByVODIDResponse';
export type { DownloadVideosForSubscriptionRequest } from './models/DownloadVideosForSubscriptionRequest';
export type { File } from './models/File';
export { FileType } from './models/FileType';
export type { GenerateArgsResponse } from './models/GenerateArgsResponse';
export type { GenerateNewApiKeyResponse } from './models/GenerateNewApiKeyResponse';
@@ -98,6 +100,7 @@ export type { UpdateCategoriesRequest } from './models/UpdateCategoriesRequest';
export type { UpdateCategoryRequest } from './models/UpdateCategoryRequest';
export type { UpdateConcurrentStreamRequest } from './models/UpdateConcurrentStreamRequest';
export type { UpdateConcurrentStreamResponse } from './models/UpdateConcurrentStreamResponse';
export type { UpdateFileRequest } from './models/UpdateFileRequest';
export type { UpdatePlaylistRequest } from './models/UpdatePlaylistRequest';
export type { UpdaterStatus } from './models/UpdaterStatus';
export type { UpdateServerRequest } from './models/UpdateServerRequest';

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface AddFileToPlaylistRequest {
export type AddFileToPlaylistRequest = {
file_uid: string;
playlist_id: string;
}
};

View File

@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
import { UserPermission } from './UserPermission';
import { YesNo } from './YesNo';
import type { UserPermission } from './UserPermission';
import type { YesNo } from './YesNo';
export interface BaseChangePermissionsRequest {
export type BaseChangePermissionsRequest = {
permission: UserPermission;
new_value: YesNo;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { CategoryRule } from './CategoryRule';
import type { CategoryRule } from './CategoryRule';
export interface Category {
export type Category = {
name?: string;
uid?: string;
rules?: Array<CategoryRule>;
@@ -12,4 +12,4 @@ export interface Category {
* Overrides file output for downloaded files in category
*/
custom_output?: string;
}
};

View File

@@ -2,11 +2,10 @@
/* tslint:disable */
/* eslint-disable */
export interface CategoryRule {
export type CategoryRule = {
preceding_operator?: CategoryRule.preceding_operator;
comparator?: CategoryRule.comparator;
}
};
export namespace CategoryRule {

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { BaseChangePermissionsRequest } from './BaseChangePermissionsRequest';
import type { BaseChangePermissionsRequest } from './BaseChangePermissionsRequest';
export interface ChangeRolePermissionsRequest extends BaseChangePermissionsRequest {
role: string;
}
export type ChangeRolePermissionsRequest = (BaseChangePermissionsRequest & {
role: string;
});

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { BaseChangePermissionsRequest } from './BaseChangePermissionsRequest';
import type { BaseChangePermissionsRequest } from './BaseChangePermissionsRequest';
export interface ChangeUserPermissionsRequest extends BaseChangePermissionsRequest {
user_uid: string;
}
export type ChangeUserPermissionsRequest = (BaseChangePermissionsRequest & {
user_uid: string;
});

View File

@@ -2,10 +2,9 @@
/* tslint:disable */
/* eslint-disable */
export interface CheckConcurrentStreamRequest {
export type CheckConcurrentStreamRequest = {
/**
* UID of the concurrent stream
*/
uid: string;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { ConcurrentStream } from './ConcurrentStream';
import type { ConcurrentStream } from './ConcurrentStream';
export interface CheckConcurrentStreamResponse {
export type CheckConcurrentStreamResponse = {
stream: ConcurrentStream;
}
};

View File

@@ -0,0 +1,9 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type ClearDownloadsRequest = {
clear_finished?: boolean;
clear_paused?: boolean;
clear_errors?: boolean;
};

View File

@@ -2,9 +2,8 @@
/* tslint:disable */
/* eslint-disable */
export interface ConcurrentStream {
export type ConcurrentStream = {
playback_timestamp?: number;
unix_timestamp?: number;
playing?: boolean;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface Config {
export type Config = {
YoutubeDLMaterial: any;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { Config } from './Config';
import type { Config } from './Config';
export interface ConfigResponse {
export type ConfigResponse = {
config_file: Config;
success: boolean;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface CreateCategoryRequest {
export type CreateCategoryRequest = {
name: string;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { Category } from './Category';
import type { Category } from './Category';
export interface CreateCategoryResponse {
export type CreateCategoryResponse = {
new_category?: Category;
success?: boolean;
}
};

View File

@@ -2,11 +2,11 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface CreatePlaylistRequest {
export type CreatePlaylistRequest = {
playlistName: string;
uids: Array<string>;
type: FileType;
thumbnailURL: string;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { Playlist } from './Playlist';
import type { Playlist } from './Playlist';
export interface CreatePlaylistResponse {
export type CreatePlaylistResponse = {
new_playlist: Playlist;
success: boolean;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface CropFileSettings {
export type CropFileSettings = {
cropFileStart: number;
cropFileEnd: number;
}
};

View File

@@ -2,13 +2,12 @@
/* tslint:disable */
/* eslint-disable */
export interface DBBackup {
export type DBBackup = {
name: string;
timestamp: number;
size: number;
source: DBBackup.source;
}
};
export namespace DBBackup {

View File

@@ -2,17 +2,17 @@
/* tslint:disable */
/* eslint-disable */
import { TableInfo } from './TableInfo';
import type { TableInfo } from './TableInfo';
export interface DBInfoResponse {
export type DBInfoResponse = {
using_local_db?: boolean;
stats_by_table?: {
files?: TableInfo,
playlists?: TableInfo,
categories?: TableInfo,
subscriptions?: TableInfo,
users?: TableInfo,
roles?: TableInfo,
download_queue?: TableInfo,
files?: TableInfo;
playlists?: TableInfo;
categories?: TableInfo;
subscriptions?: TableInfo;
users?: TableInfo;
roles?: TableInfo;
download_queue?: TableInfo;
};
}
};

View File

@@ -2,11 +2,16 @@
/* tslint:disable */
/* eslint-disable */
import type { Category } from './Category';
export interface DatabaseFile {
export type DatabaseFile = {
id: string;
title: string;
/**
* Backup if thumbnailPath is not defined
*/
thumbnailURL: string;
thumbnailPath?: string;
isAudio: boolean;
/**
* In seconds
@@ -14,9 +19,15 @@ export interface DatabaseFile {
duration: number;
url: string;
uploader: string;
/**
* In bytes
*/
size: number;
path: string;
upload_date: string;
uid: string;
sharingEnabled?: boolean;
}
category?: Category;
view_count?: number;
local_view_count?: number;
};

View File

@@ -0,0 +1,14 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type DeleteAllFilesResponse = {
/**
* Number of files found matching search parameters
*/
file_count?: number;
/**
* Number of files removed
*/
delete_count?: number;
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface DeleteCategoryRequest {
export type DeleteCategoryRequest = {
category_uid: string;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface DeleteMp3Mp4Request {
export type DeleteMp3Mp4Request = {
uid: string;
blacklistMode?: boolean;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface DeletePlaylistRequest {
export type DeletePlaylistRequest = {
playlist_id: string;
type: FileType;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { SubscriptionRequestData } from './SubscriptionRequestData';
import type { SubscriptionRequestData } from './SubscriptionRequestData';
export interface DeleteSubscriptionFileRequest {
export type DeleteSubscriptionFileRequest = {
file: string;
file_uid?: string;
sub: SubscriptionRequestData;
@@ -12,4 +12,4 @@ export interface DeleteSubscriptionFileRequest {
* If true, does not remove id from archive. Only valid if youtube-dl archive is enabled in settings.
*/
deleteForever?: boolean;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface DeleteUserRequest {
export type DeleteUserRequest = {
uid: string;
}
};

View File

@@ -1,7 +0,0 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type Dictionary<T> = {
[key: string]: T;
}

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface Download {
export type Download = {
uid: string;
ui_uid?: string;
running: boolean;
@@ -23,4 +22,4 @@ export interface Download {
user_uid?: string;
sub_id?: string;
sub_name?: string;
}
};

View File

@@ -2,9 +2,8 @@
/* tslint:disable */
/* eslint-disable */
export interface DownloadArchiveRequest {
export type DownloadArchiveRequest = {
sub: {
archive_dir: string,
archive_dir: string;
};
}
};

View File

@@ -2,13 +2,13 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface DownloadFileRequest {
export type DownloadFileRequest = {
uid?: string;
uuid?: string;
sub_id?: string;
playlist_id?: string;
url?: string;
type?: FileType;
}
};

View File

@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
import { CropFileSettings } from './CropFileSettings';
import { FileType } from './FileType';
import type { CropFileSettings } from './CropFileSettings';
import type { FileType } from './FileType';
export interface DownloadRequest {
export type DownloadRequest = {
url: string;
/**
* Video format code. Overrides other quality options.
@@ -41,4 +41,4 @@ export interface DownloadRequest {
maxBitrate?: string;
type?: FileType;
cropFileSettings?: CropFileSettings;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Download } from './Download';
import type { Download } from './Download';
export interface DownloadResponse {
export type DownloadResponse = {
download?: Download;
}
};

View File

@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import { Subscription } from './Subscription';
import type { FileType } from './FileType';
import type { Subscription } from './Subscription';
export interface DownloadTwitchChatByVODIDRequest {
export type DownloadTwitchChatByVODIDRequest = {
/**
* File ID
*/
@@ -20,4 +20,4 @@ export interface DownloadTwitchChatByVODIDRequest {
*/
uuid?: string;
sub?: Subscription;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { TwitchChatMessage } from './TwitchChatMessage';
import type { TwitchChatMessage } from './TwitchChatMessage';
export interface DownloadTwitchChatByVODIDResponse {
export type DownloadTwitchChatByVODIDResponse = {
chat: Array<TwitchChatMessage>;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface DownloadVideosForSubscriptionRequest {
export type DownloadVideosForSubscriptionRequest = {
subID: string;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export enum FileType {
AUDIO = 'audio',
VIDEO = 'video',

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GenerateArgsResponse {
export type GenerateArgsResponse = {
args?: Array<string>;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GenerateNewApiKeyResponse {
export type GenerateNewApiKeyResponse = {
new_api_key: string;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Category } from './Category';
import type { Category } from './Category';
export interface GetAllCategoriesResponse {
export type GetAllCategoriesResponse = {
categories: Array<Category>;
}
};

View File

@@ -2,10 +2,9 @@
/* tslint:disable */
/* eslint-disable */
export interface GetAllDownloadsRequest {
export type GetAllDownloadsRequest = {
/**
* Filters downloads with the array
*/
uids?: Array<string> | null;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Download } from './Download';
import type { Download } from './Download';
export interface GetAllDownloadsResponse {
export type GetAllDownloadsResponse = {
downloads?: Array<Download>;
}
};

View File

@@ -2,13 +2,13 @@
/* tslint:disable */
/* eslint-disable */
import { DatabaseFile } from './DatabaseFile';
import { Playlist } from './Playlist';
import type { DatabaseFile } from './DatabaseFile';
import type { Playlist } from './Playlist';
export interface GetAllFilesResponse {
export type GetAllFilesResponse = {
files: Array<DatabaseFile>;
/**
* All video playlists
*/
playlists: Array<Playlist>;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Subscription } from './Subscription';
import type { Subscription } from './Subscription';
export interface GetAllSubscriptionsResponse {
export type GetAllSubscriptionsResponse = {
subscriptions: Array<Subscription>;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Task } from './Task';
import type { Task } from './Task';
export interface GetAllTasksResponse {
export type GetAllTasksResponse = {
tasks?: Array<Task>;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { DBBackup } from './DBBackup';
import type { DBBackup } from './DBBackup';
export interface GetDBBackupsResponse {
export type GetDBBackupsResponse = {
tasks?: Array<DBBackup>;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GetDownloadRequest {
export type GetDownloadRequest = {
download_uid: string;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Download } from './Download';
import type { Download } from './Download';
export interface GetDownloadResponse {
export type GetDownloadResponse = {
download?: Download;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GetFileFormatsRequest {
export type GetFileFormatsRequest = {
url?: string;
}
};

View File

@@ -2,11 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { File } from './File';
export interface GetFileFormatsResponse {
export type GetFileFormatsResponse = {
success: boolean;
result: {
formats?: Array<any>,
formats?: Array<any>;
};
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface GetFileRequest {
export type GetFileRequest = {
/**
* Video UID
*/
@@ -14,4 +14,4 @@ export interface GetFileRequest {
* User UID
*/
uuid?: string;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { DatabaseFile } from './DatabaseFile';
import type { DatabaseFile } from './DatabaseFile';
export interface GetFileResponse {
export type GetFileResponse = {
success: boolean;
file?: DatabaseFile;
}
};

View File

@@ -2,10 +2,10 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import { Subscription } from './Subscription';
import type { FileType } from './FileType';
import type { Subscription } from './Subscription';
export interface GetFullTwitchChatRequest {
export type GetFullTwitchChatRequest = {
/**
* File ID
*/
@@ -16,4 +16,4 @@ export interface GetFullTwitchChatRequest {
*/
uuid?: string;
sub?: Subscription;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface GetFullTwitchChatResponse {
export type GetFullTwitchChatResponse = {
success: boolean;
error?: string;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GetLogsRequest {
export type GetLogsRequest = {
lines?: number;
}
};

View File

@@ -2,11 +2,10 @@
/* tslint:disable */
/* eslint-disable */
export interface GetLogsResponse {
export type GetLogsResponse = {
/**
* Number of lines to retrieve from the bottom
*/
logs?: string;
success?: boolean;
}
};

View File

@@ -2,13 +2,13 @@
/* tslint:disable */
/* eslint-disable */
import { DatabaseFile } from './DatabaseFile';
import { Playlist } from './Playlist';
import type { DatabaseFile } from './DatabaseFile';
import type { Playlist } from './Playlist';
export interface GetMp3sResponse {
export type GetMp3sResponse = {
mp3s: Array<DatabaseFile>;
/**
* All audio playlists
*/
playlists: Array<Playlist>;
}
};

View File

@@ -2,13 +2,13 @@
/* tslint:disable */
/* eslint-disable */
import { DatabaseFile } from './DatabaseFile';
import { Playlist } from './Playlist';
import type { DatabaseFile } from './DatabaseFile';
import type { Playlist } from './Playlist';
export interface GetMp4sResponse {
export type GetMp4sResponse = {
mp4s: Array<DatabaseFile>;
/**
* All video playlists
*/
playlists: Array<Playlist>;
}
};

View File

@@ -2,11 +2,11 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface GetPlaylistRequest {
export type GetPlaylistRequest = {
playlist_id: string;
type?: FileType;
uuid?: string;
include_file_metadata?: boolean;
}
};

View File

@@ -2,11 +2,11 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import { Playlist } from './Playlist';
import type { FileType } from './FileType';
import type { Playlist } from './Playlist';
export interface GetPlaylistResponse {
export type GetPlaylistResponse = {
playlist: Playlist;
type: FileType;
success: boolean;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GetPlaylistsRequest {
export type GetPlaylistsRequest = {
include_categories?: boolean;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Playlist } from './Playlist';
import type { Playlist } from './Playlist';
export interface GetPlaylistsResponse {
export type GetPlaylistsResponse = {
playlists: Array<Playlist>;
}
};

View File

@@ -2,15 +2,15 @@
/* tslint:disable */
/* eslint-disable */
import { UserPermission } from './UserPermission';
import type { UserPermission } from './UserPermission';
export interface GetRolesResponse {
export type GetRolesResponse = {
roles: {
admin?: {
permissions?: Array<UserPermission>,
},
user?: {
permissions?: Array<UserPermission>,
},
permissions?: Array<UserPermission>;
};
}
user?: {
permissions?: Array<UserPermission>;
};
};
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface GetSubscriptionRequest {
export type GetSubscriptionRequest = {
/**
* Subscription ID
*/
@@ -12,4 +11,4 @@ export interface GetSubscriptionRequest {
* Subscription name
*/
name?: string;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { Subscription } from './Subscription';
import type { Subscription } from './Subscription';
export interface GetSubscriptionResponse {
export type GetSubscriptionResponse = {
subscription: Subscription;
files: Array<any>;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface GetTaskRequest {
export type GetTaskRequest = {
task_key: string;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Task } from './Task';
import type { Task } from './Task';
export interface GetTaskResponse {
export type GetTaskResponse = {
task?: Task;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { User } from './User';
import type { User } from './User';
export interface GetUsersResponse {
export type GetUsersResponse = {
users: Array<User>;
}
};

View File

@@ -2,12 +2,11 @@
/* tslint:disable */
/* eslint-disable */
export interface IncrementViewCountRequest {
export type IncrementViewCountRequest = {
file_uid: string;
sub_id?: string;
/**
* User UID
*/
uuid?: string;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface LoginRequest {
export type LoginRequest = {
username: string;
password: string;
}
};

View File

@@ -2,12 +2,12 @@
/* tslint:disable */
/* eslint-disable */
import { User } from './User';
import { UserPermission } from './UserPermission';
import type { User } from './User';
import type { UserPermission } from './UserPermission';
export interface LoginResponse {
export type LoginResponse = {
user?: User;
token?: string;
permissions?: Array<UserPermission>;
available_permissions?: Array<UserPermission>;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { FileType } from './FileType';
import type { FileType } from './FileType';
export interface Playlist {
export type Playlist = {
name: string;
uids: Array<string>;
id: string;
@@ -13,4 +13,5 @@ export interface Playlist {
registered: number;
duration: number;
user_uid?: string;
}
auto?: boolean;
};

View File

@@ -2,9 +2,8 @@
/* tslint:disable */
/* eslint-disable */
export interface RegisterRequest {
export type RegisterRequest = {
userid: string;
username: string;
password: string;
}
};

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { User } from './User';
import type { User } from './User';
export interface RegisterResponse {
export type RegisterResponse = {
user?: User;
}
};

View File

@@ -2,7 +2,6 @@
/* tslint:disable */
/* eslint-disable */
export interface RestoreDBBackupRequest {
export type RestoreDBBackupRequest = {
file_name: string;
}
};

View File

@@ -2,16 +2,15 @@
/* tslint:disable */
/* eslint-disable */
export interface Schedule {
export type Schedule = {
type: Schedule.type;
data: {
dayOfWeek?: Array<number>,
hour?: number,
minute?: number,
timestamp?: number,
dayOfWeek?: Array<number>;
hour?: number;
minute?: number;
timestamp?: number;
};
};
}
export namespace Schedule {

View File

@@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
import { Config } from './Config';
import type { Config } from './Config';
export interface SetConfigRequest {
export type SetConfigRequest = {
new_config_file: Config;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface SharingToggle {
export type SharingToggle = {
uid: string;
is_playlist?: boolean;
}
};

View File

@@ -2,8 +2,7 @@
/* tslint:disable */
/* eslint-disable */
export interface SubscribeRequest {
export type SubscribeRequest = {
name: string;
url: string;
timerange?: string;
@@ -11,4 +10,4 @@ export interface SubscribeRequest {
customArgs?: string;
customFileOutput?: string;
maxQuality?: string;
}
};

View File

@@ -2,9 +2,9 @@
/* tslint:disable */
/* eslint-disable */
import { Subscription } from './Subscription';
import type { Subscription } from './Subscription';
export interface SubscribeResponse {
export type SubscribeResponse = {
new_sub: Subscription;
error?: string;
}
};

Some files were not shown because too many files have changed in this diff Show More