mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-01-11 20:10:20 +00:00
prettier fix + updated to node 22 + added new workflow + crunchyroll updates + --version fix
This commit is contained in:
parent
8365e9d9e4
commit
130d964b64
144 changed files with 19708 additions and 18998 deletions
178
.github/ISSUE_TEMPLATE/bug.yml
vendored
178
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -1,93 +1,93 @@
|
||||||
name: Bug
|
name: Bug
|
||||||
description: File a bug report
|
description: File a bug report
|
||||||
assignees:
|
assignees:
|
||||||
- AnimeDL
|
- AnimeDL
|
||||||
- AnidlSupport
|
- AnidlSupport
|
||||||
labels:
|
labels:
|
||||||
- bug
|
- bug
|
||||||
title: "[BUG]: "
|
title: '[BUG]: '
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for reporting the issues you found and have with this program.
|
Thank you for reporting the issues you found and have with this program.
|
||||||
This template will guide you through all the information we need.
|
This template will guide you through all the information we need.
|
||||||
- type: input
|
- type: input
|
||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: Program version
|
label: Program version
|
||||||
description: "Which version of the program do you use?"
|
description: 'Which version of the program do you use?'
|
||||||
placeholder: "1.0.0"
|
placeholder: '1.0.0'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: opsystem
|
id: opsystem
|
||||||
attributes:
|
attributes:
|
||||||
label: Operating System
|
label: Operating System
|
||||||
description: "Please tell us what OS you are using."
|
description: 'Please tell us what OS you are using.'
|
||||||
options:
|
options:
|
||||||
- Windows
|
- Windows
|
||||||
- Linux
|
- Linux
|
||||||
- MacOS
|
- MacOS
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: gui
|
id: gui
|
||||||
attributes:
|
attributes:
|
||||||
label: Type
|
label: Type
|
||||||
description: "Please tell us if you are using the gui or the cli version."
|
description: 'Please tell us if you are using the gui or the cli version.'
|
||||||
options:
|
options:
|
||||||
- CLI
|
- CLI
|
||||||
- GUI
|
- GUI
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: service
|
id: service
|
||||||
attributes:
|
attributes:
|
||||||
label: Service
|
label: Service
|
||||||
description: "Please tell us what service the bug occured in."
|
description: 'Please tell us what service the bug occured in.'
|
||||||
options:
|
options:
|
||||||
- Crunchyroll
|
- Crunchyroll
|
||||||
- Hidive
|
- Hidive
|
||||||
- AnimationDigitalNetwork
|
- AnimationDigitalNetwork
|
||||||
- AnimeOnegai
|
- AnimeOnegai
|
||||||
- All
|
- All
|
||||||
- Irrelevant
|
- Irrelevant
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: command
|
id: command
|
||||||
attributes:
|
attributes:
|
||||||
label: Command used
|
label: Command used
|
||||||
description: "Please tell us what command you used."
|
description: 'Please tell us what command you used.'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: ShowID
|
id: ShowID
|
||||||
attributes:
|
attributes:
|
||||||
label: Show ID
|
label: Show ID
|
||||||
description: "Please provide the ID of an example show."
|
description: 'Please provide the ID of an example show.'
|
||||||
placeholder: "1234"
|
placeholder: '1234'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: Episode
|
id: Episode
|
||||||
attributes:
|
attributes:
|
||||||
label: Episode
|
label: Episode
|
||||||
description: "Please provide the episode ID you used as an example."
|
description: 'Please provide the episode ID you used as an example.'
|
||||||
placeholder: "1"
|
placeholder: '1'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: output
|
id: output
|
||||||
attributes:
|
attributes:
|
||||||
label: Console Output
|
label: Console Output
|
||||||
description: "Please paste the console output from the beginning till termination here. If you are using the gui open the log folder under 'Debug > Open Log Folder' in the Menu. Please copy the content of latest.log here."
|
description: "Please paste the console output from the beginning till termination here. If you are using the gui open the log folder under 'Debug > Open Log Folder' in the Menu. Please copy the content of latest.log here."
|
||||||
render: Shell
|
render: Shell
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: additionalInfos
|
id: additionalInfos
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional Information
|
label: Additional Information
|
||||||
description: "Do you have any additional information you can provide?"
|
description: 'Do you have any additional information you can provide?'
|
||||||
|
|
|
||||||
50
.github/ISSUE_TEMPLATE/feature.yml
vendored
50
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -1,29 +1,29 @@
|
||||||
name: Enhancement
|
name: Enhancement
|
||||||
description: Suggest a enhancement or feature
|
description: Suggest a enhancement or feature
|
||||||
labels:
|
labels:
|
||||||
- enhancement
|
- enhancement
|
||||||
title: "[Feedback]: "
|
title: '[Feedback]: '
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for giving feedback with this program.
|
Thank you for giving feedback with this program.
|
||||||
This template will guide you through all the information we need.
|
This template will guide you through all the information we need.
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: programversion
|
id: programversion
|
||||||
attributes:
|
attributes:
|
||||||
label: Type
|
label: Type
|
||||||
description: "Is this suggestion for the CLI, GUI, or Both?"
|
description: 'Is this suggestion for the CLI, GUI, or Both?'
|
||||||
options:
|
options:
|
||||||
- CLI
|
- CLI
|
||||||
- GUI
|
- GUI
|
||||||
- Both
|
- Both
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: suggestion
|
id: suggestion
|
||||||
attributes:
|
attributes:
|
||||||
label: Suggestion
|
label: Suggestion
|
||||||
description: "What is your suggestion?"
|
description: 'What is your suggestion?'
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
|
||||||
13
.github/dependabot.yml
vendored
13
.github/dependabot.yml
vendored
|
|
@ -1,6 +1,11 @@
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: 'npm'
|
||||||
directory: "/"
|
directory: '/'
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: 'daily'
|
||||||
|
open-pull-requests-limit: 0
|
||||||
|
allow:
|
||||||
|
- dependency-type: 'direct'
|
||||||
|
ignore:
|
||||||
|
- dependency-type: 'all'
|
||||||
|
|
|
||||||
40
.github/workflows/auto-documentation.yml
vendored
40
.github/workflows/auto-documentation.yml
vendored
|
|
@ -1,26 +1,26 @@
|
||||||
name: auto-documentation
|
name: auto-documentation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
documentation:
|
documentation:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
- run: pnpm i
|
- run: pnpm i
|
||||||
- run: pnpm run docs
|
- run: pnpm run docs
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
with:
|
with:
|
||||||
commit_message: ${{ github.event.head_commit.message }} + Documentation
|
commit_message: ${{ github.event.head_commit.message }} + Documentation
|
||||||
|
|
|
||||||
51
.github/workflows/docker.yml
vendored
51
.github/workflows/docker.yml
vendored
|
|
@ -3,31 +3,30 @@
|
||||||
name: build and push docker image
|
name: build and push docker image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-node:
|
build-node:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
runs-on: ubuntu-latest
|
steps:
|
||||||
steps:
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/checkout@v2
|
- name: Set up Docker Buildx
|
||||||
- name: Set up Docker Buildx
|
id: buildx
|
||||||
id: buildx
|
uses: docker/setup-buildx-action@v1
|
||||||
uses: docker/setup-buildx-action@v1
|
- name: Login to DockerHub
|
||||||
- name: Login to DockerHub
|
if: ${{ github.ref == 'refs/heads/master' }}
|
||||||
if: ${{ github.ref == 'refs/heads/master' }}
|
uses: docker/login-action@v1
|
||||||
uses: docker/login-action@v1
|
with:
|
||||||
with:
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
- name: Build and push Docker images
|
||||||
- name: Build and push Docker images
|
uses: docker/build-push-action@v2.9.0
|
||||||
uses: docker/build-push-action@v2.9.0
|
with:
|
||||||
with:
|
github-token: ${{ github.token }}
|
||||||
github-token: ${{ github.token }}
|
push: ${{ github.ref == 'refs/heads/master' }}
|
||||||
push: ${{ github.ref == 'refs/heads/master' }}
|
tags: |
|
||||||
tags: |
|
"multidl/multi-downloader-nx:latest"
|
||||||
"multidl/multi-downloader-nx:latest"
|
- name: Image digest
|
||||||
- name: Image digest
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
|
|
|
||||||
122
.github/workflows/release-matrix.yml
vendored
122
.github/workflows/release-matrix.yml
vendored
|
|
@ -1,66 +1,66 @@
|
||||||
name: Release Builds
|
name: Release Builds
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [ published ]
|
types: [published]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
build_type: [ linux, macos, windows ]
|
build_type: [linux, macos, windows]
|
||||||
build_arch: [ x64 ]
|
build_arch: [x64]
|
||||||
gui: [ gui, cli ]
|
gui: [gui, cli]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- name: Install Node modules
|
- name: Install Node modules
|
||||||
run: |
|
run: |
|
||||||
pnpm install
|
pnpm install
|
||||||
- name: Get name and version from package.json
|
- name: Get name and version from package.json
|
||||||
run: |
|
run: |
|
||||||
test -n $(node -p -e "require('./package.json').name") &&
|
test -n $(node -p -e "require('./package.json').name") &&
|
||||||
test -n $(node -p -e "require('./package.json').version") &&
|
test -n $(node -p -e "require('./package.json').version") &&
|
||||||
echo PACKAGE_NAME=$(node -p -e "require('./package.json').name") >> $GITHUB_ENV &&
|
echo PACKAGE_NAME=$(node -p -e "require('./package.json').name") >> $GITHUB_ENV &&
|
||||||
echo PACKAGE_VERSION=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV || exit 1
|
echo PACKAGE_VERSION=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV || exit 1
|
||||||
- name: Make build
|
- name: Make build
|
||||||
run: pnpm run build-${{ matrix.build_type }}-${{ matrix.gui }}
|
run: pnpm run build-${{ matrix.build_type }}-${{ matrix.gui }}
|
||||||
- name: Upload release
|
- name: Upload release
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
upload_url: ${{ github.event.release.upload_url }}
|
||||||
asset_name: multi-downloader-nx-${{ matrix.build_type }}-${{ matrix.gui }}.7z
|
asset_name: multi-downloader-nx-${{ matrix.build_type }}-${{ matrix.gui }}.7z
|
||||||
asset_path: ./lib/_builds/multi-downloader-nx-${{ matrix.build_type }}-${{ matrix.build_arch }}-${{ matrix.gui }}.7z
|
asset_path: ./lib/_builds/multi-downloader-nx-${{ matrix.build_type }}-${{ matrix.build_arch }}-${{ matrix.gui }}.7z
|
||||||
asset_content_type: application/x-7z-compressed
|
asset_content_type: application/x-7z-compressed
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
build-docker:
|
build-docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push Docker images
|
- name: Build and push Docker images
|
||||||
uses: docker/build-push-action@v2.9.0
|
uses: docker/build-push-action@v2.9.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
"multidl/multi-downloader-nx:${{ github.event.release.tag_name }}"
|
"multidl/multi-downloader-nx:${{ github.event.release.tag_name }}"
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|
|
||||||
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
|
|
@ -7,6 +7,20 @@ on:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
tsc:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
check-latest: true
|
||||||
|
- run: pnpm i
|
||||||
|
- run: npx tsc
|
||||||
eslint:
|
eslint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -17,10 +31,24 @@ jobs:
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- run: pnpm i
|
- run: pnpm i
|
||||||
- run: npx eslint . --quiet
|
- run: pnpm run eslint
|
||||||
|
prettier:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
check-latest: true
|
||||||
|
- run: pnpm i
|
||||||
|
- run: pnpm run prettier
|
||||||
test:
|
test:
|
||||||
needs: eslint
|
needs: eslint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
@ -32,7 +60,7 @@ jobs:
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- run: pnpm i
|
- run: pnpm i
|
||||||
- run: pnpm run test
|
- run: pnpm run test
|
||||||
|
|
|
||||||
23
.prettierignore
Normal file
23
.prettierignore
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Build
|
||||||
|
build
|
||||||
|
lib
|
||||||
|
|
||||||
|
# Local
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
logs
|
||||||
|
ffmpeg
|
||||||
|
mkvmerge
|
||||||
|
fonts
|
||||||
|
*.json
|
||||||
|
*.md
|
||||||
|
*.yaml
|
||||||
|
!package.json
|
||||||
|
!tsconfig.json
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
# Auto generated
|
||||||
|
docs
|
||||||
|
|
||||||
36
.prettierrc
36
.prettierrc
|
|
@ -1,20 +1,20 @@
|
||||||
{
|
{
|
||||||
"arrowParens": "always",
|
"arrowParens": "always",
|
||||||
"bracketSameLine": false,
|
"bracketSameLine": false,
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"embeddedLanguageFormatting": "auto",
|
"embeddedLanguageFormatting": "auto",
|
||||||
"htmlWhitespaceSensitivity": "strict",
|
"htmlWhitespaceSensitivity": "strict",
|
||||||
"insertPragma": false,
|
"insertPragma": false,
|
||||||
"jsxSingleQuote": false,
|
"jsxSingleQuote": false,
|
||||||
"proseWrap": "never",
|
"proseWrap": "never",
|
||||||
"quoteProps": "as-needed",
|
"quoteProps": "as-needed",
|
||||||
"requirePragma": false,
|
"requirePragma": false,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"useTabs": true,
|
"useTabs": true,
|
||||||
"vueIndentScriptAndStyle": false,
|
"vueIndentScriptAndStyle": false,
|
||||||
"printWidth": 180,
|
"printWidth": 180,
|
||||||
"endOfLine": "auto"
|
"endOfLine": "auto"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
@types/adnPlayerConfig.d.ts
vendored
34
@types/adnPlayerConfig.d.ts
vendored
|
|
@ -3,48 +3,48 @@ export interface ADNPlayerConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Player {
|
export interface Player {
|
||||||
image: string;
|
image: string;
|
||||||
options: Options;
|
options: Options;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
user: User;
|
user: User;
|
||||||
chromecast: Chromecast;
|
chromecast: Chromecast;
|
||||||
ios: Ios;
|
ios: Ios;
|
||||||
video: Video;
|
video: Video;
|
||||||
dock: any[];
|
dock: any[];
|
||||||
preference: Preference;
|
preference: Preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Chromecast {
|
export interface Chromecast {
|
||||||
appId: string;
|
appId: string;
|
||||||
refreshTokenUrl: string;
|
refreshTokenUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Ios {
|
export interface Ios {
|
||||||
videoUrl: string;
|
videoUrl: string;
|
||||||
appUrl: string;
|
appUrl: string;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Preference {
|
export interface Preference {
|
||||||
quality: string;
|
quality: string;
|
||||||
autoplay: boolean;
|
autoplay: boolean;
|
||||||
language: string;
|
language: string;
|
||||||
green: boolean;
|
green: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
hasAccess: boolean;
|
hasAccess: boolean;
|
||||||
profileId: number;
|
profileId: number;
|
||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
refreshTokenUrl: string;
|
refreshTokenUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Video {
|
export interface Video {
|
||||||
startDate: null;
|
startDate: null;
|
||||||
currentDate: Date;
|
currentDate: Date;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
free: boolean;
|
free: boolean;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
@types/adnSearch.d.ts
vendored
66
@types/adnSearch.d.ts
vendored
|
|
@ -4,40 +4,40 @@ export interface ADNSearch {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ADNSearchShow {
|
export interface ADNSearchShow {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
originalTitle: string;
|
originalTitle: string;
|
||||||
shortTitle: string;
|
shortTitle: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
age: string;
|
age: string;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
summary: string;
|
summary: string;
|
||||||
image: string;
|
image: string;
|
||||||
image2x: string;
|
image2x: string;
|
||||||
imageHorizontal: string;
|
imageHorizontal: string;
|
||||||
imageHorizontal2x: string;
|
imageHorizontal2x: string;
|
||||||
url: string;
|
url: string;
|
||||||
urlPath: string;
|
urlPath: string;
|
||||||
episodeCount: number;
|
episodeCount: number;
|
||||||
genres: string[];
|
genres: string[];
|
||||||
copyright: string;
|
copyright: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
ratingsCount: number;
|
ratingsCount: number;
|
||||||
commentsCount: number;
|
commentsCount: number;
|
||||||
qualities: string[];
|
qualities: string[];
|
||||||
simulcast: boolean;
|
simulcast: boolean;
|
||||||
free: boolean;
|
free: boolean;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
download: boolean;
|
download: boolean;
|
||||||
basedOn: string;
|
basedOn: string;
|
||||||
tagline: null;
|
tagline: null;
|
||||||
firstReleaseYear: string;
|
firstReleaseYear: string;
|
||||||
productionStudio: string;
|
productionStudio: string;
|
||||||
countryOfOrigin: string;
|
countryOfOrigin: string;
|
||||||
productionTeam: ProductionTeam[];
|
productionTeam: ProductionTeam[];
|
||||||
nextVideoReleaseDate: null;
|
nextVideoReleaseDate: null;
|
||||||
indexable: boolean;
|
indexable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductionTeam {
|
export interface ProductionTeam {
|
||||||
|
|
|
||||||
48
@types/adnStreams.d.ts
vendored
48
@types/adnStreams.d.ts
vendored
|
|
@ -1,14 +1,14 @@
|
||||||
export interface ADNStreams {
|
export interface ADNStreams {
|
||||||
links: Links;
|
links: Links;
|
||||||
video: Video;
|
video: Video;
|
||||||
metadata: Metadata;
|
metadata: Metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Links {
|
export interface Links {
|
||||||
streaming: Streaming;
|
streaming: Streaming;
|
||||||
subtitles: Subtitles;
|
subtitles: Subtitles;
|
||||||
history: string;
|
history: string;
|
||||||
nextVideoUrl: string;
|
nextVideoUrl: string;
|
||||||
previousVideoUrl: string;
|
previousVideoUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,10 +18,10 @@ export interface Streaming {
|
||||||
|
|
||||||
export interface Streams {
|
export interface Streams {
|
||||||
mobile: string;
|
mobile: string;
|
||||||
sd: string;
|
sd: string;
|
||||||
hd: string;
|
hd: string;
|
||||||
fhd: string;
|
fhd: string;
|
||||||
auto: string;
|
auto: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Subtitles {
|
export interface Subtitles {
|
||||||
|
|
@ -29,23 +29,23 @@ export interface Subtitles {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Metadata {
|
export interface Metadata {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
summary: null;
|
summary: null;
|
||||||
rating: number;
|
rating: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Video {
|
export interface Video {
|
||||||
guid: string;
|
guid: string;
|
||||||
id: number;
|
id: number;
|
||||||
currentTime: number;
|
currentTime: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
url: string;
|
url: string;
|
||||||
image: string;
|
image: string;
|
||||||
tcEpisodeStart?:string;
|
tcEpisodeStart?: string;
|
||||||
tcEpisodeEnd?: string;
|
tcEpisodeEnd?: string;
|
||||||
tcIntroStart?: string;
|
tcIntroStart?: string;
|
||||||
tcIntroEnd?: string;
|
tcIntroEnd?: string;
|
||||||
tcEndingStart?: string;
|
tcEndingStart?: string;
|
||||||
tcEndingEnd?: string;
|
tcEndingEnd?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
@types/adnSubtitles.d.ts
vendored
8
@types/adnSubtitles.d.ts
vendored
|
|
@ -3,9 +3,9 @@ export interface ADNSubtitles {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Subtitle {
|
export interface Subtitle {
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
positionAlign: string;
|
positionAlign: string;
|
||||||
lineAlign: string;
|
lineAlign: string;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
122
@types/adnVideos.d.ts
vendored
122
@types/adnVideos.d.ts
vendored
|
|
@ -3,72 +3,72 @@ export interface ADNVideos {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ADNVideo {
|
export interface ADNVideo {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
name: string;
|
name: string;
|
||||||
number: string;
|
number: string;
|
||||||
shortNumber: string;
|
shortNumber: string;
|
||||||
season: string;
|
season: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
type: string;
|
type: string;
|
||||||
order: number;
|
order: number;
|
||||||
image: string;
|
image: string;
|
||||||
image2x: string;
|
image2x: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
releaseDate: Date;
|
releaseDate: Date;
|
||||||
duration: number;
|
duration: number;
|
||||||
url: string;
|
url: string;
|
||||||
urlPath: string;
|
urlPath: string;
|
||||||
embeddedUrl: string;
|
embeddedUrl: string;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
qualities: string[];
|
qualities: string[];
|
||||||
rating: number;
|
rating: number;
|
||||||
ratingsCount: number;
|
ratingsCount: number;
|
||||||
commentsCount: number;
|
commentsCount: number;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
download: boolean;
|
download: boolean;
|
||||||
free: boolean;
|
free: boolean;
|
||||||
freeWithAds: boolean;
|
freeWithAds: boolean;
|
||||||
show: Show;
|
show: Show;
|
||||||
indexable: boolean;
|
indexable: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Show {
|
export interface Show {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
originalTitle: string;
|
originalTitle: string;
|
||||||
shortTitle: string;
|
shortTitle: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
age: string;
|
age: string;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
summary: string;
|
summary: string;
|
||||||
image: string;
|
image: string;
|
||||||
image2x: string;
|
image2x: string;
|
||||||
imageHorizontal: string;
|
imageHorizontal: string;
|
||||||
imageHorizontal2x: string;
|
imageHorizontal2x: string;
|
||||||
url: string;
|
url: string;
|
||||||
urlPath: string;
|
urlPath: string;
|
||||||
episodeCount: number;
|
episodeCount: number;
|
||||||
genres: string[];
|
genres: string[];
|
||||||
copyright: string;
|
copyright: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
ratingsCount: number;
|
ratingsCount: number;
|
||||||
commentsCount: number;
|
commentsCount: number;
|
||||||
qualities: string[];
|
qualities: string[];
|
||||||
simulcast: boolean;
|
simulcast: boolean;
|
||||||
free: boolean;
|
free: boolean;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
download: boolean;
|
download: boolean;
|
||||||
basedOn: string;
|
basedOn: string;
|
||||||
tagline: string;
|
tagline: string;
|
||||||
firstReleaseYear: string;
|
firstReleaseYear: string;
|
||||||
productionStudio: string;
|
productionStudio: string;
|
||||||
countryOfOrigin: string;
|
countryOfOrigin: string;
|
||||||
productionTeam: ProductionTeam[];
|
productionTeam: ProductionTeam[];
|
||||||
nextVideoReleaseDate: Date;
|
nextVideoReleaseDate: Date;
|
||||||
indexable: boolean;
|
indexable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductionTeam {
|
export interface ProductionTeam {
|
||||||
|
|
|
||||||
138
@types/animeOnegaiSearch.d.ts
vendored
138
@types/animeOnegaiSearch.d.ts
vendored
|
|
@ -7,82 +7,82 @@ export interface AOSearchResult {
|
||||||
/**
|
/**
|
||||||
* Asset ID
|
* Asset ID
|
||||||
*/
|
*/
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
title: string;
|
title: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
excerpt: string;
|
excerpt: string;
|
||||||
description: string;
|
description: string;
|
||||||
bg: string;
|
bg: string;
|
||||||
poster: string;
|
poster: string;
|
||||||
entry: string;
|
entry: string;
|
||||||
code_name: string;
|
code_name: string;
|
||||||
/**
|
/**
|
||||||
* The Video ID required to get the streams
|
* The Video ID required to get the streams
|
||||||
*/
|
*/
|
||||||
video_entry: string;
|
video_entry: string;
|
||||||
trailer: string;
|
trailer: string;
|
||||||
year: number;
|
year: number;
|
||||||
/**
|
/**
|
||||||
* Asset Type, Known Possibilities
|
* Asset Type, Known Possibilities
|
||||||
* * 1 - Video
|
* * 1 - Video
|
||||||
* * 2 - Series
|
* * 2 - Series
|
||||||
*/
|
*/
|
||||||
asset_type: 1 | 2;
|
asset_type: 1 | 2;
|
||||||
status: number;
|
status: number;
|
||||||
permalink: string;
|
permalink: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
subtitles: boolean;
|
subtitles: boolean;
|
||||||
price: number;
|
price: number;
|
||||||
rent_price: number;
|
rent_price: number;
|
||||||
rating: number;
|
rating: number;
|
||||||
color: number | null;
|
color: number | null;
|
||||||
classification: number;
|
classification: number;
|
||||||
brazil_classification: null | string;
|
brazil_classification: null | string;
|
||||||
likes: number;
|
likes: number;
|
||||||
views: number;
|
views: number;
|
||||||
button: string;
|
button: string;
|
||||||
stream_url: string;
|
stream_url: string;
|
||||||
stream_url_backup: string;
|
stream_url_backup: string;
|
||||||
copyright: null | string;
|
copyright: null | string;
|
||||||
skip_intro: null | string;
|
skip_intro: null | string;
|
||||||
ending: null | string;
|
ending: null | string;
|
||||||
bumper_intro: string;
|
bumper_intro: string;
|
||||||
ads: string;
|
ads: string;
|
||||||
age_restriction: boolean | null;
|
age_restriction: boolean | null;
|
||||||
epg: null;
|
epg: null;
|
||||||
allow_languages: string[] | null;
|
allow_languages: string[] | null;
|
||||||
allow_countries: string[] | null;
|
allow_countries: string[] | null;
|
||||||
classification_text: string;
|
classification_text: string;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
resign: boolean;
|
resign: boolean;
|
||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
actors_list: null;
|
actors_list: null;
|
||||||
voiceactors_list: null;
|
voiceactors_list: null;
|
||||||
artdirectors_list: null;
|
artdirectors_list: null;
|
||||||
audios_list: null;
|
audios_list: null;
|
||||||
awards_list: null;
|
awards_list: null;
|
||||||
companies_list: null;
|
companies_list: null;
|
||||||
countries_list: null;
|
countries_list: null;
|
||||||
directors_list: null;
|
directors_list: null;
|
||||||
edition_list: null;
|
edition_list: null;
|
||||||
genres_list: null;
|
genres_list: null;
|
||||||
music_list: null;
|
music_list: null;
|
||||||
photograpy_list: null;
|
photograpy_list: null;
|
||||||
producer_list: null;
|
producer_list: null;
|
||||||
screenwriter_list: null;
|
screenwriter_list: null;
|
||||||
season_list: null;
|
season_list: null;
|
||||||
tags_list: null;
|
tags_list: null;
|
||||||
chapter_id: number;
|
chapter_id: number;
|
||||||
chapter_entry: string;
|
chapter_entry: string;
|
||||||
chapter_poster: string;
|
chapter_poster: string;
|
||||||
progress_time: number;
|
progress_time: number;
|
||||||
progress_percent: number;
|
progress_percent: number;
|
||||||
included_subscription: number;
|
included_subscription: number;
|
||||||
paid_content: number;
|
paid_content: number;
|
||||||
rent_content: number;
|
rent_content: number;
|
||||||
objectID: string;
|
objectID: string;
|
||||||
lang: string;
|
lang: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
56
@types/animeOnegaiSeasons.d.ts
vendored
56
@types/animeOnegaiSeasons.d.ts
vendored
|
|
@ -1,36 +1,36 @@
|
||||||
export interface AnimeOnegaiSeasons {
|
export interface AnimeOnegaiSeasons {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
number: number;
|
number: number;
|
||||||
asset_id: number;
|
asset_id: number;
|
||||||
entry: string;
|
entry: string;
|
||||||
description: string;
|
description: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
allow_languages: string[];
|
allow_languages: string[];
|
||||||
allow_countries: string[];
|
allow_countries: string[];
|
||||||
list: Episode[];
|
list: Episode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Episode {
|
export interface Episode {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
number: number;
|
number: number;
|
||||||
description: string;
|
description: string;
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
entry: string;
|
entry: string;
|
||||||
video_entry: string;
|
video_entry: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
season_id: number;
|
season_id: number;
|
||||||
stream_url: string;
|
stream_url: string;
|
||||||
skip_intro: null;
|
skip_intro: null;
|
||||||
ending: null;
|
ending: null;
|
||||||
open_free: boolean;
|
open_free: boolean;
|
||||||
asset_id: number;
|
asset_id: number;
|
||||||
age_restriction: boolean;
|
age_restriction: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
178
@types/animeOnegaiSeries.d.ts
vendored
178
@types/animeOnegaiSeries.d.ts
vendored
|
|
@ -1,111 +1,111 @@
|
||||||
export interface AnimeOnegaiSeries {
|
export interface AnimeOnegaiSeries {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
title: string;
|
title: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
excerpt: string;
|
excerpt: string;
|
||||||
description: string;
|
description: string;
|
||||||
bg: string;
|
bg: string;
|
||||||
poster: string;
|
poster: string;
|
||||||
entry: string;
|
entry: string;
|
||||||
code_name: string;
|
code_name: string;
|
||||||
/**
|
/**
|
||||||
* The Video ID required to get the streams
|
* The Video ID required to get the streams
|
||||||
*/
|
*/
|
||||||
video_entry: string;
|
video_entry: string;
|
||||||
trailer: string;
|
trailer: string;
|
||||||
year: number;
|
year: number;
|
||||||
asset_type: number;
|
asset_type: number;
|
||||||
status: number;
|
status: number;
|
||||||
permalink: string;
|
permalink: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
subtitles: boolean;
|
subtitles: boolean;
|
||||||
price: number;
|
price: number;
|
||||||
rent_price: number;
|
rent_price: number;
|
||||||
rating: number;
|
rating: number;
|
||||||
color: number;
|
color: number;
|
||||||
classification: number;
|
classification: number;
|
||||||
brazil_classification: string;
|
brazil_classification: string;
|
||||||
likes: number;
|
likes: number;
|
||||||
views: number;
|
views: number;
|
||||||
button: string;
|
button: string;
|
||||||
stream_url: string;
|
stream_url: string;
|
||||||
stream_url_backup: string;
|
stream_url_backup: string;
|
||||||
copyright: string;
|
copyright: string;
|
||||||
skip_intro: null;
|
skip_intro: null;
|
||||||
ending: null;
|
ending: null;
|
||||||
bumper_intro: string;
|
bumper_intro: string;
|
||||||
ads: string;
|
ads: string;
|
||||||
age_restriction: boolean;
|
age_restriction: boolean;
|
||||||
epg: null;
|
epg: null;
|
||||||
allow_languages: string[];
|
allow_languages: string[];
|
||||||
allow_countries: string[];
|
allow_countries: string[];
|
||||||
classification_text: string;
|
classification_text: string;
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
resign: boolean;
|
resign: boolean;
|
||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
actors_list: CtorsList[];
|
actors_list: CtorsList[];
|
||||||
voiceactors_list: CtorsList[];
|
voiceactors_list: CtorsList[];
|
||||||
artdirectors_list: any[];
|
artdirectors_list: any[];
|
||||||
audios_list: SList[];
|
audios_list: SList[];
|
||||||
awards_list: any[];
|
awards_list: any[];
|
||||||
companies_list: any[];
|
companies_list: any[];
|
||||||
countries_list: any[];
|
countries_list: any[];
|
||||||
directors_list: CtorsList[];
|
directors_list: CtorsList[];
|
||||||
edition_list: any[];
|
edition_list: any[];
|
||||||
genres_list: SList[];
|
genres_list: SList[];
|
||||||
music_list: any[];
|
music_list: any[];
|
||||||
photograpy_list: any[];
|
photograpy_list: any[];
|
||||||
producer_list: any[];
|
producer_list: any[];
|
||||||
screenwriter_list: any[];
|
screenwriter_list: any[];
|
||||||
season_list: any[];
|
season_list: any[];
|
||||||
tags_list: TagsList[];
|
tags_list: TagsList[];
|
||||||
chapter_id: number;
|
chapter_id: number;
|
||||||
chapter_entry: string;
|
chapter_entry: string;
|
||||||
chapter_poster: string;
|
chapter_poster: string;
|
||||||
progress_time: number;
|
progress_time: number;
|
||||||
progress_percent: number;
|
progress_percent: number;
|
||||||
included_subscription: number;
|
included_subscription: number;
|
||||||
paid_content: number;
|
paid_content: number;
|
||||||
rent_content: number;
|
rent_content: number;
|
||||||
objectID: string;
|
objectID: string;
|
||||||
lang: string;
|
lang: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CtorsList {
|
export interface CtorsList {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
Permalink?: string;
|
Permalink?: string;
|
||||||
country: number | null;
|
country: number | null;
|
||||||
year: number | null;
|
year: number | null;
|
||||||
death: number | null;
|
death: number | null;
|
||||||
image: string;
|
image: string;
|
||||||
genre: null;
|
genre: null;
|
||||||
description: string;
|
description: string;
|
||||||
permalink?: string;
|
permalink?: string;
|
||||||
background?: string;
|
background?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SList {
|
export interface SList {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
age_restriction?: number;
|
age_restriction?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TagsList {
|
export interface TagsList {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
position: number;
|
position: number;
|
||||||
status: boolean;
|
status: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
72
@types/animeOnegaiStream.d.ts
vendored
72
@types/animeOnegaiStream.d.ts
vendored
|
|
@ -1,41 +1,41 @@
|
||||||
export interface AnimeOnegaiStream {
|
export interface AnimeOnegaiStream {
|
||||||
ID: number;
|
ID: number;
|
||||||
CreatedAt: Date;
|
|
||||||
UpdatedAt: Date;
|
|
||||||
DeletedAt: null;
|
|
||||||
name: string;
|
|
||||||
source_url: string;
|
|
||||||
backup_url: string;
|
|
||||||
live: boolean;
|
|
||||||
token_handler: number;
|
|
||||||
entry: string;
|
|
||||||
job: string;
|
|
||||||
drm: boolean;
|
|
||||||
transcoding_content_id: string;
|
|
||||||
transcoding_asset_id: string;
|
|
||||||
status: number;
|
|
||||||
thumbnail: string;
|
|
||||||
hls: string;
|
|
||||||
dash: string;
|
|
||||||
widevine_proxy: string;
|
|
||||||
playready_proxy: string;
|
|
||||||
apple_licence: string;
|
|
||||||
apple_certificate: string;
|
|
||||||
dpath: string;
|
|
||||||
dbin: string;
|
|
||||||
subtitles: Subtitle[];
|
|
||||||
origin: number;
|
|
||||||
offline_entry: string;
|
|
||||||
offline_status: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Subtitle {
|
|
||||||
ID: number;
|
|
||||||
CreatedAt: Date;
|
CreatedAt: Date;
|
||||||
UpdatedAt: Date;
|
UpdatedAt: Date;
|
||||||
DeletedAt: null;
|
DeletedAt: null;
|
||||||
name: string;
|
name: string;
|
||||||
lang: string;
|
source_url: string;
|
||||||
entry_id: string;
|
backup_url: string;
|
||||||
url: string;
|
live: boolean;
|
||||||
|
token_handler: number;
|
||||||
|
entry: string;
|
||||||
|
job: string;
|
||||||
|
drm: boolean;
|
||||||
|
transcoding_content_id: string;
|
||||||
|
transcoding_asset_id: string;
|
||||||
|
status: number;
|
||||||
|
thumbnail: string;
|
||||||
|
hls: string;
|
||||||
|
dash: string;
|
||||||
|
widevine_proxy: string;
|
||||||
|
playready_proxy: string;
|
||||||
|
apple_licence: string;
|
||||||
|
apple_certificate: string;
|
||||||
|
dpath: string;
|
||||||
|
dbin: string;
|
||||||
|
subtitles: Subtitle[];
|
||||||
|
origin: number;
|
||||||
|
offline_entry: string;
|
||||||
|
offline_status: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Subtitle {
|
||||||
|
ID: number;
|
||||||
|
CreatedAt: Date;
|
||||||
|
UpdatedAt: Date;
|
||||||
|
DeletedAt: null;
|
||||||
|
name: string;
|
||||||
|
lang: string;
|
||||||
|
entry_id: string;
|
||||||
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
165
@types/crunchyAndroidEpisodes.d.ts
vendored
165
@types/crunchyAndroidEpisodes.d.ts
vendored
|
|
@ -1,85 +1,85 @@
|
||||||
import { Images } from './crunchyEpisodeList';
|
import { Images } from './crunchyEpisodeList';
|
||||||
|
|
||||||
export interface CrunchyAndroidEpisodes {
|
export interface CrunchyAndroidEpisodes {
|
||||||
__class__: string;
|
__class__: string;
|
||||||
__href__: string;
|
__href__: string;
|
||||||
__resource_key__: string;
|
__resource_key__: string;
|
||||||
__links__: object;
|
__links__: object;
|
||||||
__actions__: object;
|
__actions__: object;
|
||||||
total: number;
|
total: number;
|
||||||
items: CrunchyAndroidEpisode[];
|
items: CrunchyAndroidEpisode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyAndroidEpisode {
|
export interface CrunchyAndroidEpisode {
|
||||||
__class__: string;
|
__class__: string;
|
||||||
__href__: string;
|
__href__: string;
|
||||||
__resource_key__: string;
|
__resource_key__: string;
|
||||||
__links__: Links;
|
__links__: Links;
|
||||||
__actions__: Actions;
|
__actions__: Actions;
|
||||||
playback: string;
|
playback: string;
|
||||||
id: string;
|
id: string;
|
||||||
channel_id: ChannelID;
|
channel_id: ChannelID;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
series_title: string;
|
series_title: string;
|
||||||
series_slug_title: string;
|
series_slug_title: string;
|
||||||
season_id: string;
|
season_id: string;
|
||||||
season_title: string;
|
season_title: string;
|
||||||
season_slug_title: string;
|
season_slug_title: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
episode: string;
|
episode: string;
|
||||||
episode_number: number;
|
episode_number: number;
|
||||||
sequence_number: number;
|
sequence_number: number;
|
||||||
production_episode_id: string;
|
production_episode_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
description: string;
|
description: string;
|
||||||
next_episode_id: string;
|
next_episode_id: string;
|
||||||
next_episode_title: string;
|
next_episode_title: string;
|
||||||
hd_flag: boolean;
|
hd_flag: boolean;
|
||||||
maturity_ratings: MaturityRating[];
|
maturity_ratings: MaturityRating[];
|
||||||
extended_maturity_rating: Actions;
|
extended_maturity_rating: Actions;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
episode_air_date: Date;
|
episode_air_date: Date;
|
||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
availability_starts: Date;
|
availability_starts: Date;
|
||||||
availability_ends: Date;
|
availability_ends: Date;
|
||||||
eligible_region: string;
|
eligible_region: string;
|
||||||
available_date: Date;
|
available_date: Date;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
premium_date: Date;
|
premium_date: Date;
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_clip: boolean;
|
is_clip: boolean;
|
||||||
seo_title: string;
|
seo_title: string;
|
||||||
seo_description: string;
|
seo_description: string;
|
||||||
season_tags: string[];
|
season_tags: string[];
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
versions: Version[];
|
versions: Version[];
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
media_type: MediaType;
|
media_type: MediaType;
|
||||||
slug: string;
|
slug: string;
|
||||||
images: Images;
|
images: Images;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
listing_id: string;
|
listing_id: string;
|
||||||
hide_season_title?: boolean;
|
hide_season_title?: boolean;
|
||||||
hide_season_number?: boolean;
|
hide_season_number?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
seq_id: string;
|
seq_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Links {
|
export interface Links {
|
||||||
'episode/channel': Link;
|
'episode/channel': Link;
|
||||||
'episode/next_episode': Link;
|
'episode/next_episode': Link;
|
||||||
'episode/season': Link;
|
'episode/season': Link;
|
||||||
'episode/series': Link;
|
'episode/series': Link;
|
||||||
streams: Link;
|
streams: Link;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Link {
|
export interface Link {
|
||||||
|
|
@ -87,9 +87,9 @@ export interface Link {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Thumbnail {
|
export interface Thumbnail {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
type: string;
|
type: string;
|
||||||
source: string;
|
source: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,28 +109,27 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MediaType {
|
export enum MediaType {
|
||||||
Episode = 'episode',
|
Episode = 'episode'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChannelID {
|
export enum ChannelID {
|
||||||
Crunchyroll = 'crunchyroll',
|
Crunchyroll = 'crunchyroll'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MaturityRating {
|
export enum MaturityRating {
|
||||||
Tv14 = 'TV-14',
|
Tv14 = 'TV-14'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
variant: string;
|
variant: string;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
258
@types/crunchyAndroidObject.d.ts
vendored
258
@types/crunchyAndroidObject.d.ts
vendored
|
|
@ -1,49 +1,49 @@
|
||||||
import { ImageType, Images, Image } from './objectInfo';
|
import { ImageType, Images, Image } from './objectInfo';
|
||||||
|
|
||||||
export interface CrunchyAndroidObject {
|
export interface CrunchyAndroidObject {
|
||||||
__class__: string;
|
__class__: string;
|
||||||
__href__: string;
|
__href__: string;
|
||||||
__resource_key__: string;
|
__resource_key__: string;
|
||||||
__links__: object;
|
__links__: object;
|
||||||
__actions__: object;
|
__actions__: object;
|
||||||
total: number;
|
total: number;
|
||||||
items: AndroidObject[];
|
items: AndroidObject[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AndroidObject {
|
export interface AndroidObject {
|
||||||
__class__: string;
|
__class__: string;
|
||||||
__href__: string;
|
__href__: string;
|
||||||
__links__: Links;
|
__links__: Links;
|
||||||
__actions__: Actions;
|
__actions__: Actions;
|
||||||
id: string;
|
id: string;
|
||||||
external_id: string;
|
external_id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
promo_title: string;
|
promo_title: string;
|
||||||
promo_description: string;
|
promo_description: string;
|
||||||
type: string;
|
type: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
images: Images;
|
images: Images;
|
||||||
movie_listing_metadata?: MovieListingMetadata;
|
movie_listing_metadata?: MovieListingMetadata;
|
||||||
movie_metadata?: MovieMetadata;
|
movie_metadata?: MovieMetadata;
|
||||||
playback?: string;
|
playback?: string;
|
||||||
episode_metadata?: EpisodeMetadata;
|
episode_metadata?: EpisodeMetadata;
|
||||||
streams_link?: string;
|
streams_link?: string;
|
||||||
season_metadata?: SeasonMetadata;
|
season_metadata?: SeasonMetadata;
|
||||||
linked_resource_key: string;
|
linked_resource_key: string;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
f_num: string;
|
f_num: string;
|
||||||
s_num: string;
|
s_num: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Links {
|
export interface Links {
|
||||||
'episode/season': LinkData;
|
'episode/season': LinkData;
|
||||||
'episode/series': LinkData;
|
'episode/series': LinkData;
|
||||||
resource: LinkData;
|
resource: LinkData;
|
||||||
'resource/channel': LinkData;
|
'resource/channel': LinkData;
|
||||||
streams: LinkData;
|
streams: LinkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LinkData {
|
export interface LinkData {
|
||||||
|
|
@ -51,119 +51,119 @@ export interface LinkData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeMetadata {
|
export interface EpisodeMetadata {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
availability_ends: Date;
|
availability_ends: Date;
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
availability_starts: Date;
|
availability_starts: Date;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
eligible_region: string;
|
eligible_region: string;
|
||||||
episode: string;
|
episode: string;
|
||||||
episode_air_date: Date;
|
episode_air_date: Date;
|
||||||
episode_number: number;
|
episode_number: number;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
is_clip: boolean;
|
is_clip: boolean;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
season_id: string;
|
season_id: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
season_slug_title: string;
|
season_slug_title: string;
|
||||||
season_title: string;
|
season_title: string;
|
||||||
sequence_number: number;
|
sequence_number: number;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
series_slug_title: string;
|
series_slug_title: string;
|
||||||
series_title: string;
|
series_title: string;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
versions: EpisodeMetadataVersion[];
|
versions: EpisodeMetadataVersion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieListingMetadata {
|
export interface MovieListingMetadata {
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
first_movie_id: string;
|
first_movie_id: string;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
movie_release_year: number;
|
movie_release_year: number;
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories: string[];
|
tenant_categories: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieMetadata {
|
export interface MovieMetadata {
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
movie_listing_id: string;
|
movie_listing_id: string;
|
||||||
movie_listing_slug_title: string;
|
movie_listing_slug_title: string;
|
||||||
movie_listing_title: string;
|
movie_listing_title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeasonMetadata {
|
export interface SeasonMetadata {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
audio_locales: Locale[];
|
audio_locales: Locale[];
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
season_display_number: string;
|
season_display_number: string;
|
||||||
season_sequence_number: number;
|
season_sequence_number: number;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
versions: SeasonMetadataVersion[];
|
versions: SeasonMetadataVersion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeasonMetadataVersion {
|
export interface SeasonMetadataVersion {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
export interface SeriesMetadata {
|
export interface SeriesMetadata {
|
||||||
audio_locales: Locale[];
|
audio_locales: Locale[];
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
episode_count: number;
|
episode_count: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_simulcast: boolean;
|
is_simulcast: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
season_count: number;
|
season_count: number;
|
||||||
series_launch_year: number;
|
series_launch_year: number;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Locale {
|
export enum Locale {
|
||||||
|
|
@ -182,5 +182,5 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
@types/crunchyAndroidStreams.d.ts
vendored
70
@types/crunchyAndroidStreams.d.ts
vendored
|
|
@ -1,37 +1,21 @@
|
||||||
export interface CrunchyAndroidStreams {
|
|
||||||
__class__: string;
|
|
||||||
__href__: string;
|
|
||||||
__resource_key__: string;
|
|
||||||
__links__: Links;
|
|
||||||
__actions__: Record<unknown, unknown>;
|
|
||||||
media_id: string;
|
|
||||||
audio_locale: Locale;
|
|
||||||
subtitles: Subtitles;
|
|
||||||
closed_captions: Subtitles;
|
|
||||||
streams: Streams;
|
|
||||||
bifs: string[];
|
|
||||||
versions: Version[];
|
|
||||||
captions: Record<unknown, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Subtitles {
|
export interface Subtitles {
|
||||||
'': Subtitle;
|
'': Subtitle;
|
||||||
'en-US'?: Subtitle;
|
'en-US'?: Subtitle;
|
||||||
'es-LA'?: Subtitle;
|
'es-LA'?: Subtitle;
|
||||||
'es-419'?: Subtitle;
|
'es-419'?: Subtitle;
|
||||||
'es-ES'?: Subtitle;
|
'es-ES'?: Subtitle;
|
||||||
'pt-BR'?: Subtitle;
|
'pt-BR'?: Subtitle;
|
||||||
'fr-FR'?: Subtitle;
|
'fr-FR'?: Subtitle;
|
||||||
'de-DE'?: Subtitle;
|
'de-DE'?: Subtitle;
|
||||||
'ar-ME'?: Subtitle;
|
'ar-ME'?: Subtitle;
|
||||||
'ar-SA'?: Subtitle;
|
'ar-SA'?: Subtitle;
|
||||||
'it-IT'?: Subtitle;
|
'it-IT'?: Subtitle;
|
||||||
'ru-RU'?: Subtitle;
|
'ru-RU'?: Subtitle;
|
||||||
'tr-TR'?: Subtitle;
|
'tr-TR'?: Subtitle;
|
||||||
'hi-IN'?: Subtitle;
|
'hi-IN'?: Subtitle;
|
||||||
'zh-CN'?: Subtitle;
|
'zh-CN'?: Subtitle;
|
||||||
'ko-KR'?: Subtitle;
|
'ko-KR'?: Subtitle;
|
||||||
'ja-JP'?: Subtitle;
|
'ja-JP'?: Subtitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Links {
|
export interface Links {
|
||||||
|
|
@ -48,8 +32,8 @@ export interface Streams {
|
||||||
|
|
||||||
export interface Download {
|
export interface Download {
|
||||||
hardsub_locale: Locale;
|
hardsub_locale: Locale;
|
||||||
hardsub_lang?: string;
|
hardsub_lang?: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Urls {
|
export interface Urls {
|
||||||
|
|
@ -58,17 +42,17 @@ export interface Urls {
|
||||||
|
|
||||||
export interface Subtitle {
|
export interface Subtitle {
|
||||||
locale: Locale;
|
locale: Locale;
|
||||||
url: string;
|
url: string;
|
||||||
format: string;
|
format: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
variant: string;
|
variant: string;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,5 +73,5 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
@types/crunchyChapters.d.ts
vendored
38
@types/crunchyChapters.d.ts
vendored
|
|
@ -1,26 +1,26 @@
|
||||||
export interface CrunchyChapters {
|
export interface CrunchyChapters {
|
||||||
[key: string]: CrunchyChapter;
|
[key: string]: CrunchyChapter;
|
||||||
lastUpdate: Date;
|
lastUpdate: Date;
|
||||||
mediaId: string;
|
mediaId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyChapter {
|
export interface CrunchyChapter {
|
||||||
approverId: string;
|
approverId: string;
|
||||||
distributionNumber: string;
|
distributionNumber: string;
|
||||||
end: number;
|
end: number;
|
||||||
start: number;
|
start: number;
|
||||||
title: string;
|
title: string;
|
||||||
seriesId: string;
|
seriesId: string;
|
||||||
new: boolean;
|
new: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyOldChapter {
|
export interface CrunchyOldChapter {
|
||||||
media_id: string;
|
media_id: string;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
comparedWith: string;
|
comparedWith: string;
|
||||||
ordering: string;
|
ordering: string;
|
||||||
last_updated: Date;
|
last_updated: Date;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
148
@types/crunchyEpisodeList.d.ts
vendored
148
@types/crunchyEpisodeList.d.ts
vendored
|
|
@ -2,69 +2,69 @@ import { Links } from './crunchyAndroidEpisodes';
|
||||||
|
|
||||||
export interface CrunchyEpisodeList {
|
export interface CrunchyEpisodeList {
|
||||||
total: number;
|
total: number;
|
||||||
data: CrunchyEpisode[];
|
data: CrunchyEpisode[];
|
||||||
meta: Meta;
|
meta: Meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyEpisode {
|
export interface CrunchyEpisode {
|
||||||
next_episode_id: string;
|
next_episode_id: string;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
next_episode_title: string;
|
next_episode_title: string;
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
series_slug_title: string;
|
series_slug_title: string;
|
||||||
series_title: string;
|
series_title: string;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
versions: Version[] | null;
|
versions: Version[] | null;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
sequence_number: number;
|
sequence_number: number;
|
||||||
eligible_region: Record<unknown>;
|
eligible_region: Record<unknown>;
|
||||||
availability_starts: Date;
|
availability_starts: Date;
|
||||||
images: Images;
|
images: Images;
|
||||||
season_id: string;
|
season_id: string;
|
||||||
seo_title: string;
|
seo_title: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
title: string;
|
title: string;
|
||||||
production_episode_id: string;
|
production_episode_id: string;
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
season_title: string;
|
season_title: string;
|
||||||
seo_description: string;
|
seo_description: string;
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
id: string;
|
id: string;
|
||||||
media_type: MediaType;
|
media_type: MediaType;
|
||||||
availability_ends: Date;
|
availability_ends: Date;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
playback: string;
|
playback: string;
|
||||||
channel_id: ChannelID;
|
channel_id: ChannelID;
|
||||||
episode: string;
|
episode: string;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
listing_id: string;
|
listing_id: string;
|
||||||
episode_air_date: Date;
|
episode_air_date: Date;
|
||||||
slug: string;
|
slug: string;
|
||||||
available_date: Date;
|
available_date: Date;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
description: string;
|
description: string;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
premium_date: Date;
|
premium_date: Date;
|
||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
season_slug_title: string;
|
season_slug_title: string;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
episode_number: number;
|
episode_number: number;
|
||||||
season_tags: any[];
|
season_tags: any[];
|
||||||
maturity_ratings: MaturityRating[];
|
maturity_ratings: MaturityRating[];
|
||||||
streams_link?: string;
|
streams_link?: string;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
is_clip: boolean;
|
is_clip: boolean;
|
||||||
hd_flag: boolean;
|
hd_flag: boolean;
|
||||||
hide_season_title?: boolean;
|
hide_season_title?: boolean;
|
||||||
hide_season_number?: boolean;
|
hide_season_number?: boolean;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
seq_id: string;
|
seq_id: string;
|
||||||
__links__?: Links;
|
__links__?: Links;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Locale {
|
export enum Locale {
|
||||||
|
|
@ -83,52 +83,52 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChannelID {
|
export enum ChannelID {
|
||||||
Crunchyroll = 'crunchyroll',
|
Crunchyroll = 'crunchyroll'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Images {
|
export interface Images {
|
||||||
poster_tall?: Array<Image[]>;
|
poster_tall?: Array<Image[]>;
|
||||||
poster_wide?: Array<Image[]>;
|
poster_wide?: Array<Image[]>;
|
||||||
promo_image?: Array<Image[]>;
|
promo_image?: Array<Image[]>;
|
||||||
thumbnail?: Array<Image[]>;
|
thumbnail?: Array<Image[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Image {
|
export interface Image {
|
||||||
height: number;
|
height: number;
|
||||||
source: string;
|
source: string;
|
||||||
type: ImageType;
|
type: ImageType;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ImageType {
|
export enum ImageType {
|
||||||
PosterTall = 'poster_tall',
|
PosterTall = 'poster_tall',
|
||||||
PosterWide = 'poster_wide',
|
PosterWide = 'poster_wide',
|
||||||
PromoImage = 'promo_image',
|
PromoImage = 'promo_image',
|
||||||
Thumbnail = 'thumbnail',
|
Thumbnail = 'thumbnail'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MaturityRating {
|
export enum MaturityRating {
|
||||||
Tv14 = 'TV-14',
|
Tv14 = 'TV-14'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MediaType {
|
export enum MediaType {
|
||||||
Episode = 'episode',
|
Episode = 'episode'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Meta {
|
export interface Meta {
|
||||||
versions_considered?: boolean;
|
versions_considered?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
56
@types/crunchyPlayStreams.d.ts
vendored
56
@types/crunchyPlayStreams.d.ts
vendored
|
|
@ -1,44 +1,44 @@
|
||||||
import { Locale } from './playbackData';
|
import { Locale } from './playbackData';
|
||||||
|
|
||||||
export interface CrunchyPlayStream {
|
export interface CrunchyPlayStream {
|
||||||
assetId: string;
|
assetId: string;
|
||||||
audioLocale: Locale;
|
audioLocale: Locale;
|
||||||
bifs: string;
|
bifs: string;
|
||||||
burnedInLocale: string;
|
burnedInLocale: string;
|
||||||
captions: { [key: string]: Caption };
|
captions: { [key: string]: Caption };
|
||||||
hardSubs: { [key: string]: HardSub };
|
hardSubs: { [key: string]: HardSub };
|
||||||
playbackType: string;
|
playbackType: string;
|
||||||
session: Session;
|
session: Session;
|
||||||
subtitles: { [key: string]: Subtitle };
|
subtitles: { [key: string]: Subtitle };
|
||||||
token: string;
|
token: string;
|
||||||
url: string;
|
url: string;
|
||||||
versions: any[];
|
versions: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Caption {
|
export interface Caption {
|
||||||
format: string;
|
format: string;
|
||||||
language: string;
|
language: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HardSub {
|
export interface HardSub {
|
||||||
hlang: string;
|
hlang: string;
|
||||||
url: string;
|
url: string;
|
||||||
quality: string;
|
quality: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
renewSeconds: number;
|
renewSeconds: number;
|
||||||
noNetworkRetryIntervalSeconds: number;
|
noNetworkRetryIntervalSeconds: number;
|
||||||
noNetworkTimeoutSeconds: number;
|
noNetworkTimeoutSeconds: number;
|
||||||
maximumPauseSeconds: number;
|
maximumPauseSeconds: number;
|
||||||
endOfVideoUnloadSeconds: number;
|
endOfVideoUnloadSeconds: number;
|
||||||
sessionExpirationSeconds: number;
|
sessionExpirationSeconds: number;
|
||||||
usesStreamLimits: boolean;
|
usesStreamLimits: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Subtitle {
|
export interface Subtitle {
|
||||||
format: string;
|
format: string;
|
||||||
language: string;
|
language: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
206
@types/crunchySearch.d.ts
vendored
206
@types/crunchySearch.d.ts
vendored
|
|
@ -2,79 +2,79 @@
|
||||||
|
|
||||||
export interface CrunchySearch {
|
export interface CrunchySearch {
|
||||||
total: number;
|
total: number;
|
||||||
data: CrunchySearchData[];
|
data: CrunchySearchData[];
|
||||||
meta: Record<string, unknown>;
|
meta: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchySearchData {
|
export interface CrunchySearchData {
|
||||||
type: string;
|
type: string;
|
||||||
count: number;
|
count: number;
|
||||||
items: CrunchySearchItem[];
|
items: CrunchySearchItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchySearchItem {
|
export interface CrunchySearchItem {
|
||||||
title: string;
|
title: string;
|
||||||
images: Images;
|
images: Images;
|
||||||
series_metadata?: SeriesMetadata;
|
series_metadata?: SeriesMetadata;
|
||||||
promo_description: string;
|
promo_description: string;
|
||||||
external_id: string;
|
external_id: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
new: boolean;
|
new: boolean;
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
channel_id: ChannelID;
|
channel_id: ChannelID;
|
||||||
description: string;
|
description: string;
|
||||||
linked_resource_key: string;
|
linked_resource_key: string;
|
||||||
type: ItemType;
|
type: ItemType;
|
||||||
id: string;
|
id: string;
|
||||||
promo_title: string;
|
promo_title: string;
|
||||||
search_metadata: SearchMetadata;
|
search_metadata: SearchMetadata;
|
||||||
movie_listing_metadata?: MovieListingMetadata;
|
movie_listing_metadata?: MovieListingMetadata;
|
||||||
playback?: string;
|
playback?: string;
|
||||||
streams_link?: string;
|
streams_link?: string;
|
||||||
episode_metadata?: EpisodeMetadata;
|
episode_metadata?: EpisodeMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChannelID {
|
export enum ChannelID {
|
||||||
Crunchyroll = 'crunchyroll',
|
Crunchyroll = 'crunchyroll'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeMetadata {
|
export interface EpisodeMetadata {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
availability_ends: Date;
|
availability_ends: Date;
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
availability_starts: Date;
|
availability_starts: Date;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
eligible_region: string[];
|
eligible_region: string[];
|
||||||
episode: string;
|
episode: string;
|
||||||
episode_air_date: Date;
|
episode_air_date: Date;
|
||||||
episode_number: number;
|
episode_number: number;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
is_clip: boolean;
|
is_clip: boolean;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: MaturityRating[];
|
maturity_ratings: MaturityRating[];
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
season_id: string;
|
season_id: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
season_slug_title: string;
|
season_slug_title: string;
|
||||||
season_title: string;
|
season_title: string;
|
||||||
sequence_number: number;
|
sequence_number: number;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
series_slug_title: string;
|
series_slug_title: string;
|
||||||
series_title: string;
|
series_title: string;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
versions: Version[] | null;
|
versions: Version[] | null;
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Locale {
|
export enum Locale {
|
||||||
|
|
@ -93,65 +93,65 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MaturityRating {
|
export enum MaturityRating {
|
||||||
Tv14 = 'TV-14',
|
Tv14 = 'TV-14',
|
||||||
TvMa = 'TV-MA',
|
TvMa = 'TV-MA'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Images {
|
export interface Images {
|
||||||
poster_tall?: Array<Image[]>;
|
poster_tall?: Array<Image[]>;
|
||||||
poster_wide?: Array<Image[]>;
|
poster_wide?: Array<Image[]>;
|
||||||
promo_image?: Array<Image[]>;
|
promo_image?: Array<Image[]>;
|
||||||
thumbnail?: Array<Image[]>;
|
thumbnail?: Array<Image[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Image {
|
export interface Image {
|
||||||
height: number;
|
height: number;
|
||||||
source: string;
|
source: string;
|
||||||
type: ImageType;
|
type: ImageType;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ImageType {
|
export enum ImageType {
|
||||||
PosterTall = 'poster_tall',
|
PosterTall = 'poster_tall',
|
||||||
PosterWide = 'poster_wide',
|
PosterWide = 'poster_wide',
|
||||||
PromoImage = 'promo_image',
|
PromoImage = 'promo_image',
|
||||||
Thumbnail = 'thumbnail',
|
Thumbnail = 'thumbnail'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieListingMetadata {
|
export interface MovieListingMetadata {
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
first_movie_id: string;
|
first_movie_id: string;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
movie_release_year: number;
|
movie_release_year: number;
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
subtitle_locales: any[];
|
subtitle_locales: any[];
|
||||||
tenant_categories: string[];
|
tenant_categories: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchMetadata {
|
export interface SearchMetadata {
|
||||||
|
|
@ -159,25 +159,25 @@ export interface SearchMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeriesMetadata {
|
export interface SeriesMetadata {
|
||||||
audio_locales: Locale[];
|
audio_locales: Locale[];
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
episode_count: number;
|
episode_count: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_simulcast: boolean;
|
is_simulcast: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: MaturityRating[];
|
maturity_ratings: MaturityRating[];
|
||||||
season_count: number;
|
season_count: number;
|
||||||
series_launch_year: number;
|
series_launch_year: number;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ItemType {
|
export enum ItemType {
|
||||||
Episode = 'episode',
|
Episode = 'episode',
|
||||||
MovieListing = 'movie_listing',
|
MovieListing = 'movie_listing',
|
||||||
Series = 'series',
|
Series = 'series'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
317
@types/crunchyTypes.d.ts
vendored
317
@types/crunchyTypes.d.ts
vendored
|
|
@ -5,180 +5,191 @@ import { DownloadInfo } from './messageHandler';
|
||||||
import { CrunchyVideoPlayStreams, CrunchyAudioPlayStreams } from './enums';
|
import { CrunchyVideoPlayStreams, CrunchyAudioPlayStreams } from './enums';
|
||||||
|
|
||||||
export type CrunchyDownloadOptions = {
|
export type CrunchyDownloadOptions = {
|
||||||
hslang: string,
|
hslang: string;
|
||||||
// kstream: number,
|
// kstream: number,
|
||||||
cstream: keyof typeof CrunchyVideoPlayStreams,
|
cstream: keyof typeof CrunchyVideoPlayStreams;
|
||||||
vstream: keyof typeof CrunchyVideoPlayStreams,
|
vstream: keyof typeof CrunchyVideoPlayStreams;
|
||||||
astream: keyof typeof CrunchyAudioPlayStreams,
|
astream: keyof typeof CrunchyAudioPlayStreams;
|
||||||
tsd?: boolean,
|
tsd?: boolean;
|
||||||
novids?: boolean,
|
novids?: boolean;
|
||||||
noaudio?: boolean,
|
noaudio?: boolean;
|
||||||
x: number,
|
x: number;
|
||||||
q: number,
|
q: number;
|
||||||
fileName: string,
|
fileName: string;
|
||||||
numbers: number,
|
numbers: number;
|
||||||
partsize: number,
|
partsize: number;
|
||||||
callbackMaker?: (data: DownloadInfo) => HLSCallback,
|
callbackMaker?: (data: DownloadInfo) => HLSCallback;
|
||||||
timeout: number,
|
timeout: number;
|
||||||
waittime: number,
|
waittime: number;
|
||||||
fsRetryTime: number,
|
fsRetryTime: number;
|
||||||
dlsubs: string[],
|
dlsubs: string[];
|
||||||
skipsubs: boolean,
|
skipsubs: boolean;
|
||||||
nosubs?: boolean,
|
nosubs?: boolean;
|
||||||
mp4: boolean,
|
mp4: boolean;
|
||||||
override: string[],
|
override: string[];
|
||||||
videoTitle: string,
|
videoTitle: string;
|
||||||
force: 'Y'|'y'|'N'|'n'|'C'|'c',
|
force: 'Y' | 'y' | 'N' | 'n' | 'C' | 'c';
|
||||||
ffmpegOptions: string[],
|
ffmpegOptions: string[];
|
||||||
mkvmergeOptions: string[],
|
mkvmergeOptions: string[];
|
||||||
defaultSub: LanguageItem,
|
defaultSub: LanguageItem;
|
||||||
defaultAudio: LanguageItem,
|
defaultAudio: LanguageItem;
|
||||||
ccTag: string,
|
ccTag: string;
|
||||||
dlVideoOnce: boolean,
|
dlVideoOnce: boolean;
|
||||||
skipmux?: boolean,
|
skipmux?: boolean;
|
||||||
syncTiming: boolean,
|
syncTiming: boolean;
|
||||||
nocleanup: boolean,
|
nocleanup: boolean;
|
||||||
chapters: boolean,
|
chapters: boolean;
|
||||||
fontName: string | undefined,
|
fontName: string | undefined;
|
||||||
originalFontSize: boolean,
|
originalFontSize: boolean;
|
||||||
fontSize: number,
|
fontSize: number;
|
||||||
dubLang: string[],
|
dubLang: string[];
|
||||||
}
|
// Subtitle Fix Options
|
||||||
|
srtAssFix: boolean;
|
||||||
|
layoutResFix: boolean;
|
||||||
|
scaledBorderAndShadowFix: boolean;
|
||||||
|
scaledBorderAndShadow: 'yes' | 'no';
|
||||||
|
originalScriptFix: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type CrunchyMultiDownload = {
|
export type CrunchyMultiDownload = {
|
||||||
absolute?: boolean,
|
absolute?: boolean;
|
||||||
dubLang: string[],
|
dubLang: string[];
|
||||||
all?: boolean,
|
all?: boolean;
|
||||||
but?: boolean,
|
but?: boolean;
|
||||||
e?: string,
|
e?: string;
|
||||||
s?: string
|
s?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type CrunchyMuxOptions = {
|
export type CrunchyMuxOptions = {
|
||||||
output: string,
|
output: string;
|
||||||
skipSubMux?: boolean
|
skipSubMux?: boolean;
|
||||||
keepAllVideos?: bolean
|
keepAllVideos?: bolean;
|
||||||
novids?: boolean,
|
novids?: boolean;
|
||||||
mp4: boolean,
|
mp4: boolean;
|
||||||
forceMuxer?: 'ffmpeg'|'mkvmerge',
|
forceMuxer?: 'ffmpeg' | 'mkvmerge';
|
||||||
nocleanup?: boolean,
|
nocleanup?: boolean;
|
||||||
videoTitle: string,
|
videoTitle: string;
|
||||||
ffmpegOptions: string[],
|
ffmpegOptions: string[];
|
||||||
mkvmergeOptions: string[],
|
mkvmergeOptions: string[];
|
||||||
defaultSub: LanguageItem,
|
defaultSub: LanguageItem;
|
||||||
defaultAudio: LanguageItem,
|
defaultAudio: LanguageItem;
|
||||||
ccTag: string,
|
ccTag: string;
|
||||||
syncTiming: boolean,
|
syncTiming: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type CrunchyEpMeta = {
|
export type CrunchyEpMeta = {
|
||||||
data: {
|
data: {
|
||||||
mediaId: string,
|
mediaId: string;
|
||||||
lang?: LanguageItem,
|
lang?: LanguageItem;
|
||||||
playback?: string,
|
playback?: string;
|
||||||
versions?: EpisodeVersion[] | null,
|
versions?: EpisodeVersion[] | null;
|
||||||
isSubbed: boolean,
|
isSubbed: boolean;
|
||||||
isDubbed: boolean,
|
isDubbed: boolean;
|
||||||
}[],
|
}[];
|
||||||
seriesTitle: string,
|
seriesTitle: string;
|
||||||
seasonTitle: string,
|
seasonTitle: string;
|
||||||
episodeNumber: string,
|
episodeNumber: string;
|
||||||
episodeTitle: string,
|
episodeTitle: string;
|
||||||
seasonID: string,
|
seasonID: string;
|
||||||
season: number,
|
season: number;
|
||||||
showID: string,
|
showID: string;
|
||||||
e: string,
|
e: string;
|
||||||
image: string,
|
image: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DownloadedMedia = {
|
export type DownloadedMedia =
|
||||||
type: 'Video',
|
| {
|
||||||
lang: LanguageItem,
|
type: 'Video';
|
||||||
path: string,
|
lang: LanguageItem;
|
||||||
isPrimary?: boolean
|
path: string;
|
||||||
} | {
|
isPrimary?: boolean;
|
||||||
type: 'Audio',
|
}
|
||||||
lang: LanguageItem,
|
| {
|
||||||
path: string,
|
type: 'Audio';
|
||||||
isPrimary?: boolean
|
lang: LanguageItem;
|
||||||
} | {
|
path: string;
|
||||||
type: 'Chapters',
|
isPrimary?: boolean;
|
||||||
lang: LanguageItem,
|
}
|
||||||
path: string
|
| {
|
||||||
} | ({
|
type: 'Chapters';
|
||||||
type: 'Subtitle',
|
lang: LanguageItem;
|
||||||
signs: boolean,
|
path: string;
|
||||||
cc: boolean
|
}
|
||||||
} & sxItem )
|
| ({
|
||||||
|
type: 'Subtitle';
|
||||||
|
signs: boolean;
|
||||||
|
cc: boolean;
|
||||||
|
} & sxItem);
|
||||||
|
|
||||||
export type ParseItem = {
|
export type ParseItem = {
|
||||||
__class__?: string;
|
__class__?: string;
|
||||||
isSelected?: boolean,
|
isSelected?: boolean;
|
||||||
type?: string,
|
type?: string;
|
||||||
id: string,
|
id: string;
|
||||||
title: string,
|
title: string;
|
||||||
playback?: string,
|
playback?: string;
|
||||||
season_number?: number|string,
|
season_number?: number | string;
|
||||||
episode_number?: number|string,
|
episode_number?: number | string;
|
||||||
season_count?: number|string,
|
season_count?: number | string;
|
||||||
is_premium_only?: boolean,
|
is_premium_only?: boolean;
|
||||||
hide_metadata?: boolean,
|
hide_metadata?: boolean;
|
||||||
seq_id?: string,
|
seq_id?: string;
|
||||||
f_num?: string,
|
f_num?: string;
|
||||||
s_num?: string
|
s_num?: string;
|
||||||
external_id?: string,
|
external_id?: string;
|
||||||
ep_num?: string
|
ep_num?: string;
|
||||||
last_public?: string,
|
last_public?: string;
|
||||||
subtitle_locales?: string[],
|
subtitle_locales?: string[];
|
||||||
availability_notes?: string,
|
availability_notes?: string;
|
||||||
identifier?: string,
|
identifier?: string;
|
||||||
versions?: Version[] | null,
|
versions?: Version[] | null;
|
||||||
media_type?: string | null,
|
media_type?: string | null;
|
||||||
movie_release_year?: number | null,
|
movie_release_year?: number | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface SeriesSearch {
|
export interface SeriesSearch {
|
||||||
total: number;
|
total: number;
|
||||||
data: SeriesSearchItem[];
|
data: SeriesSearchItem[];
|
||||||
meta: Meta;
|
meta: Meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeriesSearchItem {
|
export interface SeriesSearchItem {
|
||||||
description: string;
|
description: string;
|
||||||
seo_description: string;
|
seo_description: string;
|
||||||
number_of_episodes: number;
|
number_of_episodes: number;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
season_sequence_number: number;
|
season_sequence_number: number;
|
||||||
season_tags: string[];
|
season_tags: string[];
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
audio_locale: string;
|
audio_locale: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
images: Record<unknown>;
|
images: Record<unknown>;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
versions: Version[];
|
versions: Version[];
|
||||||
title: string;
|
title: string;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
audio_locales: string[];
|
audio_locales: string[];
|
||||||
subtitle_locales: string[];
|
subtitle_locales: string[];
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
season_display_number: string;
|
season_display_number: string;
|
||||||
is_complete: boolean;
|
is_complete: boolean;
|
||||||
keywords: any[];
|
keywords: any[];
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
is_simulcast: boolean;
|
is_simulcast: boolean;
|
||||||
seo_title: string;
|
seo_title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeVersion {
|
export interface EpisodeVersion {
|
||||||
|
|
@ -207,7 +218,7 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Meta {
|
export interface Meta {
|
||||||
|
|
|
||||||
6
@types/downloadedFile.d.ts
vendored
6
@types/downloadedFile.d.ts
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
import { LanguageItem } from '../modules/module.langsData';
|
import { LanguageItem } from '../modules/module.langsData';
|
||||||
|
|
||||||
export type DownloadedFile = {
|
export type DownloadedFile = {
|
||||||
path: string,
|
path: string;
|
||||||
lang: LanguageItem
|
lang: LanguageItem;
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
export enum CrunchyVideoPlayStreams {
|
export enum CrunchyVideoPlayStreams {
|
||||||
'androidtv' = 'tv/android_tv',
|
'androidtv' = 'tv/android_tv',
|
||||||
'android' = 'android/phone',
|
'android' = 'android/phone',
|
||||||
'androidtab'= 'android/tablet'
|
'androidtab' = 'android/tablet'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CrunchyAudioPlayStreams {
|
export enum CrunchyAudioPlayStreams {
|
||||||
'androidtv' = 'tv/android_tv',
|
'androidtv' = 'tv/android_tv',
|
||||||
'android' = 'android/phone',
|
'android' = 'android/phone',
|
||||||
'androidtab'= 'android/tablet'
|
'androidtab' = 'android/tablet'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
598
@types/episode.d.ts
vendored
598
@types/episode.d.ts
vendored
|
|
@ -1,391 +1,391 @@
|
||||||
// Generated by https://quicktype.io
|
// Generated by https://quicktype.io
|
||||||
|
|
||||||
export interface EpisodeData {
|
export interface EpisodeData {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
mediaDict: { [key: string]: string };
|
mediaDict: { [key: string]: string };
|
||||||
episodeSlug: string;
|
episodeSlug: string;
|
||||||
starRating: number;
|
starRating: number;
|
||||||
parent: EpisodeDataParent;
|
parent: EpisodeDataParent;
|
||||||
number: string;
|
number: string;
|
||||||
description: string;
|
description: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
seriesBanner: string;
|
seriesBanner: string;
|
||||||
media: Media[];
|
media: Media[];
|
||||||
externalItemId: string;
|
externalItemId: string;
|
||||||
contentId: string;
|
contentId: string;
|
||||||
metaItems: MetaItems;
|
metaItems: MetaItems;
|
||||||
thumb: string;
|
thumb: string;
|
||||||
type: Type;
|
type: Type;
|
||||||
default: { [key: string]: Default };
|
default: { [key: string]: Default };
|
||||||
published: boolean;
|
published: boolean;
|
||||||
versions: VersionClass[];
|
versions: VersionClass[];
|
||||||
mediaCategory: string;
|
mediaCategory: string;
|
||||||
order: number;
|
order: number;
|
||||||
seriesVersions: any[];
|
seriesVersions: any[];
|
||||||
source: Source;
|
source: Source;
|
||||||
ids: EpisodeDataIDS;
|
ids: EpisodeDataIDS;
|
||||||
runtime: string;
|
runtime: string;
|
||||||
siblings: PreviousSeasonEpisode[];
|
siblings: PreviousSeasonEpisode[];
|
||||||
seriesTitle: string;
|
seriesTitle: string;
|
||||||
seriesSlug: string;
|
seriesSlug: string;
|
||||||
next: Next;
|
next: Next;
|
||||||
previousSeasonEpisode: PreviousSeasonEpisode;
|
previousSeasonEpisode: PreviousSeasonEpisode;
|
||||||
seasonTitle: string;
|
seasonTitle: string;
|
||||||
quality: Quality;
|
quality: Quality;
|
||||||
ratings: Array<string[]>;
|
ratings: Array<string[]>;
|
||||||
languages: TitleElement[];
|
languages: TitleElement[];
|
||||||
releaseDate: string;
|
releaseDate: string;
|
||||||
historicalSelections: HistoricalSelections;
|
historicalSelections: HistoricalSelections;
|
||||||
userRating: UserRating;
|
userRating: UserRating;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Default {
|
export interface Default {
|
||||||
items: DefaultItem[];
|
items: DefaultItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DefaultItem {
|
export interface DefaultItem {
|
||||||
languages: string[];
|
languages: string[];
|
||||||
territories: string[];
|
territories: string[];
|
||||||
version: null;
|
version: null;
|
||||||
value: Value[];
|
value: Value[];
|
||||||
devices: any[];
|
devices: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Value {
|
export interface Value {
|
||||||
name: MetaType;
|
name: MetaType;
|
||||||
value: string;
|
value: string;
|
||||||
label: Label;
|
label: Label;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Label {
|
export enum Label {
|
||||||
Rating = 'Rating',
|
Rating = 'Rating',
|
||||||
RatingSystem = 'Rating System',
|
RatingSystem = 'Rating System',
|
||||||
ReleaseDate = 'Release Date',
|
ReleaseDate = 'Release Date',
|
||||||
Synopsis = 'Synopsis',
|
Synopsis = 'Synopsis',
|
||||||
SynopsisType = 'Synopsis Type',
|
SynopsisType = 'Synopsis Type'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MetaType {
|
export enum MetaType {
|
||||||
Rating = 'rating',
|
Rating = 'rating',
|
||||||
RatingSystemType = 'RatingSystemType',
|
RatingSystemType = 'RatingSystemType',
|
||||||
ReleaseDate = 'release-date',
|
ReleaseDate = 'release-date',
|
||||||
Synopsis = 'synopsis',
|
Synopsis = 'synopsis',
|
||||||
Synopsistype = 'synopsistype',
|
Synopsistype = 'synopsistype',
|
||||||
VideoRatingType = 'VideoRatingType',
|
VideoRatingType = 'VideoRatingType'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HistoricalSelections {
|
export interface HistoricalSelections {
|
||||||
version: string;
|
version: string;
|
||||||
language: string;
|
language: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeDataIDS {
|
export interface EpisodeDataIDS {
|
||||||
externalShowId: string;
|
externalShowId: string;
|
||||||
externalSeasonId: string;
|
externalSeasonId: string;
|
||||||
externalEpisodeId: string;
|
externalEpisodeId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TitleElement {
|
export enum TitleElement {
|
||||||
Empty = '',
|
Empty = '',
|
||||||
English = 'English',
|
English = 'English'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Media {
|
export interface Media {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
experienceType: string;
|
experienceType: string;
|
||||||
created: string;
|
created: string;
|
||||||
createdBy: string;
|
createdBy: string;
|
||||||
itemFieldData: Next;
|
itemFieldData: Next;
|
||||||
keyPath: string;
|
keyPath: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
complianceStatus: null;
|
complianceStatus: null;
|
||||||
events: any[];
|
events: any[];
|
||||||
clients: string[];
|
clients: string[];
|
||||||
qcStatus: null;
|
qcStatus: null;
|
||||||
qcStatusDate: null;
|
qcStatusDate: null;
|
||||||
image: string;
|
image: string;
|
||||||
thumb: string;
|
thumb: string;
|
||||||
ext: string;
|
ext: string;
|
||||||
avails: Avail[];
|
avails: Avail[];
|
||||||
version: string;
|
version: string;
|
||||||
startTimecode: null;
|
startTimecode: null;
|
||||||
endTimecode: null;
|
endTimecode: null;
|
||||||
versionId: string;
|
versionId: string;
|
||||||
mediaType: string;
|
mediaType: string;
|
||||||
status: string;
|
status: string;
|
||||||
languages: LanguageClass[];
|
languages: LanguageClass[];
|
||||||
territories: any[];
|
territories: any[];
|
||||||
devices: any[];
|
devices: any[];
|
||||||
keyType: string;
|
keyType: string;
|
||||||
purpose: null;
|
purpose: null;
|
||||||
externalItemId: null | string;
|
externalItemId: null | string;
|
||||||
proxyId: null;
|
proxyId: null;
|
||||||
externalDbId: null;
|
externalDbId: null;
|
||||||
mediaChildren: MediaChild[];
|
mediaChildren: MediaChild[];
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
parent: MediaChildParent;
|
parent: MediaChildParent;
|
||||||
filePath: null | string;
|
filePath: null | string;
|
||||||
mediaInfo: Next;
|
mediaInfo: Next;
|
||||||
type: string;
|
type: string;
|
||||||
approved: boolean;
|
approved: boolean;
|
||||||
mediaKey: string;
|
mediaKey: string;
|
||||||
itemFields: any[];
|
itemFields: any[];
|
||||||
source: Source;
|
source: Source;
|
||||||
fieldData: Next;
|
fieldData: Next;
|
||||||
sourceId: null | string;
|
sourceId: null | string;
|
||||||
timecodeOverride: null;
|
timecodeOverride: null;
|
||||||
seriesTitle: string;
|
seriesTitle: string;
|
||||||
episodeTitle: string;
|
episodeTitle: string;
|
||||||
genre: any[];
|
genre: any[];
|
||||||
txDate: string;
|
txDate: string;
|
||||||
description: string;
|
description: string;
|
||||||
synopsis: string;
|
synopsis: string;
|
||||||
resolution: null;
|
resolution: null;
|
||||||
restrictedAccess: boolean;
|
restrictedAccess: boolean;
|
||||||
createdById: string;
|
createdById: string;
|
||||||
userIdsWithAccess: any[];
|
userIdsWithAccess: any[];
|
||||||
runtime?: number;
|
runtime?: number;
|
||||||
language?: TitleElement;
|
language?: TitleElement;
|
||||||
purchased: boolean;
|
purchased: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Avail {
|
export interface Avail {
|
||||||
id: number;
|
id: number;
|
||||||
description: string;
|
description: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
startDate: string;
|
startDate: string;
|
||||||
ids: AvailIDS;
|
ids: AvailIDS;
|
||||||
originalAirDate: null;
|
originalAirDate: null;
|
||||||
physicalReleaseDate: null;
|
physicalReleaseDate: null;
|
||||||
preorderDate: null;
|
preorderDate: null;
|
||||||
language: TitleElement;
|
language: TitleElement;
|
||||||
territory: string;
|
territory: string;
|
||||||
territoryCode: string;
|
territoryCode: string;
|
||||||
license: string;
|
license: string;
|
||||||
parentAvail: null;
|
parentAvail: null;
|
||||||
item: number;
|
item: number;
|
||||||
version: string;
|
version: string;
|
||||||
applyToLevel: null;
|
applyToLevel: null;
|
||||||
availLevel: string;
|
availLevel: string;
|
||||||
availDisplayCode: string;
|
availDisplayCode: string;
|
||||||
availStatus: string;
|
availStatus: string;
|
||||||
bundleOnly: boolean;
|
bundleOnly: boolean;
|
||||||
contentOwnerOrganization: string;
|
contentOwnerOrganization: string;
|
||||||
currency: null;
|
currency: null;
|
||||||
price: null;
|
price: null;
|
||||||
purchase: string;
|
purchase: string;
|
||||||
priceValue: string;
|
priceValue: string;
|
||||||
resolutionFormat: null;
|
resolutionFormat: null;
|
||||||
runtimeMilliseconds: null;
|
runtimeMilliseconds: null;
|
||||||
seasonOrEpisodeNumber: null;
|
seasonOrEpisodeNumber: null;
|
||||||
tmsid: null;
|
tmsid: null;
|
||||||
deviceList: string;
|
deviceList: string;
|
||||||
tvodSku: null;
|
tvodSku: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AvailIDS {
|
export interface AvailIDS {
|
||||||
externalSeasonId: string;
|
externalSeasonId: string;
|
||||||
externalAsianId: null;
|
externalAsianId: null;
|
||||||
externalShowId: string;
|
externalShowId: string;
|
||||||
externalEpisodeId: string;
|
externalEpisodeId: string;
|
||||||
externalEnglishId: string;
|
externalEnglishId: string;
|
||||||
externalAlphaId: string;
|
externalAlphaId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Next = Record<string, unknown>
|
export type Next = Record<string, unknown>;
|
||||||
|
|
||||||
export interface LanguageClass {
|
export interface LanguageClass {
|
||||||
code: string;
|
code: string;
|
||||||
id: number;
|
id: number;
|
||||||
title: TitleElement;
|
title: TitleElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MediaChild {
|
export interface MediaChild {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
experienceType: string;
|
experienceType: string;
|
||||||
created: string;
|
created: string;
|
||||||
createdBy: string;
|
createdBy: string;
|
||||||
itemFieldData: Next;
|
itemFieldData: Next;
|
||||||
keyPath: null;
|
keyPath: null;
|
||||||
filename: string;
|
filename: string;
|
||||||
complianceStatus: null;
|
complianceStatus: null;
|
||||||
events: any[];
|
events: any[];
|
||||||
clients: string[];
|
clients: string[];
|
||||||
qcStatus: null;
|
qcStatus: null;
|
||||||
qcStatusDate: null;
|
qcStatusDate: null;
|
||||||
image: string;
|
image: string;
|
||||||
ext: string;
|
ext: string;
|
||||||
avails: any[];
|
avails: any[];
|
||||||
version: string;
|
version: string;
|
||||||
startTimecode: null;
|
startTimecode: null;
|
||||||
endTimecode: null;
|
endTimecode: null;
|
||||||
versionId: string;
|
versionId: string;
|
||||||
mediaType: string;
|
mediaType: string;
|
||||||
status: string;
|
status: string;
|
||||||
languages: LanguageClass[];
|
languages: LanguageClass[];
|
||||||
territories: any[];
|
territories: any[];
|
||||||
devices: any[];
|
devices: any[];
|
||||||
keyType: string;
|
keyType: string;
|
||||||
purpose: null;
|
purpose: null;
|
||||||
externalItemId: string;
|
externalItemId: string;
|
||||||
proxyId: null;
|
proxyId: null;
|
||||||
externalDbId: null;
|
externalDbId: null;
|
||||||
mediaChildren: any[];
|
mediaChildren: any[];
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
parent: MediaChildParent;
|
parent: MediaChildParent;
|
||||||
filePath: string;
|
filePath: string;
|
||||||
mediaInfo: MediaInfo;
|
mediaInfo: MediaInfo;
|
||||||
type: string;
|
type: string;
|
||||||
approved: boolean;
|
approved: boolean;
|
||||||
mediaKey: null;
|
mediaKey: null;
|
||||||
itemFields: any[];
|
itemFields: any[];
|
||||||
source: Source;
|
source: Source;
|
||||||
fieldData: Next;
|
fieldData: Next;
|
||||||
sourceId: null;
|
sourceId: null;
|
||||||
timecodeOverride: null;
|
timecodeOverride: null;
|
||||||
seriesTitle: string;
|
seriesTitle: string;
|
||||||
episodeTitle: string;
|
episodeTitle: string;
|
||||||
genre: any[];
|
genre: any[];
|
||||||
txDate: string;
|
txDate: string;
|
||||||
description: string;
|
description: string;
|
||||||
synopsis: string;
|
synopsis: string;
|
||||||
resolution: null | string;
|
resolution: null | string;
|
||||||
restrictedAccess: boolean;
|
restrictedAccess: boolean;
|
||||||
createdById: string;
|
createdById: string;
|
||||||
userIdsWithAccess: any[];
|
userIdsWithAccess: any[];
|
||||||
language: TitleElement;
|
language: TitleElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MediaInfo {
|
export interface MediaInfo {
|
||||||
imageAspectRatio: null | string;
|
imageAspectRatio: null | string;
|
||||||
format: string;
|
format: string;
|
||||||
scanMode: null | string;
|
scanMode: null | string;
|
||||||
burnedInSubtitleLanguage: string;
|
burnedInSubtitleLanguage: string;
|
||||||
screenAspectRatio: null | string;
|
screenAspectRatio: null | string;
|
||||||
subtitleFormat: null | string;
|
subtitleFormat: null | string;
|
||||||
subtitleContent: null | string;
|
subtitleContent: null | string;
|
||||||
frameHeight: number | null;
|
frameHeight: number | null;
|
||||||
frameWidth: number | null;
|
frameWidth: number | null;
|
||||||
video: Video;
|
video: Video;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Video {
|
export interface Video {
|
||||||
codecId: null | string;
|
codecId: null | string;
|
||||||
container: null | string;
|
container: null | string;
|
||||||
encodingRate: number | null;
|
encodingRate: number | null;
|
||||||
frameRate: null | string;
|
frameRate: null | string;
|
||||||
height: number | null;
|
height: number | null;
|
||||||
width: number | null;
|
width: number | null;
|
||||||
duration: number | null;
|
duration: number | null;
|
||||||
bitRate: number | null;
|
bitRate: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MediaChildParent {
|
export interface MediaChildParent {
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
catalogParent: CatalogParent;
|
catalogParent: CatalogParent;
|
||||||
slug: string;
|
slug: string;
|
||||||
grandparentId: number;
|
grandparentId: number;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CatalogParent {
|
export interface CatalogParent {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Source {
|
export enum Source {
|
||||||
Dbb = 'dbb',
|
Dbb = 'dbb'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetaItems {
|
export interface MetaItems {
|
||||||
items: Items;
|
items: Items;
|
||||||
filters: Filters;
|
filters: Filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Filters {
|
export interface Filters {
|
||||||
territory: any[];
|
territory: any[];
|
||||||
language: any[];
|
language: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Items {
|
export interface Items {
|
||||||
'release-date': AnimationProductionStudio;
|
'release-date': AnimationProductionStudio;
|
||||||
rating: AnimationProductionStudio;
|
rating: AnimationProductionStudio;
|
||||||
synopsis: AnimationProductionStudio;
|
synopsis: AnimationProductionStudio;
|
||||||
'animation-production-studio': AnimationProductionStudio;
|
'animation-production-studio': AnimationProductionStudio;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnimationProductionStudio {
|
export interface AnimationProductionStudio {
|
||||||
items: AnimationProductionStudioItem[];
|
items: AnimationProductionStudioItem[];
|
||||||
label: string;
|
label: string;
|
||||||
id: number;
|
id: number;
|
||||||
slug: string;
|
slug: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnimationProductionStudioItem {
|
export interface AnimationProductionStudioItem {
|
||||||
id: number;
|
id: number;
|
||||||
metaType: MetaType;
|
metaType: MetaType;
|
||||||
metaTypeId: string;
|
metaTypeId: string;
|
||||||
client: null;
|
client: null;
|
||||||
languages: TitleElement;
|
languages: TitleElement;
|
||||||
territories: string;
|
territories: string;
|
||||||
devices: string;
|
devices: string;
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
value: Value[];
|
value: Value[];
|
||||||
approved: boolean;
|
approved: boolean;
|
||||||
version: null;
|
version: null;
|
||||||
source: Source;
|
source: Source;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeDataParent {
|
export interface EpisodeDataParent {
|
||||||
seasonId: number;
|
seasonId: number;
|
||||||
seasonNumber: string;
|
seasonNumber: string;
|
||||||
title: string;
|
title: string;
|
||||||
titleSlug: string;
|
titleSlug: string;
|
||||||
titleType: string;
|
titleType: string;
|
||||||
titleId: number;
|
titleId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PreviousSeasonEpisode {
|
export interface PreviousSeasonEpisode {
|
||||||
seasonTitle?: string;
|
seasonTitle?: string;
|
||||||
mediaCategory: Type;
|
mediaCategory: Type;
|
||||||
thumb: string;
|
thumb: string;
|
||||||
title: string;
|
title: string;
|
||||||
image: string;
|
image: string;
|
||||||
number: string;
|
number: string;
|
||||||
id: number;
|
id: number;
|
||||||
version: string[];
|
version: string[];
|
||||||
order: number;
|
order: number;
|
||||||
slug: string;
|
slug: string;
|
||||||
season?: number;
|
season?: number;
|
||||||
languages?: TitleElement[];
|
languages?: TitleElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Type {
|
export enum Type {
|
||||||
Episode = 'episode',
|
Episode = 'episode',
|
||||||
Ova = 'ova',
|
Ova = 'ova'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Quality {
|
export interface Quality {
|
||||||
quality: string;
|
quality: string;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserRating {
|
export interface UserRating {
|
||||||
overall: number;
|
overall: number;
|
||||||
ja: number;
|
ja: number;
|
||||||
eng: number;
|
eng: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VersionClass {
|
export interface VersionClass {
|
||||||
compliance_approved: boolean;
|
compliance_approved: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
version_id: string;
|
version_id: string;
|
||||||
is_default: boolean;
|
is_default: boolean;
|
||||||
runtime: string;
|
runtime: string;
|
||||||
external_id: string;
|
external_id: string;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
156
@types/github.d.ts
vendored
156
@types/github.d.ts
vendored
|
|
@ -1,106 +1,106 @@
|
||||||
export type GithubTag = {
|
export type GithubTag = {
|
||||||
name: string,
|
name: string;
|
||||||
zipball_url: string,
|
zipball_url: string;
|
||||||
tarball_url: string,
|
tarball_url: string;
|
||||||
commit: {
|
commit: {
|
||||||
sha: string,
|
sha: string;
|
||||||
url: string
|
url: string;
|
||||||
},
|
};
|
||||||
node_id: string
|
node_id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface TagCompare {
|
export interface TagCompare {
|
||||||
url: string;
|
url: string;
|
||||||
html_url: string;
|
html_url: string;
|
||||||
permalink_url: string;
|
permalink_url: string;
|
||||||
diff_url: string;
|
diff_url: string;
|
||||||
patch_url: string;
|
patch_url: string;
|
||||||
base_commit: BaseCommitClass;
|
base_commit: BaseCommitClass;
|
||||||
merge_base_commit: BaseCommitClass;
|
merge_base_commit: BaseCommitClass;
|
||||||
status: string;
|
status: string;
|
||||||
ahead_by: number;
|
ahead_by: number;
|
||||||
behind_by: number;
|
behind_by: number;
|
||||||
total_commits: number;
|
total_commits: number;
|
||||||
commits: BaseCommitClass[];
|
commits: BaseCommitClass[];
|
||||||
files: File[];
|
files: File[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseCommitClass {
|
export interface BaseCommitClass {
|
||||||
sha: string;
|
sha: string;
|
||||||
node_id: string;
|
node_id: string;
|
||||||
commit: BaseCommitCommit;
|
commit: BaseCommitCommit;
|
||||||
url: string;
|
url: string;
|
||||||
html_url: string;
|
html_url: string;
|
||||||
comments_url: string;
|
comments_url: string;
|
||||||
author: BaseCommitAuthor;
|
author: BaseCommitAuthor;
|
||||||
committer: BaseCommitAuthor;
|
committer: BaseCommitAuthor;
|
||||||
parents: Parent[];
|
parents: Parent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseCommitAuthor {
|
export interface BaseCommitAuthor {
|
||||||
login: string;
|
login: string;
|
||||||
id: number;
|
id: number;
|
||||||
node_id: string;
|
node_id: string;
|
||||||
avatar_url: string;
|
avatar_url: string;
|
||||||
gravatar_id: string;
|
gravatar_id: string;
|
||||||
url: string;
|
url: string;
|
||||||
html_url: string;
|
html_url: string;
|
||||||
followers_url: string;
|
followers_url: string;
|
||||||
following_url: string;
|
following_url: string;
|
||||||
gists_url: string;
|
gists_url: string;
|
||||||
starred_url: string;
|
starred_url: string;
|
||||||
subscriptions_url: string;
|
subscriptions_url: string;
|
||||||
organizations_url: string;
|
organizations_url: string;
|
||||||
repos_url: string;
|
repos_url: string;
|
||||||
events_url: string;
|
events_url: string;
|
||||||
received_events_url: string;
|
received_events_url: string;
|
||||||
type: string;
|
type: string;
|
||||||
site_admin: boolean;
|
site_admin: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseCommitCommit {
|
export interface BaseCommitCommit {
|
||||||
author: PurpleAuthor;
|
author: PurpleAuthor;
|
||||||
committer: PurpleAuthor;
|
committer: PurpleAuthor;
|
||||||
message: string;
|
message: string;
|
||||||
tree: Tree;
|
tree: Tree;
|
||||||
url: string;
|
url: string;
|
||||||
comment_count: number;
|
comment_count: number;
|
||||||
verification: Verification;
|
verification: Verification;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PurpleAuthor {
|
export interface PurpleAuthor {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
date: string;
|
date: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Tree {
|
export interface Tree {
|
||||||
sha: string;
|
sha: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Verification {
|
export interface Verification {
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
reason: string;
|
reason: string;
|
||||||
signature: string;
|
signature: string;
|
||||||
payload: string;
|
payload: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Parent {
|
export interface Parent {
|
||||||
sha: string;
|
sha: string;
|
||||||
url: string;
|
url: string;
|
||||||
html_url: string;
|
html_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface File {
|
export interface File {
|
||||||
sha: string;
|
sha: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
status: string;
|
status: string;
|
||||||
additions: number;
|
additions: number;
|
||||||
deletions: number;
|
deletions: number;
|
||||||
changes: number;
|
changes: number;
|
||||||
blob_url: string;
|
blob_url: string;
|
||||||
raw_url: string;
|
raw_url: string;
|
||||||
contents_url: string;
|
contents_url: string;
|
||||||
patch: string;
|
patch: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
92
@types/hidiveDashboard.d.ts
vendored
92
@types/hidiveDashboard.d.ts
vendored
|
|
@ -1,70 +1,70 @@
|
||||||
export interface HidiveDashboard {
|
export interface HidiveDashboard {
|
||||||
Code: number;
|
Code: number;
|
||||||
Status: string;
|
Status: string;
|
||||||
Message: null;
|
Message: null;
|
||||||
Messages: object;
|
Messages: object;
|
||||||
Data: Data;
|
Data: Data;
|
||||||
Timestamp: string;
|
Timestamp: string;
|
||||||
IPAddress: string;
|
IPAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Data {
|
export interface Data {
|
||||||
TitleRows: TitleRow[];
|
TitleRows: TitleRow[];
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TitleRow {
|
export interface TitleRow {
|
||||||
Name: string;
|
Name: string;
|
||||||
Titles: Title[];
|
Titles: Title[];
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Title {
|
export interface Title {
|
||||||
Id: number;
|
Id: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
ShortSynopsis: string;
|
ShortSynopsis: string;
|
||||||
MediumSynopsis: string;
|
MediumSynopsis: string;
|
||||||
LongSynopsis: string;
|
LongSynopsis: string;
|
||||||
KeyArtUrl: string;
|
KeyArtUrl: string;
|
||||||
MasterArtUrl: string;
|
MasterArtUrl: string;
|
||||||
Rating: null | string;
|
Rating: null | string;
|
||||||
OverallRating: number;
|
OverallRating: number;
|
||||||
RatingCount: number;
|
RatingCount: number;
|
||||||
MALScore: null;
|
MALScore: null;
|
||||||
UserRating: number;
|
UserRating: number;
|
||||||
RunTime: number | null;
|
RunTime: number | null;
|
||||||
ShowInfoTitle: string;
|
ShowInfoTitle: string;
|
||||||
FirstPremiereDate: Date;
|
FirstPremiereDate: Date;
|
||||||
EpisodeCount: number;
|
EpisodeCount: number;
|
||||||
SeasonName: string;
|
SeasonName: string;
|
||||||
RokuHDArtUrl: string;
|
RokuHDArtUrl: string;
|
||||||
RokuSDArtUrl: string;
|
RokuSDArtUrl: string;
|
||||||
IsRateable: boolean;
|
IsRateable: boolean;
|
||||||
InQueue: boolean;
|
InQueue: boolean;
|
||||||
IsFavorite: boolean;
|
IsFavorite: boolean;
|
||||||
IsContinueWatching: boolean;
|
IsContinueWatching: boolean;
|
||||||
ContinueWatching: ContinueWatching;
|
ContinueWatching: ContinueWatching;
|
||||||
Episodes: any[];
|
Episodes: any[];
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContinueWatching {
|
export interface ContinueWatching {
|
||||||
Id: string;
|
Id: string;
|
||||||
ProfileId: number;
|
ProfileId: number;
|
||||||
EpisodeId: number;
|
EpisodeId: number;
|
||||||
Status: Status | null;
|
Status: Status | null;
|
||||||
CurrentTime: number;
|
CurrentTime: number;
|
||||||
UserId: number;
|
UserId: number;
|
||||||
TitleId: number;
|
TitleId: number;
|
||||||
SeasonId: number;
|
SeasonId: number;
|
||||||
VideoId: number;
|
VideoId: number;
|
||||||
TotalSeconds: number;
|
TotalSeconds: number;
|
||||||
CreatedDT: Date;
|
CreatedDT: Date;
|
||||||
ModifiedDT: Date | null;
|
ModifiedDT: Date | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Status {
|
export enum Status {
|
||||||
Paused = 'Paused',
|
Paused = 'Paused',
|
||||||
Playing = 'Playing',
|
Playing = 'Playing',
|
||||||
Watching = 'Watching',
|
Watching = 'Watching'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
124
@types/hidiveEpisodeList.d.ts
vendored
124
@types/hidiveEpisodeList.d.ts
vendored
|
|
@ -1,9 +1,9 @@
|
||||||
export interface HidiveEpisodeList {
|
export interface HidiveEpisodeList {
|
||||||
Code: number;
|
Code: number;
|
||||||
Status: string;
|
Status: string;
|
||||||
Message: null;
|
Message: null;
|
||||||
Messages: Record<unknown, unknown>;
|
Messages: Record<unknown, unknown>;
|
||||||
Data: Data;
|
Data: Data;
|
||||||
Timestamp: string;
|
Timestamp: string;
|
||||||
IPAddress: string;
|
IPAddress: string;
|
||||||
}
|
}
|
||||||
|
|
@ -13,72 +13,72 @@ export interface Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveTitle {
|
export interface HidiveTitle {
|
||||||
Id: number;
|
Id: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
ShortSynopsis: string;
|
ShortSynopsis: string;
|
||||||
MediumSynopsis: string;
|
MediumSynopsis: string;
|
||||||
LongSynopsis: string;
|
LongSynopsis: string;
|
||||||
KeyArtUrl: string;
|
KeyArtUrl: string;
|
||||||
MasterArtUrl: string;
|
MasterArtUrl: string;
|
||||||
Rating: string;
|
Rating: string;
|
||||||
OverallRating: number;
|
OverallRating: number;
|
||||||
RatingCount: number;
|
RatingCount: number;
|
||||||
MALScore: null;
|
MALScore: null;
|
||||||
UserRating: number;
|
UserRating: number;
|
||||||
RunTime: number;
|
RunTime: number;
|
||||||
ShowInfoTitle: string;
|
ShowInfoTitle: string;
|
||||||
FirstPremiereDate: Date;
|
FirstPremiereDate: Date;
|
||||||
EpisodeCount: number;
|
EpisodeCount: number;
|
||||||
SeasonName: string;
|
SeasonName: string;
|
||||||
RokuHDArtUrl: string;
|
RokuHDArtUrl: string;
|
||||||
RokuSDArtUrl: string;
|
RokuSDArtUrl: string;
|
||||||
IsRateable: boolean;
|
IsRateable: boolean;
|
||||||
InQueue: boolean;
|
InQueue: boolean;
|
||||||
IsFavorite: boolean;
|
IsFavorite: boolean;
|
||||||
IsContinueWatching: boolean;
|
IsContinueWatching: boolean;
|
||||||
ContinueWatching: ContinueWatching;
|
ContinueWatching: ContinueWatching;
|
||||||
Episodes: HidiveEpisode[];
|
Episodes: HidiveEpisode[];
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContinueWatching {
|
export interface ContinueWatching {
|
||||||
Id: string;
|
Id: string;
|
||||||
ProfileId: number;
|
ProfileId: number;
|
||||||
EpisodeId: number;
|
EpisodeId: number;
|
||||||
Status: string;
|
Status: string;
|
||||||
CurrentTime: number;
|
CurrentTime: number;
|
||||||
UserId: number;
|
UserId: number;
|
||||||
TitleId: number;
|
TitleId: number;
|
||||||
SeasonId: number;
|
SeasonId: number;
|
||||||
VideoId: number;
|
VideoId: number;
|
||||||
TotalSeconds: number;
|
TotalSeconds: number;
|
||||||
CreatedDT: Date;
|
CreatedDT: Date;
|
||||||
ModifiedDT: Date;
|
ModifiedDT: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveEpisode {
|
export interface HidiveEpisode {
|
||||||
Id: number;
|
Id: number;
|
||||||
Number: number;
|
Number: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
Summary: string;
|
Summary: string;
|
||||||
HIDIVEPremiereDate: Date;
|
HIDIVEPremiereDate: Date;
|
||||||
ScreenShotSmallUrl: string;
|
ScreenShotSmallUrl: string;
|
||||||
ScreenShotCompressedUrl: string;
|
ScreenShotCompressedUrl: string;
|
||||||
SeasonNumber: number;
|
SeasonNumber: number;
|
||||||
TitleId: number;
|
TitleId: number;
|
||||||
SeasonNumberValue: number;
|
SeasonNumberValue: number;
|
||||||
EpisodeNumberValue: number;
|
EpisodeNumberValue: number;
|
||||||
VideoKey: string;
|
VideoKey: string;
|
||||||
DisplayNameLong: string;
|
DisplayNameLong: string;
|
||||||
PercentProgress: number;
|
PercentProgress: number;
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveEpisodeExtra extends HidiveEpisode {
|
export interface HidiveEpisodeExtra extends HidiveEpisode {
|
||||||
titleId: number;
|
titleId: number;
|
||||||
epKey: string;
|
epKey: string;
|
||||||
nameLong: string;
|
nameLong: string;
|
||||||
seriesTitle: string;
|
seriesTitle: string;
|
||||||
seriesId?: number;
|
seriesId?: number;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
72
@types/hidiveSearch.d.ts
vendored
72
@types/hidiveSearch.d.ts
vendored
|
|
@ -1,47 +1,47 @@
|
||||||
export interface HidiveSearch {
|
export interface HidiveSearch {
|
||||||
Code: number;
|
Code: number;
|
||||||
Status: string;
|
Status: string;
|
||||||
Message: null;
|
Message: null;
|
||||||
Messages: Record<unknown, unknown>;
|
Messages: Record<unknown, unknown>;
|
||||||
Data: HidiveSearchData;
|
Data: HidiveSearchData;
|
||||||
Timestamp: string;
|
Timestamp: string;
|
||||||
IPAddress: string;
|
IPAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveSearchData {
|
export interface HidiveSearchData {
|
||||||
Query: string;
|
Query: string;
|
||||||
Slug: string;
|
Slug: string;
|
||||||
TitleResults: HidiveSearchItem[];
|
TitleResults: HidiveSearchItem[];
|
||||||
SearchId: number;
|
SearchId: number;
|
||||||
IsSearchPinned: boolean;
|
IsSearchPinned: boolean;
|
||||||
IsPinnedSearchAvailable: boolean;
|
IsPinnedSearchAvailable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveSearchItem {
|
export interface HidiveSearchItem {
|
||||||
Id: number;
|
Id: number;
|
||||||
Name: string;
|
Name: string;
|
||||||
ShortSynopsis: string;
|
ShortSynopsis: string;
|
||||||
MediumSynopsis: string;
|
MediumSynopsis: string;
|
||||||
LongSynopsis: string;
|
LongSynopsis: string;
|
||||||
KeyArtUrl: string;
|
KeyArtUrl: string;
|
||||||
MasterArtUrl: string;
|
MasterArtUrl: string;
|
||||||
Rating: string;
|
Rating: string;
|
||||||
OverallRating: number;
|
OverallRating: number;
|
||||||
RatingCount: number;
|
RatingCount: number;
|
||||||
MALScore: null;
|
MALScore: null;
|
||||||
UserRating: number;
|
UserRating: number;
|
||||||
RunTime: number | null;
|
RunTime: number | null;
|
||||||
ShowInfoTitle: string;
|
ShowInfoTitle: string;
|
||||||
FirstPremiereDate: Date;
|
FirstPremiereDate: Date;
|
||||||
EpisodeCount: number;
|
EpisodeCount: number;
|
||||||
SeasonName: string;
|
SeasonName: string;
|
||||||
RokuHDArtUrl: string;
|
RokuHDArtUrl: string;
|
||||||
RokuSDArtUrl: string;
|
RokuSDArtUrl: string;
|
||||||
IsRateable: boolean;
|
IsRateable: boolean;
|
||||||
InQueue: boolean;
|
InQueue: boolean;
|
||||||
IsFavorite: boolean;
|
IsFavorite: boolean;
|
||||||
IsContinueWatching: boolean;
|
IsContinueWatching: boolean;
|
||||||
ContinueWatching: null;
|
ContinueWatching: null;
|
||||||
Episodes: any[];
|
Episodes: any[];
|
||||||
LoadTime: number;
|
LoadTime: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
82
@types/hidiveTypes.d.ts
vendored
82
@types/hidiveTypes.d.ts
vendored
|
|
@ -1,61 +1,63 @@
|
||||||
export interface HidiveVideoList {
|
export interface HidiveVideoList {
|
||||||
Code: number;
|
Code: number;
|
||||||
Status: string;
|
Status: string;
|
||||||
Message: null;
|
Message: null;
|
||||||
Messages: Record<unknown, unknown>;
|
Messages: Record<unknown, unknown>;
|
||||||
Data: HidiveVideo;
|
Data: HidiveVideo;
|
||||||
Timestamp: string;
|
Timestamp: string;
|
||||||
IPAddress: string;
|
IPAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveVideo {
|
export interface HidiveVideo {
|
||||||
ShowAds: boolean;
|
ShowAds: boolean;
|
||||||
CaptionCssUrl: string;
|
CaptionCssUrl: string;
|
||||||
FontSize: number;
|
FontSize: number;
|
||||||
FontScale: number;
|
FontScale: number;
|
||||||
CaptionLanguages: string[];
|
CaptionLanguages: string[];
|
||||||
CaptionLanguage: string;
|
CaptionLanguage: string;
|
||||||
CaptionVttUrls: Record<string, string>;
|
CaptionVttUrls: Record<string, string>;
|
||||||
VideoLanguages: string[];
|
VideoLanguages: string[];
|
||||||
VideoLanguage: string;
|
VideoLanguage: string;
|
||||||
VideoUrls: Record<string, HidiveStreamList>;
|
VideoUrls: Record<string, HidiveStreamList>;
|
||||||
FontColorName: string;
|
FontColorName: string;
|
||||||
AutoPlayNextEpisode: boolean;
|
AutoPlayNextEpisode: boolean;
|
||||||
MaxStreams: number;
|
MaxStreams: number;
|
||||||
CurrentTime: number;
|
CurrentTime: number;
|
||||||
FontColorCode: string;
|
FontColorCode: string;
|
||||||
RunTime: number;
|
RunTime: number;
|
||||||
AdUrl: null;
|
AdUrl: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveStreamList {
|
export interface HidiveStreamList {
|
||||||
hls: string[];
|
hls: string[];
|
||||||
drm: string[];
|
drm: string[];
|
||||||
drmEnabled: boolean;
|
drmEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveStreamInfo extends HidiveStreamList {
|
export interface HidiveStreamInfo extends HidiveStreamList {
|
||||||
language?: string;
|
language?: string;
|
||||||
episodeTitle?: string;
|
episodeTitle?: string;
|
||||||
seriesTitle?: string;
|
seriesTitle?: string;
|
||||||
season?: number;
|
season?: number;
|
||||||
episodeNumber?: number;
|
episodeNumber?: number;
|
||||||
uncut?: boolean;
|
uncut?: boolean;
|
||||||
image?: string;
|
image?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HidiveSubtitleInfo {
|
export interface HidiveSubtitleInfo {
|
||||||
language: string;
|
language: string;
|
||||||
cc: boolean;
|
cc: boolean;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DownloadedMedia = {
|
export type DownloadedMedia =
|
||||||
type: 'Video',
|
| {
|
||||||
lang: LanguageItem,
|
type: 'Video';
|
||||||
path: string,
|
lang: LanguageItem;
|
||||||
uncut: boolean
|
path: string;
|
||||||
} | ({
|
uncut: boolean;
|
||||||
type: 'Subtitle',
|
}
|
||||||
cc: boolean
|
| ({
|
||||||
} & sxItem )
|
type: 'Subtitle';
|
||||||
|
cc: boolean;
|
||||||
|
} & sxItem);
|
||||||
|
|
|
||||||
10
@types/iso639.d.ts
vendored
10
@types/iso639.d.ts
vendored
|
|
@ -1,9 +1,9 @@
|
||||||
declare module 'iso-639' {
|
declare module 'iso-639' {
|
||||||
export type iso639Type = {
|
export type iso639Type = {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
'639-1'?: string,
|
'639-1'?: string;
|
||||||
'639-2'?: string
|
'639-2'?: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export const iso_639_2: iso639Type;
|
export const iso_639_2: iso639Type;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
229
@types/items.d.ts
vendored
229
@types/items.d.ts
vendored
|
|
@ -1,169 +1,168 @@
|
||||||
export interface Item {
|
export interface Item {
|
||||||
// Added later
|
// Added later
|
||||||
id: string,
|
id: string;
|
||||||
id_split: (number|string)[]
|
id_split: (number | string)[];
|
||||||
// Added from the start
|
// Added from the start
|
||||||
mostRecentSvodJpnUs: MostRecentSvodJpnUs;
|
mostRecentSvodJpnUs: MostRecentSvodJpnUs;
|
||||||
synopsis: string;
|
synopsis: string;
|
||||||
mediaCategory: ContentType;
|
mediaCategory: ContentType;
|
||||||
mostRecentSvodUsEndTimestamp: number;
|
mostRecentSvodUsEndTimestamp: number;
|
||||||
quality: QualityClass;
|
quality: QualityClass;
|
||||||
genres: Genre[];
|
genres: Genre[];
|
||||||
titleImages: TitleImages;
|
titleImages: TitleImages;
|
||||||
engAllTerritoryAvail: EngAllTerritoryAvail;
|
engAllTerritoryAvail: EngAllTerritoryAvail;
|
||||||
thumb: string;
|
thumb: string;
|
||||||
mostRecentSvodJpnAllTerrStartTimestamp: number;
|
mostRecentSvodJpnAllTerrStartTimestamp: number;
|
||||||
title: string;
|
title: string;
|
||||||
starRating: number;
|
starRating: number;
|
||||||
primaryAvail: PrimaryAvail;
|
primaryAvail: PrimaryAvail;
|
||||||
access: Access[];
|
access: Access[];
|
||||||
version: Version[];
|
version: Version[];
|
||||||
mostRecentSvodJpnAllTerrEndTimestamp: number;
|
mostRecentSvodJpnAllTerrEndTimestamp: number;
|
||||||
itemId: number;
|
itemId: number;
|
||||||
versionAudio: VersionAudio;
|
versionAudio: VersionAudio;
|
||||||
contentType: ContentType;
|
contentType: ContentType;
|
||||||
mostRecentSvodUsStartTimestamp: number;
|
mostRecentSvodUsStartTimestamp: number;
|
||||||
poster: string;
|
poster: string;
|
||||||
mostRecentSvodEngAllTerrEndTimestamp: number;
|
mostRecentSvodEngAllTerrEndTimestamp: number;
|
||||||
mostRecentSvodJpnUsStartTimestamp: number;
|
mostRecentSvodJpnUsStartTimestamp: number;
|
||||||
mostRecentSvodJpnUsEndTimestamp: number;
|
mostRecentSvodJpnUsEndTimestamp: number;
|
||||||
mostRecentSvodStartTimestamp: number;
|
mostRecentSvodStartTimestamp: number;
|
||||||
mostRecentSvod: MostRecent;
|
mostRecentSvod: MostRecent;
|
||||||
altAvail: AltAvail;
|
altAvail: AltAvail;
|
||||||
ids: IDs;
|
ids: IDs;
|
||||||
mostRecentSvodUs: MostRecent;
|
mostRecentSvodUs: MostRecent;
|
||||||
item: Item;
|
item: Item;
|
||||||
mostRecentSvodEngAllTerrStartTimestamp: number;
|
mostRecentSvodEngAllTerrStartTimestamp: number;
|
||||||
audio: string[];
|
audio: string[];
|
||||||
mostRecentAvod: MostRecent;
|
mostRecentAvod: MostRecent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ContentType {
|
export enum ContentType {
|
||||||
Episode = 'episode',
|
Episode = 'episode',
|
||||||
Ova = 'ova',
|
Ova = 'ova'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDs {
|
export interface IDs {
|
||||||
externalShowId: ID;
|
externalShowId: ID;
|
||||||
externalSeasonId: ExternalSeasonID;
|
externalSeasonId: ExternalSeasonID;
|
||||||
externalEpisodeId: string;
|
externalEpisodeId: string;
|
||||||
externalAsianId?: string
|
externalAsianId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Item {
|
export interface Item {
|
||||||
seasonTitle: string;
|
seasonTitle: string;
|
||||||
seasonId: number;
|
seasonId: number;
|
||||||
episodeOrder: number;
|
episodeOrder: number;
|
||||||
episodeSlug: string;
|
episodeSlug: string;
|
||||||
created: Date;
|
created: Date;
|
||||||
titleSlug: string;
|
titleSlug: string;
|
||||||
episodeNum: string;
|
episodeNum: string;
|
||||||
episodeId: number;
|
episodeId: number;
|
||||||
titleId: number;
|
titleId: number;
|
||||||
seasonNum: string;
|
seasonNum: string;
|
||||||
ratings: Array<string[]>;
|
ratings: Array<string[]>;
|
||||||
showImage: string;
|
showImage: string;
|
||||||
titleName: string;
|
titleName: string;
|
||||||
runtime: string;
|
runtime: string;
|
||||||
episodeName: string;
|
episodeName: string;
|
||||||
seasonOrder: number;
|
seasonOrder: number;
|
||||||
titleExternalId: string;
|
titleExternalId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface MostRecent {
|
export interface MostRecent {
|
||||||
image?: string;
|
image?: string;
|
||||||
siblingStartTimestamp?: string;
|
siblingStartTimestamp?: string;
|
||||||
devices?: Device[];
|
devices?: Device[];
|
||||||
availId?: number;
|
availId?: number;
|
||||||
distributor?: Distributor;
|
distributor?: Distributor;
|
||||||
quality?: MostRecentAvodQuality;
|
quality?: MostRecentAvodQuality;
|
||||||
endTimestamp?: string;
|
endTimestamp?: string;
|
||||||
mediaCategory?: ContentType;
|
mediaCategory?: ContentType;
|
||||||
isPromo?: boolean;
|
isPromo?: boolean;
|
||||||
siblingType?: Purchase;
|
siblingType?: Purchase;
|
||||||
version?: Version;
|
version?: Version;
|
||||||
territory?: Territory;
|
territory?: Territory;
|
||||||
startDate?: Date;
|
startDate?: Date;
|
||||||
endDate?: Date;
|
endDate?: Date;
|
||||||
versionId?: number;
|
versionId?: number;
|
||||||
tier?: Device | null;
|
tier?: Device | null;
|
||||||
purchase?: Purchase;
|
purchase?: Purchase;
|
||||||
startTimestamp?: string;
|
startTimestamp?: string;
|
||||||
language?: Audio;
|
language?: Audio;
|
||||||
itemTitle?: string;
|
itemTitle?: string;
|
||||||
ids?: MostRecentAvodIDS;
|
ids?: MostRecentAvodIDS;
|
||||||
experience?: number;
|
experience?: number;
|
||||||
siblingEndTimestamp?: string;
|
siblingEndTimestamp?: string;
|
||||||
item?: Item;
|
item?: Item;
|
||||||
subscriptionRequired?: boolean;
|
subscriptionRequired?: boolean;
|
||||||
purchased?: boolean;
|
purchased?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MostRecentAvodIDS {
|
export interface MostRecentAvodIDS {
|
||||||
externalSeasonId: ExternalSeasonID;
|
externalSeasonId: ExternalSeasonID;
|
||||||
externalAsianId: null;
|
externalAsianId: null;
|
||||||
externalShowId: ID;
|
externalShowId: ID;
|
||||||
externalEpisodeId: string;
|
externalEpisodeId: string;
|
||||||
externalEnglishId: string;
|
externalEnglishId: string;
|
||||||
externalAlphaId: string;
|
externalAlphaId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Purchase {
|
export enum Purchase {
|
||||||
AVOD = 'A-VOD',
|
AVOD = 'A-VOD',
|
||||||
Dfov = 'DFOV',
|
Dfov = 'DFOV',
|
||||||
Est = 'EST',
|
Est = 'EST',
|
||||||
Svod = 'SVOD',
|
Svod = 'SVOD'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Version {
|
export enum Version {
|
||||||
Simulcast = 'Simulcast',
|
Simulcast = 'Simulcast',
|
||||||
Uncut = 'Uncut',
|
Uncut = 'Uncut'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MostRecentSvodJpnUs = Record<string, any>
|
export type MostRecentSvodJpnUs = Record<string, any>;
|
||||||
|
|
||||||
export interface QualityClass {
|
export interface QualityClass {
|
||||||
quality: QualityQuality;
|
quality: QualityQuality;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum QualityQuality {
|
export enum QualityQuality {
|
||||||
HD = 'HD',
|
HD = 'HD',
|
||||||
SD = 'SD',
|
SD = 'SD'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TitleImages {
|
export interface TitleImages {
|
||||||
showThumbnail: string;
|
showThumbnail: string;
|
||||||
showBackgroundSite: string;
|
showBackgroundSite: string;
|
||||||
showDetailHeaderDesktop: string;
|
showDetailHeaderDesktop: string;
|
||||||
continueWatchingDesktop: string;
|
continueWatchingDesktop: string;
|
||||||
showDetailHeroSite: string;
|
showDetailHeroSite: string;
|
||||||
appleHorizontalBannerShow: string;
|
appleHorizontalBannerShow: string;
|
||||||
backgroundImageXbox_360: string;
|
backgroundImageXbox_360: string;
|
||||||
applePosterCover: string;
|
applePosterCover: string;
|
||||||
showDetailBoxArtTablet: string;
|
showDetailBoxArtTablet: string;
|
||||||
featuredShowBackgroundTablet: string;
|
featuredShowBackgroundTablet: string;
|
||||||
backgroundImageAppletvfiretv: string;
|
backgroundImageAppletvfiretv: string;
|
||||||
newShowDetailHero: string;
|
newShowDetailHero: string;
|
||||||
showDetailHeroDesktop: string;
|
showDetailHeroDesktop: string;
|
||||||
showKeyart: string;
|
showKeyart: string;
|
||||||
continueWatchingMobile: string;
|
continueWatchingMobile: string;
|
||||||
featuredSpotlightShowPhone: string;
|
featuredSpotlightShowPhone: string;
|
||||||
appleHorizontalBannerMovie: string;
|
appleHorizontalBannerMovie: string;
|
||||||
featuredSpotlightShowTablet: string;
|
featuredSpotlightShowTablet: string;
|
||||||
showDetailBoxArtPhone: string;
|
showDetailBoxArtPhone: string;
|
||||||
featuredShowBackgroundPhone: string;
|
featuredShowBackgroundPhone: string;
|
||||||
appleSquareCover: string;
|
appleSquareCover: string;
|
||||||
backgroundVideo: string;
|
backgroundVideo: string;
|
||||||
showMasterKeyArt: string;
|
showMasterKeyArt: string;
|
||||||
newShowDetailHeroPhone: string;
|
newShowDetailHeroPhone: string;
|
||||||
showDetailBoxArtXbox_360: string;
|
showDetailBoxArtXbox_360: string;
|
||||||
showDetailHeaderMobile: string;
|
showDetailHeaderMobile: string;
|
||||||
showLogo: string;
|
showLogo: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VersionAudio {
|
export interface VersionAudio {
|
||||||
Uncut?: Audio[];
|
Uncut?: Audio[];
|
||||||
Simulcast: Audio[];
|
Simulcast: Audio[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
@types/m3u8-parsed.d.ts
vendored
74
@types/m3u8-parsed.d.ts
vendored
|
|
@ -1,49 +1,49 @@
|
||||||
declare module 'm3u8-parsed' {
|
declare module 'm3u8-parsed' {
|
||||||
export type M3U8 = {
|
export type M3U8 = {
|
||||||
allowCache: boolean,
|
allowCache: boolean;
|
||||||
discontinuityStarts: [],
|
discontinuityStarts: [];
|
||||||
segments: {
|
segments: {
|
||||||
duration: number,
|
duration: number;
|
||||||
byterange?: {
|
byterange?: {
|
||||||
length: number,
|
length: number;
|
||||||
offset: number
|
offset: number;
|
||||||
},
|
};
|
||||||
uri: string,
|
uri: string;
|
||||||
key: {
|
key: {
|
||||||
method: string,
|
method: string;
|
||||||
uri: string,
|
uri: string;
|
||||||
},
|
};
|
||||||
timeline: number
|
timeline: number;
|
||||||
}[],
|
}[];
|
||||||
version: number,
|
version: number;
|
||||||
mediaGroups: {
|
mediaGroups: {
|
||||||
[type: string]: {
|
[type: string]: {
|
||||||
[index: string]: {
|
[index: string]: {
|
||||||
[language: string]: {
|
[language: string]: {
|
||||||
default: boolean,
|
default: boolean;
|
||||||
autoselect: boolean,
|
autoselect: boolean;
|
||||||
language: string,
|
language: string;
|
||||||
uri: string
|
uri: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
},
|
};
|
||||||
playlists: {
|
playlists: {
|
||||||
uri: string,
|
uri: string;
|
||||||
timeline: number,
|
timeline: number;
|
||||||
attributes: {
|
attributes: {
|
||||||
'CLOSED-CAPTIONS': string,
|
'CLOSED-CAPTIONS': string;
|
||||||
'AUDIO': string,
|
AUDIO: string;
|
||||||
'FRAME-RATE': number,
|
'FRAME-RATE': number;
|
||||||
'RESOLUTION': {
|
RESOLUTION: {
|
||||||
width: number,
|
width: number;
|
||||||
height: number
|
height: number;
|
||||||
},
|
};
|
||||||
'CODECS': string,
|
CODECS: string;
|
||||||
'AVERAGE-BANDWIDTH': string,
|
'AVERAGE-BANDWIDTH': string;
|
||||||
'BANDWIDTH': number
|
BANDWIDTH: number;
|
||||||
}
|
};
|
||||||
}[],
|
}[];
|
||||||
}
|
};
|
||||||
export default function (data: string): M3U8;
|
export default function (data: string): M3U8;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
265
@types/messageHandler.d.ts
vendored
265
@types/messageHandler.d.ts
vendored
|
|
@ -4,111 +4,145 @@ import type { AvailableMuxer } from '../modules/module.args';
|
||||||
import { LanguageItem } from '../modules/module.langsData';
|
import { LanguageItem } from '../modules/module.langsData';
|
||||||
|
|
||||||
export interface MessageHandler {
|
export interface MessageHandler {
|
||||||
name: string
|
name: string;
|
||||||
auth: (data: AuthData) => Promise<AuthResponse>;
|
auth: (data: AuthData) => Promise<AuthResponse>;
|
||||||
version: () => Promise<string>;
|
version: () => Promise<string>;
|
||||||
checkToken: () => Promise<CheckTokenResponse>;
|
checkToken: () => Promise<CheckTokenResponse>;
|
||||||
search: (data: SearchData) => Promise<SearchResponse>,
|
search: (data: SearchData) => Promise<SearchResponse>;
|
||||||
availableDubCodes: () => Promise<string[]>,
|
availableDubCodes: () => Promise<string[]>;
|
||||||
availableSubCodes: () => Promise<string[]>,
|
availableSubCodes: () => Promise<string[]>;
|
||||||
handleDefault: (name: string) => Promise<any>,
|
handleDefault: (name: string) => Promise<any>;
|
||||||
resolveItems: (data: ResolveItemsData) => Promise<boolean>,
|
resolveItems: (data: ResolveItemsData) => Promise<boolean>;
|
||||||
listEpisodes: (id: string) => Promise<EpisodeListResponse>,
|
listEpisodes: (id: string) => Promise<EpisodeListResponse>;
|
||||||
downloadItem: (data: QueueItem) => void,
|
downloadItem: (data: QueueItem) => void;
|
||||||
isDownloading: () => Promise<boolean>,
|
isDownloading: () => Promise<boolean>;
|
||||||
openFolder: (path: FolderTypes) => void,
|
openFolder: (path: FolderTypes) => void;
|
||||||
openFile: (data: [FolderTypes, string]) => void,
|
openFile: (data: [FolderTypes, string]) => void;
|
||||||
openURL: (data: string) => void;
|
openURL: (data: string) => void;
|
||||||
getQueue: () => Promise<QueueItem[]>,
|
getQueue: () => Promise<QueueItem[]>;
|
||||||
removeFromQueue: (index: number) => void,
|
removeFromQueue: (index: number) => void;
|
||||||
clearQueue: () => void,
|
clearQueue: () => void;
|
||||||
setDownloadQueue: (data: boolean) => void,
|
setDownloadQueue: (data: boolean) => void;
|
||||||
getDownloadQueue: () => Promise<boolean>
|
getDownloadQueue: () => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FolderTypes = 'content' | 'config';
|
export type FolderTypes = 'content' | 'config';
|
||||||
|
|
||||||
export type QueueItem = {
|
export type QueueItem = {
|
||||||
title: string,
|
title: string;
|
||||||
episode: string,
|
episode: string;
|
||||||
fileName: string,
|
fileName: string;
|
||||||
dlsubs: string[],
|
dlsubs: string[];
|
||||||
parent: {
|
parent: {
|
||||||
title: string,
|
title: string;
|
||||||
season: string
|
season: string;
|
||||||
},
|
};
|
||||||
q: number,
|
q: number;
|
||||||
dlVideoOnce: boolean,
|
dlVideoOnce: boolean;
|
||||||
dubLang: string[],
|
dubLang: string[];
|
||||||
image: string,
|
image: string;
|
||||||
} & ResolveItemsData
|
} & ResolveItemsData;
|
||||||
|
|
||||||
export type ResolveItemsData = {
|
export type ResolveItemsData = {
|
||||||
id: string,
|
id: string;
|
||||||
dubLang: string[],
|
dubLang: string[];
|
||||||
all: boolean,
|
all: boolean;
|
||||||
but: boolean,
|
but: boolean;
|
||||||
novids: boolean,
|
novids: boolean;
|
||||||
noaudio: boolean
|
noaudio: boolean;
|
||||||
dlVideoOnce: boolean,
|
dlVideoOnce: boolean;
|
||||||
e: string,
|
e: string;
|
||||||
fileName: string,
|
fileName: string;
|
||||||
q: number,
|
q: number;
|
||||||
dlsubs: string[]
|
dlsubs: string[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type SearchResponseItem = {
|
export type SearchResponseItem = {
|
||||||
image: string,
|
image: string;
|
||||||
name: string,
|
name: string;
|
||||||
desc?: string,
|
desc?: string;
|
||||||
id: string,
|
id: string;
|
||||||
lang?: string[],
|
lang?: string[];
|
||||||
rating: number
|
rating: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Episode = {
|
export type Episode = {
|
||||||
e: string,
|
e: string;
|
||||||
lang: string[],
|
lang: string[];
|
||||||
name: string,
|
name: string;
|
||||||
season: string,
|
season: string;
|
||||||
seasonTitle: string,
|
seasonTitle: string;
|
||||||
episode: string,
|
episode: string;
|
||||||
id: string,
|
id: string;
|
||||||
img: string,
|
img: string;
|
||||||
description: string,
|
description: string;
|
||||||
time: string
|
time: string;
|
||||||
}
|
|
||||||
|
|
||||||
export type SearchResponse = ResponseBase<SearchResponseItem[]>
|
|
||||||
export type EpisodeListResponse = ResponseBase<Episode[]>
|
|
||||||
|
|
||||||
export type FuniEpisodeData = {
|
|
||||||
title: string,
|
|
||||||
episode: string,
|
|
||||||
epsiodeNumber: string,
|
|
||||||
episodeID: string,
|
|
||||||
seasonTitle: string,
|
|
||||||
seasonNumber: string,
|
|
||||||
ids: {
|
|
||||||
episode: string,
|
|
||||||
show: string,
|
|
||||||
season: string
|
|
||||||
},
|
|
||||||
image: string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AuthData = { username: string, password: string };
|
export type SearchResponse = ResponseBase<SearchResponseItem[]>;
|
||||||
export type SearchData = { search: string, page?: number, 'search-type'?: string, 'search-locale'?: string };
|
export type EpisodeListResponse = ResponseBase<Episode[]>;
|
||||||
export type FuniGetShowData = { id: number, e?: string, but: boolean, all: boolean };
|
|
||||||
export type FuniGetEpisodeData = { subs: FuniSubsData, fnSlug: FuniEpisodeData, simul?: boolean; dubLang: string[], s: string }
|
export type FuniEpisodeData = {
|
||||||
export type FuniStreamData = { force?: 'Y'|'y'|'N'|'n'|'C'|'c', callbackMaker?: (data: DownloadInfo) => HLSCallback, q: number, x: number, fileName: string, numbers: number, novids?: boolean,
|
title: string;
|
||||||
timeout: number, partsize: number, fsRetryTime: number, noaudio?: boolean, mp4: boolean, ass: boolean, fontSize: number, fontName?: string, skipmux?: boolean,
|
episode: string;
|
||||||
forceMuxer: AvailableMuxer | undefined, simul: boolean, skipSubMux: boolean, nocleanup: boolean, override: string[], videoTitle: string,
|
epsiodeNumber: string;
|
||||||
ffmpegOptions: string[], mkvmergeOptions: string[], defaultAudio: LanguageItem, defaultSub: LanguageItem, ccTag: string }
|
episodeID: string;
|
||||||
export type FuniSubsData = { nosubs?: boolean, sub: boolean, dlsubs: string[], ccTag: string }
|
seasonTitle: string;
|
||||||
|
seasonNumber: string;
|
||||||
|
ids: {
|
||||||
|
episode: string;
|
||||||
|
show: string;
|
||||||
|
season: string;
|
||||||
|
};
|
||||||
|
image: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AuthData = { username: string; password: string };
|
||||||
|
export type SearchData = { search: string; page?: number; 'search-type'?: string; 'search-locale'?: string };
|
||||||
|
export type FuniGetShowData = { id: number; e?: string; but: boolean; all: boolean };
|
||||||
|
export type FuniGetEpisodeData = { subs: FuniSubsData; fnSlug: FuniEpisodeData; simul?: boolean; dubLang: string[]; s: string };
|
||||||
|
export type FuniStreamData = {
|
||||||
|
force?: 'Y' | 'y' | 'N' | 'n' | 'C' | 'c';
|
||||||
|
callbackMaker?: (data: DownloadInfo) => HLSCallback;
|
||||||
|
q: number;
|
||||||
|
x: number;
|
||||||
|
fileName: string;
|
||||||
|
numbers: number;
|
||||||
|
novids?: boolean;
|
||||||
|
timeout: number;
|
||||||
|
partsize: number;
|
||||||
|
fsRetryTime: number;
|
||||||
|
noaudio?: boolean;
|
||||||
|
mp4: boolean;
|
||||||
|
ass: boolean;
|
||||||
|
fontSize: number;
|
||||||
|
fontName?: string;
|
||||||
|
skipmux?: boolean;
|
||||||
|
forceMuxer: AvailableMuxer | undefined;
|
||||||
|
simul: boolean;
|
||||||
|
skipSubMux: boolean;
|
||||||
|
nocleanup: boolean;
|
||||||
|
override: string[];
|
||||||
|
videoTitle: string;
|
||||||
|
ffmpegOptions: string[];
|
||||||
|
mkvmergeOptions: string[];
|
||||||
|
defaultAudio: LanguageItem;
|
||||||
|
defaultSub: LanguageItem;
|
||||||
|
ccTag: string;
|
||||||
|
};
|
||||||
|
export type FuniSubsData = { nosubs?: boolean; sub: boolean; dlsubs: string[]; ccTag: string };
|
||||||
export type DownloadData = {
|
export type DownloadData = {
|
||||||
hslang?: string; id: string, e: string, dubLang: string[], dlsubs: string[], fileName: string, q: number, novids: boolean, noaudio: boolean, dlVideoOnce: boolean
|
hslang?: string;
|
||||||
}
|
id: string;
|
||||||
|
e: string;
|
||||||
|
dubLang: string[];
|
||||||
|
dlsubs: string[];
|
||||||
|
fileName: string;
|
||||||
|
q: number;
|
||||||
|
novids: boolean;
|
||||||
|
noaudio: boolean;
|
||||||
|
dlVideoOnce: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type AuthResponse = ResponseBase<undefined>;
|
export type AuthResponse = ResponseBase<undefined>;
|
||||||
export type FuniSearchReponse = ResponseBase<FunimationSearch>;
|
export type FuniSearchReponse = ResponseBase<FunimationSearch>;
|
||||||
|
|
@ -116,46 +150,47 @@ export type FuniShowResponse = ResponseBase<FuniEpisodeData[]>;
|
||||||
export type FuniGetEpisodeResponse = ResponseBase<undefined>;
|
export type FuniGetEpisodeResponse = ResponseBase<undefined>;
|
||||||
export type CheckTokenResponse = ResponseBase<undefined>;
|
export type CheckTokenResponse = ResponseBase<undefined>;
|
||||||
|
|
||||||
|
export type ResponseBase<T> =
|
||||||
export type ResponseBase<T> = ({
|
| {
|
||||||
isOk: true,
|
isOk: true;
|
||||||
value: T
|
value: T;
|
||||||
} | {
|
}
|
||||||
isOk: false,
|
| {
|
||||||
reason: Error
|
isOk: false;
|
||||||
});
|
reason: Error;
|
||||||
|
};
|
||||||
|
|
||||||
export type ProgressData = {
|
export type ProgressData = {
|
||||||
total: number,
|
total: number;
|
||||||
cur: number,
|
cur: number;
|
||||||
percent: number|string,
|
percent: number | string;
|
||||||
time: number,
|
time: number;
|
||||||
downloadSpeed: number,
|
downloadSpeed: number;
|
||||||
bytes: number
|
bytes: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PossibleMessages = keyof ServiceHandler;
|
export type PossibleMessages = keyof ServiceHandler;
|
||||||
|
|
||||||
export type DownloadInfo = {
|
export type DownloadInfo = {
|
||||||
image: string,
|
image: string;
|
||||||
parent: {
|
parent: {
|
||||||
title: string
|
title: string;
|
||||||
},
|
};
|
||||||
title: string,
|
title: string;
|
||||||
language: LanguageItem,
|
language: LanguageItem;
|
||||||
fileName: string
|
fileName: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ExtendedProgress = {
|
export type ExtendedProgress = {
|
||||||
progress: ProgressData,
|
progress: ProgressData;
|
||||||
downloadInfo: DownloadInfo
|
downloadInfo: DownloadInfo;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type GuiState = {
|
export type GuiState = {
|
||||||
setup: boolean,
|
setup: boolean;
|
||||||
services: Record<string, GuiStateService>
|
services: Record<string, GuiStateService>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type GuiStateService = {
|
export type GuiStateService = {
|
||||||
queue: QueueItem[]
|
queue: QueueItem[];
|
||||||
}
|
};
|
||||||
|
|
|
||||||
152
@types/mpd-parser.d.ts
vendored
152
@types/mpd-parser.d.ts
vendored
|
|
@ -1,101 +1,101 @@
|
||||||
declare module 'mpd-parser' {
|
declare module 'mpd-parser' {
|
||||||
export type Segment = {
|
export type Segment = {
|
||||||
uri: string,
|
uri: string;
|
||||||
timeline: number,
|
timeline: number;
|
||||||
duration: number,
|
duration: number;
|
||||||
resolvedUri: string,
|
resolvedUri: string;
|
||||||
map: {
|
map: {
|
||||||
uri: string,
|
uri: string;
|
||||||
resolvedUri: string,
|
resolvedUri: string;
|
||||||
byterange?: {
|
byterange?: {
|
||||||
length: number,
|
length: number;
|
||||||
offset: number
|
offset: number;
|
||||||
}
|
};
|
||||||
},
|
};
|
||||||
byterange?: {
|
byterange?: {
|
||||||
length: number,
|
length: number;
|
||||||
offset: number
|
offset: number;
|
||||||
},
|
};
|
||||||
number: number,
|
number: number;
|
||||||
presentationTime: number
|
presentationTime: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Sidx = {
|
export type Sidx = {
|
||||||
uri: string,
|
uri: string;
|
||||||
resolvedUri: string,
|
resolvedUri: string;
|
||||||
byterange: {
|
byterange: {
|
||||||
length: number,
|
length: number;
|
||||||
offset: number
|
offset: number;
|
||||||
},
|
};
|
||||||
map: {
|
map: {
|
||||||
uri: string,
|
uri: string;
|
||||||
resolvedUri: string,
|
resolvedUri: string;
|
||||||
byterange: {
|
byterange: {
|
||||||
length: number,
|
length: number;
|
||||||
offset: number
|
offset: number;
|
||||||
}
|
};
|
||||||
},
|
};
|
||||||
duration: number,
|
duration: number;
|
||||||
timeline: number,
|
timeline: number;
|
||||||
presentationTime: number,
|
presentationTime: number;
|
||||||
number: number
|
number: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Playlist = {
|
export type Playlist = {
|
||||||
attributes: {
|
attributes: {
|
||||||
NAME: string,
|
NAME: string;
|
||||||
BANDWIDTH: number,
|
BANDWIDTH: number;
|
||||||
CODECS: string,
|
CODECS: string;
|
||||||
'PROGRAM-ID': number,
|
'PROGRAM-ID': number;
|
||||||
// Following for video only
|
// Following for video only
|
||||||
'FRAME-RATE'?: number,
|
'FRAME-RATE'?: number;
|
||||||
AUDIO?: string, // audio stream name
|
AUDIO?: string; // audio stream name
|
||||||
SUBTITLES?: string,
|
SUBTITLES?: string;
|
||||||
RESOLUTION?: {
|
RESOLUTION?: {
|
||||||
width: number,
|
width: number;
|
||||||
height: number
|
height: number;
|
||||||
}
|
};
|
||||||
},
|
};
|
||||||
uri: string,
|
uri: string;
|
||||||
endList: boolean,
|
endList: boolean;
|
||||||
timeline: number,
|
timeline: number;
|
||||||
resolvedUri: string,
|
resolvedUri: string;
|
||||||
targetDuration: number,
|
targetDuration: number;
|
||||||
discontinuitySequence: number,
|
discontinuitySequence: number;
|
||||||
discontinuityStarts: [],
|
discontinuityStarts: [];
|
||||||
timelineStarts: {
|
timelineStarts: {
|
||||||
start: number,
|
start: number;
|
||||||
timeline: number
|
timeline: number;
|
||||||
}[],
|
}[];
|
||||||
mediaSequence: number,
|
mediaSequence: number;
|
||||||
contentProtection?: {
|
contentProtection?: {
|
||||||
[type: string]: {
|
[type: string]: {
|
||||||
pssh?: Uint8Array
|
pssh?: Uint8Array;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
segments: Segment[]
|
segments: Segment[];
|
||||||
sidx?: Sidx
|
sidx?: Sidx;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Manifest = {
|
export type Manifest = {
|
||||||
allowCache: boolean,
|
allowCache: boolean;
|
||||||
discontinuityStarts: [],
|
discontinuityStarts: [];
|
||||||
segments: [],
|
segments: [];
|
||||||
endList: true,
|
endList: true;
|
||||||
duration: number,
|
duration: number;
|
||||||
playlists: Playlist[],
|
playlists: Playlist[];
|
||||||
mediaGroups: {
|
mediaGroups: {
|
||||||
AUDIO: {
|
AUDIO: {
|
||||||
audio: {
|
audio: {
|
||||||
[name: string]: {
|
[name: string]: {
|
||||||
language: string,
|
language: string;
|
||||||
autoselect: boolean,
|
autoselect: boolean;
|
||||||
default: boolean,
|
default: boolean;
|
||||||
playlists: Playlist[]
|
playlists: Playlist[];
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export function parse(manifest: string): Manifest
|
export function parse(manifest: string): Manifest;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
58
@types/newHidiveEpisode.d.ts
vendored
58
@types/newHidiveEpisode.d.ts
vendored
|
|
@ -1,43 +1,43 @@
|
||||||
export interface NewHidiveEpisode {
|
export interface NewHidiveEpisode {
|
||||||
description: string;
|
description: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
title: string;
|
title: string;
|
||||||
categories: string[];
|
categories: string[];
|
||||||
contentDownload: ContentDownload;
|
contentDownload: ContentDownload;
|
||||||
favourite: boolean;
|
favourite: boolean;
|
||||||
subEvents: any[];
|
subEvents: any[];
|
||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
posterUrl: string;
|
posterUrl: string;
|
||||||
offlinePlaybackLanguages: string[];
|
offlinePlaybackLanguages: string[];
|
||||||
externalAssetId: string;
|
externalAssetId: string;
|
||||||
maxHeight: number;
|
maxHeight: number;
|
||||||
rating: Rating;
|
rating: Rating;
|
||||||
episodeInformation: EpisodeInformation;
|
episodeInformation: EpisodeInformation;
|
||||||
id: number;
|
id: number;
|
||||||
accessLevel: string;
|
accessLevel: string;
|
||||||
playerUrlCallback: string;
|
playerUrlCallback: string;
|
||||||
thumbnailsPreview: string;
|
thumbnailsPreview: string;
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
plugins: any[];
|
plugins: any[];
|
||||||
watchStatus: string;
|
watchStatus: string;
|
||||||
computedReleases: any[];
|
computedReleases: any[];
|
||||||
licences: any[];
|
licences: any[];
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContentDownload {
|
export interface ContentDownload {
|
||||||
permission: string;
|
permission: string;
|
||||||
period: string;
|
period: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeInformation {
|
export interface EpisodeInformation {
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
episodeNumber: number;
|
episodeNumber: number;
|
||||||
season: number;
|
season: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Rating {
|
export interface Rating {
|
||||||
rating: string;
|
rating: string;
|
||||||
descriptors: any[];
|
descriptors: any[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
@types/newHidivePlayback.d.ts
vendored
24
@types/newHidivePlayback.d.ts
vendored
|
|
@ -1,33 +1,33 @@
|
||||||
export interface NewHidivePlayback {
|
export interface NewHidivePlayback {
|
||||||
watermark: null;
|
watermark: null;
|
||||||
skipMarkers: any[];
|
skipMarkers: any[];
|
||||||
annotations: null;
|
annotations: null;
|
||||||
dash: Format[];
|
dash: Format[];
|
||||||
hls: Format[];
|
hls: Format[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Format {
|
export interface Format {
|
||||||
subtitles: Subtitle[];
|
subtitles: Subtitle[];
|
||||||
url: string;
|
url: string;
|
||||||
drm: DRM;
|
drm: DRM;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DRM {
|
export interface DRM {
|
||||||
encryptionMode: string;
|
encryptionMode: string;
|
||||||
containerType: string;
|
containerType: string;
|
||||||
jwtToken: string;
|
jwtToken: string;
|
||||||
url: string;
|
url: string;
|
||||||
keySystems: string[];
|
keySystems: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Subtitle {
|
export interface Subtitle {
|
||||||
format: Formats;
|
format: Formats;
|
||||||
language: string;
|
language: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Formats {
|
export enum Formats {
|
||||||
Scc = 'scc',
|
Scc = 'scc',
|
||||||
Srt = 'srt',
|
Srt = 'srt',
|
||||||
Vtt = 'vtt',
|
Vtt = 'vtt'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
@types/newHidiveSearch.d.ts
vendored
74
@types/newHidiveSearch.d.ts
vendored
|
|
@ -3,56 +3,56 @@ export interface NewHidiveSearch {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Result {
|
export interface Result {
|
||||||
hits: Hit[];
|
hits: Hit[];
|
||||||
nbHits: number;
|
nbHits: number;
|
||||||
page: number;
|
page: number;
|
||||||
nbPages: number;
|
nbPages: number;
|
||||||
hitsPerPage: number;
|
hitsPerPage: number;
|
||||||
exhaustiveNbHits: boolean;
|
exhaustiveNbHits: boolean;
|
||||||
exhaustiveTypo: boolean;
|
exhaustiveTypo: boolean;
|
||||||
exhaustive: Exhaustive;
|
exhaustive: Exhaustive;
|
||||||
query: string;
|
query: string;
|
||||||
params: string;
|
params: string;
|
||||||
index: string;
|
index: string;
|
||||||
renderingContent: object;
|
renderingContent: object;
|
||||||
processingTimeMS: number;
|
processingTimeMS: number;
|
||||||
processingTimingsMS: ProcessingTimingsMS;
|
processingTimingsMS: ProcessingTimingsMS;
|
||||||
serverTimeMS: number;
|
serverTimeMS: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Exhaustive {
|
export interface Exhaustive {
|
||||||
nbHits: boolean;
|
nbHits: boolean;
|
||||||
typo: boolean;
|
typo: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Hit {
|
export interface Hit {
|
||||||
type: string;
|
type: string;
|
||||||
weight: number;
|
weight: number;
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
meta: object;
|
meta: object;
|
||||||
coverUrl: string;
|
coverUrl: string;
|
||||||
smallCoverUrl: string;
|
smallCoverUrl: string;
|
||||||
seasonsCount: number;
|
seasonsCount: number;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
localisations: HitLocalisations;
|
localisations: HitLocalisations;
|
||||||
ratings: Ratings;
|
ratings: Ratings;
|
||||||
objectID: string;
|
objectID: string;
|
||||||
_highlightResult: HighlightResult;
|
_highlightResult: HighlightResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HighlightResult {
|
export interface HighlightResult {
|
||||||
name: Description;
|
name: Description;
|
||||||
description: Description;
|
description: Description;
|
||||||
tags: Description[];
|
tags: Description[];
|
||||||
localisations: HighlightResultLocalisations;
|
localisations: HighlightResultLocalisations;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Description {
|
export interface Description {
|
||||||
value: string;
|
value: string;
|
||||||
matchLevel: string;
|
matchLevel: string;
|
||||||
matchedWords: string[];
|
matchedWords: string[];
|
||||||
fullyHighlighted?: boolean;
|
fullyHighlighted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ export interface HighlightResultLocalisations {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PurpleEnUS {
|
export interface PurpleEnUS {
|
||||||
title: Description;
|
title: Description;
|
||||||
description: Description;
|
description: Description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ export interface HitLocalisations {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HitLocalization {
|
export interface HitLocalization {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,6 +83,6 @@ export interface ProcessingTimingsMS {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Request {
|
export interface Request {
|
||||||
queue: number;
|
queue: number;
|
||||||
roundTrip: number;
|
roundTrip: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
108
@types/newHidiveSeason.d.ts
vendored
108
@types/newHidiveSeason.d.ts
vendored
|
|
@ -1,52 +1,52 @@
|
||||||
export interface NewHidiveSeason {
|
export interface NewHidiveSeason {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
smallCoverUrl: string;
|
smallCoverUrl: string;
|
||||||
coverUrl: string;
|
coverUrl: string;
|
||||||
titleUrl: string;
|
titleUrl: string;
|
||||||
posterUrl: string;
|
posterUrl: string;
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
episodeCount: number;
|
episodeCount: number;
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
rating: Rating;
|
rating: Rating;
|
||||||
contentRating: Rating;
|
contentRating: Rating;
|
||||||
id: number;
|
id: number;
|
||||||
series: Series;
|
series: Series;
|
||||||
episodes: Episode[];
|
episodes: Episode[];
|
||||||
paging: Paging;
|
paging: Paging;
|
||||||
licences: any[];
|
licences: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Rating {
|
export interface Rating {
|
||||||
rating: string;
|
rating: string;
|
||||||
descriptors: any[];
|
descriptors: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Episode {
|
export interface Episode {
|
||||||
accessLevel: string;
|
accessLevel: string;
|
||||||
availablePurchases?: any[];
|
availablePurchases?: any[];
|
||||||
licenceIds?: any[];
|
licenceIds?: any[];
|
||||||
type: string;
|
type: string;
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
posterUrl: string;
|
posterUrl: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
favourite: boolean;
|
favourite: boolean;
|
||||||
contentDownload: ContentDownload;
|
contentDownload: ContentDownload;
|
||||||
offlinePlaybackLanguages: string[];
|
offlinePlaybackLanguages: string[];
|
||||||
externalAssetId: string;
|
externalAssetId: string;
|
||||||
subEvents: any[];
|
subEvents: any[];
|
||||||
maxHeight: number;
|
maxHeight: number;
|
||||||
thumbnailsPreview: string;
|
thumbnailsPreview: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
episodeInformation: EpisodeInformation;
|
episodeInformation: EpisodeInformation;
|
||||||
categories: string[];
|
categories: string[];
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
watchStatus: string;
|
watchStatus: string;
|
||||||
computedReleases: any[];
|
computedReleases: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContentDownload {
|
export interface ContentDownload {
|
||||||
|
|
@ -54,24 +54,24 @@ export interface ContentDownload {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeInformation {
|
export interface EpisodeInformation {
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
episodeNumber: number;
|
episodeNumber: number;
|
||||||
season: number;
|
season: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Paging {
|
export interface Paging {
|
||||||
moreDataAvailable: boolean;
|
moreDataAvailable: boolean;
|
||||||
lastSeen: number;
|
lastSeen: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Series {
|
export interface Series {
|
||||||
seriesId: number;
|
seriesId: number;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
rating: Rating;
|
rating: Rating;
|
||||||
contentRating: Rating;
|
contentRating: Rating;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NewHidiveSeriesExtra extends Series {
|
export interface NewHidiveSeriesExtra extends Series {
|
||||||
|
|
@ -79,11 +79,11 @@ export interface NewHidiveSeriesExtra extends Series {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NewHidiveEpisodeExtra extends Episode {
|
export interface NewHidiveEpisodeExtra extends Episode {
|
||||||
titleId: number;
|
titleId: number;
|
||||||
nameLong: string;
|
nameLong: string;
|
||||||
seasonTitle: string;
|
seasonTitle: string;
|
||||||
seriesTitle: string;
|
seriesTitle: string;
|
||||||
seriesId?: number;
|
seriesId?: number;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
jwtToken?: string;
|
jwtToken?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
@types/newHidiveSeries.d.ts
vendored
36
@types/newHidiveSeries.d.ts
vendored
|
|
@ -1,35 +1,35 @@
|
||||||
export interface NewHidiveSeries {
|
export interface NewHidiveSeries {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
smallCoverUrl: string;
|
smallCoverUrl: string;
|
||||||
coverUrl: string;
|
coverUrl: string;
|
||||||
titleUrl: string;
|
titleUrl: string;
|
||||||
posterUrl: string;
|
posterUrl: string;
|
||||||
seasons: Season[];
|
seasons: Season[];
|
||||||
rating: Rating;
|
rating: Rating;
|
||||||
contentRating: Rating;
|
contentRating: Rating;
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
paging: Paging;
|
paging: Paging;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Rating {
|
export interface Rating {
|
||||||
rating: string;
|
rating: string;
|
||||||
descriptors: any[];
|
descriptors: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Paging {
|
export interface Paging {
|
||||||
moreDataAvailable: boolean;
|
moreDataAvailable: boolean;
|
||||||
lastSeen: number;
|
lastSeen: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Season {
|
export interface Season {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
longDescription: string;
|
longDescription: string;
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
episodeCount: number;
|
episodeCount: number;
|
||||||
displayableTags: any[];
|
displayableTags: any[];
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
266
@types/objectInfo.d.ts
vendored
266
@types/objectInfo.d.ts
vendored
|
|
@ -2,42 +2,42 @@
|
||||||
|
|
||||||
export interface ObjectInfo {
|
export interface ObjectInfo {
|
||||||
total: number;
|
total: number;
|
||||||
data: CrunchyObject[];
|
data: CrunchyObject[];
|
||||||
meta: Record<unknown>;
|
meta: Record<unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyObject {
|
export interface CrunchyObject {
|
||||||
__links__?: Links;
|
__links__?: Links;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
images: Images;
|
images: Images;
|
||||||
linked_resource_key: string;
|
linked_resource_key: string;
|
||||||
description: string;
|
description: string;
|
||||||
promo_description: string;
|
promo_description: string;
|
||||||
external_id: string;
|
external_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
series_metadata?: SeriesMetadata;
|
series_metadata?: SeriesMetadata;
|
||||||
id: string;
|
id: string;
|
||||||
slug_title: string;
|
slug_title: string;
|
||||||
type: string;
|
type: string;
|
||||||
promo_title: string;
|
promo_title: string;
|
||||||
movie_listing_metadata?: MovieListingMetadata;
|
movie_listing_metadata?: MovieListingMetadata;
|
||||||
movie_metadata?: MovieMetadata;
|
movie_metadata?: MovieMetadata;
|
||||||
playback?: string;
|
playback?: string;
|
||||||
episode_metadata?: EpisodeMetadata;
|
episode_metadata?: EpisodeMetadata;
|
||||||
streams_link?: string;
|
streams_link?: string;
|
||||||
season_metadata?: SeasonMetadata;
|
season_metadata?: SeasonMetadata;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
f_num: string;
|
f_num: string;
|
||||||
s_num: string;
|
s_num: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Links {
|
export interface Links {
|
||||||
'episode/season': LinkData;
|
'episode/season': LinkData;
|
||||||
'episode/series': LinkData;
|
'episode/series': LinkData;
|
||||||
resource: LinkData;
|
resource: LinkData;
|
||||||
'resource/channel': LinkData;
|
'resource/channel': LinkData;
|
||||||
streams: LinkData;
|
streams: LinkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LinkData {
|
export interface LinkData {
|
||||||
|
|
@ -45,150 +45,150 @@ export interface LinkData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeMetadata {
|
export interface EpisodeMetadata {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
availability_ends: Date;
|
availability_ends: Date;
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
availability_starts: Date;
|
availability_starts: Date;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
eligible_region: string;
|
eligible_region: string;
|
||||||
episode: string;
|
episode: string;
|
||||||
episode_air_date: Date;
|
episode_air_date: Date;
|
||||||
episode_number: number;
|
episode_number: number;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
is_clip: boolean;
|
is_clip: boolean;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
season_id: string;
|
season_id: string;
|
||||||
season_number: number;
|
season_number: number;
|
||||||
season_slug_title: string;
|
season_slug_title: string;
|
||||||
season_title: string;
|
season_title: string;
|
||||||
sequence_number: number;
|
sequence_number: number;
|
||||||
series_id: string;
|
series_id: string;
|
||||||
series_slug_title: string;
|
series_slug_title: string;
|
||||||
series_title: string;
|
series_title: string;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
versions: EpisodeMetadataVersion[];
|
versions: EpisodeMetadataVersion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EpisodeMetadataVersion {
|
export interface EpisodeMetadataVersion {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Images {
|
export interface Images {
|
||||||
poster_tall?: Array<Image[]>;
|
poster_tall?: Array<Image[]>;
|
||||||
poster_wide?: Array<Image[]>;
|
poster_wide?: Array<Image[]>;
|
||||||
promo_image?: Array<Image[]>;
|
promo_image?: Array<Image[]>;
|
||||||
thumbnail?: Array<Image[]>;
|
thumbnail?: Array<Image[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Image {
|
export interface Image {
|
||||||
height: number;
|
height: number;
|
||||||
source: string;
|
source: string;
|
||||||
type: ImageType;
|
type: ImageType;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ImageType {
|
export enum ImageType {
|
||||||
PosterTall = 'poster_tall',
|
PosterTall = 'poster_tall',
|
||||||
PosterWide = 'poster_wide',
|
PosterWide = 'poster_wide',
|
||||||
PromoImage = 'promo_image',
|
PromoImage = 'promo_image',
|
||||||
Thumbnail = 'thumbnail',
|
Thumbnail = 'thumbnail'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieListingMetadata {
|
export interface MovieListingMetadata {
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
available_date: null;
|
available_date: null;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
first_movie_id: string;
|
first_movie_id: string;
|
||||||
free_available_date: Date;
|
free_available_date: Date;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
movie_release_year: number;
|
movie_release_year: number;
|
||||||
premium_available_date: Date;
|
premium_available_date: Date;
|
||||||
premium_date: null;
|
premium_date: null;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories: string[];
|
tenant_categories: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieMetadata {
|
export interface MovieMetadata {
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
available_offline: boolean;
|
available_offline: boolean;
|
||||||
closed_captions_available: boolean;
|
closed_captions_available: boolean;
|
||||||
duration_ms: number;
|
duration_ms: number;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
movie_listing_id: string;
|
movie_listing_id: string;
|
||||||
movie_listing_slug_title: string;
|
movie_listing_slug_title: string;
|
||||||
movie_listing_title: string;
|
movie_listing_title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeasonMetadata {
|
export interface SeasonMetadata {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
audio_locales: Locale[];
|
audio_locales: Locale[];
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
season_display_number: string;
|
season_display_number: string;
|
||||||
season_sequence_number: number;
|
season_sequence_number: number;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
versions: SeasonMetadataVersion[];
|
versions: SeasonMetadataVersion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SeasonMetadataVersion {
|
export interface SeasonMetadataVersion {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
export interface SeriesMetadata {
|
export interface SeriesMetadata {
|
||||||
audio_locales: Locale[];
|
audio_locales: Locale[];
|
||||||
availability_notes: string;
|
availability_notes: string;
|
||||||
episode_count: number;
|
episode_count: number;
|
||||||
extended_description: string;
|
extended_description: string;
|
||||||
extended_maturity_rating: Record<unknown>;
|
extended_maturity_rating: Record<unknown>;
|
||||||
is_dubbed: boolean;
|
is_dubbed: boolean;
|
||||||
is_mature: boolean;
|
is_mature: boolean;
|
||||||
is_simulcast: boolean;
|
is_simulcast: boolean;
|
||||||
is_subbed: boolean;
|
is_subbed: boolean;
|
||||||
mature_blocked: boolean;
|
mature_blocked: boolean;
|
||||||
maturity_ratings: string[];
|
maturity_ratings: string[];
|
||||||
season_count: number;
|
season_count: number;
|
||||||
series_launch_year: number;
|
series_launch_year: number;
|
||||||
subtitle_locales: Locale[];
|
subtitle_locales: Locale[];
|
||||||
tenant_categories?: string[];
|
tenant_categories?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Locale {
|
export enum Locale {
|
||||||
|
|
@ -207,5 +207,5 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
@types/pkg.d.ts
vendored
2
@types/pkg.d.ts
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
declare module 'pkg' {
|
declare module 'pkg' {
|
||||||
export async function exec(config: string[]);
|
export async function exec(config: string[]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
131
@types/playbackData.d.ts
vendored
131
@types/playbackData.d.ts
vendored
|
|
@ -7,96 +7,95 @@ export interface PlaybackData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StreamList {
|
export interface StreamList {
|
||||||
download_hls: CrunchyStreams;
|
download_hls: CrunchyStreams;
|
||||||
drm_adaptive_hls: CrunchyStreams;
|
drm_adaptive_hls: CrunchyStreams;
|
||||||
multitrack_adaptive_hls_v2: CrunchyStreams;
|
multitrack_adaptive_hls_v2: CrunchyStreams;
|
||||||
vo_adaptive_hls: CrunchyStreams;
|
vo_adaptive_hls: CrunchyStreams;
|
||||||
vo_drm_adaptive_hls: CrunchyStreams;
|
vo_drm_adaptive_hls: CrunchyStreams;
|
||||||
adaptive_hls: CrunchyStreams;
|
adaptive_hls: CrunchyStreams;
|
||||||
drm_download_dash: CrunchyStreams;
|
drm_download_dash: CrunchyStreams;
|
||||||
drm_download_hls: CrunchyStreams;
|
drm_download_hls: CrunchyStreams;
|
||||||
drm_multitrack_adaptive_hls_v2: CrunchyStreams;
|
drm_multitrack_adaptive_hls_v2: CrunchyStreams;
|
||||||
vo_drm_adaptive_dash: CrunchyStreams;
|
vo_drm_adaptive_dash: CrunchyStreams;
|
||||||
adaptive_dash: CrunchyStreams;
|
adaptive_dash: CrunchyStreams;
|
||||||
urls: CrunchyStreams;
|
urls: CrunchyStreams;
|
||||||
vo_adaptive_dash: CrunchyStreams;
|
vo_adaptive_dash: CrunchyStreams;
|
||||||
download_dash: CrunchyStreams;
|
download_dash: CrunchyStreams;
|
||||||
drm_adaptive_dash: CrunchyStreams;
|
drm_adaptive_dash: CrunchyStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrunchyStreams {
|
export interface CrunchyStreams {
|
||||||
'': StreamDetails;
|
'': StreamDetails;
|
||||||
'en-US'?: StreamDetails;
|
'en-US'?: StreamDetails;
|
||||||
'es-LA'?: StreamDetails;
|
'es-LA'?: StreamDetails;
|
||||||
'es-419'?: StreamDetails;
|
'es-419'?: StreamDetails;
|
||||||
'es-ES'?: StreamDetails;
|
'es-ES'?: StreamDetails;
|
||||||
'pt-BR'?: StreamDetails;
|
'pt-BR'?: StreamDetails;
|
||||||
'fr-FR'?: StreamDetails;
|
'fr-FR'?: StreamDetails;
|
||||||
'de-DE'?: StreamDetails;
|
'de-DE'?: StreamDetails;
|
||||||
'ar-ME'?: StreamDetails;
|
'ar-ME'?: StreamDetails;
|
||||||
'ar-SA'?: StreamDetails;
|
'ar-SA'?: StreamDetails;
|
||||||
'it-IT'?: StreamDetails;
|
'it-IT'?: StreamDetails;
|
||||||
'ru-RU'?: StreamDetails;
|
'ru-RU'?: StreamDetails;
|
||||||
'tr-TR'?: StreamDetails;
|
'tr-TR'?: StreamDetails;
|
||||||
'hi-IN'?: StreamDetails;
|
'hi-IN'?: StreamDetails;
|
||||||
'zh-CN'?: StreamDetails;
|
'zh-CN'?: StreamDetails;
|
||||||
'ko-KR'?: StreamDetails;
|
'ko-KR'?: StreamDetails;
|
||||||
'ja-JP'?: StreamDetails;
|
'ja-JP'?: StreamDetails;
|
||||||
[string: string]: StreamDetails;
|
[string: string]: StreamDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StreamDetails {
|
export interface StreamDetails {
|
||||||
//hardsub_locale: Locale;
|
//hardsub_locale: Locale;
|
||||||
hardsub_locale: string;
|
hardsub_locale: string;
|
||||||
url: string;
|
url: string;
|
||||||
hardsub_lang?: string;
|
hardsub_lang?: string;
|
||||||
audio_lang?: string;
|
audio_lang?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
export interface Meta {
|
export interface Meta {
|
||||||
media_id: string;
|
media_id: string;
|
||||||
subtitles: Subtitles;
|
subtitles: Subtitles;
|
||||||
bifs: string[];
|
bifs: string[];
|
||||||
versions: Version[];
|
versions: Version[];
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
closed_captions: Subtitles;
|
closed_captions: Subtitles;
|
||||||
captions: Subtitles;
|
captions: Subtitles;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Subtitles {
|
export interface Subtitles {
|
||||||
''?: SubtitleInfo;
|
''?: SubtitleInfo;
|
||||||
'en-US'?: SubtitleInfo;
|
'en-US'?: SubtitleInfo;
|
||||||
'es-LA'?: SubtitleInfo;
|
'es-LA'?: SubtitleInfo;
|
||||||
'es-419'?: SubtitleInfo;
|
'es-419'?: SubtitleInfo;
|
||||||
'es-ES'?: SubtitleInfo;
|
'es-ES'?: SubtitleInfo;
|
||||||
'pt-BR'?: SubtitleInfo;
|
'pt-BR'?: SubtitleInfo;
|
||||||
'fr-FR'?: SubtitleInfo;
|
'fr-FR'?: SubtitleInfo;
|
||||||
'de-DE'?: SubtitleInfo;
|
'de-DE'?: SubtitleInfo;
|
||||||
'ar-ME'?: SubtitleInfo;
|
'ar-ME'?: SubtitleInfo;
|
||||||
'ar-SA'?: SubtitleInfo;
|
'ar-SA'?: SubtitleInfo;
|
||||||
'it-IT'?: SubtitleInfo;
|
'it-IT'?: SubtitleInfo;
|
||||||
'ru-RU'?: SubtitleInfo;
|
'ru-RU'?: SubtitleInfo;
|
||||||
'tr-TR'?: SubtitleInfo;
|
'tr-TR'?: SubtitleInfo;
|
||||||
'hi-IN'?: SubtitleInfo;
|
'hi-IN'?: SubtitleInfo;
|
||||||
'zh-CN'?: SubtitleInfo;
|
'zh-CN'?: SubtitleInfo;
|
||||||
'ko-KR'?: SubtitleInfo;
|
'ko-KR'?: SubtitleInfo;
|
||||||
'ja-JP'?: SubtitleInfo;
|
'ja-JP'?: SubtitleInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface SubtitleInfo {
|
export interface SubtitleInfo {
|
||||||
format: string;
|
format: string;
|
||||||
locale: Locale;
|
locale: Locale;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
export interface Version {
|
export interface Version {
|
||||||
audio_locale: Locale;
|
audio_locale: Locale;
|
||||||
guid: string;
|
guid: string;
|
||||||
is_premium_only: boolean;
|
is_premium_only: boolean;
|
||||||
media_guid: string;
|
media_guid: string;
|
||||||
original: boolean;
|
original: boolean;
|
||||||
season_guid: string;
|
season_guid: string;
|
||||||
variant: string;
|
variant: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Locale {
|
export enum Locale {
|
||||||
|
|
@ -116,5 +115,5 @@ export enum Locale {
|
||||||
hiIN = 'hi-IN',
|
hiIN = 'hi-IN',
|
||||||
zhCN = 'zh-CN',
|
zhCN = 'zh-CN',
|
||||||
koKR = 'ko-KR',
|
koKR = 'ko-KR',
|
||||||
jaJP = 'ja-JP',
|
jaJP = 'ja-JP'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
@types/randomEvents.d.ts
vendored
16
@types/randomEvents.d.ts
vendored
|
|
@ -1,15 +1,15 @@
|
||||||
import { ExtendedProgress, QueueItem } from './messageHandler';
|
import { ExtendedProgress, QueueItem } from './messageHandler';
|
||||||
|
|
||||||
export type RandomEvents = {
|
export type RandomEvents = {
|
||||||
progress: ExtendedProgress,
|
progress: ExtendedProgress;
|
||||||
finish: undefined,
|
finish: undefined;
|
||||||
queueChange: QueueItem[],
|
queueChange: QueueItem[];
|
||||||
current: QueueItem|undefined
|
current: QueueItem | undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface RandomEvent<T extends keyof RandomEvents> {
|
export interface RandomEvent<T extends keyof RandomEvents> {
|
||||||
name: T,
|
name: T;
|
||||||
data: RandomEvents[T]
|
data: RandomEvents[T];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Handler<T extends keyof RandomEvents> = (data: RandomEvent<T>) => unknown;
|
export type Handler<T extends keyof RandomEvents> = (data: RandomEvent<T>) => unknown;
|
||||||
|
|
|
||||||
2
@types/removeNPMAbsolutePaths.d.ts
vendored
2
@types/removeNPMAbsolutePaths.d.ts
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
declare module 'removeNPMAbsolutePaths' {
|
declare module 'removeNPMAbsolutePaths' {
|
||||||
export default async function modulesCleanup(path: string);
|
export default async function modulesCleanup(path: string);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
@types/serviceClassInterface.d.ts
vendored
4
@types/serviceClassInterface.d.ts
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
export interface ServiceClass {
|
export interface ServiceClass {
|
||||||
cli: () => Promise<boolean|undefined|void>
|
cli: () => Promise<boolean | undefined | void>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
@types/streamData.d.ts
vendored
24
@types/streamData.d.ts
vendored
|
|
@ -1,28 +1,28 @@
|
||||||
// Generated by https://quicktype.io
|
// Generated by https://quicktype.io
|
||||||
|
|
||||||
export interface StreamData {
|
export interface StreamData {
|
||||||
items: Item[];
|
items: Item[];
|
||||||
watchHistorySaveInterval: number;
|
watchHistorySaveInterval: number;
|
||||||
errors?: Error[]
|
errors?: Error[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Error {
|
export interface Error {
|
||||||
detail: string,
|
detail: string;
|
||||||
code: number
|
code: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Item {
|
export interface Item {
|
||||||
src: string;
|
src: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
isPromo: boolean;
|
isPromo: boolean;
|
||||||
videoType: string;
|
videoType: string;
|
||||||
aips: Aip[];
|
aips: Aip[];
|
||||||
experienceId: string;
|
experienceId: string;
|
||||||
showAds: boolean;
|
showAds: boolean;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Aip {
|
export interface Aip {
|
||||||
out: number;
|
out: number;
|
||||||
in: number;
|
in: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
@types/updateFile.d.ts
vendored
6
@types/updateFile.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
export type UpdateFile = {
|
export type UpdateFile = {
|
||||||
lastCheck: number,
|
lastCheck: number;
|
||||||
nextCheck: number
|
nextCheck: number;
|
||||||
}
|
};
|
||||||
|
|
|
||||||
74
@types/ws.d.ts
vendored
74
@types/ws.d.ts
vendored
|
|
@ -1,45 +1,45 @@
|
||||||
import { GUIConfig } from '../modules/module.cfg-loader';
|
import { GUIConfig } from '../modules/module.cfg-loader';
|
||||||
import { AuthResponse, CheckTokenResponse, EpisodeListResponse, FolderTypes, QueueItem, ResolveItemsData, SearchData, SearchResponse } from './messageHandler';
|
import { AuthResponse, CheckTokenResponse, EpisodeListResponse, FolderTypes, QueueItem, ResolveItemsData, SearchData, SearchResponse } from './messageHandler';
|
||||||
|
|
||||||
export type WSMessage<T extends keyof MessageTypes, P extends 0|1 = 0> = {
|
export type WSMessage<T extends keyof MessageTypes, P extends 0 | 1 = 0> = {
|
||||||
name: T,
|
name: T;
|
||||||
data: MessageTypes[T][P]
|
data: MessageTypes[T][P];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type WSMessageWithID<T extends keyof MessageTypes, P extends 0|1 = 0> = WSMessage<T, P> & {
|
export type WSMessageWithID<T extends keyof MessageTypes, P extends 0 | 1 = 0> = WSMessage<T, P> & {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type UnknownWSMessage = {
|
export type UnknownWSMessage = {
|
||||||
name: keyof MessageTypes,
|
name: keyof MessageTypes;
|
||||||
data: MessageTypes[keyof MessageTypes][0],
|
data: MessageTypes[keyof MessageTypes][0];
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MessageTypes = {
|
export type MessageTypes = {
|
||||||
'auth': [AuthData, AuthResponse],
|
auth: [AuthData, AuthResponse];
|
||||||
'version': [undefined, string],
|
version: [undefined, string];
|
||||||
'checkToken': [undefined, CheckTokenResponse],
|
checkToken: [undefined, CheckTokenResponse];
|
||||||
'search': [SearchData, SearchResponse],
|
search: [SearchData, SearchResponse];
|
||||||
'default': [string, unknown],
|
default: [string, unknown];
|
||||||
'availableDubCodes': [undefined, string[]],
|
availableDubCodes: [undefined, string[]];
|
||||||
'availableSubCodes': [undefined, string[]],
|
availableSubCodes: [undefined, string[]];
|
||||||
'resolveItems': [ResolveItemsData, boolean],
|
resolveItems: [ResolveItemsData, boolean];
|
||||||
'listEpisodes': [string, EpisodeListResponse],
|
listEpisodes: [string, EpisodeListResponse];
|
||||||
'downloadItem': [QueueItem, undefined],
|
downloadItem: [QueueItem, undefined];
|
||||||
'isDownloading': [undefined, boolean],
|
isDownloading: [undefined, boolean];
|
||||||
'openFolder': [FolderTypes, undefined],
|
openFolder: [FolderTypes, undefined];
|
||||||
'changeProvider': [undefined, boolean],
|
changeProvider: [undefined, boolean];
|
||||||
'type': [undefined, 'crunchy'|'hidive'|'ao'|'adn'|undefined],
|
type: [undefined, 'crunchy' | 'hidive' | 'ao' | 'adn' | undefined];
|
||||||
'setup': ['crunchy'|'hidive'|'ao'|'adn'|undefined, undefined],
|
setup: ['crunchy' | 'hidive' | 'ao' | 'adn' | undefined, undefined];
|
||||||
'openFile': [[FolderTypes, string], undefined],
|
openFile: [[FolderTypes, string], undefined];
|
||||||
'openURL': [string, undefined],
|
openURL: [string, undefined];
|
||||||
'isSetup': [undefined, boolean],
|
isSetup: [undefined, boolean];
|
||||||
'setupServer': [GUIConfig, boolean],
|
setupServer: [GUIConfig, boolean];
|
||||||
'requirePassword': [undefined, boolean],
|
requirePassword: [undefined, boolean];
|
||||||
'getQueue': [undefined, QueueItem[]],
|
getQueue: [undefined, QueueItem[]];
|
||||||
'removeFromQueue': [number, undefined],
|
removeFromQueue: [number, undefined];
|
||||||
'clearQueue': [undefined, undefined],
|
clearQueue: [undefined, undefined];
|
||||||
'setDownloadQueue': [boolean, undefined],
|
setDownloadQueue: [boolean, undefined];
|
||||||
'getDownloadQueue': [undefined, boolean]
|
getDownloadQueue: [undefined, boolean];
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
ffmpeg: "ffmpeg.exe"
|
ffmpeg: 'ffmpeg.exe'
|
||||||
mkvmerge: "mkvmerge.exe"
|
mkvmerge: 'mkvmerge.exe'
|
||||||
ffprobe: "ffprobe.exe"
|
ffprobe: 'ffprobe.exe'
|
||||||
mp4decrypt: "mp4decrypt.exe"
|
mp4decrypt: 'mp4decrypt.exe'
|
||||||
shaka: "shaka-packager.exe"
|
shaka: 'shaka-packager.exe'
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,16 @@ dlVideoOnce: false
|
||||||
# Whether to keep all downloaded videos or only a single copy
|
# Whether to keep all downloaded videos or only a single copy
|
||||||
keepAllVideos: false
|
keepAllVideos: false
|
||||||
# What to use as the file name template
|
# What to use as the file name template
|
||||||
fileName: "[${service}] ${showTitle} - S${season}E${episode} [${height}p]"
|
fileName: '[${service}] ${showTitle} - S${season}E${episode} [${height}p]'
|
||||||
# What Audio languages to download
|
# What Audio languages to download
|
||||||
dubLang: ["jpn"]
|
dubLang: ['jpn']
|
||||||
# What Subtitle languages to download
|
# What Subtitle languages to download
|
||||||
dlsubs: ["all"]
|
dlsubs: ['all']
|
||||||
# What language Audio to set as default
|
# What language Audio to set as default
|
||||||
defaultAudio: "jpn"
|
defaultAudio: 'jpn'
|
||||||
# Video Playback Endpoint (Crunchyroll)
|
# Video Playback Endpoint (Crunchyroll)
|
||||||
vstream: "androidtv"
|
vstream: 'androidtv'
|
||||||
# Audio Playback Endpoint (Crunchyroll)
|
# Audio Playback Endpoint (Crunchyroll)
|
||||||
astream: "android"
|
astream: 'android'
|
||||||
# Total Session Death (Could kill active streaming sessions from watching users if account shared, use with caution) (Crunchyroll)
|
# Total Session Death (Could kill active streaming sessions from watching users if account shared, use with caution) (Crunchyroll)
|
||||||
tsd: false
|
tsd: false
|
||||||
|
|
|
||||||
6130
crunchy.ts
6130
crunchy.ts
File diff suppressed because it is too large
Load diff
28
dev.js
28
dev.js
|
|
@ -3,19 +3,21 @@ const path = require('path');
|
||||||
const toRun = process.argv.slice(2).join(' ').split('---');
|
const toRun = process.argv.slice(2).join(' ').split('---');
|
||||||
|
|
||||||
const waitForProcess = async (proc) => {
|
const waitForProcess = async (proc) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
proc.stdout?.on('data', (data) => process.stdout.write(data));
|
proc.stdout?.on('data', (data) => process.stdout.write(data));
|
||||||
proc.stderr?.on('data', (data) => process.stderr.write(data));
|
proc.stderr?.on('data', (data) => process.stderr.write(data));
|
||||||
proc.on('close', resolve);
|
proc.on('close', resolve);
|
||||||
proc.on('error', reject);
|
proc.on('error', reject);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await waitForProcess(exec('pnpm run tsc test false'));
|
await waitForProcess(exec('pnpm run tsc test false'));
|
||||||
for (let command of toRun) {
|
for (let command of toRun) {
|
||||||
await waitForProcess(exec(`node index.js --service hidive ${command}`, {
|
await waitForProcess(
|
||||||
cwd: path.join(__dirname, 'lib')
|
exec(`node index.js --service hidive ${command}`, {
|
||||||
}));
|
cwd: path.join(__dirname, 'lib')
|
||||||
}
|
})
|
||||||
})();
|
);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
|
||||||
|
|
@ -2,61 +2,46 @@
|
||||||
|
|
||||||
import eslint from '@eslint/js';
|
import eslint from '@eslint/js';
|
||||||
import tseslint from 'typescript-eslint';
|
import tseslint from 'typescript-eslint';
|
||||||
|
import prettier from 'eslint-config-prettier';
|
||||||
|
|
||||||
export default tseslint.config(
|
export default tseslint.config(
|
||||||
eslint.configs.recommended,
|
eslint.configs.recommended,
|
||||||
...tseslint.configs.recommended,
|
...tseslint.configs.recommended,
|
||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
'no-console': 2,
|
'no-console': 2,
|
||||||
'react/prop-types': 0,
|
'react/prop-types': 0,
|
||||||
'react-hooks/exhaustive-deps': 0,
|
'react-hooks/exhaustive-deps': 0,
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
'@typescript-eslint/no-unsafe-declaration-merging': 'warn',
|
'@typescript-eslint/no-unsafe-declaration-merging': 'warn',
|
||||||
'@typescript-eslint/no-unused-vars' : 'warn',
|
'@typescript-eslint/no-unused-vars': 'warn',
|
||||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||||
'indent': [
|
indent: ['error', 4],
|
||||||
'error',
|
'linebreak-style': ['warn', 'windows'],
|
||||||
4
|
quotes: ['error', 'single', { avoidEscape: true }],
|
||||||
],
|
semi: ['error', 'always']
|
||||||
'linebreak-style': [
|
},
|
||||||
'warn',
|
languageOptions: {
|
||||||
'windows'
|
parserOptions: {
|
||||||
],
|
ecmaFeatures: {
|
||||||
'quotes': [
|
jsx: true
|
||||||
'error',
|
},
|
||||||
'single'
|
ecmaVersion: 2020,
|
||||||
],
|
sourceType: 'module'
|
||||||
'semi': [
|
},
|
||||||
'error',
|
parser: tseslint.parser
|
||||||
'always'
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
languageOptions: {
|
ignores: ['**/lib', '**/videos', '**/build', 'dev.js', 'tsc.ts']
|
||||||
parserOptions: {
|
},
|
||||||
ecmaFeatures: {
|
{
|
||||||
jsx: true,
|
files: ['gui/react/**/*'],
|
||||||
},
|
rules: {
|
||||||
ecmaVersion: 2020,
|
'no-console': 0,
|
||||||
sourceType: 'module'
|
indent: 'off'
|
||||||
},
|
}
|
||||||
parser: tseslint.parser
|
},
|
||||||
}
|
// Disables all rules that conflict with prettier
|
||||||
},
|
prettier
|
||||||
{
|
);
|
||||||
ignores: [
|
|
||||||
'**/lib',
|
|
||||||
'**/videos/*.ts',
|
|
||||||
'**/build',
|
|
||||||
'dev.js',
|
|
||||||
'tsc.ts'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['gui/react/**/*'],
|
|
||||||
rules: {
|
|
||||||
'no-console': 0,
|
|
||||||
'indent': 'off'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
|
||||||
2
gui.ts
2
gui.ts
|
|
@ -1,3 +1,3 @@
|
||||||
process.env.isGUI = 'true';
|
process.env.isGUI = 'true';
|
||||||
import './modules/log';
|
import './modules/log';
|
||||||
import './gui/server/index';
|
import './gui/server/index';
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"presets": ["@babel/preset-env","@babel/preset-react", "@babel/preset-typescript"]
|
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,4 @@
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Multi Downloader</title>
|
<title>Multi Downloader</title>
|
||||||
<link rel="icon" type="image/webp" href="favicon.webp">
|
<link rel="icon" type="image/webp" href="favicon.webp" />
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<meta
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval'" />
|
||||||
http-equiv="Content-Security-Policy"
|
|
||||||
content="script-src 'self' 'unsafe-eval'"
|
|
||||||
/>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
|
||||||
8
gui/react/src/@types/FC.d.ts
vendored
8
gui/react/src/@types/FC.d.ts
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
type FCWithChildren<T = object> = React.FC<{
|
type FCWithChildren<T = object> = React.FC<
|
||||||
children?: React.ReactNode[]|React.ReactNode
|
{
|
||||||
} & T>
|
children?: React.ReactNode[] | React.ReactNode;
|
||||||
|
} & T
|
||||||
|
>;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@ import React from 'react';
|
||||||
import Layout from './Layout';
|
import Layout from './Layout';
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return <Layout />;
|
||||||
<Layout />
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,36 @@ import StartQueueButton from './components/StartQueue';
|
||||||
import MenuBar from './components/MenuBar/MenuBar';
|
import MenuBar from './components/MenuBar/MenuBar';
|
||||||
|
|
||||||
const Layout: React.FC = () => {
|
const Layout: React.FC = () => {
|
||||||
|
const messageHandler = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
const messageHandler = React.useContext(messageChannelContext);
|
return (
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '100%', alignItems: 'center' }}>
|
||||||
return <Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '100%', alignItems: 'center',}}>
|
<MenuBar />
|
||||||
<MenuBar />
|
<Box
|
||||||
<Box sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
width: '93vw',
|
width: '93vw',
|
||||||
maxWidth: '93rem',
|
maxWidth: '93rem',
|
||||||
maxHeight: '3rem'
|
maxHeight: '3rem'
|
||||||
//backgroundColor: '#ffffff',
|
//backgroundColor: '#ffffff',
|
||||||
}}>
|
}}
|
||||||
<LogoutButton />
|
>
|
||||||
<AuthButton />
|
<LogoutButton />
|
||||||
<Button variant="contained" startIcon={<Folder />} onClick={() => messageHandler?.openFolder('content')} sx={{ height: '37px' }}>Open Output Directory</Button>
|
<AuthButton />
|
||||||
<Button variant="contained" startIcon={<ClearAll />} onClick={() => messageHandler?.clearQueue() } sx={{ height: '37px' }}>Clear Queue</Button>
|
<Button variant="contained" startIcon={<Folder />} onClick={() => messageHandler?.openFolder('content')} sx={{ height: '37px' }}>
|
||||||
<AddToQueue />
|
Open Output Directory
|
||||||
<StartQueueButton />
|
</Button>
|
||||||
</Box>
|
<Button variant="contained" startIcon={<ClearAll />} onClick={() => messageHandler?.clearQueue()} sx={{ height: '37px' }}>
|
||||||
<MainFrame />
|
Clear Queue
|
||||||
</Box>;
|
</Button>
|
||||||
|
<AddToQueue />
|
||||||
|
<StartQueueButton />
|
||||||
|
</Box>
|
||||||
|
<MainFrame />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Container, Box, ThemeProvider, createTheme, Theme } from '@mui/material';
|
import { Container, Box, ThemeProvider, createTheme, Theme } from '@mui/material';
|
||||||
|
|
||||||
const makeTheme = (mode: 'dark'|'light') : Partial<Theme> => {
|
const makeTheme = (mode: 'dark' | 'light'): Partial<Theme> => {
|
||||||
return createTheme({
|
return createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
mode,
|
mode
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const Style: FCWithChildren = ({children}) => {
|
const Style: FCWithChildren = ({ children }) => {
|
||||||
return <ThemeProvider theme={makeTheme('dark')}>
|
return (
|
||||||
<Box sx={{ }}/>
|
<ThemeProvider theme={makeTheme('dark')}>
|
||||||
{children}
|
<Box sx={{}} />
|
||||||
</ThemeProvider>;
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Style;
|
export default Style;
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,24 @@ import EpisodeListing from './DownloadSelector/Listing/EpisodeListing';
|
||||||
import SearchBox from './SearchBox/SearchBox';
|
import SearchBox from './SearchBox/SearchBox';
|
||||||
|
|
||||||
const AddToQueue: React.FC = () => {
|
const AddToQueue: React.FC = () => {
|
||||||
const [isOpen, setOpen] = React.useState(false);
|
const [isOpen, setOpen] = React.useState(false);
|
||||||
|
|
||||||
return <Box>
|
return (
|
||||||
<EpisodeListing />
|
<Box>
|
||||||
<Dialog open={isOpen} onClose={() => setOpen(false)} maxWidth='md' PaperProps={{ elevation:4 }}>
|
<EpisodeListing />
|
||||||
<Box>
|
<Dialog open={isOpen} onClose={() => setOpen(false)} maxWidth="md" PaperProps={{ elevation: 4 }}>
|
||||||
<SearchBox />
|
<Box>
|
||||||
<Divider variant='middle'/>
|
<SearchBox />
|
||||||
<DownloadSelector onFinish={() => setOpen(false)} />
|
<Divider variant="middle" />
|
||||||
</Box>
|
<DownloadSelector onFinish={() => setOpen(false)} />
|
||||||
</Dialog>
|
</Box>
|
||||||
<Button variant='contained' onClick={() => setOpen(true)} sx={{ maxHeight: '2.3rem' }}>
|
</Dialog>
|
||||||
<Add />
|
<Button variant="contained" onClick={() => setOpen(true)} sx={{ maxHeight: '2.3rem' }}>
|
||||||
Add to Queue
|
<Add />
|
||||||
</Button>
|
Add to Queue
|
||||||
</Box>;
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddToQueue;
|
export default AddToQueue;
|
||||||
|
|
|
||||||
|
|
@ -8,320 +8,398 @@ import { useSnackbar } from 'notistack';
|
||||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||||
|
|
||||||
type DownloadSelectorProps = {
|
type DownloadSelectorProps = {
|
||||||
onFinish?: () => unknown
|
onFinish?: () => unknown;
|
||||||
}
|
|
||||||
|
|
||||||
const DownloadSelector: React.FC<DownloadSelectorProps> = ({ onFinish }) => {
|
|
||||||
const messageHandler = React.useContext(messageChannelContext);
|
|
||||||
const [store, dispatch] = useStore();
|
|
||||||
const [availableDubs, setAvailableDubs] = React.useState<string[]>([]);
|
|
||||||
const [availableSubs, setAvailableSubs ] = React.useState<string[]>([]);
|
|
||||||
const [ loading, setLoading ] = React.useState(false);
|
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
|
||||||
const ITEM_HEIGHT = 48;
|
|
||||||
const ITEM_PADDING_TOP = 8;
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
/* If we don't wait the response is undefined? */
|
|
||||||
await new Promise((resolve) => setTimeout(() => resolve(undefined), 100));
|
|
||||||
const dubLang = messageHandler?.handleDefault('dubLang');
|
|
||||||
const subLang = messageHandler?.handleDefault('dlsubs');
|
|
||||||
const q = messageHandler?.handleDefault('q');
|
|
||||||
const fileName = messageHandler?.handleDefault('fileName');
|
|
||||||
const dlVideoOnce = messageHandler?.handleDefault('dlVideoOnce');
|
|
||||||
const result = await Promise.all([dubLang, subLang, q, fileName, dlVideoOnce]);
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: {
|
|
||||||
...store.downloadOptions,
|
|
||||||
dubLang: result[0],
|
|
||||||
dlsubs: result[1],
|
|
||||||
q: result[2],
|
|
||||||
fileName: result[3],
|
|
||||||
dlVideoOnce: result[4],
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setAvailableDubs(await messageHandler?.availableDubCodes() ?? []);
|
|
||||||
setAvailableSubs(await messageHandler?.availableSubCodes() ?? []);
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addToQueue = async () => {
|
|
||||||
setLoading(true);
|
|
||||||
const res = await messageHandler?.resolveItems(store.downloadOptions);
|
|
||||||
if (!res)
|
|
||||||
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
|
||||||
variant: 'error'
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
if (onFinish)
|
|
||||||
onFinish();
|
|
||||||
};
|
|
||||||
|
|
||||||
const listEpisodes = async () => {
|
|
||||||
if (!store.downloadOptions.id) {
|
|
||||||
return enqueueSnackbar('Please enter a ID', {
|
|
||||||
variant: 'error'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
const res = await messageHandler?.listEpisodes(store.downloadOptions.id);
|
|
||||||
if (!res || !res.isOk) {
|
|
||||||
setLoading(false);
|
|
||||||
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
|
||||||
variant: 'error'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dispatch({
|
|
||||||
type: 'episodeListing',
|
|
||||||
payload: res.value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
|
|
||||||
<Box sx={{display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
margin: '5px',
|
|
||||||
}}>
|
|
||||||
<Box sx={{
|
|
||||||
width: '50rem',
|
|
||||||
height: '21rem',
|
|
||||||
margin: '10px',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
//backgroundColor: '#ffffff30',
|
|
||||||
}}>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '0.7rem',
|
|
||||||
//backgroundColor: '#ff000030'
|
|
||||||
}}>
|
|
||||||
<Typography sx={{fontSize: '1.4rem'}}>
|
|
||||||
General Options
|
|
||||||
</Typography>
|
|
||||||
<TextField value={store.downloadOptions.id} required onChange={e => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, id: e.target.value }
|
|
||||||
});
|
|
||||||
}} label='Show ID'/>
|
|
||||||
<TextField type='number' value={store.downloadOptions.q} required onChange={e => {
|
|
||||||
const parsed = parseInt(e.target.value);
|
|
||||||
if (isNaN(parsed) || parsed < 0 || parsed > 10)
|
|
||||||
return;
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, q: parsed }
|
|
||||||
});
|
|
||||||
}} label='Quality Level (0 for max)'/>
|
|
||||||
<Box sx={{ display: 'flex', gap: '5px' }}>
|
|
||||||
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, noaudio: !store.downloadOptions.noaudio } })} variant={store.downloadOptions.noaudio ? 'contained' : 'outlined'}>Skip Audio</Button>
|
|
||||||
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, novids: !store.downloadOptions.novids } })} variant={store.downloadOptions.novids ? 'contained' : 'outlined'}>Skip Video</Button>
|
|
||||||
</Box>
|
|
||||||
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, dlVideoOnce: !store.downloadOptions.dlVideoOnce } })} variant={store.downloadOptions.dlVideoOnce ? 'contained' : 'outlined'}>Skip Unnecessary</Button>
|
|
||||||
<Tooltip title={store.service == 'hidive' ? '' :
|
|
||||||
<Typography>
|
|
||||||
Simulcast is only supported on Hidive
|
|
||||||
</Typography>}
|
|
||||||
arrow placement='top'
|
|
||||||
>
|
|
||||||
<Box>
|
|
||||||
<Button sx={{ textTransform: 'none'}} disabled={store.service != 'hidive'} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, simul: !store.downloadOptions.simul } })} variant={store.downloadOptions.simul ? 'contained' : 'outlined'}>Download Simulcast ver.</Button>
|
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '0.7rem',
|
|
||||||
//backgroundColor: '#00000020'
|
|
||||||
}}>
|
|
||||||
<Typography sx={{fontSize: '1.4rem'}}>
|
|
||||||
Episode Options
|
|
||||||
</Typography>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: '1px'
|
|
||||||
}}>
|
|
||||||
<Box sx={{
|
|
||||||
borderColor: '#595959',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderWidth: '1px',
|
|
||||||
borderRadius: '5px',
|
|
||||||
//backgroundColor: '#ff4567',
|
|
||||||
width: '15rem',
|
|
||||||
height: '3.5rem',
|
|
||||||
display: 'flex',
|
|
||||||
'&:hover' : {
|
|
||||||
borderColor: '#ffffff',
|
|
||||||
},
|
|
||||||
}}>
|
|
||||||
<InputBase sx={{
|
|
||||||
ml: 2,
|
|
||||||
flex: 1,
|
|
||||||
}}
|
|
||||||
disabled={store.downloadOptions.all} value={store.downloadOptions.e} required onChange={e => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, e: e.target.value }
|
|
||||||
});
|
|
||||||
}} placeholder='Episode Select'/>
|
|
||||||
<Divider orientation='vertical'/>
|
|
||||||
<LoadingButton loading={loading} disableElevation disableFocusRipple disableRipple disableTouchRipple onClick={listEpisodes} variant='text' sx={{ textTransform: 'none'}}><Typography>List<br/>Episodes</Typography></LoadingButton>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, all: !store.downloadOptions.all } })} variant={store.downloadOptions.all ? 'contained' : 'outlined'}>Download All</Button>
|
|
||||||
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, but: !store.downloadOptions.but } })} variant={store.downloadOptions.but ? 'contained' : 'outlined'}>Download All but</Button>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '0.7rem',
|
|
||||||
//backgroundColor: '#00ff0020'
|
|
||||||
}}>
|
|
||||||
<Typography sx={{fontSize: '1.4rem'}}>
|
|
||||||
Language Options
|
|
||||||
</Typography>
|
|
||||||
<MultiSelect
|
|
||||||
title='Dub Languages'
|
|
||||||
values={availableDubs}
|
|
||||||
selected={store.downloadOptions.dubLang}
|
|
||||||
onChange={(e) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, dubLang: e }
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
allOption
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MultiSelect
|
|
||||||
title='Sub Languages'
|
|
||||||
values={availableSubs}
|
|
||||||
selected={store.downloadOptions.dlsubs}
|
|
||||||
onChange={(e) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, dlsubs: e }
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tooltip title={store.service == 'crunchy' ? '' :
|
|
||||||
<Typography>
|
|
||||||
Hardsubs are only supported on Crunchyroll
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
arrow placement='top'>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '100%',
|
|
||||||
gap: '1rem'
|
|
||||||
}}>
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
borderRadius: '5px',
|
|
||||||
//backgroundColor: '#ff4567',
|
|
||||||
width: '15rem',
|
|
||||||
height: '3.5rem',
|
|
||||||
display: 'flex',
|
|
||||||
}}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel id='hsLabel'>Hardsub Language</InputLabel>
|
|
||||||
<Select
|
|
||||||
MenuProps={{
|
|
||||||
PaperProps: {
|
|
||||||
style: {
|
|
||||||
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
|
||||||
width: 250
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
labelId='hsLabel'
|
|
||||||
label='Hardsub Language'
|
|
||||||
disabled={store.service != 'crunchy'}
|
|
||||||
value={store.downloadOptions.hslang}
|
|
||||||
onChange={(e) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, hslang: (e.target.value as string) === '' ? undefined : e.target.value as string }
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem value=''>No Hardsub</MenuItem>
|
|
||||||
{availableSubs.map((lang) => {
|
|
||||||
if(lang === 'all' || lang === 'none')
|
|
||||||
return undefined;
|
|
||||||
return <MenuItem value={lang}>{lang}</MenuItem>;
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
|
|
||||||
<Tooltip title={
|
|
||||||
<Typography>
|
|
||||||
Downloads the hardsub version of the selected subtitle.<br/>Subtitles are displayed <b>PERMANENTLY!</b><br/>You can choose only <b>1</b> subtitle per video!
|
|
||||||
</Typography>
|
|
||||||
} arrow placement='top'>
|
|
||||||
<InfoOutlinedIcon sx={{
|
|
||||||
transition: '100ms',
|
|
||||||
ml: '0.35rem',
|
|
||||||
mr: '0.65rem',
|
|
||||||
'&:hover' : {
|
|
||||||
color: '#ffffff30',
|
|
||||||
}
|
|
||||||
}} />
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginBottom: '20px'}}/>
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '100%',
|
|
||||||
gap: '15px'
|
|
||||||
}}>
|
|
||||||
<TextField value={store.downloadOptions.fileName} onChange={e => {
|
|
||||||
dispatch({
|
|
||||||
type: 'downloadOptions',
|
|
||||||
payload: { ...store.downloadOptions, fileName: e.target.value }
|
|
||||||
});
|
|
||||||
}} sx={{ width: '87%' }} label='Filename Overwrite' />
|
|
||||||
<Tooltip title={
|
|
||||||
<Typography>
|
|
||||||
Click here to see the documentation
|
|
||||||
</Typography>
|
|
||||||
} arrow placement='top'>
|
|
||||||
<Link href='https://github.com/anidl/multi-downloader-nx/blob/master/docs/DOCUMENTATION.md#filename-template' rel="noopener noreferrer" target="_blank">
|
|
||||||
<InfoOutlinedIcon sx={{
|
|
||||||
transition: '100ms',
|
|
||||||
'&:hover' : {
|
|
||||||
color: '#ffffff30',
|
|
||||||
}
|
|
||||||
}} />
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginTop: '10px'}}/>
|
|
||||||
|
|
||||||
<LoadingButton sx={{ margin: '15px', textTransform: 'none' }} loading={loading} onClick={addToQueue} variant='contained'>Add to Queue</LoadingButton>
|
|
||||||
|
|
||||||
</Box>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DownloadSelector;
|
const DownloadSelector: React.FC<DownloadSelectorProps> = ({ onFinish }) => {
|
||||||
|
const messageHandler = React.useContext(messageChannelContext);
|
||||||
|
const [store, dispatch] = useStore();
|
||||||
|
const [availableDubs, setAvailableDubs] = React.useState<string[]>([]);
|
||||||
|
const [availableSubs, setAvailableSubs] = React.useState<string[]>([]);
|
||||||
|
const [loading, setLoading] = React.useState(false);
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
const ITEM_HEIGHT = 48;
|
||||||
|
const ITEM_PADDING_TOP = 8;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
/* If we don't wait the response is undefined? */
|
||||||
|
await new Promise((resolve) => setTimeout(() => resolve(undefined), 100));
|
||||||
|
const dubLang = messageHandler?.handleDefault('dubLang');
|
||||||
|
const subLang = messageHandler?.handleDefault('dlsubs');
|
||||||
|
const q = messageHandler?.handleDefault('q');
|
||||||
|
const fileName = messageHandler?.handleDefault('fileName');
|
||||||
|
const dlVideoOnce = messageHandler?.handleDefault('dlVideoOnce');
|
||||||
|
const result = await Promise.all([dubLang, subLang, q, fileName, dlVideoOnce]);
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: {
|
||||||
|
...store.downloadOptions,
|
||||||
|
dubLang: result[0],
|
||||||
|
dlsubs: result[1],
|
||||||
|
q: result[2],
|
||||||
|
fileName: result[3],
|
||||||
|
dlVideoOnce: result[4]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setAvailableDubs((await messageHandler?.availableDubCodes()) ?? []);
|
||||||
|
setAvailableSubs((await messageHandler?.availableSubCodes()) ?? []);
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addToQueue = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
const res = await messageHandler?.resolveItems(store.downloadOptions);
|
||||||
|
if (!res)
|
||||||
|
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
||||||
|
variant: 'error'
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
if (onFinish) onFinish();
|
||||||
|
};
|
||||||
|
|
||||||
|
const listEpisodes = async () => {
|
||||||
|
if (!store.downloadOptions.id) {
|
||||||
|
return enqueueSnackbar('Please enter a ID', {
|
||||||
|
variant: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
const res = await messageHandler?.listEpisodes(store.downloadOptions.id);
|
||||||
|
if (!res || !res.isOk) {
|
||||||
|
setLoading(false);
|
||||||
|
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
||||||
|
variant: 'error'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dispatch({
|
||||||
|
type: 'episodeListing',
|
||||||
|
payload: res.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', margin: '5px' }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '50rem',
|
||||||
|
height: '21rem',
|
||||||
|
margin: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
//backgroundColor: '#ffffff30',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.7rem'
|
||||||
|
//backgroundColor: '#ff000030'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontSize: '1.4rem' }}>General Options</Typography>
|
||||||
|
<TextField
|
||||||
|
value={store.downloadOptions.id}
|
||||||
|
required
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, id: e.target.value }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
label="Show ID"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="number"
|
||||||
|
value={store.downloadOptions.q}
|
||||||
|
required
|
||||||
|
onChange={(e) => {
|
||||||
|
const parsed = parseInt(e.target.value);
|
||||||
|
if (isNaN(parsed) || parsed < 0 || parsed > 10) return;
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, q: parsed }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
label="Quality Level (0 for max)"
|
||||||
|
/>
|
||||||
|
<Box sx={{ display: 'flex', gap: '5px' }}>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, noaudio: !store.downloadOptions.noaudio } })}
|
||||||
|
variant={store.downloadOptions.noaudio ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Skip Audio
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, novids: !store.downloadOptions.novids } })}
|
||||||
|
variant={store.downloadOptions.novids ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Skip Video
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, dlVideoOnce: !store.downloadOptions.dlVideoOnce } })}
|
||||||
|
variant={store.downloadOptions.dlVideoOnce ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Skip Unnecessary
|
||||||
|
</Button>
|
||||||
|
<Tooltip title={store.service == 'hidive' ? '' : <Typography>Simulcast is only supported on Hidive</Typography>} arrow placement="top">
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
disabled={store.service != 'hidive'}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, simul: !store.downloadOptions.simul } })}
|
||||||
|
variant={store.downloadOptions.simul ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Download Simulcast ver.
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.7rem'
|
||||||
|
//backgroundColor: '#00000020'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontSize: '1.4rem' }}>Episode Options</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '1px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
borderColor: '#595959',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderWidth: '1px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
//backgroundColor: '#ff4567',
|
||||||
|
width: '15rem',
|
||||||
|
height: '3.5rem',
|
||||||
|
display: 'flex',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: '#ffffff'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<InputBase
|
||||||
|
sx={{
|
||||||
|
ml: 2,
|
||||||
|
flex: 1
|
||||||
|
}}
|
||||||
|
disabled={store.downloadOptions.all}
|
||||||
|
value={store.downloadOptions.e}
|
||||||
|
required
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, e: e.target.value }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
placeholder="Episode Select"
|
||||||
|
/>
|
||||||
|
<Divider orientation="vertical" />
|
||||||
|
<LoadingButton
|
||||||
|
loading={loading}
|
||||||
|
disableElevation
|
||||||
|
disableFocusRipple
|
||||||
|
disableRipple
|
||||||
|
disableTouchRipple
|
||||||
|
onClick={listEpisodes}
|
||||||
|
variant="text"
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
List
|
||||||
|
<br />
|
||||||
|
Episodes
|
||||||
|
</Typography>
|
||||||
|
</LoadingButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, all: !store.downloadOptions.all } })}
|
||||||
|
variant={store.downloadOptions.all ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Download All
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ textTransform: 'none' }}
|
||||||
|
onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, but: !store.downloadOptions.but } })}
|
||||||
|
variant={store.downloadOptions.but ? 'contained' : 'outlined'}
|
||||||
|
>
|
||||||
|
Download All but
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.7rem'
|
||||||
|
//backgroundColor: '#00ff0020'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontSize: '1.4rem' }}>Language Options</Typography>
|
||||||
|
<MultiSelect
|
||||||
|
title="Dub Languages"
|
||||||
|
values={availableDubs}
|
||||||
|
selected={store.downloadOptions.dubLang}
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, dubLang: e }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
allOption
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MultiSelect
|
||||||
|
title="Sub Languages"
|
||||||
|
values={availableSubs}
|
||||||
|
selected={store.downloadOptions.dlsubs}
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, dlsubs: e }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip title={store.service == 'crunchy' ? '' : <Typography>Hardsubs are only supported on Crunchyroll</Typography>} arrow placement="top">
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
|
gap: '1rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
borderRadius: '5px',
|
||||||
|
//backgroundColor: '#ff4567',
|
||||||
|
width: '15rem',
|
||||||
|
height: '3.5rem',
|
||||||
|
display: 'flex'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel id="hsLabel">Hardsub Language</InputLabel>
|
||||||
|
<Select
|
||||||
|
MenuProps={{
|
||||||
|
PaperProps: {
|
||||||
|
style: {
|
||||||
|
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||||
|
width: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
labelId="hsLabel"
|
||||||
|
label="Hardsub Language"
|
||||||
|
disabled={store.service != 'crunchy'}
|
||||||
|
value={store.downloadOptions.hslang}
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, hslang: (e.target.value as string) === '' ? undefined : (e.target.value as string) }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value="">No Hardsub</MenuItem>
|
||||||
|
{availableSubs.map((lang) => {
|
||||||
|
if (lang === 'all' || lang === 'none') return undefined;
|
||||||
|
return <MenuItem value={lang}>{lang}</MenuItem>;
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<Typography>
|
||||||
|
Downloads the hardsub version of the selected subtitle.
|
||||||
|
<br />
|
||||||
|
Subtitles are displayed <b>PERMANENTLY!</b>
|
||||||
|
<br />
|
||||||
|
You can choose only <b>1</b> subtitle per video!
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<InfoOutlinedIcon
|
||||||
|
sx={{
|
||||||
|
transition: '100ms',
|
||||||
|
ml: '0.35rem',
|
||||||
|
mr: '0.65rem',
|
||||||
|
'&:hover': {
|
||||||
|
color: '#ffffff30'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginBottom: '20px' }} />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%',
|
||||||
|
gap: '15px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
value={store.downloadOptions.fileName}
|
||||||
|
onChange={(e) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'downloadOptions',
|
||||||
|
payload: { ...store.downloadOptions, fileName: e.target.value }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
sx={{ width: '87%' }}
|
||||||
|
label="Filename Overwrite"
|
||||||
|
/>
|
||||||
|
<Tooltip title={<Typography>Click here to see the documentation</Typography>} arrow placement="top">
|
||||||
|
<Link href="https://github.com/anidl/multi-downloader-nx/blob/master/docs/DOCUMENTATION.md#filename-template" rel="noopener noreferrer" target="_blank">
|
||||||
|
<InfoOutlinedIcon
|
||||||
|
sx={{
|
||||||
|
transition: '100ms',
|
||||||
|
'&:hover': {
|
||||||
|
color: '#ffffff30'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginTop: '10px' }} />
|
||||||
|
|
||||||
|
<LoadingButton sx={{ margin: '15px', textTransform: 'none' }} loading={loading} onClick={addToQueue} variant="contained">
|
||||||
|
Add to Queue
|
||||||
|
</LoadingButton>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DownloadSelector;
|
||||||
|
|
|
||||||
|
|
@ -5,187 +5,205 @@ import useStore from '../../../../hooks/useStore';
|
||||||
import ContextMenu from '../../../reusable/ContextMenu';
|
import ContextMenu from '../../../reusable/ContextMenu';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
|
|
||||||
|
|
||||||
const EpisodeListing: React.FC = () => {
|
const EpisodeListing: React.FC = () => {
|
||||||
const [store, dispatch] = useStore();
|
const [store, dispatch] = useStore();
|
||||||
|
|
||||||
const [season, setSeason] = React.useState<'all'|string>('all');
|
const [season, setSeason] = React.useState<'all' | string>('all');
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
const seasons = React.useMemo(() => {
|
const seasons = React.useMemo(() => {
|
||||||
const s: string[] = [];
|
const s: string[] = [];
|
||||||
for (const {season} of store.episodeListing) {
|
for (const { season } of store.episodeListing) {
|
||||||
if (s.includes(season))
|
if (s.includes(season)) continue;
|
||||||
continue;
|
s.push(season);
|
||||||
s.push(season);
|
}
|
||||||
}
|
return s;
|
||||||
return s;
|
}, [store.episodeListing]);
|
||||||
}, [ store.episodeListing ]);
|
|
||||||
|
|
||||||
const [selected, setSelected] = React.useState<string[]>([]);
|
const [selected, setSelected] = React.useState<string[]>([]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setSelected(parseSelect(store.downloadOptions.e));
|
setSelected(parseSelect(store.downloadOptions.e));
|
||||||
}, [ store.episodeListing ]);
|
}, [store.episodeListing]);
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'episodeListing',
|
type: 'episodeListing',
|
||||||
payload: []
|
payload: []
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'downloadOptions',
|
type: 'downloadOptions',
|
||||||
payload: {
|
payload: {
|
||||||
...store.downloadOptions,
|
...store.downloadOptions,
|
||||||
e: `${([...new Set([...parseSelect(store.downloadOptions.e), ...selected])]).join(',')}`
|
e: `${[...new Set([...parseSelect(store.downloadOptions.e), ...selected])].join(',')}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEpisodesForSeason = (season: string|'all') => {
|
const getEpisodesForSeason = (season: string | 'all') => {
|
||||||
return store.episodeListing.filter((a) => season === 'all' ? true : a.season === season);
|
return store.episodeListing.filter((a) => (season === 'all' ? true : a.season === season));
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Dialog open={store.episodeListing.length > 0} onClose={close} scroll='paper' maxWidth='xl' sx={{ p: 2 }}>
|
return (
|
||||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 200px 20px' }}>
|
<Dialog open={store.episodeListing.length > 0} onClose={close} scroll="paper" maxWidth="xl" sx={{ p: 2 }}>
|
||||||
<Typography color='text.primary' variant="h5" sx={{ textAlign: 'center', alignItems: 'center', justifyContent: 'center', display: 'flex' }}>
|
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 200px 20px' }}>
|
||||||
Episodes
|
<Typography color="text.primary" variant="h5" sx={{ textAlign: 'center', alignItems: 'center', justifyContent: 'center', display: 'flex' }}>
|
||||||
</Typography>
|
Episodes
|
||||||
<FormControl sx={{ mr: 2, mt: 2 }}>
|
</Typography>
|
||||||
<InputLabel id='seasonSelectLabel'>Season</InputLabel>
|
<FormControl sx={{ mr: 2, mt: 2 }}>
|
||||||
<Select labelId="seasonSelectLabel" label='Season' value={season} onChange={(e) => setSeason(e.target.value)}>
|
<InputLabel id="seasonSelectLabel">Season</InputLabel>
|
||||||
<MenuItem value='all'>Show all Epsiodes</MenuItem>
|
<Select labelId="seasonSelectLabel" label="Season" value={season} onChange={(e) => setSeason(e.target.value)}>
|
||||||
{seasons.map((a, index) => {
|
<MenuItem value="all">Show all Epsiodes</MenuItem>
|
||||||
return <MenuItem value={a} key={`MenuItem_SeasonSelect_${index}`}>
|
{seasons.map((a, index) => {
|
||||||
{a}
|
return (
|
||||||
</MenuItem>;
|
<MenuItem value={a} key={`MenuItem_SeasonSelect_${index}`}>
|
||||||
})}
|
{a}
|
||||||
</Select>
|
</MenuItem>
|
||||||
</FormControl>
|
);
|
||||||
</Box>
|
})}
|
||||||
<List>
|
</Select>
|
||||||
<ListItem sx={{ display: 'grid', gridTemplateColumns: '25px 1fr 5fr' }}>
|
</FormControl>
|
||||||
<Checkbox
|
</Box>
|
||||||
indeterminate={store.episodeListing.some(a => selected.includes(a.e)) && !store.episodeListing.every(a => selected.includes(a.e))}
|
<List>
|
||||||
checked={store.episodeListing.every(a => selected.includes(a.e))}
|
<ListItem sx={{ display: 'grid', gridTemplateColumns: '25px 1fr 5fr' }}>
|
||||||
onChange={() => {
|
<Checkbox
|
||||||
if (selected.length > 0) {
|
indeterminate={store.episodeListing.some((a) => selected.includes(a.e)) && !store.episodeListing.every((a) => selected.includes(a.e))}
|
||||||
setSelected([]);
|
checked={store.episodeListing.every((a) => selected.includes(a.e))}
|
||||||
} else {
|
onChange={() => {
|
||||||
setSelected(getEpisodesForSeason(season).map(a => a.e));
|
if (selected.length > 0) {
|
||||||
}
|
setSelected([]);
|
||||||
}}
|
} else {
|
||||||
/>
|
setSelected(getEpisodesForSeason(season).map((a) => a.e));
|
||||||
</ListItem>
|
}
|
||||||
{getEpisodesForSeason(season).map((item, index, { length }) => {
|
}}
|
||||||
const e = isNaN(parseInt(item.e)) ? item.e : parseInt(item.e);
|
/>
|
||||||
const idStr = `S${item.season}E${e}`;
|
</ListItem>
|
||||||
const isSelected = selected.includes(e.toString());
|
{getEpisodesForSeason(season).map((item, index, { length }) => {
|
||||||
const imageRef = React.createRef<HTMLImageElement>();
|
const e = isNaN(parseInt(item.e)) ? item.e : parseInt(item.e);
|
||||||
const summaryRef = React.createRef<HTMLParagraphElement>();
|
const idStr = `S${item.season}E${e}`;
|
||||||
return <Box {...{ mouseData: isSelected }} key={`Episode_List_Item_${index}`}>
|
const isSelected = selected.includes(e.toString());
|
||||||
<ListItem sx={{backdropFilter: isSelected ? 'brightness(1.5)' : '', '&:hover': {backdropFilter: 'brightness(1.5)'}, display: 'grid', gridTemplateColumns: '25px 50px 1fr 5fr' }}
|
const imageRef = React.createRef<HTMLImageElement>();
|
||||||
onClick={() => {
|
const summaryRef = React.createRef<HTMLParagraphElement>();
|
||||||
let arr: string[] = [];
|
return (
|
||||||
if (isSelected) {
|
<Box {...{ mouseData: isSelected }} key={`Episode_List_Item_${index}`}>
|
||||||
arr = [...selected.filter(a => a !== e.toString())];
|
<ListItem
|
||||||
} else {
|
sx={{
|
||||||
arr = [...selected, e.toString()];
|
backdropFilter: isSelected ? 'brightness(1.5)' : '',
|
||||||
}
|
'&:hover': { backdropFilter: 'brightness(1.5)' },
|
||||||
setSelected(arr.filter(a => a.length > 0));
|
display: 'grid',
|
||||||
}}>
|
gridTemplateColumns: '25px 50px 1fr 5fr'
|
||||||
{ isSelected ? <CheckBox /> : <CheckBoxOutlineBlank /> }
|
}}
|
||||||
<Typography color='text.primary' sx={{ textAlign: 'center' }}>
|
onClick={() => {
|
||||||
{idStr}
|
let arr: string[] = [];
|
||||||
</Typography>
|
if (isSelected) {
|
||||||
<img ref={imageRef} style={{ width: 'inherit', maxHeight: '200px', minWidth: '150px' }} src={item.img} alt="thumbnail" />
|
arr = [...selected.filter((a) => a !== e.toString())];
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', pl: 1 }}>
|
} else {
|
||||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr min-content' }}>
|
arr = [...selected, e.toString()];
|
||||||
<Typography color='text.primary' variant="h5">
|
}
|
||||||
{item.name}
|
setSelected(arr.filter((a) => a.length > 0));
|
||||||
</Typography>
|
}}
|
||||||
<Typography color='text.primary'>
|
>
|
||||||
{item.time.startsWith('00:') ? item.time.slice(3) : item.time}
|
{isSelected ? <CheckBox /> : <CheckBoxOutlineBlank />}
|
||||||
</Typography>
|
<Typography color="text.primary" sx={{ textAlign: 'center' }}>
|
||||||
</Box>
|
{idStr}
|
||||||
<Typography color='text.primary' ref={summaryRef}>
|
</Typography>
|
||||||
{item.description}
|
<img ref={imageRef} style={{ width: 'inherit', maxHeight: '200px', minWidth: '150px' }} src={item.img} alt="thumbnail" />
|
||||||
</Typography>
|
<Box sx={{ display: 'flex', flexDirection: 'column', pl: 1 }}>
|
||||||
<Box sx={{ display: 'grid', gridTemplateColumns: 'fit-content 1fr' }}>
|
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr min-content' }}>
|
||||||
<Typography>
|
<Typography color="text.primary" variant="h5">
|
||||||
<br />
|
{item.name}
|
||||||
Available audio languages: {item.lang.join(', ')}
|
</Typography>
|
||||||
</Typography>
|
<Typography color="text.primary">{item.time.startsWith('00:') ? item.time.slice(3) : item.time}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
<Typography color="text.primary" ref={summaryRef}>
|
||||||
</ListItem>
|
{item.description}
|
||||||
<ContextMenu options={[ { text: 'Copy image URL', onClick: async () => {
|
</Typography>
|
||||||
await navigator.clipboard.writeText(item.img);
|
<Box sx={{ display: 'grid', gridTemplateColumns: 'fit-content 1fr' }}>
|
||||||
enqueueSnackbar('Copied URL to clipboard', {
|
<Typography>
|
||||||
variant: 'info'
|
<br />
|
||||||
});
|
Available audio languages: {item.lang.join(', ')}
|
||||||
}},
|
</Typography>
|
||||||
{
|
</Box>
|
||||||
text: 'Open image in new tab',
|
</Box>
|
||||||
onClick: () => {
|
</ListItem>
|
||||||
window.open(item.img);
|
<ContextMenu
|
||||||
}
|
options={[
|
||||||
} ]} popupItem={imageRef as RefObject<HTMLElement>} />
|
{
|
||||||
<ContextMenu options={[
|
text: 'Copy image URL',
|
||||||
{
|
onClick: async () => {
|
||||||
onClick: async () => {
|
await navigator.clipboard.writeText(item.img);
|
||||||
await navigator.clipboard.writeText(item.description!);
|
enqueueSnackbar('Copied URL to clipboard', {
|
||||||
enqueueSnackbar('Copied summary to clipboard', {
|
variant: 'info'
|
||||||
variant: 'info'
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
text: 'Copy summary to clipboard'
|
{
|
||||||
}
|
text: 'Open image in new tab',
|
||||||
]} popupItem={summaryRef as RefObject<HTMLElement>} />
|
onClick: () => {
|
||||||
{index < length - 1 && <Divider />}
|
window.open(item.img);
|
||||||
</Box>;
|
}
|
||||||
})}
|
}
|
||||||
</List>
|
]}
|
||||||
</Dialog>;
|
popupItem={imageRef as RefObject<HTMLElement>}
|
||||||
|
/>
|
||||||
|
<ContextMenu
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
onClick: async () => {
|
||||||
|
await navigator.clipboard.writeText(item.description!);
|
||||||
|
enqueueSnackbar('Copied summary to clipboard', {
|
||||||
|
variant: 'info'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
text: 'Copy summary to clipboard'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
popupItem={summaryRef as RefObject<HTMLElement>}
|
||||||
|
/>
|
||||||
|
{index < length - 1 && <Divider />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseSelect = (s: string): string[] => {
|
const parseSelect = (s: string): string[] => {
|
||||||
const ret: string[] = [];
|
const ret: string[] = [];
|
||||||
s.split(',').forEach(item => {
|
s.split(',').forEach((item) => {
|
||||||
if (item.includes('-')) {
|
if (item.includes('-')) {
|
||||||
const split = item.split('-');
|
const split = item.split('-');
|
||||||
if (split.length !== 2)
|
if (split.length !== 2) return;
|
||||||
return;
|
const match = split[0].match(/[A-Za-z]+/);
|
||||||
const match = split[0].match(/[A-Za-z]+/);
|
if (match && match.length > 0) {
|
||||||
if (match && match.length > 0) {
|
if (match.index && match.index !== 0) {
|
||||||
if (match.index && match.index !== 0) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
const letters = split[0].substring(0, match[0].length);
|
||||||
const letters = split[0].substring(0, match[0].length);
|
const number = parseInt(split[0].substring(match[0].length));
|
||||||
const number = parseInt(split[0].substring(match[0].length));
|
const b = parseInt(split[1]);
|
||||||
const b = parseInt(split[1]);
|
if (isNaN(number) || isNaN(b)) {
|
||||||
if (isNaN(number) || isNaN(b)) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
for (let i = number; i <= b; i++) {
|
||||||
for (let i = number; i <= b; i++) {
|
ret.push(`${letters}${i}`);
|
||||||
ret.push(`${letters}${i}`);
|
}
|
||||||
}
|
} else {
|
||||||
|
const a = parseInt(split[0]);
|
||||||
} else {
|
const b = parseInt(split[1]);
|
||||||
const a = parseInt(split[0]);
|
if (isNaN(a) || isNaN(b)) {
|
||||||
const b = parseInt(split[1]);
|
return;
|
||||||
if (isNaN(a) || isNaN(b)) {
|
}
|
||||||
return;
|
for (let i = a; i <= b; i++) {
|
||||||
}
|
ret.push(`${i}`);
|
||||||
for (let i = a; i <= b; i++) {
|
}
|
||||||
ret.push(`${i}`);
|
}
|
||||||
}
|
} else {
|
||||||
}
|
ret.push(item);
|
||||||
} else {
|
}
|
||||||
ret.push(item);
|
});
|
||||||
}
|
return [...new Set(ret)];
|
||||||
});
|
|
||||||
return [...new Set(ret)];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EpisodeListing;
|
export default EpisodeListing;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
.listitem-hover:hover {
|
.listitem-hover:hover {
|
||||||
-webkit-filter: brightness(70%);
|
-webkit-filter: brightness(70%);
|
||||||
filter: brightness(70%);
|
filter: brightness(70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.listitem-hover {
|
.listitem-hover {
|
||||||
transition: filter 0.1s ease-in;
|
transition: filter 0.1s ease-in;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,112 +8,144 @@ import ContextMenu from '../../reusable/ContextMenu';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
|
|
||||||
const SearchBox: React.FC = () => {
|
const SearchBox: React.FC = () => {
|
||||||
const messageHandler = React.useContext(messageChannelContext);
|
const messageHandler = React.useContext(messageChannelContext);
|
||||||
const [store, dispatch] = useStore();
|
const [store, dispatch] = useStore();
|
||||||
const [search, setSearch] = React.useState('');
|
const [search, setSearch] = React.useState('');
|
||||||
|
|
||||||
const [focus, setFocus] = React.useState(false);
|
const [focus, setFocus] = React.useState(false);
|
||||||
|
|
||||||
const [searchResult, setSearchResult] = React.useState<undefined|SearchResponse>();
|
const [searchResult, setSearchResult] = React.useState<undefined | SearchResponse>();
|
||||||
const anchor = React.useRef<HTMLDivElement>(null);
|
const anchor = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
const selectItem = (id: string) => {
|
const selectItem = (id: string) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'downloadOptions',
|
type: 'downloadOptions',
|
||||||
payload: {
|
payload: {
|
||||||
...store.downloadOptions,
|
...store.downloadOptions,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (search.trim().length === 0)
|
if (search.trim().length === 0) return setSearchResult({ isOk: true, value: [] });
|
||||||
return setSearchResult({ isOk: true, value: [] });
|
|
||||||
|
|
||||||
const timeOutId = setTimeout(async () => {
|
const timeOutId = setTimeout(async () => {
|
||||||
if (search.trim().length > 3) {
|
if (search.trim().length > 3) {
|
||||||
const s = await messageHandler?.search({search});
|
const s = await messageHandler?.search({ search });
|
||||||
if (s && s.isOk)
|
if (s && s.isOk) s.value = s.value.slice(0, 10);
|
||||||
s.value = s.value.slice(0, 10);
|
setSearchResult(s);
|
||||||
setSearchResult(s);
|
}
|
||||||
}
|
}, 500);
|
||||||
}, 500);
|
return () => clearTimeout(timeOutId);
|
||||||
return () => clearTimeout(timeOutId);
|
}, [search]);
|
||||||
}, [search]);
|
|
||||||
|
|
||||||
const anchorBounding = anchor.current?.getBoundingClientRect();
|
const anchorBounding = anchor.current?.getBoundingClientRect();
|
||||||
return <ClickAwayListener onClickAway={() => setFocus(false)}>
|
return (
|
||||||
<Box sx={{ m: 2 }}>
|
<ClickAwayListener onClickAway={() => setFocus(false)}>
|
||||||
<TextField ref={anchor} value={search} onClick={() => setFocus(true)} onChange={e => setSearch(e.target.value)} variant='outlined' label='Search' fullWidth />
|
<Box sx={{ m: 2 }}>
|
||||||
{searchResult !== undefined && searchResult.isOk && searchResult.value.length > 0 && focus &&
|
<TextField ref={anchor} value={search} onClick={() => setFocus(true)} onChange={(e) => setSearch(e.target.value)} variant="outlined" label="Search" fullWidth />
|
||||||
<Paper sx={{ position: 'fixed', maxHeight: '50%', width: `${anchorBounding?.width}px`,
|
{searchResult !== undefined && searchResult.isOk && searchResult.value.length > 0 && focus && (
|
||||||
left: anchorBounding?.x, top: (anchorBounding?.y ?? 0) + (anchorBounding?.height ?? 0), zIndex: 99, overflowY: 'scroll'}}>
|
<Paper
|
||||||
<List>
|
sx={{
|
||||||
{searchResult && searchResult.isOk ?
|
position: 'fixed',
|
||||||
searchResult.value.map((a, ind, arr) => {
|
maxHeight: '50%',
|
||||||
const imageRef = React.createRef<HTMLImageElement>();
|
width: `${anchorBounding?.width}px`,
|
||||||
const summaryRef = React.createRef<HTMLParagraphElement>();
|
left: anchorBounding?.x,
|
||||||
return <Box key={a.id}>
|
top: (anchorBounding?.y ?? 0) + (anchorBounding?.height ?? 0),
|
||||||
<ListItem className='listitem-hover' onClick={() => {
|
zIndex: 99,
|
||||||
selectItem(a.id);
|
overflowY: 'scroll'
|
||||||
setFocus(false);
|
}}
|
||||||
}}>
|
>
|
||||||
<Box sx={{ display: 'flex' }}>
|
<List>
|
||||||
<Box sx={{ width: '20%', height: '100%', pr: 2 }}>
|
{searchResult && searchResult.isOk ? (
|
||||||
<img ref={imageRef} src={a.image} style={{ width: '100%', height: 'auto' }} alt="thumbnail"/>
|
searchResult.value.map((a, ind, arr) => {
|
||||||
</Box>
|
const imageRef = React.createRef<HTMLImageElement>();
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', maxWidth: '70%' }}>
|
const summaryRef = React.createRef<HTMLParagraphElement>();
|
||||||
<Typography variant='h6' component='h6' color='text.primary' sx={{ }}>
|
return (
|
||||||
{a.name}
|
<Box key={a.id}>
|
||||||
</Typography>
|
<ListItem
|
||||||
{a.desc && <Typography variant='caption' component='p' color='text.primary' sx={{ pt: 1, pb: 1 }} ref={summaryRef}>
|
className="listitem-hover"
|
||||||
{a.desc}
|
onClick={() => {
|
||||||
</Typography>}
|
selectItem(a.id);
|
||||||
{a.lang && <Typography variant='caption' component='p' color='text.primary' sx={{ }}>
|
setFocus(false);
|
||||||
Languages: {a.lang.join(', ')}
|
}}
|
||||||
</Typography>}
|
>
|
||||||
<Typography variant='caption' component='p' color='text.primary' sx={{ }}>
|
<Box sx={{ display: 'flex' }}>
|
||||||
ID: {a.id}
|
<Box sx={{ width: '20%', height: '100%', pr: 2 }}>
|
||||||
</Typography>
|
<img ref={imageRef} src={a.image} style={{ width: '100%', height: 'auto' }} alt="thumbnail" />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
<Box sx={{ display: 'flex', flexDirection: 'column', maxWidth: '70%' }}>
|
||||||
</ListItem>
|
<Typography variant="h6" component="h6" color="text.primary" sx={{}}>
|
||||||
<ContextMenu options={[ { text: 'Copy image URL', onClick: async () => {
|
{a.name}
|
||||||
await navigator.clipboard.writeText(a.image);
|
</Typography>
|
||||||
enqueueSnackbar('Copied URL to clipboard', {
|
{a.desc && (
|
||||||
variant: 'info'
|
<Typography variant="caption" component="p" color="text.primary" sx={{ pt: 1, pb: 1 }} ref={summaryRef}>
|
||||||
});
|
{a.desc}
|
||||||
}},
|
</Typography>
|
||||||
{
|
)}
|
||||||
text: 'Open image in new tab',
|
{a.lang && (
|
||||||
onClick: () => {
|
<Typography variant="caption" component="p" color="text.primary" sx={{}}>
|
||||||
window.open(a.image);
|
Languages: {a.lang.join(', ')}
|
||||||
}
|
</Typography>
|
||||||
} ]} popupItem={imageRef as RefObject<HTMLElement>} />
|
)}
|
||||||
{a.desc &&
|
<Typography variant="caption" component="p" color="text.primary" sx={{}}>
|
||||||
<ContextMenu options={[
|
ID: {a.id}
|
||||||
{
|
</Typography>
|
||||||
onClick: async () => {
|
</Box>
|
||||||
await navigator.clipboard.writeText(a.desc!);
|
</Box>
|
||||||
enqueueSnackbar('Copied summary to clipboard', {
|
</ListItem>
|
||||||
variant: 'info'
|
<ContextMenu
|
||||||
});
|
options={[
|
||||||
},
|
{
|
||||||
text: 'Copy summary to clipboard'
|
text: 'Copy image URL',
|
||||||
}
|
onClick: async () => {
|
||||||
]} popupItem={summaryRef as RefObject<HTMLElement>} />
|
await navigator.clipboard.writeText(a.image);
|
||||||
}
|
enqueueSnackbar('Copied URL to clipboard', {
|
||||||
{(ind < arr.length - 1) && <Divider />}
|
variant: 'info'
|
||||||
</Box>;
|
});
|
||||||
})
|
}
|
||||||
: <></>}
|
},
|
||||||
</List>
|
{
|
||||||
</Paper>}
|
text: 'Open image in new tab',
|
||||||
</Box>
|
onClick: () => {
|
||||||
</ClickAwayListener>;
|
window.open(a.image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
popupItem={imageRef as RefObject<HTMLElement>}
|
||||||
|
/>
|
||||||
|
{a.desc && (
|
||||||
|
<ContextMenu
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
onClick: async () => {
|
||||||
|
await navigator.clipboard.writeText(a.desc!);
|
||||||
|
enqueueSnackbar('Copied summary to clipboard', {
|
||||||
|
variant: 'info'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
text: 'Copy summary to clipboard'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
popupItem={summaryRef as RefObject<HTMLElement>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{ind < arr.length - 1 && <Divider />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</ClickAwayListener>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SearchBox;
|
export default SearchBox;
|
||||||
|
|
|
||||||
|
|
@ -6,107 +6,115 @@ import Require from './Require';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
|
|
||||||
const AuthButton: React.FC = () => {
|
const AuthButton: React.FC = () => {
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
const [username, setUsername] = React.useState('');
|
const [username, setUsername] = React.useState('');
|
||||||
const [password, setPassword] = React.useState('');
|
const [password, setPassword] = React.useState('');
|
||||||
|
|
||||||
const [usernameError, setUsernameError] = React.useState(false);
|
const [usernameError, setUsernameError] = React.useState(false);
|
||||||
const [passwordError, setPasswordError] = React.useState(false);
|
const [passwordError, setPasswordError] = React.useState(false);
|
||||||
|
|
||||||
const messageChannel = React.useContext(messageChannelContext);
|
const messageChannel = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
const [loading, setLoading] = React.useState(false);
|
const [loading, setLoading] = React.useState(false);
|
||||||
const [error, setError] = React.useState<Error|undefined>(undefined);
|
const [error, setError] = React.useState<Error | undefined>(undefined);
|
||||||
const [authed, setAuthed] = React.useState(false);
|
const [authed, setAuthed] = React.useState(false);
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
setAuthed((await messageChannel?.checkToken())?.isOk ?? false);
|
setAuthed((await messageChannel?.checkToken())?.isOk ?? false);
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => { checkAuth(); }, []);
|
React.useEffect(() => {
|
||||||
|
checkAuth();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!messageChannel)
|
if (!messageChannel) throw new Error('Invalid state'); //The components to confirm only render if the messageChannel is not undefinded
|
||||||
throw new Error('Invalid state'); //The components to confirm only render if the messageChannel is not undefinded
|
if (username.trim().length === 0) return setUsernameError(true);
|
||||||
if (username.trim().length === 0)
|
if (password.trim().length === 0) return setPasswordError(true);
|
||||||
return setUsernameError(true);
|
setUsernameError(false);
|
||||||
if (password.trim().length === 0)
|
setPasswordError(false);
|
||||||
return setPasswordError(true);
|
setLoading(true);
|
||||||
setUsernameError(false);
|
|
||||||
setPasswordError(false);
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
const res = await messageChannel.auth({ username, password });
|
const res = await messageChannel.auth({ username, password });
|
||||||
if (res.isOk) {
|
if (res.isOk) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
snackbar.enqueueSnackbar('Logged in', {
|
snackbar.enqueueSnackbar('Logged in', {
|
||||||
variant: 'success'
|
variant: 'success'
|
||||||
});
|
});
|
||||||
setUsername('');
|
setUsername('');
|
||||||
setPassword('');
|
setPassword('');
|
||||||
} else {
|
} else {
|
||||||
setError(res.reason);
|
setError(res.reason);
|
||||||
}
|
}
|
||||||
await checkAuth();
|
await checkAuth();
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Require value={messageChannel}>
|
return (
|
||||||
<Dialog open={open}>
|
<Require value={messageChannel}>
|
||||||
<Dialog open={!!error}>
|
<Dialog open={open}>
|
||||||
<DialogTitle>Error during Authentication</DialogTitle>
|
<Dialog open={!!error}>
|
||||||
<DialogContentText>
|
<DialogTitle>Error during Authentication</DialogTitle>
|
||||||
{error?.name}
|
<DialogContentText>
|
||||||
{error?.message}
|
{error?.name}
|
||||||
</DialogContentText>
|
{error?.message}
|
||||||
<DialogActions>
|
</DialogContentText>
|
||||||
<Button onClick={() => setError(undefined)}>Close</Button>
|
<DialogActions>
|
||||||
</DialogActions>
|
<Button onClick={() => setError(undefined)}>Close</Button>
|
||||||
</Dialog>
|
</DialogActions>
|
||||||
<DialogTitle sx={{ flexGrow: 1 }}>Authentication</DialogTitle>
|
</Dialog>
|
||||||
<DialogContent>
|
<DialogTitle sx={{ flexGrow: 1 }}>Authentication</DialogTitle>
|
||||||
<DialogContentText>
|
<DialogContent>
|
||||||
Here, you need to enter your username (most likely your Email) and your password.<br />
|
<DialogContentText>
|
||||||
These information are not stored anywhere and are only used to authenticate with the service once.
|
Here, you need to enter your username (most likely your Email) and your password.
|
||||||
</DialogContentText>
|
<br />
|
||||||
<TextField
|
These information are not stored anywhere and are only used to authenticate with the service once.
|
||||||
error={usernameError}
|
</DialogContentText>
|
||||||
helperText={usernameError ? 'Please enter something before submiting' : undefined}
|
<TextField
|
||||||
margin="dense"
|
error={usernameError}
|
||||||
id="username"
|
helperText={usernameError ? 'Please enter something before submiting' : undefined}
|
||||||
label="Username"
|
margin="dense"
|
||||||
type="text"
|
id="username"
|
||||||
fullWidth
|
label="Username"
|
||||||
variant="standard"
|
type="text"
|
||||||
value={username}
|
fullWidth
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
variant="standard"
|
||||||
disabled={loading}
|
value={username}
|
||||||
/>
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
<TextField
|
disabled={loading}
|
||||||
error={passwordError}
|
/>
|
||||||
helperText={passwordError ? 'Please enter something before submiting' : undefined}
|
<TextField
|
||||||
margin="dense"
|
error={passwordError}
|
||||||
id="password"
|
helperText={passwordError ? 'Please enter something before submiting' : undefined}
|
||||||
label="Password"
|
margin="dense"
|
||||||
type="password"
|
id="password"
|
||||||
fullWidth
|
label="Password"
|
||||||
variant="standard"
|
type="password"
|
||||||
value={password}
|
fullWidth
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
variant="standard"
|
||||||
disabled={loading}
|
value={password}
|
||||||
/>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
</DialogContent>
|
disabled={loading}
|
||||||
<DialogActions>
|
/>
|
||||||
{loading && <CircularProgress size={30}/>}
|
</DialogContent>
|
||||||
<Button disabled={loading} onClick={() => setOpen(false)}>Close</Button>
|
<DialogActions>
|
||||||
<Button disabled={loading} onClick={() => handleSubmit()}>Authenticate</Button>
|
{loading && <CircularProgress size={30} />}
|
||||||
</DialogActions>
|
<Button disabled={loading} onClick={() => setOpen(false)}>
|
||||||
</Dialog>
|
Close
|
||||||
<Button startIcon={authed ? <Check />: <Close />} variant="contained" onClick={() => setOpen(true)}>Authenticate</Button>
|
</Button>
|
||||||
</Require>;
|
<Button disabled={loading} onClick={() => handleSubmit()}>
|
||||||
|
Authenticate
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
<Button startIcon={authed ? <Check /> : <Close />} variant="contained" onClick={() => setOpen(true)}>
|
||||||
|
Authenticate
|
||||||
|
</Button>
|
||||||
|
</Require>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AuthButton;
|
export default AuthButton;
|
||||||
|
|
|
||||||
|
|
@ -6,32 +6,26 @@ import { messageChannelContext } from '../provider/MessageChannel';
|
||||||
import Require from './Require';
|
import Require from './Require';
|
||||||
|
|
||||||
const LogoutButton: React.FC = () => {
|
const LogoutButton: React.FC = () => {
|
||||||
const messageChannel = React.useContext(messageChannelContext);
|
const messageChannel = React.useContext(messageChannelContext);
|
||||||
const [, dispatch] = useStore();
|
const [, dispatch] = useStore();
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
if (await messageChannel?.isDownloading())
|
if (await messageChannel?.isDownloading()) return alert('You are currently downloading. Please finish the download first.');
|
||||||
return alert('You are currently downloading. Please finish the download first.');
|
if (await messageChannel?.logout())
|
||||||
if (await messageChannel?.logout())
|
dispatch({
|
||||||
dispatch({
|
type: 'service',
|
||||||
type: 'service',
|
payload: undefined
|
||||||
payload: undefined
|
});
|
||||||
});
|
else alert('Unable to change service');
|
||||||
else
|
};
|
||||||
alert('Unable to change service');
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Require value={messageChannel}>
|
|
||||||
<Button
|
|
||||||
startIcon={<ExitToApp />}
|
|
||||||
variant='contained'
|
|
||||||
onClick={logout}
|
|
||||||
sx={{ maxHeight: '2.3rem' }}
|
|
||||||
>
|
|
||||||
Service select
|
|
||||||
</Button>
|
|
||||||
</Require>;
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Require value={messageChannel}>
|
||||||
|
<Button startIcon={<ExitToApp />} variant="contained" onClick={logout} sx={{ maxHeight: '2.3rem' }}>
|
||||||
|
Service select
|
||||||
|
</Button>
|
||||||
|
</Require>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogoutButton;
|
export default LogoutButton;
|
||||||
|
|
|
||||||
|
|
@ -4,37 +4,37 @@ import { RandomEvent } from '../../../../../../@types/randomEvents';
|
||||||
import { messageChannelContext } from '../../../provider/MessageChannel';
|
import { messageChannelContext } from '../../../provider/MessageChannel';
|
||||||
|
|
||||||
const useDownloadManager = () => {
|
const useDownloadManager = () => {
|
||||||
const messageHandler = React.useContext(messageChannelContext);
|
const messageHandler = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
const [progressData, setProgressData] = React.useState<ExtendedProgress|undefined>();
|
const [progressData, setProgressData] = React.useState<ExtendedProgress | undefined>();
|
||||||
const [current, setCurrent] = React.useState<undefined|QueueItem>();
|
const [current, setCurrent] = React.useState<undefined | QueueItem>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const handler = (ev: RandomEvent<'progress'>) => {
|
|
||||||
console.log(ev.data);
|
|
||||||
setProgressData(ev.data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const currentHandler = (ev: RandomEvent<'current'>) => {
|
React.useEffect(() => {
|
||||||
setCurrent(ev.data);
|
const handler = (ev: RandomEvent<'progress'>) => {
|
||||||
};
|
console.log(ev.data);
|
||||||
|
setProgressData(ev.data);
|
||||||
const finishHandler = () => {
|
};
|
||||||
setProgressData(undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
messageHandler?.randomEvents.on('progress', handler);
|
const currentHandler = (ev: RandomEvent<'current'>) => {
|
||||||
messageHandler?.randomEvents.on('current', currentHandler);
|
setCurrent(ev.data);
|
||||||
messageHandler?.randomEvents.on('finish', finishHandler);
|
};
|
||||||
|
|
||||||
return () => {
|
const finishHandler = () => {
|
||||||
messageHandler?.randomEvents.removeListener('progress', handler);
|
setProgressData(undefined);
|
||||||
messageHandler?.randomEvents.removeListener('finish', finishHandler);
|
};
|
||||||
messageHandler?.randomEvents.removeListener('current', currentHandler);
|
|
||||||
};
|
messageHandler?.randomEvents.on('progress', handler);
|
||||||
}, [messageHandler]);
|
messageHandler?.randomEvents.on('current', currentHandler);
|
||||||
|
messageHandler?.randomEvents.on('finish', finishHandler);
|
||||||
return { data: progressData, current};
|
|
||||||
|
return () => {
|
||||||
|
messageHandler?.randomEvents.removeListener('progress', handler);
|
||||||
|
messageHandler?.randomEvents.removeListener('finish', finishHandler);
|
||||||
|
messageHandler?.randomEvents.removeListener('current', currentHandler);
|
||||||
|
};
|
||||||
|
}, [messageHandler]);
|
||||||
|
|
||||||
|
return { data: progressData, current };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useDownloadManager;
|
export default useDownloadManager;
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ import React from 'react';
|
||||||
import Queue from './Queue/Queue';
|
import Queue from './Queue/Queue';
|
||||||
|
|
||||||
const MainFrame: React.FC = () => {
|
const MainFrame: React.FC = () => {
|
||||||
return <Box sx={{ }}>
|
return (
|
||||||
<Queue />
|
<Box sx={{}}>
|
||||||
</Box>;
|
<Queue />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MainFrame;
|
export default MainFrame;
|
||||||
|
|
|
||||||
|
|
@ -7,414 +7,537 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import useDownloadManager from '../DownloadManager/DownloadManager';
|
import useDownloadManager from '../DownloadManager/DownloadManager';
|
||||||
|
|
||||||
const Queue: React.FC = () => {
|
const Queue: React.FC = () => {
|
||||||
const { data, current } = useDownloadManager();
|
const { data, current } = useDownloadManager();
|
||||||
const queue = React.useContext(queueContext);
|
const queue = React.useContext(queueContext);
|
||||||
const msg = React.useContext(messageChannelContext);
|
const msg = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
|
if (!msg) return <>Never</>;
|
||||||
|
|
||||||
if (!msg)
|
return data || queue.length > 0 ? (
|
||||||
return <>Never</>;
|
<>
|
||||||
|
{data && (
|
||||||
return data || queue.length > 0 ? <>
|
<>
|
||||||
{data && <>
|
<Box
|
||||||
<Box sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center'
|
||||||
}}>
|
}}
|
||||||
<Box sx={{
|
>
|
||||||
marginTop: '2rem',
|
<Box
|
||||||
marginBottom: '1rem',
|
sx={{
|
||||||
height: '12rem',
|
marginTop: '2rem',
|
||||||
width: '93vw',
|
marginBottom: '1rem',
|
||||||
maxWidth: '93rem',
|
height: '12rem',
|
||||||
backgroundColor: '#282828',
|
width: '93vw',
|
||||||
boxShadow: '0px 0px 50px #00000090',
|
maxWidth: '93rem',
|
||||||
borderRadius: '10px',
|
backgroundColor: '#282828',
|
||||||
display: 'flex',
|
boxShadow: '0px 0px 50px #00000090',
|
||||||
transition: '250ms'
|
borderRadius: '10px',
|
||||||
}}>
|
display: 'flex',
|
||||||
<img style={{
|
transition: '250ms'
|
||||||
borderRadius: '5px',
|
}}
|
||||||
margin: '5px',
|
>
|
||||||
boxShadow: '0px 0px 10px #00000090',
|
<img
|
||||||
userSelect: 'none',
|
style={{
|
||||||
}}
|
borderRadius: '5px',
|
||||||
src={data.downloadInfo.image} height='auto' width='auto' alt="Thumbnail" />
|
margin: '5px',
|
||||||
<Box
|
boxShadow: '0px 0px 10px #00000090',
|
||||||
sx={{
|
userSelect: 'none'
|
||||||
display: 'flex',
|
}}
|
||||||
flexDirection: 'column',
|
src={data.downloadInfo.image}
|
||||||
width: '100%',
|
height="auto"
|
||||||
justifyContent: 'center'
|
width="auto"
|
||||||
}}>
|
alt="Thumbnail"
|
||||||
<Box sx={{
|
/>
|
||||||
display: 'flex',
|
<Box
|
||||||
}}>
|
sx={{
|
||||||
<Box sx={{
|
display: 'flex',
|
||||||
//backgroundColor: '#ff0000',
|
flexDirection: 'column',
|
||||||
width: '70%',
|
width: '100%',
|
||||||
marginLeft: '10px'
|
justifyContent: 'center'
|
||||||
}}>
|
}}
|
||||||
<Box sx={{
|
>
|
||||||
flexDirection: 'column',
|
<Box
|
||||||
display: 'flex',
|
sx={{
|
||||||
justifyContent: 'space-between',
|
display: 'flex'
|
||||||
}}>
|
}}
|
||||||
<Typography color='text.primary' sx={{
|
>
|
||||||
fontSize: '1.8rem',
|
<Box
|
||||||
}}>
|
sx={{
|
||||||
{data.downloadInfo.parent.title}
|
//backgroundColor: '#ff0000',
|
||||||
</Typography>
|
width: '70%',
|
||||||
<Typography color='text.primary' sx={{
|
marginLeft: '10px'
|
||||||
fontSize: '1.2rem',
|
}}
|
||||||
}}>
|
>
|
||||||
{data.downloadInfo.title}
|
<Box
|
||||||
</Typography>
|
sx={{
|
||||||
</Box>
|
flexDirection: 'column',
|
||||||
</Box>
|
display: 'flex',
|
||||||
<Box sx={{
|
justifyContent: 'space-between'
|
||||||
//backgroundColor: '#00ff00',
|
}}
|
||||||
width: '30%',
|
>
|
||||||
display: 'flex',
|
<Typography
|
||||||
flexDirection: 'column',
|
color="text.primary"
|
||||||
justifyContent: 'center',
|
sx={{
|
||||||
alignItems: 'center',
|
fontSize: '1.8rem'
|
||||||
}}>
|
}}
|
||||||
<Typography color='text.primary' sx={{
|
>
|
||||||
fontSize: '1.8rem',
|
{data.downloadInfo.parent.title}
|
||||||
}}>
|
</Typography>
|
||||||
Downloading: {data.downloadInfo.language.name}
|
<Typography
|
||||||
</Typography>
|
color="text.primary"
|
||||||
</Box>
|
sx={{
|
||||||
</Box>
|
fontSize: '1.2rem'
|
||||||
<Box sx={{
|
}}
|
||||||
height: '50%',
|
>
|
||||||
display: 'flex',
|
{data.downloadInfo.title}
|
||||||
flexDirection: 'column',
|
</Typography>
|
||||||
justifyContent: 'center',
|
</Box>
|
||||||
alignItems: 'center',
|
</Box>
|
||||||
//backgroundColor: '#0000ff',
|
<Box
|
||||||
}}>
|
sx={{
|
||||||
<LinearProgress variant='determinate'
|
//backgroundColor: '#00ff00',
|
||||||
sx={{
|
width: '30%',
|
||||||
height: '20px',
|
display: 'flex',
|
||||||
width: '97.53%',
|
flexDirection: 'column',
|
||||||
margin: '10px',
|
justifyContent: 'center',
|
||||||
boxShadow: '0px 0px 10px #00000090',
|
alignItems: 'center'
|
||||||
borderRadius: '10px',
|
}}
|
||||||
}} value={(typeof data.progress.percent === 'string' ? parseInt(data.progress.percent) : data.progress.percent)}
|
>
|
||||||
/>
|
<Typography
|
||||||
<Box>
|
color="text.primary"
|
||||||
<Typography color='text.primary'
|
sx={{
|
||||||
sx={{
|
fontSize: '1.8rem'
|
||||||
fontSize: '1.3rem',
|
}}
|
||||||
}}>
|
>
|
||||||
{data.progress.cur} / {(data.progress.total)} parts ({data.progress.percent}% | {formatTime(data.progress.time)} | {(data.progress.downloadSpeed / 1024 / 1024).toFixed(2)} MB/s | {(data.progress.bytes / 1024 / 1024).toFixed(2)}MB)
|
Downloading: {data.downloadInfo.language.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
<Box
|
||||||
</Box>
|
sx={{
|
||||||
</Box>
|
height: '50%',
|
||||||
</>
|
display: 'flex',
|
||||||
}
|
flexDirection: 'column',
|
||||||
{
|
justifyContent: 'center',
|
||||||
current && !data && <>
|
alignItems: 'center'
|
||||||
<Box sx={{
|
//backgroundColor: '#0000ff',
|
||||||
display: 'flex',
|
}}
|
||||||
flexDirection: 'column',
|
>
|
||||||
alignItems: 'center',
|
<LinearProgress
|
||||||
}}>
|
variant="determinate"
|
||||||
<Box sx={{
|
sx={{
|
||||||
marginTop: '2rem',
|
height: '20px',
|
||||||
marginBottom: '1rem',
|
width: '97.53%',
|
||||||
height: '12rem',
|
margin: '10px',
|
||||||
width: '93vw',
|
boxShadow: '0px 0px 10px #00000090',
|
||||||
maxWidth: '93rem',
|
borderRadius: '10px'
|
||||||
backgroundColor: '#282828',
|
}}
|
||||||
boxShadow: '0px 0px 50px #00000090',
|
value={typeof data.progress.percent === 'string' ? parseInt(data.progress.percent) : data.progress.percent}
|
||||||
borderRadius: '10px',
|
/>
|
||||||
display: 'flex',
|
<Box>
|
||||||
overflow: 'hidden',
|
<Typography
|
||||||
transition: '250ms'
|
color="text.primary"
|
||||||
}}>
|
sx={{
|
||||||
<img style={{
|
fontSize: '1.3rem'
|
||||||
borderRadius: '5px',
|
}}
|
||||||
margin: '5px',
|
>
|
||||||
boxShadow: '0px 0px 10px #00000090',
|
{data.progress.cur} / {data.progress.total} parts ({data.progress.percent}% | {formatTime(data.progress.time)} |{' '}
|
||||||
userSelect: 'none',
|
{(data.progress.downloadSpeed / 1024 / 1024).toFixed(2)} MB/s | {(data.progress.bytes / 1024 / 1024).toFixed(2)}MB)
|
||||||
maxWidth: '20.5rem',
|
</Typography>
|
||||||
}}
|
</Box>
|
||||||
src={current.image} height='auto' width='auto' alt="Thumbnail" />
|
</Box>
|
||||||
<Box
|
</Box>
|
||||||
sx={{
|
</Box>
|
||||||
display: 'flex',
|
</Box>
|
||||||
flexDirection: 'column',
|
</>
|
||||||
width: '100%',
|
)}
|
||||||
justifyContent: 'center',
|
{current && !data && (
|
||||||
//backgroundColor: '#ffffff0f'
|
<>
|
||||||
}}>
|
<Box
|
||||||
<Box sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
}}>
|
alignItems: 'center'
|
||||||
<Box sx={{
|
}}
|
||||||
width: '70%',
|
>
|
||||||
marginLeft: '10px'
|
<Box
|
||||||
}}>
|
sx={{
|
||||||
<Box sx={{
|
marginTop: '2rem',
|
||||||
flexDirection: 'column',
|
marginBottom: '1rem',
|
||||||
display: 'flex',
|
height: '12rem',
|
||||||
justifyContent: 'space-between',
|
width: '93vw',
|
||||||
}}>
|
maxWidth: '93rem',
|
||||||
<Typography color='text.primary' sx={{
|
backgroundColor: '#282828',
|
||||||
fontSize: '1.8rem',
|
boxShadow: '0px 0px 50px #00000090',
|
||||||
}}>
|
borderRadius: '10px',
|
||||||
{current.parent.title}
|
display: 'flex',
|
||||||
</Typography>
|
overflow: 'hidden',
|
||||||
<Typography color='text.primary' sx={{
|
transition: '250ms'
|
||||||
fontSize: '1.2rem',
|
}}
|
||||||
}}>
|
>
|
||||||
{current.title}
|
<img
|
||||||
</Typography>
|
style={{
|
||||||
</Box>
|
borderRadius: '5px',
|
||||||
</Box>
|
margin: '5px',
|
||||||
<Box sx={{
|
boxShadow: '0px 0px 10px #00000090',
|
||||||
//backgroundColor: '#00ff00',
|
userSelect: 'none',
|
||||||
width: '30%',
|
maxWidth: '20.5rem'
|
||||||
display: 'flex',
|
}}
|
||||||
flexDirection: 'column',
|
src={current.image}
|
||||||
justifyContent: 'center',
|
height="auto"
|
||||||
alignItems: 'center',
|
width="auto"
|
||||||
}}>
|
alt="Thumbnail"
|
||||||
<Box sx={{
|
/>
|
||||||
display: 'flex',
|
<Box
|
||||||
alignItems: 'center',
|
sx={{
|
||||||
justifyContent: 'space-between',
|
display: 'flex',
|
||||||
position: 'relative',
|
flexDirection: 'column',
|
||||||
}}>
|
width: '100%',
|
||||||
<Typography color='text.primary' sx={{
|
justifyContent: 'center'
|
||||||
fontSize: '1.8rem',
|
//backgroundColor: '#ffffff0f'
|
||||||
}}>
|
}}
|
||||||
Downloading:
|
>
|
||||||
</Typography>
|
<Box
|
||||||
<CircularProgress variant="indeterminate" sx={{
|
sx={{
|
||||||
marginLeft: '2rem',
|
display: 'flex'
|
||||||
}}/>
|
}}
|
||||||
</Box>
|
>
|
||||||
</Box>
|
<Box
|
||||||
</Box>
|
sx={{
|
||||||
<Box sx={{
|
width: '70%',
|
||||||
height: '50%',
|
marginLeft: '10px'
|
||||||
display: 'flex',
|
}}
|
||||||
flexDirection: 'column',
|
>
|
||||||
justifyContent: 'center',
|
<Box
|
||||||
alignItems: 'center',
|
sx={{
|
||||||
//backgroundColor: '#0000ff',
|
flexDirection: 'column',
|
||||||
}}>
|
display: 'flex',
|
||||||
<LinearProgress variant='indeterminate'
|
justifyContent: 'space-between'
|
||||||
sx={{
|
}}
|
||||||
height: '20px',
|
>
|
||||||
width: '97.53%',
|
<Typography
|
||||||
margin: '10px',
|
color="text.primary"
|
||||||
boxShadow: '0px 0px 10px #00000090',
|
sx={{
|
||||||
borderRadius: '10px',
|
fontSize: '1.8rem'
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Box>
|
{current.parent.title}
|
||||||
<Typography color='text.primary'
|
</Typography>
|
||||||
sx={{
|
<Typography
|
||||||
fontSize: '1.3rem',
|
color="text.primary"
|
||||||
}}>
|
sx={{
|
||||||
0 / ? parts (0% | XX:XX | 0 MB/s | 0MB)
|
fontSize: '1.2rem'
|
||||||
</Typography>
|
}}
|
||||||
</Box>
|
>
|
||||||
</Box>
|
{current.title}
|
||||||
</Box>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
<Box
|
||||||
}
|
sx={{
|
||||||
{queue.map((queueItem, index, { length }) => {
|
//backgroundColor: '#00ff00',
|
||||||
return <Box key={`queue_item_${index}`} sx={{
|
width: '30%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
mb: '-1.5rem',
|
flexDirection: 'column',
|
||||||
flexDirection: 'column',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center'
|
||||||
}}>
|
}}
|
||||||
<Box sx={{
|
>
|
||||||
marginTop: '1.5rem',
|
<Box
|
||||||
marginBottom: '1.5rem',
|
sx={{
|
||||||
height: '11rem',
|
display: 'flex',
|
||||||
width: '90vw',
|
alignItems: 'center',
|
||||||
maxWidth: '90rem',
|
justifyContent: 'space-between',
|
||||||
backgroundColor: '#282828',
|
position: 'relative'
|
||||||
boxShadow: '0px 0px 10px #00000090',
|
}}
|
||||||
borderRadius: '10px',
|
>
|
||||||
display: 'flex',
|
<Typography
|
||||||
overflow: 'hidden',
|
color="text.primary"
|
||||||
}}>
|
sx={{
|
||||||
<img style={{
|
fontSize: '1.8rem'
|
||||||
borderRadius: '5px',
|
}}
|
||||||
margin: '5px',
|
>
|
||||||
boxShadow: '0px 0px 5px #00000090',
|
Downloading:
|
||||||
userSelect: 'none',
|
</Typography>
|
||||||
maxWidth: '18.5rem'
|
<CircularProgress
|
||||||
}}
|
variant="indeterminate"
|
||||||
src={queueItem.image} height='auto' width='auto' alt="Thumbnail" />
|
sx={{
|
||||||
<Box sx={{
|
marginLeft: '2rem'
|
||||||
margin: '5px',
|
}}
|
||||||
display: 'flex',
|
/>
|
||||||
width: '100%',
|
</Box>
|
||||||
justifyContent: 'space-between',
|
</Box>
|
||||||
}}>
|
</Box>
|
||||||
<Box sx={{
|
<Box
|
||||||
width: '30%',
|
sx={{
|
||||||
marginRight: '5px',
|
height: '50%',
|
||||||
marginLeft: '5px',
|
display: 'flex',
|
||||||
display: 'flex',
|
flexDirection: 'column',
|
||||||
flexDirection: 'column',
|
justifyContent: 'center',
|
||||||
justifyContent: 'space-between',
|
alignItems: 'center'
|
||||||
overflow: 'hidden',
|
//backgroundColor: '#0000ff',
|
||||||
textOverflow: 'ellipsis',
|
}}
|
||||||
}}>
|
>
|
||||||
<Typography color='text.primary' sx={{
|
<LinearProgress
|
||||||
fontSize: '1.8rem',
|
variant="indeterminate"
|
||||||
overflow: 'hidden',
|
sx={{
|
||||||
whiteSpace: 'nowrap',
|
height: '20px',
|
||||||
textOverflow: 'ellipsis',
|
width: '97.53%',
|
||||||
}}>
|
margin: '10px',
|
||||||
{queueItem.parent.title}
|
boxShadow: '0px 0px 10px #00000090',
|
||||||
</Typography>
|
borderRadius: '10px'
|
||||||
<Typography color='text.primary' sx={{
|
}}
|
||||||
fontSize: '1.6rem',
|
/>
|
||||||
marginTop: '-0.4rem',
|
<Box>
|
||||||
marginBottom: '0.4rem',
|
<Typography
|
||||||
}}>
|
color="text.primary"
|
||||||
S{queueItem.parent.season}E{queueItem.episode}
|
sx={{
|
||||||
</Typography>
|
fontSize: '1.3rem'
|
||||||
<Typography color='text.primary' sx={{
|
}}
|
||||||
fontSize: '1.2rem',
|
>
|
||||||
marginTop: '-0.4rem',
|
0 / ? parts (0% | XX:XX | 0 MB/s | 0MB)
|
||||||
marginBottom: '0.4rem',
|
</Typography>
|
||||||
textOverflow: 'ellipsis',
|
</Box>
|
||||||
}}>
|
</Box>
|
||||||
{queueItem.title}
|
</Box>
|
||||||
</Typography>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{
|
</>
|
||||||
width: '40%',
|
)}
|
||||||
marginRight: '5px',
|
{queue.map((queueItem, index, { length }) => {
|
||||||
marginLeft: '5px',
|
return (
|
||||||
display: 'flex',
|
<Box
|
||||||
flexDirection: 'column',
|
key={`queue_item_${index}`}
|
||||||
overflow: 'hidden',
|
sx={{
|
||||||
whiteSpace: 'nowrap',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
mb: '-1.5rem',
|
||||||
}}>
|
flexDirection: 'column',
|
||||||
<Typography color='text.primary' sx={{
|
alignItems: 'center'
|
||||||
fontSize: '1.8rem',
|
}}
|
||||||
overflow: 'hidden',
|
>
|
||||||
whiteSpace: 'nowrap',
|
<Box
|
||||||
textOverflow: 'ellipsis',
|
sx={{
|
||||||
}}>
|
marginTop: '1.5rem',
|
||||||
Dub(s): {queueItem.dubLang.join(', ')}
|
marginBottom: '1.5rem',
|
||||||
</Typography>
|
height: '11rem',
|
||||||
<Typography color='text.primary' sx={{
|
width: '90vw',
|
||||||
fontSize: '1.8rem',
|
maxWidth: '90rem',
|
||||||
overflow: 'hidden',
|
backgroundColor: '#282828',
|
||||||
whiteSpace: 'nowrap',
|
boxShadow: '0px 0px 10px #00000090',
|
||||||
textOverflow: 'ellipsis',
|
borderRadius: '10px',
|
||||||
}}>
|
display: 'flex',
|
||||||
Sub(s): {queueItem.dlsubs.join(', ')}
|
overflow: 'hidden'
|
||||||
</Typography>
|
}}
|
||||||
<Typography color='text.primary' sx={{
|
>
|
||||||
fontSize: '1.8rem',
|
<img
|
||||||
|
style={{
|
||||||
}}>
|
borderRadius: '5px',
|
||||||
Quality: {queueItem.q}
|
margin: '5px',
|
||||||
</Typography>
|
boxShadow: '0px 0px 5px #00000090',
|
||||||
</Box>
|
userSelect: 'none',
|
||||||
<Box sx={{
|
maxWidth: '18.5rem'
|
||||||
marginRight: '5px',
|
}}
|
||||||
marginLeft: '5px',
|
src={queueItem.image}
|
||||||
width: '30%',
|
height="auto"
|
||||||
justifyContent: 'center',
|
width="auto"
|
||||||
alignItems: 'center',
|
alt="Thumbnail"
|
||||||
display: 'flex'
|
/>
|
||||||
}}>
|
<Box
|
||||||
<Tooltip title="Delete from queue" arrow placement='top'>
|
sx={{
|
||||||
<IconButton
|
margin: '5px',
|
||||||
onClick={() => {
|
display: 'flex',
|
||||||
msg.removeFromQueue(index);
|
width: '100%',
|
||||||
}}
|
justifyContent: 'space-between'
|
||||||
sx={{
|
}}
|
||||||
backgroundColor: '#ff573a25',
|
>
|
||||||
height: '40px',
|
<Box
|
||||||
transition: '250ms',
|
sx={{
|
||||||
'&:hover' : {
|
width: '30%',
|
||||||
backgroundColor: '#ff573a',
|
marginRight: '5px',
|
||||||
}
|
marginLeft: '5px',
|
||||||
}}>
|
display: 'flex',
|
||||||
<DeleteIcon />
|
flexDirection: 'column',
|
||||||
</IconButton>
|
justifyContent: 'space-between',
|
||||||
</Tooltip>
|
overflow: 'hidden',
|
||||||
</Box>
|
textOverflow: 'ellipsis'
|
||||||
</Box>
|
}}
|
||||||
</Box>
|
>
|
||||||
</Box>
|
<Typography
|
||||||
;
|
color="text.primary"
|
||||||
})}
|
sx={{
|
||||||
</> : <Box sx={{
|
fontSize: '1.8rem',
|
||||||
display: 'flex',
|
overflow: 'hidden',
|
||||||
width: '100%',
|
whiteSpace: 'nowrap',
|
||||||
height: '12rem',
|
textOverflow: 'ellipsis'
|
||||||
flexDirection: 'column',
|
}}
|
||||||
alignItems: 'center',
|
>
|
||||||
}}>
|
{queueItem.parent.title}
|
||||||
<Typography color='text.primary' sx={{
|
</Typography>
|
||||||
fontSize: '2rem',
|
<Typography
|
||||||
margin: '10px'
|
color="text.primary"
|
||||||
}}>
|
sx={{
|
||||||
Selected episodes will be shown here
|
fontSize: '1.6rem',
|
||||||
</Typography>
|
marginTop: '-0.4rem',
|
||||||
<Box sx={{
|
marginBottom: '0.4rem'
|
||||||
display: 'flex',
|
}}
|
||||||
margin: '10px'
|
>
|
||||||
}}>
|
S{queueItem.parent.season}E{queueItem.episode}
|
||||||
<Skeleton variant='rectangular' height={'10rem'} width={'20rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
</Typography>
|
||||||
<Box sx={{
|
<Typography
|
||||||
display: 'flex',
|
color="text.primary"
|
||||||
flexDirection: 'column',
|
sx={{
|
||||||
}}>
|
fontSize: '1.2rem',
|
||||||
<Skeleton variant='text' height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
marginTop: '-0.4rem',
|
||||||
<Skeleton variant='text' height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
marginBottom: '0.4rem',
|
||||||
</Box>
|
textOverflow: 'ellipsis'
|
||||||
</Box>
|
}}
|
||||||
<Box sx={{
|
>
|
||||||
display: 'flex',
|
{queueItem.title}
|
||||||
margin: '10px'
|
</Typography>
|
||||||
}}>
|
</Box>
|
||||||
<Skeleton variant='rectangular' height={'10rem'} width={'20rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
<Box
|
||||||
<Box sx={{
|
sx={{
|
||||||
display: 'flex',
|
width: '40%',
|
||||||
flexDirection: 'column',
|
marginRight: '5px',
|
||||||
}}>
|
marginLeft: '5px',
|
||||||
<Skeleton variant='text' height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
display: 'flex',
|
||||||
<Skeleton variant='text' height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }}/>
|
flexDirection: 'column',
|
||||||
</Box>
|
overflow: 'hidden',
|
||||||
</Box>
|
whiteSpace: 'nowrap',
|
||||||
</Box>;
|
justifyContent: 'space-between'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
color="text.primary"
|
||||||
|
sx={{
|
||||||
|
fontSize: '1.8rem',
|
||||||
|
overflow: 'hidden',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textOverflow: 'ellipsis'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Dub(s): {queueItem.dubLang.join(', ')}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
color="text.primary"
|
||||||
|
sx={{
|
||||||
|
fontSize: '1.8rem',
|
||||||
|
overflow: 'hidden',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textOverflow: 'ellipsis'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sub(s): {queueItem.dlsubs.join(', ')}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
color="text.primary"
|
||||||
|
sx={{
|
||||||
|
fontSize: '1.8rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Quality: {queueItem.q}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginRight: '5px',
|
||||||
|
marginLeft: '5px',
|
||||||
|
width: '30%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip title="Delete from queue" arrow placement="top">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
msg.removeFromQueue(index);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#ff573a25',
|
||||||
|
height: '40px',
|
||||||
|
transition: '250ms',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#ff573a'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
height: '12rem',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
color="text.primary"
|
||||||
|
sx={{
|
||||||
|
fontSize: '2rem',
|
||||||
|
margin: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Selected episodes will be shown here
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
margin: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton variant="rectangular" height={'10rem'} width={'20rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton variant="text" height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
<Skeleton variant="text" height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
margin: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton variant="rectangular" height={'10rem'} width={'20rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton variant="text" height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
<Skeleton variant="text" height={'100%'} width={'30rem'} sx={{ margin: '5px', borderRadius: '5px' }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTime = (time: number) => {
|
const formatTime = (time: number) => {
|
||||||
time = Math.floor(time / 1000);
|
time = Math.floor(time / 1000);
|
||||||
const minutes = Math.floor(time / 60);
|
const minutes = Math.floor(time / 60);
|
||||||
time = time % 60;
|
time = time % 60;
|
||||||
|
|
||||||
return `${minutes.toFixed(0).length < 2 ? `0${minutes}` : minutes}m${time.toFixed(0).length < 2 ? `0${time}` : time}s`;
|
return `${minutes.toFixed(0).length < 2 ? `0${minutes}` : minutes}m${time.toFixed(0).length < 2 ? `0${time}` : time}s`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Queue;
|
export default Queue;
|
||||||
|
|
|
||||||
|
|
@ -5,120 +5,134 @@ import useStore from '../../hooks/useStore';
|
||||||
import { StoreState } from '../../provider/Store';
|
import { StoreState } from '../../provider/Store';
|
||||||
|
|
||||||
const MenuBar: React.FC = () => {
|
const MenuBar: React.FC = () => {
|
||||||
const [ openMenu, setMenuOpen ] = React.useState<'settings'|'help'|undefined>();
|
const [openMenu, setMenuOpen] = React.useState<'settings' | 'help' | undefined>();
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const [store, dispatch] = useStore();
|
const [store, dispatch] = useStore();
|
||||||
|
|
||||||
const messageChannel = React.useContext(messageChannelContext);
|
const messageChannel = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!messageChannel || store.version !== '')
|
if (!messageChannel || store.version !== '') return;
|
||||||
return;
|
dispatch({
|
||||||
dispatch({
|
type: 'version',
|
||||||
type: 'version',
|
payload: await messageChannel.version()
|
||||||
payload: await messageChannel.version()
|
});
|
||||||
});
|
})();
|
||||||
})();
|
}, [messageChannel]);
|
||||||
}, [messageChannel]);
|
|
||||||
|
|
||||||
const transformService = (service: StoreState['service']) => {
|
const transformService = (service: StoreState['service']) => {
|
||||||
switch(service) {
|
switch (service) {
|
||||||
case 'crunchy':
|
case 'crunchy':
|
||||||
return 'Crunchyroll';
|
return 'Crunchyroll';
|
||||||
case 'hidive':
|
case 'hidive':
|
||||||
return 'Hidive';
|
return 'Hidive';
|
||||||
case 'ao':
|
case 'ao':
|
||||||
return 'AnimeOnegai';
|
return 'AnimeOnegai';
|
||||||
case 'adn':
|
case 'adn':
|
||||||
return 'AnimationDigitalNetwork';
|
return 'AnimationDigitalNetwork';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const msg = React.useContext(messageChannelContext);
|
const msg = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLElement>, n: 'settings'|'help') => {
|
const handleClick = (event: React.MouseEvent<HTMLElement>, n: 'settings' | 'help') => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
setMenuOpen(n);
|
setMenuOpen(n);
|
||||||
};
|
};
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
setMenuOpen(undefined);
|
setMenuOpen(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!msg)
|
if (!msg) return <></>;
|
||||||
return <></>;
|
|
||||||
|
|
||||||
return <Box sx={{ display: 'flex', marginBottom: '1rem', width: '100%', alignItems: 'center' }}>
|
return (
|
||||||
<Box sx={{ position: 'relative', left: '0%', width: '50%'}}>
|
<Box sx={{ display: 'flex', marginBottom: '1rem', width: '100%', alignItems: 'center' }}>
|
||||||
<Button onClick={(e) => handleClick(e, 'settings')}>
|
<Box sx={{ position: 'relative', left: '0%', width: '50%' }}>
|
||||||
Settings
|
<Button onClick={(e) => handleClick(e, 'settings')}>Settings</Button>
|
||||||
</Button>
|
<Button onClick={(e) => handleClick(e, 'help')}>Help</Button>
|
||||||
<Button onClick={(e) => handleClick(e, 'help')}>
|
</Box>
|
||||||
Help
|
<Menu open={openMenu === 'settings'} anchorEl={anchorEl} onClose={handleClose}>
|
||||||
</Button>
|
<MenuItem
|
||||||
</Box>
|
onClick={() => {
|
||||||
<Menu open={openMenu === 'settings'} anchorEl={anchorEl} onClose={handleClose}>
|
msg.openFolder('config');
|
||||||
<MenuItem onClick={() => {
|
handleClose();
|
||||||
msg.openFolder('config');
|
}}
|
||||||
handleClose();
|
>
|
||||||
}}>
|
Open settings folder
|
||||||
Open settings folder
|
</MenuItem>
|
||||||
</MenuItem>
|
<MenuItem
|
||||||
<MenuItem onClick={() => {
|
onClick={() => {
|
||||||
msg.openFile(['config', 'bin-path.yml']);
|
msg.openFile(['config', 'bin-path.yml']);
|
||||||
handleClose();
|
handleClose();
|
||||||
}}>
|
}}
|
||||||
Open FFmpeg/Mkvmerge file
|
>
|
||||||
</MenuItem>
|
Open FFmpeg/Mkvmerge file
|
||||||
<MenuItem onClick={() => {
|
</MenuItem>
|
||||||
msg.openFile(['config', 'cli-defaults.yml']);
|
<MenuItem
|
||||||
handleClose();
|
onClick={() => {
|
||||||
}}>
|
msg.openFile(['config', 'cli-defaults.yml']);
|
||||||
Open advanced options
|
handleClose();
|
||||||
</MenuItem>
|
}}
|
||||||
<MenuItem onClick={() => {
|
>
|
||||||
msg.openFolder('content');
|
Open advanced options
|
||||||
handleClose();
|
</MenuItem>
|
||||||
}}>
|
<MenuItem
|
||||||
Open output path
|
onClick={() => {
|
||||||
</MenuItem>
|
msg.openFolder('content');
|
||||||
</Menu>
|
handleClose();
|
||||||
<Menu open={openMenu === 'help'} anchorEl={anchorEl} onClose={handleClose}>
|
}}
|
||||||
<MenuItem onClick={() => {
|
>
|
||||||
msg.openURL('https://github.com/anidl/multi-downloader-nx');
|
Open output path
|
||||||
handleClose();
|
</MenuItem>
|
||||||
}}>
|
</Menu>
|
||||||
GitHub
|
<Menu open={openMenu === 'help'} anchorEl={anchorEl} onClose={handleClose}>
|
||||||
</MenuItem>
|
<MenuItem
|
||||||
<MenuItem onClick={() => {
|
onClick={() => {
|
||||||
msg.openURL('https://github.com/anidl/multi-downloader-nx/issues/new?assignees=AnimeDL,AnidlSupport&labels=bug&template=bug.yml&title=BUG');
|
msg.openURL('https://github.com/anidl/multi-downloader-nx');
|
||||||
handleClose();
|
handleClose();
|
||||||
}}>
|
}}
|
||||||
Report a bug
|
>
|
||||||
</MenuItem>
|
GitHub
|
||||||
<MenuItem onClick={() => {
|
</MenuItem>
|
||||||
msg.openURL('https://github.com/anidl/multi-downloader-nx/graphs/contributors');
|
<MenuItem
|
||||||
handleClose();
|
onClick={() => {
|
||||||
}}>
|
msg.openURL('https://github.com/anidl/multi-downloader-nx/issues/new?assignees=AnimeDL,AnidlSupport&labels=bug&template=bug.yml&title=BUG');
|
||||||
Contributors
|
handleClose();
|
||||||
</MenuItem>
|
}}
|
||||||
<MenuItem onClick={() => {
|
>
|
||||||
msg.openURL('https://discord.gg/qEpbWen5vq');
|
Report a bug
|
||||||
handleClose();
|
</MenuItem>
|
||||||
}}>
|
<MenuItem
|
||||||
Discord
|
onClick={() => {
|
||||||
</MenuItem>
|
msg.openURL('https://github.com/anidl/multi-downloader-nx/graphs/contributors');
|
||||||
<MenuItem onClick={() => {
|
handleClose();
|
||||||
handleClose();
|
}}
|
||||||
}}>
|
>
|
||||||
Version: {store.version}
|
Contributors
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
<MenuItem
|
||||||
<Typography variant="h5" color="text.primary">
|
onClick={() => {
|
||||||
{transformService(store.service)}
|
msg.openURL('https://discord.gg/qEpbWen5vq');
|
||||||
</Typography>
|
handleClose();
|
||||||
</Box>;
|
}}
|
||||||
|
>
|
||||||
|
Discord
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Version: {store.version}
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
<Typography variant="h5" color="text.primary">
|
||||||
|
{transformService(store.service)}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MenuBar;
|
export default MenuBar;
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,17 @@ import React from 'react';
|
||||||
import { Box, Backdrop, CircularProgress } from '@mui/material';
|
import { Box, Backdrop, CircularProgress } from '@mui/material';
|
||||||
|
|
||||||
export type RequireType<T> = {
|
export type RequireType<T> = {
|
||||||
value?: T
|
value?: T;
|
||||||
}
|
|
||||||
|
|
||||||
const Require = <T, >(props: React.PropsWithChildren<RequireType<T>>) => {
|
|
||||||
return props.value === undefined ? <Backdrop open>
|
|
||||||
<CircularProgress />
|
|
||||||
</Backdrop> : <Box>{props.children}</Box>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Require;
|
const Require = <T,>(props: React.PropsWithChildren<RequireType<T>>) => {
|
||||||
|
return props.value === undefined ? (
|
||||||
|
<Backdrop open>
|
||||||
|
<CircularProgress />
|
||||||
|
</Backdrop>
|
||||||
|
) : (
|
||||||
|
<Box>{props.children}</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Require;
|
||||||
|
|
|
||||||
|
|
@ -5,38 +5,30 @@ import { messageChannelContext } from '../provider/MessageChannel';
|
||||||
import Require from './Require';
|
import Require from './Require';
|
||||||
|
|
||||||
const StartQueueButton: React.FC = () => {
|
const StartQueueButton: React.FC = () => {
|
||||||
const messageChannel = React.useContext(messageChannelContext);
|
const messageChannel = React.useContext(messageChannelContext);
|
||||||
const [start, setStart] = React.useState(false);
|
const [start, setStart] = React.useState(false);
|
||||||
const msg = React.useContext(messageChannelContext);
|
const msg = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!msg)
|
if (!msg) return alert('Invalid state: msg not found');
|
||||||
return alert('Invalid state: msg not found');
|
setStart(await msg.getDownloadQueue());
|
||||||
setStart(await msg.getDownloadQueue());
|
})();
|
||||||
})();
|
}, []);
|
||||||
}, []);
|
|
||||||
|
|
||||||
const change = async () => {
|
const change = async () => {
|
||||||
if (await messageChannel?.isDownloading())
|
if (await messageChannel?.isDownloading()) alert('The current download will be finished before the queue stops');
|
||||||
alert('The current download will be finished before the queue stops');
|
msg?.setDownloadQueue(!start);
|
||||||
msg?.setDownloadQueue(!start);
|
setStart(!start);
|
||||||
setStart(!start);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return <Require value={messageChannel}>
|
|
||||||
<Button
|
|
||||||
startIcon={start ? <PauseCircleFilled /> : <PlayCircleFilled /> }
|
|
||||||
variant='contained'
|
|
||||||
onClick={change}
|
|
||||||
sx={{ maxHeight: '2.3rem' }}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
start ? 'Stop Queue' : 'Start Queue'
|
|
||||||
}
|
|
||||||
</Button>
|
|
||||||
</Require>;
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Require value={messageChannel}>
|
||||||
|
<Button startIcon={start ? <PauseCircleFilled /> : <PlayCircleFilled />} variant="contained" onClick={change} sx={{ maxHeight: '2.3rem' }}>
|
||||||
|
{start ? 'Stop Queue' : 'Start Queue'}
|
||||||
|
</Button>
|
||||||
|
</Require>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default StartQueueButton;
|
export default StartQueueButton;
|
||||||
|
|
|
||||||
|
|
@ -2,64 +2,74 @@ import { Box, Button, Divider, List, SxProps } from '@mui/material';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export type Option = {
|
export type Option = {
|
||||||
text: string,
|
text: string;
|
||||||
onClick: () => unknown
|
onClick: () => unknown;
|
||||||
}
|
|
||||||
|
|
||||||
export type ContextMenuProps<T extends HTMLElement> = {
|
|
||||||
options: ('divider'|Option)[],
|
|
||||||
popupItem: React.RefObject<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonSx: SxProps = {
|
|
||||||
'&:hover': {
|
|
||||||
background: 'rgb(0, 30, 60)'
|
|
||||||
},
|
|
||||||
fontSize: '0.7rem',
|
|
||||||
minHeight: '30px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
p: 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ContextMenu<T extends HTMLElement, >(props: ContextMenuProps<T>) {
|
export type ContextMenuProps<T extends HTMLElement> = {
|
||||||
const [anchor, setAnchor] = React.useState( { x: 0, y: 0 } );
|
options: ('divider' | Option)[];
|
||||||
|
popupItem: React.RefObject<T>;
|
||||||
|
};
|
||||||
|
|
||||||
const [show, setShow] = React.useState(false);
|
const buttonSx: SxProps = {
|
||||||
|
'&:hover': {
|
||||||
|
background: 'rgb(0, 30, 60)'
|
||||||
|
},
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
minHeight: '30px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
p: 0
|
||||||
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
function ContextMenu<T extends HTMLElement>(props: ContextMenuProps<T>) {
|
||||||
const { popupItem: ref } = props;
|
const [anchor, setAnchor] = React.useState({ x: 0, y: 0 });
|
||||||
if (ref.current === null)
|
|
||||||
return;
|
|
||||||
const listener = (ev: MouseEvent) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
setAnchor({ x: ev.x + 10, y: ev.y + 10 });
|
|
||||||
setShow(true);
|
|
||||||
};
|
|
||||||
ref.current.addEventListener('contextmenu', listener);
|
|
||||||
|
|
||||||
return () => {
|
const [show, setShow] = React.useState(false);
|
||||||
if (ref.current)
|
|
||||||
ref.current.removeEventListener('contextmenu', listener);
|
|
||||||
};
|
|
||||||
}, [ props.popupItem ]);
|
|
||||||
|
|
||||||
return show ? <Box sx={{ zIndex: 1400, p: 1, background: 'rgba(0, 0, 0, 0.75)', backdropFilter: 'blur(5px)', position: 'fixed', left: anchor.x, top: anchor.y }}>
|
React.useEffect(() => {
|
||||||
<List sx={{ p: 0, m: 0, display: 'flex', flexDirection: 'column' }}>
|
const { popupItem: ref } = props;
|
||||||
{props.options.map((item, i) => {
|
if (ref.current === null) return;
|
||||||
return item === 'divider' ? <Divider key={`ContextMenu_Divider_${i}_${item}`}/> :
|
const listener = (ev: MouseEvent) => {
|
||||||
<Button color='inherit' key={`ContextMenu_Value_${i}_${item}`} onClick={() => {
|
ev.preventDefault();
|
||||||
item.onClick();
|
setAnchor({ x: ev.x + 10, y: ev.y + 10 });
|
||||||
setShow(false);
|
setShow(true);
|
||||||
}} sx={buttonSx}>
|
};
|
||||||
{item.text}
|
ref.current.addEventListener('contextmenu', listener);
|
||||||
</Button>;
|
|
||||||
})}
|
return () => {
|
||||||
<Divider />
|
if (ref.current) ref.current.removeEventListener('contextmenu', listener);
|
||||||
<Button fullWidth color='inherit' onClick={() => setShow(false)} sx={buttonSx} >
|
};
|
||||||
Close
|
}, [props.popupItem]);
|
||||||
</Button>
|
|
||||||
</List>
|
return show ? (
|
||||||
</Box> : <></>;
|
<Box sx={{ zIndex: 1400, p: 1, background: 'rgba(0, 0, 0, 0.75)', backdropFilter: 'blur(5px)', position: 'fixed', left: anchor.x, top: anchor.y }}>
|
||||||
|
<List sx={{ p: 0, m: 0, display: 'flex', flexDirection: 'column' }}>
|
||||||
|
{props.options.map((item, i) => {
|
||||||
|
return item === 'divider' ? (
|
||||||
|
<Divider key={`ContextMenu_Divider_${i}_${item}`} />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
color="inherit"
|
||||||
|
key={`ContextMenu_Value_${i}_${item}`}
|
||||||
|
onClick={() => {
|
||||||
|
item.onClick();
|
||||||
|
setShow(false);
|
||||||
|
}}
|
||||||
|
sx={buttonSx}
|
||||||
|
>
|
||||||
|
{item.text}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Divider />
|
||||||
|
<Button fullWidth color="inherit" onClick={() => setShow(false)} sx={buttonSx}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ContextMenu;
|
export default ContextMenu;
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,16 @@ import React from 'react';
|
||||||
export type LinearProgressWithLabelProps = LinearProgressProps & { value: number };
|
export type LinearProgressWithLabelProps = LinearProgressProps & { value: number };
|
||||||
|
|
||||||
const LinearProgressWithLabel: React.FC<LinearProgressWithLabelProps> = (props) => {
|
const LinearProgressWithLabel: React.FC<LinearProgressWithLabelProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Box sx={{ width: '100%', mr: 1 }}>
|
<Box sx={{ width: '100%', mr: 1 }}>
|
||||||
<LinearProgress variant="determinate" {...props} />
|
<LinearProgress variant="determinate" {...props} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ minWidth: 35 }}>
|
<Box sx={{ minWidth: 35 }}>
|
||||||
<Typography variant="body2" color="text.secondary">{`${Math.round(
|
<Typography variant="body2" color="text.secondary">{`${Math.round(props.value)}%`}</Typography>
|
||||||
props.value,
|
</Box>
|
||||||
)}%`}</Typography>
|
</Box>
|
||||||
</Box>
|
);
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LinearProgressWithLabel;
|
export default LinearProgressWithLabel;
|
||||||
|
|
|
||||||
|
|
@ -2,73 +2,64 @@ import React from 'react';
|
||||||
import { FormControl, InputLabel, MenuItem, OutlinedInput, Select, Theme, useTheme } from '@mui/material';
|
import { FormControl, InputLabel, MenuItem, OutlinedInput, Select, Theme, useTheme } from '@mui/material';
|
||||||
|
|
||||||
export type MultiSelectProps = {
|
export type MultiSelectProps = {
|
||||||
values: string[],
|
values: string[];
|
||||||
selected: string[],
|
selected: string[];
|
||||||
onChange: (values: string[]) => unknown,
|
onChange: (values: string[]) => unknown;
|
||||||
title: string,
|
title: string;
|
||||||
allOption?: boolean
|
allOption?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
const ITEM_HEIGHT = 48;
|
const ITEM_HEIGHT = 48;
|
||||||
const ITEM_PADDING_TOP = 8;
|
const ITEM_PADDING_TOP = 8;
|
||||||
const MenuProps = {
|
const MenuProps = {
|
||||||
PaperProps: {
|
PaperProps: {
|
||||||
style: {
|
style: {
|
||||||
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||||
width: 250
|
width: 250
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getStyles(name: string, personName: readonly string[], theme: Theme) {
|
function getStyles(name: string, personName: readonly string[], theme: Theme) {
|
||||||
return {
|
return {
|
||||||
fontWeight:
|
fontWeight: (personName ?? []).indexOf(name) === -1 ? theme.typography.fontWeightRegular : theme.typography.fontWeightMedium
|
||||||
(personName ?? []).indexOf(name) === -1
|
};
|
||||||
? theme.typography.fontWeightRegular
|
|
||||||
: theme.typography.fontWeightMedium
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MultiSelect: React.FC<MultiSelectProps> = (props) => {
|
const MultiSelect: React.FC<MultiSelectProps> = (props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return <div>
|
return (
|
||||||
<FormControl sx={{ width: 300 }}>
|
<div>
|
||||||
<InputLabel id="multi-select-label">{props.title}</InputLabel>
|
<FormControl sx={{ width: 300 }}>
|
||||||
<Select
|
<InputLabel id="multi-select-label">{props.title}</InputLabel>
|
||||||
labelId="multi-select-label"
|
<Select
|
||||||
id="multi-select"
|
labelId="multi-select-label"
|
||||||
multiple
|
id="multi-select"
|
||||||
value={(props.selected ?? [])}
|
multiple
|
||||||
onChange={e => {
|
value={props.selected ?? []}
|
||||||
const val = typeof e.target.value === 'string' ? e.target.value.split(',') : e.target.value;
|
onChange={(e) => {
|
||||||
if (props.allOption && val.includes('all')) {
|
const val = typeof e.target.value === 'string' ? e.target.value.split(',') : e.target.value;
|
||||||
if (props.values.length === val.length - 1)
|
if (props.allOption && val.includes('all')) {
|
||||||
props.onChange([]);
|
if (props.values.length === val.length - 1) props.onChange([]);
|
||||||
else
|
else props.onChange(props.values);
|
||||||
props.onChange(props.values);
|
} else {
|
||||||
} else {
|
props.onChange(val);
|
||||||
props.onChange(val);
|
}
|
||||||
}
|
}}
|
||||||
}}
|
input={<OutlinedInput id="select-multiple-chip" label={props.title} />}
|
||||||
input={<OutlinedInput id="select-multiple-chip" label={props.title} />}
|
renderValue={(selected) => selected.join(', ')}
|
||||||
renderValue={(selected) => (
|
MenuProps={MenuProps}
|
||||||
selected.join(', ')
|
>
|
||||||
)}
|
{props.values.concat(props.allOption ? 'all' : []).map((name) => (
|
||||||
MenuProps={MenuProps}
|
<MenuItem key={`${props.title}_${name}`} value={name} style={getStyles(name, props.selected, theme)}>
|
||||||
>
|
{name}
|
||||||
{props.values.concat(props.allOption ? 'all' : []).map((name) => (
|
</MenuItem>
|
||||||
<MenuItem
|
))}
|
||||||
key={`${props.title}_${name}`}
|
</Select>
|
||||||
value={name}
|
</FormControl>
|
||||||
style={getStyles(name, props.selected, theme)}
|
</div>
|
||||||
>
|
);
|
||||||
{name}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</div>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MultiSelect;
|
export default MultiSelect;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ import React from 'react';
|
||||||
import { StoreAction, StoreContext, StoreState } from '../provider/Store';
|
import { StoreAction, StoreContext, StoreState } from '../provider/Store';
|
||||||
|
|
||||||
const useStore = () => {
|
const useStore = () => {
|
||||||
const context = React.useContext(StoreContext as unknown as React.Context<[StoreState, React.Dispatch<StoreAction<keyof StoreState>>]>);
|
const context = React.useContext(StoreContext as unknown as React.Context<[StoreState, React.Dispatch<StoreAction<keyof StoreState>>]>);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useStore must be used under Store');
|
throw new Error('useStore must be used under Store');
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useStore;
|
export default useStore;
|
||||||
|
|
|
||||||
|
|
@ -16,36 +16,35 @@ document.body.style.display = 'flex';
|
||||||
document.body.style.justifyContent = 'center';
|
document.body.style.justifyContent = 'center';
|
||||||
|
|
||||||
const notistackRef = React.createRef<SnackbarProvider>();
|
const notistackRef = React.createRef<SnackbarProvider>();
|
||||||
const onClickDismiss = (key: SnackbarKey | undefined) => () => {
|
const onClickDismiss = (key: SnackbarKey | undefined) => () => {
|
||||||
if (notistackRef.current)
|
if (notistackRef.current) notistackRef.current.closeSnackbar(key);
|
||||||
notistackRef.current.closeSnackbar(key);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const container = document.getElementById('root');
|
const container = document.getElementById('root');
|
||||||
const root = createRoot(container as HTMLElement);
|
const root = createRoot(container as HTMLElement);
|
||||||
root.render(
|
root.render(
|
||||||
<ErrorHandler>
|
<ErrorHandler>
|
||||||
<Store>
|
<Store>
|
||||||
<SnackbarProvider
|
<SnackbarProvider
|
||||||
ref={notistackRef}
|
ref={notistackRef}
|
||||||
action={(key) => (
|
action={(key) => (
|
||||||
<IconButton onClick={onClickDismiss(key)} color="inherit">
|
<IconButton onClick={onClickDismiss(key)} color="inherit">
|
||||||
<CloseOutlined />
|
<CloseOutlined />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Style>
|
<Style>
|
||||||
<MessageChannel>
|
<MessageChannel>
|
||||||
<ServiceProvider>
|
<ServiceProvider>
|
||||||
<QueueProvider>
|
<QueueProvider>
|
||||||
<Box>
|
<Box>
|
||||||
<App />
|
<App />
|
||||||
</Box>
|
</Box>
|
||||||
</QueueProvider>
|
</QueueProvider>
|
||||||
</ServiceProvider>
|
</ServiceProvider>
|
||||||
</MessageChannel>
|
</MessageChannel>
|
||||||
</Style>
|
</Style>
|
||||||
</SnackbarProvider>
|
</SnackbarProvider>
|
||||||
</Store>
|
</Store>
|
||||||
</ErrorHandler>
|
</ErrorHandler>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,44 @@
|
||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default class ErrorHandler extends React.Component<{
|
export default class ErrorHandler extends React.Component<
|
||||||
children: React.ReactNode|React.ReactNode[]
|
{
|
||||||
}, {
|
children: React.ReactNode | React.ReactNode[];
|
||||||
error?: {
|
},
|
||||||
er: Error,
|
{
|
||||||
stack: React.ErrorInfo
|
error?: {
|
||||||
}
|
er: Error;
|
||||||
}> {
|
stack: React.ErrorInfo;
|
||||||
|
};
|
||||||
constructor(props: {
|
}
|
||||||
children: React.ReactNode|React.ReactNode[]
|
> {
|
||||||
}) {
|
constructor(props: { children: React.ReactNode | React.ReactNode[] }) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { error: undefined };
|
this.state = { error: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(er: Error, stack: React.ErrorInfo) {
|
componentDidCatch(er: Error, stack: React.ErrorInfo) {
|
||||||
this.setState({ error: { er, stack } });
|
this.setState({ error: { er, stack } });
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
return this.state.error ?
|
return this.state.error ? (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', p: 2 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', p: 2 }}>
|
||||||
<Typography variant='body1' color='red'>
|
<Typography variant="body1" color="red">
|
||||||
{`${this.state.error.er.name}: ${this.state.error.er.message}`}
|
{`${this.state.error.er.name}: ${this.state.error.er.message}`}
|
||||||
<br/>
|
<br />
|
||||||
{this.state.error.stack.componentStack?.split('\n').map(a => {
|
{this.state.error.stack.componentStack?.split('\n').map((a) => {
|
||||||
return <>
|
return (
|
||||||
{a}
|
<>
|
||||||
<br/>
|
{a}
|
||||||
</>;
|
<br />
|
||||||
})}
|
</>
|
||||||
</Typography>
|
);
|
||||||
</Box> : this.props.children;
|
})}
|
||||||
}
|
</Typography>
|
||||||
}
|
</Box>
|
||||||
|
) : (
|
||||||
|
this.props.children
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,236 +9,236 @@ import { useSnackbar } from 'notistack';
|
||||||
import { LockOutlined, PowerSettingsNew } from '@mui/icons-material';
|
import { LockOutlined, PowerSettingsNew } from '@mui/icons-material';
|
||||||
import { GUIConfig } from '../../../../modules/module.cfg-loader';
|
import { GUIConfig } from '../../../../modules/module.cfg-loader';
|
||||||
|
|
||||||
export type FrontEndMessages = (MessageHandler & { randomEvents: RandomEventHandler, logout: () => Promise<boolean> });
|
export type FrontEndMessages = MessageHandler & { randomEvents: RandomEventHandler; logout: () => Promise<boolean> };
|
||||||
|
|
||||||
export class RandomEventHandler {
|
export class RandomEventHandler {
|
||||||
private handler: {
|
private handler: {
|
||||||
[eventName in keyof RandomEvents]: Handler<eventName>[]
|
[eventName in keyof RandomEvents]: Handler<eventName>[];
|
||||||
} = {
|
} = {
|
||||||
progress: [],
|
progress: [],
|
||||||
finish: [],
|
finish: [],
|
||||||
queueChange: [],
|
queueChange: [],
|
||||||
current: []
|
current: []
|
||||||
};
|
};
|
||||||
|
|
||||||
public on<T extends keyof RandomEvents>(name: T, listener: Handler<T>) {
|
public on<T extends keyof RandomEvents>(name: T, listener: Handler<T>) {
|
||||||
if (Object.prototype.hasOwnProperty.call(this.handler, name)) {
|
if (Object.prototype.hasOwnProperty.call(this.handler, name)) {
|
||||||
this.handler[name].push(listener as any);
|
this.handler[name].push(listener as any);
|
||||||
} else {
|
} else {
|
||||||
this.handler[name] = [ listener as any ];
|
this.handler[name] = [listener as any];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public emit<T extends keyof RandomEvents>(name: keyof RandomEvents, data: RandomEvent<T>) {
|
public emit<T extends keyof RandomEvents>(name: keyof RandomEvents, data: RandomEvent<T>) {
|
||||||
(this.handler[name] ?? []).forEach(handler => handler(data as any));
|
(this.handler[name] ?? []).forEach((handler) => handler(data as any));
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeListener<T extends keyof RandomEvents>(name: T, listener: Handler<T>) {
|
public removeListener<T extends keyof RandomEvents>(name: T, listener: Handler<T>) {
|
||||||
this.handler[name] = (this.handler[name] as Handler<T>[]).filter(a => a !== listener) as any;
|
this.handler[name] = (this.handler[name] as Handler<T>[]).filter((a) => a !== listener) as any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const messageChannelContext = React.createContext<FrontEndMessages|undefined>(undefined);
|
export const messageChannelContext = React.createContext<FrontEndMessages | undefined>(undefined);
|
||||||
|
|
||||||
async function messageAndResponse<T extends keyof MessageTypes>(socket: WebSocket, msg: WSMessage<T>): Promise<WSMessage<T, 1>> {
|
async function messageAndResponse<T extends keyof MessageTypes>(socket: WebSocket, msg: WSMessage<T>): Promise<WSMessage<T, 1>> {
|
||||||
const id = v4();
|
const id = v4();
|
||||||
const ret = new Promise<WSMessage<T, 1>>((resolve) => {
|
const ret = new Promise<WSMessage<T, 1>>((resolve) => {
|
||||||
const handler = function({ data }: MessageEvent) {
|
const handler = function ({ data }: MessageEvent) {
|
||||||
const parsed = JSON.parse(data.toString()) as WSMessageWithID<T, 1>;
|
const parsed = JSON.parse(data.toString()) as WSMessageWithID<T, 1>;
|
||||||
if (parsed.id === id) {
|
if (parsed.id === id) {
|
||||||
socket.removeEventListener('message', handler);
|
socket.removeEventListener('message', handler);
|
||||||
resolve(parsed);
|
resolve(parsed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
socket.addEventListener('message', handler);
|
socket.addEventListener('message', handler);
|
||||||
});
|
});
|
||||||
const toSend = msg as WSMessageWithID<T>;
|
const toSend = msg as WSMessageWithID<T>;
|
||||||
toSend.id = id;
|
toSend.id = id;
|
||||||
|
|
||||||
socket.send(JSON.stringify(toSend));
|
socket.send(JSON.stringify(toSend));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
||||||
|
const [store, dispatch] = useStore();
|
||||||
|
const [socket, setSocket] = React.useState<undefined | WebSocket>();
|
||||||
|
const [publicWS, setPublicWS] = React.useState<undefined | WebSocket>();
|
||||||
|
const [usePassword, setUsePassword] = React.useState<'waiting' | 'yes' | 'no'>('waiting');
|
||||||
|
const [isSetup, setIsSetup] = React.useState<'waiting' | 'yes' | 'no'>('waiting');
|
||||||
|
|
||||||
const [store, dispatch] = useStore();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
const [socket, setSocket] = React.useState<undefined|WebSocket>();
|
|
||||||
const [publicWS, setPublicWS] = React.useState<undefined|WebSocket>();
|
|
||||||
const [usePassword, setUsePassword] = React.useState<'waiting'|'yes'|'no'>('waiting');
|
|
||||||
const [isSetup, setIsSetup] = React.useState<'waiting'|'yes'|'no'>('waiting');
|
|
||||||
|
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
React.useEffect(() => {
|
||||||
|
const wss = new WebSocket(`${location.protocol == 'https:' ? 'wss' : 'ws'}://${process.env.NODE_ENV === 'development' ? 'localhost:3000' : window.location.host}/public`);
|
||||||
|
wss.addEventListener('open', () => {
|
||||||
|
setPublicWS(wss);
|
||||||
|
});
|
||||||
|
wss.addEventListener('error', () => {
|
||||||
|
enqueueSnackbar('Unable to connect to server. Please reload the page to try again.', { variant: 'error' });
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const wss = new WebSocket(`${location.protocol == 'https:' ? 'wss' : 'ws'}://${process.env.NODE_ENV === 'development' ? 'localhost:3000' : window.location.host}/public`);
|
(async () => {
|
||||||
wss.addEventListener('open', () => {
|
if (!publicWS) return;
|
||||||
setPublicWS(wss);
|
setUsePassword((await messageAndResponse(publicWS, { name: 'requirePassword', data: undefined })).data ? 'yes' : 'no');
|
||||||
});
|
setIsSetup((await messageAndResponse(publicWS, { name: 'isSetup', data: undefined })).data ? 'yes' : 'no');
|
||||||
wss.addEventListener('error', () => {
|
})();
|
||||||
enqueueSnackbar('Unable to connect to server. Please reload the page to try again.', { variant: 'error' });
|
}, [publicWS]);
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
const connect = (ev?: React.FormEvent<HTMLFormElement>) => {
|
||||||
(async () => {
|
let search = new URLSearchParams();
|
||||||
if (!publicWS)
|
if (ev) {
|
||||||
return;
|
ev.preventDefault();
|
||||||
setUsePassword((await messageAndResponse(publicWS, { name: 'requirePassword', data: undefined })).data ? 'yes' : 'no');
|
const formData = new FormData(ev.currentTarget);
|
||||||
setIsSetup((await messageAndResponse(publicWS, { name: 'isSetup', data: undefined })).data ? 'yes' : 'no');
|
const password = formData.get('password')?.toString();
|
||||||
})();
|
if (!password)
|
||||||
}, [publicWS]);
|
return enqueueSnackbar('Please provide both a username and password', {
|
||||||
|
variant: 'error'
|
||||||
|
});
|
||||||
|
search = new URLSearchParams({
|
||||||
|
password
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const connect = (ev?: React.FormEvent<HTMLFormElement>) => {
|
const wws = new WebSocket(
|
||||||
let search = new URLSearchParams();
|
`${location.protocol == 'https:' ? 'wss' : 'ws'}://${process.env.NODE_ENV === 'development' ? 'localhost:3000' : window.location.host}/private?${search}`
|
||||||
if (ev) {
|
);
|
||||||
ev.preventDefault();
|
wws.addEventListener('open', () => {
|
||||||
const formData = new FormData(ev.currentTarget);
|
console.log('[INFO] [WS] Connected');
|
||||||
const password = formData.get('password')?.toString();
|
setSocket(wws);
|
||||||
if (!password)
|
});
|
||||||
return enqueueSnackbar('Please provide both a username and password', {
|
wws.addEventListener('error', (er) => {
|
||||||
variant: 'error'
|
console.error('[ERROR] [WS]', er);
|
||||||
});
|
enqueueSnackbar('Unable to connect to server. Please check the password and try again.', {
|
||||||
search = new URLSearchParams({
|
variant: 'error'
|
||||||
password
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const wws = new WebSocket(`${location.protocol == 'https:' ? 'wss' : 'ws'}://${process.env.NODE_ENV === 'development' ? 'localhost:3000' : window.location.host}/private?${search}`, );
|
const setup = async (ev: React.FormEvent<HTMLFormElement>) => {
|
||||||
wws.addEventListener('open', () => {
|
ev.preventDefault();
|
||||||
console.log('[INFO] [WS] Connected');
|
if (!socket) return enqueueSnackbar('Invalid state: socket not found', { variant: 'error' });
|
||||||
setSocket(wws);
|
const formData = new FormData(ev.currentTarget);
|
||||||
});
|
const password = formData.get('password');
|
||||||
wws.addEventListener('error', (er) => {
|
const data = {
|
||||||
console.error('[ERROR] [WS]', er);
|
port: parseInt(formData.get('port')?.toString() ?? '') ?? 3000,
|
||||||
enqueueSnackbar('Unable to connect to server. Please check the password and try again.', {
|
password: password ? password.toString() : undefined
|
||||||
variant: 'error'
|
} as GUIConfig;
|
||||||
});
|
await messageAndResponse(socket, { name: 'setupServer', data });
|
||||||
});
|
enqueueSnackbar(`The following settings have been set: Port=${data.port}, Password=${data.password ?? 'noPasswordRequired'}`, {
|
||||||
};
|
variant: 'success',
|
||||||
|
persist: true
|
||||||
|
});
|
||||||
|
enqueueSnackbar('Please restart the server now.', {
|
||||||
|
variant: 'info',
|
||||||
|
persist: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const setup = async (ev: React.FormEvent<HTMLFormElement>) => {
|
const randomEventHandler = React.useMemo(() => new RandomEventHandler(), []);
|
||||||
ev.preventDefault();
|
|
||||||
if (!socket)
|
|
||||||
return enqueueSnackbar('Invalid state: socket not found', { variant: 'error' });
|
|
||||||
const formData = new FormData(ev.currentTarget);
|
|
||||||
const password = formData.get('password');
|
|
||||||
const data = {
|
|
||||||
port: parseInt(formData.get('port')?.toString() ?? '') ?? 3000,
|
|
||||||
password: password ? password.toString() : undefined
|
|
||||||
} as GUIConfig;
|
|
||||||
await messageAndResponse(socket, { name: 'setupServer', data });
|
|
||||||
enqueueSnackbar(`The following settings have been set: Port=${data.port}, Password=${data.password ?? 'noPasswordRequired'}`, {
|
|
||||||
variant: 'success',
|
|
||||||
persist: true
|
|
||||||
});
|
|
||||||
enqueueSnackbar('Please restart the server now.', {
|
|
||||||
variant: 'info',
|
|
||||||
persist: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const randomEventHandler = React.useMemo(() => new RandomEventHandler(), []);
|
React.useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (!socket) return;
|
||||||
|
const currentService = await messageAndResponse(socket, { name: 'type', data: undefined });
|
||||||
|
if (currentService.data !== undefined) return dispatch({ type: 'service', payload: currentService.data });
|
||||||
|
if (store.service !== currentService.data) messageAndResponse(socket, { name: 'setup', data: store.service });
|
||||||
|
})();
|
||||||
|
}, [store.service, dispatch, socket]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
(async () => {
|
if (!socket) return;
|
||||||
if (!socket)
|
/* finish is a placeholder */
|
||||||
return;
|
const listener = (initalData: MessageEvent<string>) => {
|
||||||
const currentService = await messageAndResponse(socket, { name: 'type', data: undefined });
|
const data = JSON.parse(initalData.data) as RandomEvent<'finish'>;
|
||||||
if (currentService.data !== undefined)
|
randomEventHandler.emit(data.name, data);
|
||||||
return dispatch({ type: 'service', payload: currentService.data });
|
};
|
||||||
if (store.service !== currentService.data)
|
socket.addEventListener('message', listener);
|
||||||
messageAndResponse(socket, { name: 'setup', data: store.service });
|
return () => {
|
||||||
})();
|
socket.removeEventListener('message', listener);
|
||||||
}, [store.service, dispatch, socket]);
|
};
|
||||||
|
}, [socket]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
if (usePassword === 'waiting') return <></>;
|
||||||
if (!socket)
|
|
||||||
return;
|
|
||||||
/* finish is a placeholder */
|
|
||||||
const listener = (initalData: MessageEvent<string>) => {
|
|
||||||
const data = JSON.parse(initalData.data) as RandomEvent<'finish'>;
|
|
||||||
randomEventHandler.emit(data.name, data);
|
|
||||||
};
|
|
||||||
socket.addEventListener('message', listener);
|
|
||||||
return () => {
|
|
||||||
socket.removeEventListener('message', listener);
|
|
||||||
};
|
|
||||||
}, [ socket ]);
|
|
||||||
|
|
||||||
if (usePassword === 'waiting')
|
if (socket === undefined) {
|
||||||
return <></>;
|
if (usePassword === 'no') {
|
||||||
|
connect(undefined);
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
||||||
|
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
||||||
|
<LockOutlined />
|
||||||
|
</Avatar>
|
||||||
|
<Typography component="h1" variant="h5" color="text.primary">
|
||||||
|
Login
|
||||||
|
</Typography>
|
||||||
|
<Box component="form" onSubmit={connect} sx={{ mt: 1 }}>
|
||||||
|
<TextField name="password" margin="normal" type="password" fullWidth variant="filled" required label={'Password'} />
|
||||||
|
<Button type="submit" variant="contained" sx={{ mt: 3, mb: 2 }} fullWidth>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
<Typography color="text.secondary" align="center" component="p" variant="body2">
|
||||||
|
You need to login in order to use this tool.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (socket === undefined) {
|
if (isSetup === 'no') {
|
||||||
if (usePassword === 'no') {
|
return (
|
||||||
connect(undefined);
|
<Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
||||||
return <></>;
|
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
||||||
}
|
<PowerSettingsNew />
|
||||||
return <Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
</Avatar>
|
||||||
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
<Typography component="h1" variant="h5" color="text.primary">
|
||||||
<LockOutlined />
|
Confirm
|
||||||
</Avatar>
|
</Typography>
|
||||||
<Typography component="h1" variant="h5" color="text.primary">
|
<Box component="form" onSubmit={setup} sx={{ mt: 1 }}>
|
||||||
Login
|
<TextField name="port" margin="normal" type="number" fullWidth variant="filled" required label={'Port'} defaultValue={3000} />
|
||||||
</Typography>
|
<TextField name="password" margin="normal" type="password" fullWidth variant="filled" label={'Password'} />
|
||||||
<Box component="form" onSubmit={connect} sx={{ mt: 1 }}>
|
<Button type="submit" variant="contained" sx={{ mt: 3, mb: 2 }} fullWidth>
|
||||||
<TextField name="password" margin='normal' type="password" fullWidth variant="filled" required label={'Password'} />
|
Confirm
|
||||||
<Button type='submit' variant='contained' sx={{ mt: 3, mb: 2 }} fullWidth>Login</Button>
|
</Button>
|
||||||
<Typography color="text.secondary" align='center' component="p" variant='body2'>
|
<Typography color="text.secondary" align="center" component="p" variant="body2">
|
||||||
You need to login in order to use this tool.
|
Please enter data that will be set to use this tool.
|
||||||
</Typography>
|
<br />
|
||||||
</Box>
|
Leave blank to use no password (NOT RECOMMENDED)!
|
||||||
</Box>;
|
</Typography>
|
||||||
}
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isSetup === 'no') {
|
const messageHandler: FrontEndMessages = {
|
||||||
return <Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
name: 'default',
|
||||||
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
auth: async (data) => (await messageAndResponse(socket, { name: 'auth', data })).data,
|
||||||
<PowerSettingsNew />
|
version: async () => (await messageAndResponse(socket, { name: 'version', data: undefined })).data,
|
||||||
</Avatar>
|
checkToken: async () => (await messageAndResponse(socket, { name: 'checkToken', data: undefined })).data,
|
||||||
<Typography component="h1" variant="h5" color="text.primary">
|
search: async (data) => (await messageAndResponse(socket, { name: 'search', data })).data,
|
||||||
Confirm
|
handleDefault: async (data) => (await messageAndResponse(socket, { name: 'default', data })).data,
|
||||||
</Typography>
|
availableDubCodes: async () => (await messageAndResponse(socket, { name: 'availableDubCodes', data: undefined })).data,
|
||||||
<Box component="form" onSubmit={setup} sx={{ mt: 1 }}>
|
availableSubCodes: async () => (await messageAndResponse(socket, { name: 'availableSubCodes', data: undefined })).data,
|
||||||
<TextField name="port" margin='normal' type="number" fullWidth variant="filled" required label={'Port'} defaultValue={3000} />
|
resolveItems: async (data) => (await messageAndResponse(socket, { name: 'resolveItems', data })).data,
|
||||||
<TextField name="password" margin='normal' type="password" fullWidth variant="filled" label={'Password'} />
|
listEpisodes: async (data) => (await messageAndResponse(socket, { name: 'listEpisodes', data })).data,
|
||||||
<Button type='submit' variant='contained' sx={{ mt: 3, mb: 2 }} fullWidth>Confirm</Button>
|
randomEvents: randomEventHandler,
|
||||||
<Typography color="text.secondary" align='center' component="p" variant='body2'>
|
downloadItem: (data) => messageAndResponse(socket, { name: 'downloadItem', data }),
|
||||||
Please enter data that will be set to use this tool.
|
isDownloading: async () => (await messageAndResponse(socket, { name: 'isDownloading', data: undefined })).data,
|
||||||
<br />
|
openFolder: async (data) => messageAndResponse(socket, { name: 'openFolder', data }),
|
||||||
Leave blank to use no password (NOT RECOMMENDED)!
|
logout: async () => (await messageAndResponse(socket, { name: 'changeProvider', data: undefined })).data,
|
||||||
</Typography>
|
openFile: async (data) => await messageAndResponse(socket, { name: 'openFile', data }),
|
||||||
</Box>
|
openURL: async (data) => await messageAndResponse(socket, { name: 'openURL', data }),
|
||||||
</Box>;
|
getQueue: async () => (await messageAndResponse(socket, { name: 'getQueue', data: undefined })).data,
|
||||||
}
|
removeFromQueue: async (data) => await messageAndResponse(socket, { name: 'removeFromQueue', data }),
|
||||||
|
clearQueue: async () => await messageAndResponse(socket, { name: 'clearQueue', data: undefined }),
|
||||||
|
setDownloadQueue: async (data) => await messageAndResponse(socket, { name: 'setDownloadQueue', data }),
|
||||||
|
getDownloadQueue: async () => (await messageAndResponse(socket, { name: 'getDownloadQueue', data: undefined })).data
|
||||||
|
};
|
||||||
|
|
||||||
const messageHandler: FrontEndMessages = {
|
return <messageChannelContext.Provider value={messageHandler}>{children}</messageChannelContext.Provider>;
|
||||||
name: 'default',
|
|
||||||
auth: async (data) => (await messageAndResponse(socket, { name: 'auth', data })).data,
|
|
||||||
version: async () => (await messageAndResponse(socket, { name: 'version', data: undefined })).data,
|
|
||||||
checkToken: async () => (await messageAndResponse(socket, { name: 'checkToken', data: undefined })).data,
|
|
||||||
search: async (data) => (await messageAndResponse(socket, { name: 'search', data })).data,
|
|
||||||
handleDefault: async (data) => (await messageAndResponse(socket, { name: 'default', data })).data,
|
|
||||||
availableDubCodes: async () => (await messageAndResponse(socket, { name: 'availableDubCodes', data: undefined})).data,
|
|
||||||
availableSubCodes: async () => (await messageAndResponse(socket, { name: 'availableSubCodes', data: undefined })).data,
|
|
||||||
resolveItems: async (data) => (await messageAndResponse(socket, { name: 'resolveItems', data })).data,
|
|
||||||
listEpisodes: async (data) => (await messageAndResponse(socket, { name: 'listEpisodes', data })).data,
|
|
||||||
randomEvents: randomEventHandler,
|
|
||||||
downloadItem: (data) => messageAndResponse(socket, { name: 'downloadItem', data }),
|
|
||||||
isDownloading: async () => (await messageAndResponse(socket, { name: 'isDownloading', data: undefined })).data,
|
|
||||||
openFolder: async (data) => messageAndResponse(socket, { name: 'openFolder', data }),
|
|
||||||
logout: async () => (await messageAndResponse(socket, { name: 'changeProvider', data: undefined })).data,
|
|
||||||
openFile: async (data) => await messageAndResponse(socket, { name: 'openFile', data }),
|
|
||||||
openURL: async (data) => await messageAndResponse(socket, { name: 'openURL', data }),
|
|
||||||
getQueue: async () => (await messageAndResponse(socket, { name: 'getQueue', data: undefined })).data,
|
|
||||||
removeFromQueue: async (data) => await messageAndResponse(socket, { name: 'removeFromQueue', data }),
|
|
||||||
clearQueue: async () => await messageAndResponse(socket, { name: 'clearQueue', data: undefined }),
|
|
||||||
setDownloadQueue: async (data) => await messageAndResponse(socket, { name: 'setDownloadQueue', data }),
|
|
||||||
getDownloadQueue: async () => (await messageAndResponse(socket, { name: 'getDownloadQueue', data: undefined })).data,
|
|
||||||
};
|
|
||||||
|
|
||||||
return <messageChannelContext.Provider value={messageHandler}>
|
|
||||||
{children}
|
|
||||||
</messageChannelContext.Provider>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MessageChannelProvider;
|
export default MessageChannelProvider;
|
||||||
|
|
|
||||||
|
|
@ -6,30 +6,28 @@ import { RandomEvent } from '../../../../@types/randomEvents';
|
||||||
export const queueContext = React.createContext<QueueItem[]>([]);
|
export const queueContext = React.createContext<QueueItem[]>([]);
|
||||||
|
|
||||||
const QueueProvider: FCWithChildren = ({ children }) => {
|
const QueueProvider: FCWithChildren = ({ children }) => {
|
||||||
const msg = React.useContext(messageChannelContext);
|
const msg = React.useContext(messageChannelContext);
|
||||||
|
|
||||||
const [ready, setReady] = React.useState(false);
|
const [ready, setReady] = React.useState(false);
|
||||||
const [queue, setQueue] = React.useState<QueueItem[]>([]);
|
const [queue, setQueue] = React.useState<QueueItem[]>([]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (msg && !ready) {
|
if (msg && !ready) {
|
||||||
msg.getQueue().then(data => {
|
msg.getQueue().then((data) => {
|
||||||
setQueue(data);
|
setQueue(data);
|
||||||
setReady(true);
|
setReady(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const listener = (ev: RandomEvent<'queueChange'>) => {
|
const listener = (ev: RandomEvent<'queueChange'>) => {
|
||||||
setQueue(ev.data);
|
setQueue(ev.data);
|
||||||
};
|
};
|
||||||
msg?.randomEvents.on('queueChange', listener);
|
msg?.randomEvents.on('queueChange', listener);
|
||||||
return () => {
|
return () => {
|
||||||
msg?.randomEvents.removeListener('queueChange', listener);
|
msg?.randomEvents.removeListener('queueChange', listener);
|
||||||
};
|
};
|
||||||
}, [ msg ]);
|
}, [msg]);
|
||||||
|
|
||||||
return <queueContext.Provider value={queue}>
|
return <queueContext.Provider value={queue}>{children}</queueContext.Provider>;
|
||||||
{children}
|
|
||||||
</queueContext.Provider>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default QueueProvider;
|
export default QueueProvider;
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,60 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Divider, Box, Button, Typography, Avatar} from '@mui/material';
|
import { Divider, Box, Button, Typography, Avatar } from '@mui/material';
|
||||||
import useStore from '../hooks/useStore';
|
import useStore from '../hooks/useStore';
|
||||||
import { StoreState } from './Store';
|
import { StoreState } from './Store';
|
||||||
|
|
||||||
type Services = 'crunchy'|'hidive'|'ao'|'adn';
|
type Services = 'crunchy' | 'hidive' | 'ao' | 'adn';
|
||||||
|
|
||||||
export const serviceContext = React.createContext<Services|undefined>(undefined);
|
export const serviceContext = React.createContext<Services | undefined>(undefined);
|
||||||
|
|
||||||
const ServiceProvider: FCWithChildren = ({ children }) => {
|
const ServiceProvider: FCWithChildren = ({ children }) => {
|
||||||
const [ { service }, dispatch ] = useStore();
|
const [{ service }, dispatch] = useStore();
|
||||||
|
|
||||||
const setService = (s: StoreState['service']) => {
|
const setService = (s: StoreState['service']) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'service',
|
type: 'service',
|
||||||
payload: s
|
payload: s
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return service === undefined ?
|
return service === undefined ? (
|
||||||
<Box sx={{ justifyContent: 'center', alignItems: 'center', display: 'flex', flexDirection: 'column', position: 'relative', top: '40vh'}}>
|
<Box sx={{ justifyContent: 'center', alignItems: 'center', display: 'flex', flexDirection: 'column', position: 'relative', top: '40vh' }}>
|
||||||
<Typography color="text.primary" variant='h3' sx={{ textAlign: 'center', mb: 5 }}>Please select your service</Typography>
|
<Typography color="text.primary" variant="h3" sx={{ textAlign: 'center', mb: 5 }}>
|
||||||
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'center' }}>
|
Please select your service
|
||||||
<Button size='large' variant="contained" onClick={() => setService('crunchy')} startIcon={<Avatar src={'https://static.crunchyroll.com/cxweb/assets/img/favicons/favicon-32x32.png'} />}>Crunchyroll</Button>
|
</Typography>
|
||||||
<Button size='large' variant="contained" onClick={() => setService('hidive')} startIcon={<Avatar src={'https://static.diceplatform.com/prod/original/dce.hidive/settings/HIDIVE_AppLogo_1024x1024.0G0vK.jpg'} />}>Hidive</Button>
|
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'center' }}>
|
||||||
<Button size='large' variant="contained" onClick={() => setService('ao')} startIcon={<Avatar src={'https://www.animeonegai.com/assets/img/anime/general/ao3-favicon.png'} />}>AnimeOnegai</Button>
|
<Button
|
||||||
<Button size='large' variant="contained" onClick={() => setService('adn')} startIcon={<Avatar src={'https://animationdigitalnetwork.com/favicon.ico'} />}>AnimationDigitalNetwork</Button>
|
size="large"
|
||||||
</Box>
|
variant="contained"
|
||||||
</Box>
|
onClick={() => setService('crunchy')}
|
||||||
: <serviceContext.Provider value={service}>
|
startIcon={<Avatar src={'https://static.crunchyroll.com/cxweb/assets/img/favicons/favicon-32x32.png'} />}
|
||||||
{children}
|
>
|
||||||
</serviceContext.Provider>;
|
Crunchyroll
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => setService('hidive')}
|
||||||
|
startIcon={<Avatar src={'https://static.diceplatform.com/prod/original/dce.hidive/settings/HIDIVE_AppLogo_1024x1024.0G0vK.jpg'} />}
|
||||||
|
>
|
||||||
|
Hidive
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => setService('ao')}
|
||||||
|
startIcon={<Avatar src={'https://www.animeonegai.com/assets/img/anime/general/ao3-favicon.png'} />}
|
||||||
|
>
|
||||||
|
AnimeOnegai
|
||||||
|
</Button>
|
||||||
|
<Button size="large" variant="contained" onClick={() => setService('adn')} startIcon={<Avatar src={'https://animationdigitalnetwork.com/favicon.ico'} />}>
|
||||||
|
AnimationDigitalNetwork
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<serviceContext.Provider value={service}>{children}</serviceContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ServiceProvider;
|
export default ServiceProvider;
|
||||||
|
|
|
||||||
|
|
@ -3,64 +3,64 @@ import { Episode } from '../../../../@types/messageHandler';
|
||||||
import { dubLanguageCodes } from '../../../../modules/module.langsData';
|
import { dubLanguageCodes } from '../../../../modules/module.langsData';
|
||||||
|
|
||||||
export type DownloadOptions = {
|
export type DownloadOptions = {
|
||||||
q: number,
|
q: number;
|
||||||
id: string,
|
id: string;
|
||||||
e: string,
|
e: string;
|
||||||
dubLang: typeof dubLanguageCodes,
|
dubLang: typeof dubLanguageCodes;
|
||||||
dlsubs: string[],
|
dlsubs: string[];
|
||||||
fileName: string,
|
fileName: string;
|
||||||
dlVideoOnce: boolean,
|
dlVideoOnce: boolean;
|
||||||
all: boolean,
|
all: boolean;
|
||||||
but: boolean,
|
but: boolean;
|
||||||
novids: boolean,
|
novids: boolean;
|
||||||
hslang?: string,
|
hslang?: string;
|
||||||
simul: boolean,
|
simul: boolean;
|
||||||
noaudio: boolean
|
noaudio: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type StoreState = {
|
export type StoreState = {
|
||||||
episodeListing: Episode[];
|
episodeListing: Episode[];
|
||||||
downloadOptions: DownloadOptions,
|
downloadOptions: DownloadOptions;
|
||||||
service: 'crunchy'|'hidive'|'ao'|'adn'|undefined,
|
service: 'crunchy' | 'hidive' | 'ao' | 'adn' | undefined;
|
||||||
version: string,
|
version: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type StoreAction<T extends (keyof StoreState)> = {
|
export type StoreAction<T extends keyof StoreState> = {
|
||||||
type: T,
|
type: T;
|
||||||
payload: StoreState[T],
|
payload: StoreState[T];
|
||||||
extraInfo?: Record<string, unknown>
|
extraInfo?: Record<string, unknown>;
|
||||||
}
|
};
|
||||||
|
|
||||||
const Reducer = <T extends keyof StoreState,>(state: StoreState, action: StoreAction<T>): StoreState => {
|
const Reducer = <T extends keyof StoreState>(state: StoreState, action: StoreAction<T>): StoreState => {
|
||||||
switch(action.type) {
|
switch (action.type) {
|
||||||
default:
|
default:
|
||||||
return { ...state, [action.type]: action.payload };
|
return { ...state, [action.type]: action.payload };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: StoreState = {
|
const initialState: StoreState = {
|
||||||
downloadOptions: {
|
downloadOptions: {
|
||||||
id: '',
|
id: '',
|
||||||
q: 0,
|
q: 0,
|
||||||
e: '',
|
e: '',
|
||||||
dubLang: [ 'jpn' ],
|
dubLang: ['jpn'],
|
||||||
dlsubs: [ 'all' ],
|
dlsubs: ['all'],
|
||||||
fileName: '',
|
fileName: '',
|
||||||
dlVideoOnce: false,
|
dlVideoOnce: false,
|
||||||
all: false,
|
all: false,
|
||||||
but: false,
|
but: false,
|
||||||
noaudio: false,
|
noaudio: false,
|
||||||
novids: false,
|
novids: false,
|
||||||
simul: false
|
simul: false
|
||||||
},
|
},
|
||||||
service: undefined,
|
service: undefined,
|
||||||
episodeListing: [],
|
episodeListing: [],
|
||||||
version: '',
|
version: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
const Store: FCWithChildren = ({children}) => {
|
const Store: FCWithChildren = ({ children }) => {
|
||||||
const [state, dispatch] = React.useReducer(Reducer, initialState);
|
const [state, dispatch] = React.useReducer(Reducer, initialState);
|
||||||
/*React.useEffect(() => {
|
/*React.useEffect(() => {
|
||||||
if (!state.unsavedChanges.has)
|
if (!state.unsavedChanges.has)
|
||||||
return;
|
return;
|
||||||
const unsavedChanges = (ev: BeforeUnloadEvent, lang: LanguageContextType) => {
|
const unsavedChanges = (ev: BeforeUnloadEvent, lang: LanguageContextType) => {
|
||||||
|
|
@ -79,13 +79,9 @@ const Store: FCWithChildren = ({children}) => {
|
||||||
return () => window.removeEventListener('beforeunload', windowListener);
|
return () => window.removeEventListener('beforeunload', windowListener);
|
||||||
}, [state.unsavedChanges.has]);*/
|
}, [state.unsavedChanges.has]);*/
|
||||||
|
|
||||||
return (
|
return <StoreContext.Provider value={[state, dispatch]}>{children}</StoreContext.Provider>;
|
||||||
<StoreContext.Provider value={[state, dispatch]}>
|
|
||||||
{children}
|
|
||||||
</StoreContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Importent Notice -- The 'queue' generic will be overriden */
|
/* Importent Notice -- The 'queue' generic will be overriden */
|
||||||
export const StoreContext = React.createContext<[StoreState, React.Dispatch<StoreAction<'downloadOptions'>>]>([initialState, undefined as any]);
|
export const StoreContext = React.createContext<[StoreState, React.Dispatch<StoreAction<'downloadOptions'>>]>([initialState, undefined as any]);
|
||||||
export default Store;
|
export default Store;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|
@ -22,8 +18,5 @@
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"downlevelIteration": true
|
"downlevelIteration": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["./src", "./webpack.config.ts"]
|
||||||
"./src",
|
}
|
||||||
"./webpack.config.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,55 +4,58 @@ import path from 'path';
|
||||||
import type { Configuration as DevServerConfig } from 'webpack-dev-server';
|
import type { Configuration as DevServerConfig } from 'webpack-dev-server';
|
||||||
|
|
||||||
const config: Configuration & DevServerConfig = {
|
const config: Configuration & DevServerConfig = {
|
||||||
devServer: {
|
devServer: {
|
||||||
proxy: [
|
proxy: [
|
||||||
{
|
{
|
||||||
target: 'http://localhost:3000',
|
target: 'http://localhost:3000',
|
||||||
context: ['/public', '/private'],
|
context: ['/public', '/private'],
|
||||||
ws: true
|
ws: true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
entry: './src/index.tsx',
|
entry: './src/index.tsx',
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(process.cwd(), './build'),
|
path: path.resolve(process.cwd(), './build'),
|
||||||
filename: 'index.js',
|
filename: 'index.js'
|
||||||
},
|
},
|
||||||
target: 'web',
|
target: 'web',
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
|
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json']
|
||||||
},
|
},
|
||||||
performance: false,
|
performance: false,
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.(ts|tsx)$/,
|
test: /\.(ts|tsx)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
'loader': 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
options: {
|
||||||
presets: [
|
presets: [
|
||||||
'@babel/typescript',
|
'@babel/typescript',
|
||||||
'@babel/preset-react',
|
'@babel/preset-react',
|
||||||
['@babel/preset-env', {
|
[
|
||||||
targets: 'defaults'
|
'@babel/preset-env',
|
||||||
}]
|
{
|
||||||
]
|
targets: 'defaults'
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
},
|
]
|
||||||
{
|
}
|
||||||
test: /\.css$/i,
|
}
|
||||||
use: ['style-loader', 'css-loader'],
|
},
|
||||||
},
|
{
|
||||||
],
|
test: /\.css$/i,
|
||||||
},
|
use: ['style-loader', 'css-loader']
|
||||||
plugins: [
|
}
|
||||||
new HtmlWebpackPlugin({
|
]
|
||||||
template: path.join(process.cwd(), 'public', 'index.html')
|
},
|
||||||
})
|
plugins: [
|
||||||
]
|
new HtmlWebpackPlugin({
|
||||||
|
template: path.join(process.cwd(), 'public', 'index.html')
|
||||||
|
})
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ app.use(express.static(path.join(workingDir, 'gui', 'server', 'build'), { maxAge
|
||||||
console.info(`\n=== Multi Downloader NX GUI ${packageJson.version} ===\n`);
|
console.info(`\n=== Multi Downloader NX GUI ${packageJson.version} ===\n`);
|
||||||
|
|
||||||
const server = app.listen(cfg.gui.port, () => {
|
const server = app.listen(cfg.gui.port, () => {
|
||||||
console.info(`GUI server started on port ${cfg.gui.port}`);
|
console.info(`GUI server started on port ${cfg.gui.port}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
new PublicWebSocket(server);
|
new PublicWebSocket(server);
|
||||||
new ServiceHandler(server);
|
new ServiceHandler(server);
|
||||||
|
|
||||||
open(`http://localhost:${cfg.gui.port}`);
|
open(`http://localhost:${cfg.gui.port}`);
|
||||||
|
|
|
||||||
|
|
@ -11,124 +11,113 @@ import WebSocketHandler from './websocket';
|
||||||
import packageJson from '../../package.json';
|
import packageJson from '../../package.json';
|
||||||
|
|
||||||
export default class ServiceHandler {
|
export default class ServiceHandler {
|
||||||
|
private service: MessageHandler | undefined = undefined;
|
||||||
|
private ws: WebSocketHandler;
|
||||||
|
private state: GuiState;
|
||||||
|
|
||||||
private service: MessageHandler|undefined = undefined;
|
constructor(server: Server<typeof IncomingMessage, typeof ServerResponse>) {
|
||||||
private ws: WebSocketHandler;
|
this.ws = new WebSocketHandler(server);
|
||||||
private state: GuiState;
|
this.handleMessages();
|
||||||
|
this.state = getState();
|
||||||
|
}
|
||||||
|
|
||||||
constructor(server: Server<typeof IncomingMessage, typeof ServerResponse>) {
|
private handleMessages() {
|
||||||
this.ws = new WebSocketHandler(server);
|
this.ws.events.on('setupServer', ({ data }, respond) => {
|
||||||
this.handleMessages();
|
writeYamlCfgFile('gui', data);
|
||||||
this.state = getState();
|
this.state.setup = true;
|
||||||
}
|
setState(this.state);
|
||||||
|
respond(true);
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
private handleMessages() {
|
this.ws.events.on('setup', ({ data }) => {
|
||||||
this.ws.events.on('setupServer', ({ data }, respond) => {
|
if (data === 'crunchy') {
|
||||||
writeYamlCfgFile('gui', data);
|
this.service = new CrunchyHandler(this.ws);
|
||||||
this.state.setup = true;
|
} else if (data === 'hidive') {
|
||||||
setState(this.state);
|
this.service = new HidiveHandler(this.ws);
|
||||||
respond(true);
|
} else if (data === 'ao') {
|
||||||
process.exit(0);
|
this.service = new AnimeOnegaiHandler(this.ws);
|
||||||
});
|
} else if (data === 'adn') {
|
||||||
|
this.service = new ADNHandler(this.ws);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.ws.events.on('setup', ({ data }) => {
|
this.ws.events.on('changeProvider', async (_, respond) => {
|
||||||
if (data === 'crunchy') {
|
if (await this.service?.isDownloading()) return respond(false);
|
||||||
this.service = new CrunchyHandler(this.ws);
|
this.service = undefined;
|
||||||
} else if (data === 'hidive') {
|
respond(true);
|
||||||
this.service = new HidiveHandler(this.ws);
|
});
|
||||||
} else if (data === 'ao') {
|
|
||||||
this.service = new AnimeOnegaiHandler(this.ws);
|
|
||||||
} else if (data === 'adn') {
|
|
||||||
this.service = new ADNHandler(this.ws);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ws.events.on('changeProvider', async (_, respond) => {
|
|
||||||
if (await this.service?.isDownloading())
|
|
||||||
return respond(false);
|
|
||||||
this.service = undefined;
|
|
||||||
respond(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ws.events.on('auth', async ({ data }, respond) => {
|
this.ws.events.on('auth', async ({ data }, respond) => {
|
||||||
if (this.service === undefined)
|
if (this.service === undefined) return respond({ isOk: false, reason: new Error('No service selected') });
|
||||||
return respond({ isOk: false, reason: new Error('No service selected') });
|
respond(await this.service.auth(data));
|
||||||
respond(await this.service.auth(data));
|
});
|
||||||
});
|
this.ws.events.on('version', async (_, respond) => {
|
||||||
this.ws.events.on('version', async (_, respond) => {
|
respond(packageJson.version);
|
||||||
respond(packageJson.version);
|
});
|
||||||
});
|
this.ws.events.on('type', async (_, respond) => respond(this.service === undefined ? undefined : (this.service.name as 'hidive' | 'crunchy' | 'ao' | 'adn')));
|
||||||
this.ws.events.on('type', async (_, respond) => respond(this.service === undefined ? undefined : this.service.name as 'hidive'|'crunchy'|'ao'|'adn'));
|
this.ws.events.on('checkToken', async (_, respond) => {
|
||||||
this.ws.events.on('checkToken', async (_, respond) => {
|
if (this.service === undefined) return respond({ isOk: false, reason: new Error('No service selected') });
|
||||||
if (this.service === undefined)
|
respond(await this.service.checkToken());
|
||||||
return respond({ isOk: false, reason: new Error('No service selected') });
|
});
|
||||||
respond(await this.service.checkToken());
|
this.ws.events.on('search', async ({ data }, respond) => {
|
||||||
});
|
if (this.service === undefined) return respond({ isOk: false, reason: new Error('No service selected') });
|
||||||
this.ws.events.on('search', async ({ data }, respond) => {
|
respond(await this.service.search(data));
|
||||||
if (this.service === undefined)
|
});
|
||||||
return respond({ isOk: false, reason: new Error('No service selected') });
|
this.ws.events.on('default', async ({ data }, respond) => {
|
||||||
respond(await this.service.search(data));
|
if (this.service === undefined) return respond({ isOk: false, reason: new Error('No service selected') });
|
||||||
});
|
respond(await this.service.handleDefault(data));
|
||||||
this.ws.events.on('default', async ({ data }, respond) => {
|
});
|
||||||
if (this.service === undefined)
|
this.ws.events.on('availableDubCodes', async (_, respond) => {
|
||||||
return respond({ isOk: false, reason: new Error('No service selected') });
|
if (this.service === undefined) return respond([]);
|
||||||
respond(await this.service.handleDefault(data));
|
respond(await this.service.availableDubCodes());
|
||||||
});
|
});
|
||||||
this.ws.events.on('availableDubCodes', async (_, respond) => {
|
this.ws.events.on('availableSubCodes', async (_, respond) => {
|
||||||
if (this.service === undefined)
|
if (this.service === undefined) return respond([]);
|
||||||
return respond([]);
|
respond(await this.service.availableSubCodes());
|
||||||
respond(await this.service.availableDubCodes());
|
});
|
||||||
});
|
this.ws.events.on('resolveItems', async ({ data }, respond) => {
|
||||||
this.ws.events.on('availableSubCodes', async (_, respond) => {
|
if (this.service === undefined) return respond(false);
|
||||||
if (this.service === undefined)
|
respond(await this.service.resolveItems(data));
|
||||||
return respond([]);
|
});
|
||||||
respond(await this.service.availableSubCodes());
|
this.ws.events.on('listEpisodes', async ({ data }, respond) => {
|
||||||
});
|
if (this.service === undefined) return respond({ isOk: false, reason: new Error('No service selected') });
|
||||||
this.ws.events.on('resolveItems', async ({ data }, respond) => {
|
respond(await this.service.listEpisodes(data));
|
||||||
if (this.service === undefined)
|
});
|
||||||
return respond(false);
|
this.ws.events.on('downloadItem', async ({ data }, respond) => {
|
||||||
respond(await this.service.resolveItems(data));
|
this.service?.downloadItem(data);
|
||||||
});
|
respond(undefined);
|
||||||
this.ws.events.on('listEpisodes', async ({ data }, respond) => {
|
});
|
||||||
if (this.service === undefined)
|
this.ws.events.on('openFolder', async ({ data }, respond) => {
|
||||||
return respond({ isOk: false, reason: new Error('No service selected') });
|
this.service?.openFolder(data);
|
||||||
respond(await this.service.listEpisodes(data));
|
respond(undefined);
|
||||||
});
|
});
|
||||||
this.ws.events.on('downloadItem', async ({ data }, respond) => {
|
this.ws.events.on('openFile', async ({ data }, respond) => {
|
||||||
this.service?.downloadItem(data);
|
this.service?.openFile(data);
|
||||||
respond(undefined);
|
respond(undefined);
|
||||||
});
|
});
|
||||||
this.ws.events.on('openFolder', async ({ data }, respond) => {
|
this.ws.events.on('openURL', async ({ data }, respond) => {
|
||||||
this.service?.openFolder(data);
|
this.service?.openURL(data);
|
||||||
respond(undefined);
|
respond(undefined);
|
||||||
});
|
});
|
||||||
this.ws.events.on('openFile', async ({ data }, respond) => {
|
this.ws.events.on('getQueue', async (_, respond) => {
|
||||||
this.service?.openFile(data);
|
respond((await this.service?.getQueue()) ?? []);
|
||||||
respond(undefined);
|
});
|
||||||
});
|
this.ws.events.on('removeFromQueue', async ({ data }, respond) => {
|
||||||
this.ws.events.on('openURL', async ({ data }, respond) => {
|
this.service?.removeFromQueue(data);
|
||||||
this.service?.openURL(data);
|
respond(undefined);
|
||||||
respond(undefined);
|
});
|
||||||
});
|
this.ws.events.on('clearQueue', async (_, respond) => {
|
||||||
this.ws.events.on('getQueue', async (_, respond) => {
|
this.service?.clearQueue();
|
||||||
respond(await this.service?.getQueue() ?? []);
|
respond(undefined);
|
||||||
});
|
});
|
||||||
this.ws.events.on('removeFromQueue', async ({ data }, respond) => {
|
this.ws.events.on('setDownloadQueue', async ({ data }, respond) => {
|
||||||
this.service?.removeFromQueue(data);
|
this.service?.setDownloadQueue(data);
|
||||||
respond(undefined);
|
respond(undefined);
|
||||||
});
|
});
|
||||||
this.ws.events.on('clearQueue', async (_, respond) => {
|
this.ws.events.on('getDownloadQueue', async (_, respond) => {
|
||||||
this.service?.clearQueue();
|
respond((await this.service?.getDownloadQueue()) ?? false);
|
||||||
respond(undefined);
|
});
|
||||||
});
|
this.ws.events.on('isDownloading', async (_, respond) => respond((await this.service?.isDownloading()) ?? false));
|
||||||
this.ws.events.on('setDownloadQueue', async ({ data }, respond) => {
|
}
|
||||||
this.service?.setDownloadQueue(data);
|
}
|
||||||
respond(undefined);
|
|
||||||
});
|
|
||||||
this.ws.events.on('getDownloadQueue', async (_, respond) => {
|
|
||||||
respond(await this.service?.getDownloadQueue() ?? false);
|
|
||||||
});
|
|
||||||
this.ws.events.on('isDownloading', async (_, respond) => respond(await this.service?.isDownloading() ?? false));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,132 +8,144 @@ import { console } from '../../../modules/log';
|
||||||
import * as yargs from '../../../modules/module.app-args';
|
import * as yargs from '../../../modules/module.app-args';
|
||||||
|
|
||||||
class ADNHandler extends Base implements MessageHandler {
|
class ADNHandler extends Base implements MessageHandler {
|
||||||
private adn: AnimationDigitalNetwork;
|
private adn: AnimationDigitalNetwork;
|
||||||
public name = 'adn';
|
public name = 'adn';
|
||||||
constructor(ws: WebSocketHandler) {
|
constructor(ws: WebSocketHandler) {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.adn = new AnimationDigitalNetwork();
|
this.adn = new AnimationDigitalNetwork();
|
||||||
this.initState();
|
this.initState();
|
||||||
this.getDefaults();
|
this.getDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDefaults() {
|
public getDefaults() {
|
||||||
const _default = yargs.appArgv(this.adn.cfg.cli, true);
|
const _default = yargs.appArgv(this.adn.cfg.cli, true);
|
||||||
if (['fr', 'de'].includes(_default.locale))
|
if (['fr', 'de'].includes(_default.locale)) this.adn.locale = _default.locale;
|
||||||
this.adn.locale = _default.locale;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async auth(data: AuthData) {
|
public async auth(data: AuthData) {
|
||||||
return this.adn.doAuth(data);
|
return this.adn.doAuth(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkToken(): Promise<CheckTokenResponse> {
|
public async checkToken(): Promise<CheckTokenResponse> {
|
||||||
//TODO: implement proper method to check token
|
//TODO: implement proper method to check token
|
||||||
return { isOk: true, value: undefined };
|
return { isOk: true, value: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async search(data: SearchData): Promise<SearchResponse> {
|
public async search(data: SearchData): Promise<SearchResponse> {
|
||||||
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
||||||
const search = await this.adn.doSearch(data);
|
const search = await this.adn.doSearch(data);
|
||||||
if (!search.isOk) {
|
if (!search.isOk) {
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
return { isOk: true, value: search.value };
|
return { isOk: true, value: search.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleDefault(name: string) {
|
public async handleDefault(name: string) {
|
||||||
return getDefault(name, this.adn.cfg.cli);
|
return getDefault(name, this.adn.cfg.cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async availableDubCodes(): Promise<string[]> {
|
public async availableDubCodes(): Promise<string[]> {
|
||||||
const dubLanguageCodesArray: string[] = [];
|
const dubLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.adn_locale)
|
if (language.adn_locale) dubLanguageCodesArray.push(language.code);
|
||||||
dubLanguageCodesArray.push(language.code);
|
}
|
||||||
}
|
return [...new Set(dubLanguageCodesArray)];
|
||||||
return [...new Set(dubLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async availableSubCodes(): Promise<string[]> {
|
public async availableSubCodes(): Promise<string[]> {
|
||||||
const subLanguageCodesArray: string[] = [];
|
const subLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.adn_locale)
|
if (language.adn_locale) subLanguageCodesArray.push(language.locale);
|
||||||
subLanguageCodesArray.push(language.locale);
|
}
|
||||||
}
|
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
||||||
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
||||||
const parse = parseInt(data.id);
|
const parse = parseInt(data.id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return false;
|
||||||
return false;
|
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
||||||
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
const res = await this.adn.selectShow(parseInt(data.id), data.e, data.but, data.all);
|
||||||
const res = await this.adn.selectShow(parseInt(data.id), data.e, data.but, data.all);
|
if (!res.isOk || !res.value) return res.isOk;
|
||||||
if (!res.isOk || !res.value)
|
this.addToQueue(
|
||||||
return res.isOk;
|
res.value.map((a) => {
|
||||||
this.addToQueue(res.value.map(a => {
|
return {
|
||||||
return {
|
...data,
|
||||||
...data,
|
ids: [a.id],
|
||||||
ids: [a.id],
|
title: a.title,
|
||||||
title: a.title,
|
parent: {
|
||||||
parent: {
|
title: a.show.shortTitle,
|
||||||
title: a.show.shortTitle,
|
season: a.season
|
||||||
season: a.season
|
},
|
||||||
},
|
e: a.shortNumber,
|
||||||
e: a.shortNumber,
|
image: a.image,
|
||||||
image: a.image,
|
episode: a.shortNumber
|
||||||
episode: a.shortNumber
|
};
|
||||||
};
|
})
|
||||||
}));
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
||||||
const parse = parseInt(id);
|
const parse = parseInt(id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return { isOk: false, reason: new Error('The ID is invalid') };
|
||||||
return { isOk: false, reason: new Error('The ID is invalid') };
|
|
||||||
|
|
||||||
const request = await this.adn.listShow(parse);
|
const request = await this.adn.listShow(parse);
|
||||||
if (!request.isOk || !request.value)
|
if (!request.isOk || !request.value) return { isOk: false, reason: new Error('Unknown upstream error, check for additional logs') };
|
||||||
return {isOk: false, reason: new Error('Unknown upstream error, check for additional logs')};
|
|
||||||
|
|
||||||
return { isOk: true, value: request.value.videos.map(function(item) {
|
return {
|
||||||
return {
|
isOk: true,
|
||||||
e: item.shortNumber,
|
value: request.value.videos.map(function (item) {
|
||||||
lang: [],
|
return {
|
||||||
name: item.title,
|
e: item.shortNumber,
|
||||||
season: item.season,
|
lang: [],
|
||||||
seasonTitle: item.show.title,
|
name: item.title,
|
||||||
episode: item.shortNumber,
|
season: item.season,
|
||||||
id: item.id+'',
|
seasonTitle: item.show.title,
|
||||||
img: item.image,
|
episode: item.shortNumber,
|
||||||
description: item.summary,
|
id: item.id + '',
|
||||||
time: item.duration+''
|
img: item.image,
|
||||||
};
|
description: item.summary,
|
||||||
})};
|
time: item.duration + ''
|
||||||
}
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async downloadItem(data: DownloadData) {
|
public async downloadItem(data: DownloadData) {
|
||||||
this.setDownloading(true);
|
this.setDownloading(true);
|
||||||
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
||||||
const _default = yargs.appArgv(this.adn.cfg.cli, true);
|
const _default = yargs.appArgv(this.adn.cfg.cli, true);
|
||||||
const res = await this.adn.selectShow(parseInt(data.id), data.e, false, false);
|
const res = await this.adn.selectShow(parseInt(data.id), data.e, false, false);
|
||||||
if (res.isOk) {
|
if (res.isOk) {
|
||||||
for (const select of res.value) {
|
for (const select of res.value) {
|
||||||
if (!(await this.adn.getEpisode(select, {..._default, skipsubs: false, callbackMaker: this.makeProgressHandler.bind(this), q: data.q, fileName: data.fileName, dlsubs: data.dlsubs, dlVideoOnce: data.dlVideoOnce, force: 'y',
|
if (
|
||||||
novids: data.novids, noaudio: data.noaudio, hslang: data.hslang || 'none', dubLang: data.dubLang }))) {
|
!(await this.adn.getEpisode(select, {
|
||||||
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
..._default,
|
||||||
er.name = 'Download error';
|
skipsubs: false,
|
||||||
this.alertError(er);
|
callbackMaker: this.makeProgressHandler.bind(this),
|
||||||
}
|
q: data.q,
|
||||||
}
|
fileName: data.fileName,
|
||||||
} else {
|
dlsubs: data.dlsubs,
|
||||||
this.alertError(new Error('Failed to download episode, check for additional logs.'));
|
dlVideoOnce: data.dlVideoOnce,
|
||||||
}
|
force: 'y',
|
||||||
this.sendMessage({ name: 'finish', data: undefined });
|
novids: data.novids,
|
||||||
this.setDownloading(false);
|
noaudio: data.noaudio,
|
||||||
this.onFinish();
|
hslang: data.hslang || 'none',
|
||||||
}
|
dubLang: data.dubLang
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
||||||
|
er.name = 'Download error';
|
||||||
|
this.alertError(er);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.alertError(new Error('Failed to download episode, check for additional logs.'));
|
||||||
|
}
|
||||||
|
this.sendMessage({ name: 'finish', data: undefined });
|
||||||
|
this.setDownloading(false);
|
||||||
|
this.onFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ADNHandler;
|
export default ADNHandler;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,14 @@
|
||||||
import { AuthData, CheckTokenResponse, DownloadData, Episode, EpisodeListResponse, MessageHandler, ResolveItemsData, SearchData, SearchResponse } from '../../../@types/messageHandler';
|
import {
|
||||||
|
AuthData,
|
||||||
|
CheckTokenResponse,
|
||||||
|
DownloadData,
|
||||||
|
Episode,
|
||||||
|
EpisodeListResponse,
|
||||||
|
MessageHandler,
|
||||||
|
ResolveItemsData,
|
||||||
|
SearchData,
|
||||||
|
SearchResponse
|
||||||
|
} from '../../../@types/messageHandler';
|
||||||
import AnimeOnegai from '../../../ao';
|
import AnimeOnegai from '../../../ao';
|
||||||
import { getDefault } from '../../../modules/module.args';
|
import { getDefault } from '../../../modules/module.args';
|
||||||
import { languages } from '../../../modules/module.langsData';
|
import { languages } from '../../../modules/module.langsData';
|
||||||
|
|
@ -8,144 +18,153 @@ import { console } from '../../../modules/log';
|
||||||
import * as yargs from '../../../modules/module.app-args';
|
import * as yargs from '../../../modules/module.app-args';
|
||||||
|
|
||||||
class AnimeOnegaiHandler extends Base implements MessageHandler {
|
class AnimeOnegaiHandler extends Base implements MessageHandler {
|
||||||
private ao: AnimeOnegai;
|
private ao: AnimeOnegai;
|
||||||
public name = 'ao';
|
public name = 'ao';
|
||||||
constructor(ws: WebSocketHandler) {
|
constructor(ws: WebSocketHandler) {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.ao = new AnimeOnegai();
|
this.ao = new AnimeOnegai();
|
||||||
this.initState();
|
this.initState();
|
||||||
this.getDefaults();
|
this.getDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDefaults() {
|
public getDefaults() {
|
||||||
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
||||||
if (['es', 'pt'].includes(_default.locale))
|
if (['es', 'pt'].includes(_default.locale)) this.ao.locale = _default.locale;
|
||||||
this.ao.locale = _default.locale;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async auth(data: AuthData) {
|
public async auth(data: AuthData) {
|
||||||
return this.ao.doAuth(data);
|
return this.ao.doAuth(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkToken(): Promise<CheckTokenResponse> {
|
public async checkToken(): Promise<CheckTokenResponse> {
|
||||||
//TODO: implement proper method to check token
|
//TODO: implement proper method to check token
|
||||||
return { isOk: true, value: undefined };
|
return { isOk: true, value: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async search(data: SearchData): Promise<SearchResponse> {
|
public async search(data: SearchData): Promise<SearchResponse> {
|
||||||
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
||||||
const search = await this.ao.doSearch(data);
|
const search = await this.ao.doSearch(data);
|
||||||
if (!search.isOk) {
|
if (!search.isOk) {
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
return { isOk: true, value: search.value };
|
return { isOk: true, value: search.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleDefault(name: string) {
|
public async handleDefault(name: string) {
|
||||||
return getDefault(name, this.ao.cfg.cli);
|
return getDefault(name, this.ao.cfg.cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async availableDubCodes(): Promise<string[]> {
|
public async availableDubCodes(): Promise<string[]> {
|
||||||
const dubLanguageCodesArray: string[] = [];
|
const dubLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.ao_locale)
|
if (language.ao_locale) dubLanguageCodesArray.push(language.code);
|
||||||
dubLanguageCodesArray.push(language.code);
|
}
|
||||||
}
|
return [...new Set(dubLanguageCodesArray)];
|
||||||
return [...new Set(dubLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async availableSubCodes(): Promise<string[]> {
|
public async availableSubCodes(): Promise<string[]> {
|
||||||
const subLanguageCodesArray: string[] = [];
|
const subLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.ao_locale)
|
if (language.ao_locale) subLanguageCodesArray.push(language.locale);
|
||||||
subLanguageCodesArray.push(language.locale);
|
}
|
||||||
}
|
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
||||||
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
||||||
const parse = parseInt(data.id);
|
const parse = parseInt(data.id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return false;
|
||||||
return false;
|
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
||||||
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
||||||
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
const res = await this.ao.selectShow(parseInt(data.id), data.e, data.but, data.all, _default);
|
||||||
const res = await this.ao.selectShow(parseInt(data.id), data.e, data.but, data.all, _default);
|
if (!res.isOk || !res.value) return res.isOk;
|
||||||
if (!res.isOk || !res.value)
|
this.addToQueue(
|
||||||
return res.isOk;
|
res.value.map((a) => {
|
||||||
this.addToQueue(res.value.map(a => {
|
return {
|
||||||
return {
|
...data,
|
||||||
...data,
|
ids: a.data.map((a) => a.videoId),
|
||||||
ids: a.data.map(a => a.videoId),
|
title: a.episodeTitle,
|
||||||
title: a.episodeTitle,
|
parent: {
|
||||||
parent: {
|
title: a.seasonTitle,
|
||||||
title: a.seasonTitle,
|
season: a.seasonTitle
|
||||||
season: a.seasonTitle
|
},
|
||||||
},
|
e: a.episodeNumber + '',
|
||||||
e: a.episodeNumber+'',
|
image: a.image,
|
||||||
image: a.image,
|
episode: a.episodeNumber + ''
|
||||||
episode: a.episodeNumber+''
|
};
|
||||||
};
|
})
|
||||||
}));
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
||||||
const parse = parseInt(id);
|
const parse = parseInt(id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return { isOk: false, reason: new Error('The ID is invalid') };
|
||||||
return { isOk: false, reason: new Error('The ID is invalid') };
|
|
||||||
|
|
||||||
const request = await this.ao.listShow(parse);
|
const request = await this.ao.listShow(parse);
|
||||||
if (!request.isOk || !request.value)
|
if (!request.isOk || !request.value) return { isOk: false, reason: new Error('Unknown upstream error, check for additional logs') };
|
||||||
return {isOk: false, reason: new Error('Unknown upstream error, check for additional logs')};
|
|
||||||
|
|
||||||
const episodes: Episode[] = [];
|
const episodes: Episode[] = [];
|
||||||
const seasonNumberTitleParse = request.series.data.title.match(/\d+$/);
|
const seasonNumberTitleParse = request.series.data.title.match(/\d+$/);
|
||||||
const seasonNumber = seasonNumberTitleParse ? parseInt(seasonNumberTitleParse[0]) : 1;
|
const seasonNumber = seasonNumberTitleParse ? parseInt(seasonNumberTitleParse[0]) : 1;
|
||||||
//request.value
|
//request.value
|
||||||
for (const episodeKey in request.value) {
|
for (const episodeKey in request.value) {
|
||||||
const episode = request.value[episodeKey][0];
|
const episode = request.value[episodeKey][0];
|
||||||
const langs = Array.from(new Set(request.value[episodeKey].map(a=>a.lang)));
|
const langs = Array.from(new Set(request.value[episodeKey].map((a) => a.lang)));
|
||||||
episodes.push({
|
episodes.push({
|
||||||
e: episode.number+'',
|
e: episode.number + '',
|
||||||
lang: langs as string[],
|
lang: langs as string[],
|
||||||
name: episode.name,
|
name: episode.name,
|
||||||
season: seasonNumber+'',
|
season: seasonNumber + '',
|
||||||
seasonTitle: '',
|
seasonTitle: '',
|
||||||
episode: episode.number+'',
|
episode: episode.number + '',
|
||||||
id: episode.video_entry+'',
|
id: episode.video_entry + '',
|
||||||
img: episode.thumbnail,
|
img: episode.thumbnail,
|
||||||
description: episode.description,
|
description: episode.description,
|
||||||
time: ''
|
time: ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { isOk: true, value: episodes };
|
return { isOk: true, value: episodes };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async downloadItem(data: DownloadData) {
|
public async downloadItem(data: DownloadData) {
|
||||||
this.setDownloading(true);
|
this.setDownloading(true);
|
||||||
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
||||||
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
const _default = yargs.appArgv(this.ao.cfg.cli, true);
|
||||||
const res = await this.ao.selectShow(parseInt(data.id), data.e, false, false, {
|
const res = await this.ao.selectShow(parseInt(data.id), data.e, false, false, {
|
||||||
..._default,
|
..._default,
|
||||||
dubLang: data.dubLang,
|
dubLang: data.dubLang,
|
||||||
e: data.e
|
e: data.e
|
||||||
});
|
});
|
||||||
if (res.isOk) {
|
if (res.isOk) {
|
||||||
for (const select of res.value) {
|
for (const select of res.value) {
|
||||||
if (!(await this.ao.downloadEpisode(select, {..._default, skipsubs: false, callbackMaker: this.makeProgressHandler.bind(this), q: data.q, fileName: data.fileName, dlsubs: data.dlsubs, dlVideoOnce: data.dlVideoOnce, force: 'y',
|
if (
|
||||||
novids: data.novids, noaudio: data.noaudio, hslang: data.hslang || 'none', dubLang: data.dubLang }))) {
|
!(await this.ao.downloadEpisode(select, {
|
||||||
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
..._default,
|
||||||
er.name = 'Download error';
|
skipsubs: false,
|
||||||
this.alertError(er);
|
callbackMaker: this.makeProgressHandler.bind(this),
|
||||||
}
|
q: data.q,
|
||||||
}
|
fileName: data.fileName,
|
||||||
} else {
|
dlsubs: data.dlsubs,
|
||||||
this.alertError(new Error('Failed to download episode, check for additional logs.'));
|
dlVideoOnce: data.dlVideoOnce,
|
||||||
}
|
force: 'y',
|
||||||
this.sendMessage({ name: 'finish', data: undefined });
|
novids: data.novids,
|
||||||
this.setDownloading(false);
|
noaudio: data.noaudio,
|
||||||
this.onFinish();
|
hslang: data.hslang || 'none',
|
||||||
}
|
dubLang: data.dubLang
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
||||||
|
er.name = 'Download error';
|
||||||
|
this.alertError(er);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.alertError(new Error('Failed to download episode, check for additional logs.'));
|
||||||
|
}
|
||||||
|
this.sendMessage({ name: 'finish', data: undefined });
|
||||||
|
this.setDownloading(false);
|
||||||
|
this.onFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AnimeOnegaiHandler;
|
export default AnimeOnegaiHandler;
|
||||||
|
|
|
||||||
|
|
@ -9,140 +9,140 @@ import { getState, setState } from '../../../modules/module.cfg-loader';
|
||||||
import packageJson from '../../../package.json';
|
import packageJson from '../../../package.json';
|
||||||
|
|
||||||
export default class Base {
|
export default class Base {
|
||||||
private state: GuiState;
|
private state: GuiState;
|
||||||
public name = 'default';
|
public name = 'default';
|
||||||
constructor(private ws: WebSocketHandler) {
|
constructor(private ws: WebSocketHandler) {
|
||||||
this.state = getState();
|
this.state = getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private downloading = false;
|
private downloading = false;
|
||||||
|
|
||||||
private queue: QueueItem[] = [];
|
private queue: QueueItem[] = [];
|
||||||
private workOnQueue = false;
|
private workOnQueue = false;
|
||||||
|
|
||||||
version(): Promise<string> {
|
version(): Promise<string> {
|
||||||
return new Promise(() => {
|
return new Promise(() => {
|
||||||
return packageJson.version;
|
return packageJson.version;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initState() {
|
initState() {
|
||||||
if (this.state.services[this.name]) {
|
if (this.state.services[this.name]) {
|
||||||
this.queue = this.state.services[this.name].queue;
|
this.queue = this.state.services[this.name].queue;
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
} else {
|
} else {
|
||||||
this.state.services[this.name] = {
|
this.state.services[this.name] = {
|
||||||
'queue': []
|
queue: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setDownloading(downloading: boolean) {
|
setDownloading(downloading: boolean) {
|
||||||
this.downloading = downloading;
|
this.downloading = downloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDownloading() {
|
getDownloading() {
|
||||||
return this.downloading;
|
return this.downloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
alertError(error: Error) {
|
alertError(error: Error) {
|
||||||
console.error(`${error}`);
|
console.error(`${error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeProgressHandler(videoInfo: DownloadInfo) {
|
makeProgressHandler(videoInfo: DownloadInfo) {
|
||||||
return ((data: ProgressData) => {
|
return (data: ProgressData) => {
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
name: 'progress',
|
name: 'progress',
|
||||||
data: {
|
data: {
|
||||||
downloadInfo: videoInfo,
|
downloadInfo: videoInfo,
|
||||||
progress: data
|
progress: data
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage<T extends keyof RandomEvents>(data: RandomEvent<T>) {
|
sendMessage<T extends keyof RandomEvents>(data: RandomEvent<T>) {
|
||||||
this.ws.sendMessage(data);
|
this.ws.sendMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isDownloading() {
|
async isDownloading() {
|
||||||
return this.downloading;
|
return this.downloading;
|
||||||
}
|
}
|
||||||
|
|
||||||
async openFolder(folderType: FolderTypes) {
|
async openFolder(folderType: FolderTypes) {
|
||||||
switch (folderType) {
|
switch (folderType) {
|
||||||
case 'content':
|
case 'content':
|
||||||
open(cfg.dir.content);
|
open(cfg.dir.content);
|
||||||
break;
|
break;
|
||||||
case 'config':
|
case 'config':
|
||||||
open(cfg.dir.config);
|
open(cfg.dir.config);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openFile(data: [FolderTypes, string]) {
|
async openFile(data: [FolderTypes, string]) {
|
||||||
switch (data[0]) {
|
switch (data[0]) {
|
||||||
case 'config':
|
case 'config':
|
||||||
open(path.join(cfg.dir.config, data[1]));
|
open(path.join(cfg.dir.config, data[1]));
|
||||||
break;
|
break;
|
||||||
case 'content':
|
case 'content':
|
||||||
throw new Error('No subfolders');
|
throw new Error('No subfolders');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openURL(data: string) {
|
async openURL(data: string) {
|
||||||
open(data);
|
open(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getQueue(): Promise<QueueItem[]> {
|
public async getQueue(): Promise<QueueItem[]> {
|
||||||
return this.queue;
|
return this.queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async removeFromQueue(index: number) {
|
public async removeFromQueue(index: number) {
|
||||||
this.queue.splice(index, 1);
|
this.queue.splice(index, 1);
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async clearQueue() {
|
public async clearQueue() {
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public addToQueue(data: QueueItem[]) {
|
public addToQueue(data: QueueItem[]) {
|
||||||
this.queue = this.queue.concat(...data);
|
this.queue = this.queue.concat(...data);
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setDownloadQueue(data: boolean) {
|
public setDownloadQueue(data: boolean) {
|
||||||
this.workOnQueue = data;
|
this.workOnQueue = data;
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDownloadQueue(): Promise<boolean> {
|
public async getDownloadQueue(): Promise<boolean> {
|
||||||
return this.workOnQueue;
|
return this.workOnQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async queueChange() {
|
private async queueChange() {
|
||||||
this.sendMessage({ name: 'queueChange', data: this.queue });
|
this.sendMessage({ name: 'queueChange', data: this.queue });
|
||||||
if (this.workOnQueue && this.queue.length > 0 && !await this.isDownloading()) {
|
if (this.workOnQueue && this.queue.length > 0 && !(await this.isDownloading())) {
|
||||||
this.setDownloading(true);
|
this.setDownloading(true);
|
||||||
this.sendMessage({ name: 'current', data: this.queue[0] });
|
this.sendMessage({ name: 'current', data: this.queue[0] });
|
||||||
this.downloadItem(this.queue[0]);
|
this.downloadItem(this.queue[0]);
|
||||||
this.queue = this.queue.slice(1);
|
this.queue = this.queue.slice(1);
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
this.state.services[this.name].queue = this.queue;
|
this.state.services[this.name].queue = this.queue;
|
||||||
setState(this.state);
|
setState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onFinish() {
|
public async onFinish() {
|
||||||
this.sendMessage({ name: 'current', data: undefined });
|
this.sendMessage({ name: 'current', data: undefined });
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Overriten
|
//Overriten
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
public async downloadItem(_: QueueItem) {
|
public async downloadItem(_: QueueItem) {
|
||||||
throw new Error('downloadItem not overriden');
|
throw new Error('downloadItem not overriden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,120 +8,133 @@ import { console } from '../../../modules/log';
|
||||||
import * as yargs from '../../../modules/module.app-args';
|
import * as yargs from '../../../modules/module.app-args';
|
||||||
|
|
||||||
class CrunchyHandler extends Base implements MessageHandler {
|
class CrunchyHandler extends Base implements MessageHandler {
|
||||||
private crunchy: Crunchy;
|
private crunchy: Crunchy;
|
||||||
public name = 'crunchy';
|
public name = 'crunchy';
|
||||||
constructor(ws: WebSocketHandler) {
|
constructor(ws: WebSocketHandler) {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.crunchy = new Crunchy();
|
this.crunchy = new Crunchy();
|
||||||
this.crunchy.refreshToken();
|
this.crunchy.refreshToken();
|
||||||
this.initState();
|
this.initState();
|
||||||
this.getDefaults();
|
this.getDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDefaults() {
|
public getDefaults() {
|
||||||
const _default = yargs.appArgv(this.crunchy.cfg.cli, true);
|
const _default = yargs.appArgv(this.crunchy.cfg.cli, true);
|
||||||
this.crunchy.locale = _default.locale;
|
this.crunchy.locale = _default.locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes (id: string): Promise<EpisodeListResponse> {
|
|
||||||
this.getDefaults();
|
|
||||||
await this.crunchy.refreshToken(true);
|
|
||||||
return { isOk: true, value: (await this.crunchy.listSeriesID(id)).list };
|
|
||||||
}
|
|
||||||
|
|
||||||
public async handleDefault(name: string) {
|
|
||||||
return getDefault(name, this.crunchy.cfg.cli);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async availableDubCodes(): Promise<string[]> {
|
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
||||||
const dubLanguageCodesArray: string[] = [];
|
this.getDefaults();
|
||||||
for(const language of languages){
|
await this.crunchy.refreshToken(true);
|
||||||
if (language.cr_locale)
|
return { isOk: true, value: (await this.crunchy.listSeriesID(id)).list };
|
||||||
dubLanguageCodesArray.push(language.code);
|
}
|
||||||
}
|
|
||||||
return [...new Set(dubLanguageCodesArray)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async availableSubCodes(): Promise<string[]> {
|
public async handleDefault(name: string) {
|
||||||
return subtitleLanguagesFilter;
|
return getDefault(name, this.crunchy.cfg.cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
public async availableDubCodes(): Promise<string[]> {
|
||||||
this.getDefaults();
|
const dubLanguageCodesArray: string[] = [];
|
||||||
await this.crunchy.refreshToken(true);
|
for (const language of languages) {
|
||||||
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
if (language.cr_locale) dubLanguageCodesArray.push(language.code);
|
||||||
const res = await this.crunchy.downloadFromSeriesID(data.id, data);
|
}
|
||||||
if (!res.isOk)
|
return [...new Set(dubLanguageCodesArray)];
|
||||||
return res.isOk;
|
}
|
||||||
this.addToQueue(res.value.map(a => {
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
|
|
||||||
ids: a.data.map(a => a.mediaId),
|
|
||||||
title: a.episodeTitle,
|
|
||||||
parent: {
|
|
||||||
title: a.seasonTitle,
|
|
||||||
season: a.season.toString()
|
|
||||||
},
|
|
||||||
e: a.e,
|
|
||||||
image: a.image,
|
|
||||||
episode: a.episodeNumber
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async search(data: SearchData): Promise<SearchResponse> {
|
public async availableSubCodes(): Promise<string[]> {
|
||||||
this.getDefaults();
|
return subtitleLanguagesFilter;
|
||||||
await this.crunchy.refreshToken(true);
|
}
|
||||||
if (!data['search-type']) data['search-type'] = 'series';
|
|
||||||
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
|
||||||
const crunchySearch = await this.crunchy.doSearch(data);
|
|
||||||
if (!crunchySearch.isOk) {
|
|
||||||
this.crunchy.refreshToken();
|
|
||||||
return crunchySearch;
|
|
||||||
}
|
|
||||||
return { isOk: true, value: crunchySearch.value };
|
|
||||||
}
|
|
||||||
|
|
||||||
public async checkToken(): Promise<CheckTokenResponse> {
|
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
||||||
if (await this.crunchy.getProfile()) {
|
this.getDefaults();
|
||||||
return { isOk: true, value: undefined };
|
await this.crunchy.refreshToken(true);
|
||||||
} else {
|
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
||||||
return { isOk: false, reason: new Error('') };
|
const res = await this.crunchy.downloadFromSeriesID(data.id, data);
|
||||||
}
|
if (!res.isOk) return res.isOk;
|
||||||
}
|
this.addToQueue(
|
||||||
|
res.value.map((a) => {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
|
||||||
public auth(data: AuthData) {
|
ids: a.data.map((a) => a.mediaId),
|
||||||
return this.crunchy.doAuth(data);
|
title: a.episodeTitle,
|
||||||
}
|
parent: {
|
||||||
|
title: a.seasonTitle,
|
||||||
|
season: a.season.toString()
|
||||||
|
},
|
||||||
|
e: a.e,
|
||||||
|
image: a.image,
|
||||||
|
episode: a.episodeNumber
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public async downloadItem(data: DownloadData) {
|
public async search(data: SearchData): Promise<SearchResponse> {
|
||||||
this.getDefaults();
|
this.getDefaults();
|
||||||
await this.crunchy.refreshToken(true);
|
await this.crunchy.refreshToken(true);
|
||||||
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
if (!data['search-type']) data['search-type'] = 'series';
|
||||||
this.setDownloading(true);
|
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
||||||
const _default = yargs.appArgv(this.crunchy.cfg.cli, true);
|
const crunchySearch = await this.crunchy.doSearch(data);
|
||||||
const res = await this.crunchy.downloadFromSeriesID(data.id, {
|
if (!crunchySearch.isOk) {
|
||||||
dubLang: data.dubLang,
|
this.crunchy.refreshToken();
|
||||||
e: data.e
|
return crunchySearch;
|
||||||
});
|
}
|
||||||
if (res.isOk) {
|
return { isOk: true, value: crunchySearch.value };
|
||||||
for (const select of res.value) {
|
}
|
||||||
if (!(await this.crunchy.downloadEpisode(select, {..._default, skipsubs: false, callbackMaker: this.makeProgressHandler.bind(this), q: data.q, fileName: data.fileName, dlsubs: data.dlsubs, dlVideoOnce: data.dlVideoOnce, force: 'y',
|
|
||||||
novids: data.novids, noaudio: data.noaudio, hslang: data.hslang || 'none' }))) {
|
public async checkToken(): Promise<CheckTokenResponse> {
|
||||||
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
if (await this.crunchy.getProfile()) {
|
||||||
er.name = 'Download error';
|
return { isOk: true, value: undefined };
|
||||||
this.alertError(er);
|
} else {
|
||||||
}
|
return { isOk: false, reason: new Error('') };
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
this.alertError(res.reason);
|
|
||||||
}
|
public auth(data: AuthData) {
|
||||||
this.sendMessage({ name: 'finish', data: undefined });
|
return this.crunchy.doAuth(data);
|
||||||
this.setDownloading(false);
|
}
|
||||||
this.onFinish();
|
|
||||||
}
|
public async downloadItem(data: DownloadData) {
|
||||||
|
this.getDefaults();
|
||||||
|
await this.crunchy.refreshToken(true);
|
||||||
|
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
||||||
|
this.setDownloading(true);
|
||||||
|
const _default = yargs.appArgv(this.crunchy.cfg.cli, true);
|
||||||
|
const res = await this.crunchy.downloadFromSeriesID(data.id, {
|
||||||
|
dubLang: data.dubLang,
|
||||||
|
e: data.e
|
||||||
|
});
|
||||||
|
if (res.isOk) {
|
||||||
|
for (const select of res.value) {
|
||||||
|
if (
|
||||||
|
!(await this.crunchy.downloadEpisode(select, {
|
||||||
|
..._default,
|
||||||
|
skipsubs: false,
|
||||||
|
callbackMaker: this.makeProgressHandler.bind(this),
|
||||||
|
q: data.q,
|
||||||
|
fileName: data.fileName,
|
||||||
|
dlsubs: data.dlsubs,
|
||||||
|
dlVideoOnce: data.dlVideoOnce,
|
||||||
|
force: 'y',
|
||||||
|
novids: data.novids,
|
||||||
|
noaudio: data.noaudio,
|
||||||
|
hslang: data.hslang || 'none'
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
const er = new Error(`Unable to download episode ${data.e} from ${data.id}`);
|
||||||
|
er.name = 'Download error';
|
||||||
|
this.alertError(er);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.alertError(res.reason);
|
||||||
|
}
|
||||||
|
this.sendMessage({ name: 'finish', data: undefined });
|
||||||
|
this.setDownloading(false);
|
||||||
|
this.onFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CrunchyHandler;
|
export default CrunchyHandler;
|
||||||
|
|
|
||||||
|
|
@ -8,120 +8,128 @@ import { console } from '../../../modules/log';
|
||||||
import * as yargs from '../../../modules/module.app-args';
|
import * as yargs from '../../../modules/module.app-args';
|
||||||
|
|
||||||
class HidiveHandler extends Base implements MessageHandler {
|
class HidiveHandler extends Base implements MessageHandler {
|
||||||
private hidive: Hidive;
|
private hidive: Hidive;
|
||||||
public name = 'hidive';
|
public name = 'hidive';
|
||||||
constructor(ws: WebSocketHandler) {
|
constructor(ws: WebSocketHandler) {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.hidive = new Hidive();
|
this.hidive = new Hidive();
|
||||||
this.initState();
|
this.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async auth(data: AuthData) {
|
public async auth(data: AuthData) {
|
||||||
return this.hidive.doAuth(data);
|
return this.hidive.doAuth(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkToken(): Promise<CheckTokenResponse> {
|
public async checkToken(): Promise<CheckTokenResponse> {
|
||||||
//TODO: implement proper method to check token
|
//TODO: implement proper method to check token
|
||||||
return { isOk: true, value: undefined };
|
return { isOk: true, value: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async search(data: SearchData): Promise<SearchResponse> {
|
public async search(data: SearchData): Promise<SearchResponse> {
|
||||||
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
console.debug(`Got search options: ${JSON.stringify(data)}`);
|
||||||
const hidiveSearch = await this.hidive.doSearch(data);
|
const hidiveSearch = await this.hidive.doSearch(data);
|
||||||
if (!hidiveSearch.isOk) {
|
if (!hidiveSearch.isOk) {
|
||||||
return hidiveSearch;
|
return hidiveSearch;
|
||||||
}
|
}
|
||||||
return { isOk: true, value: hidiveSearch.value };
|
return { isOk: true, value: hidiveSearch.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleDefault(name: string) {
|
public async handleDefault(name: string) {
|
||||||
return getDefault(name, this.hidive.cfg.cli);
|
return getDefault(name, this.hidive.cfg.cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async availableDubCodes(): Promise<string[]> {
|
public async availableDubCodes(): Promise<string[]> {
|
||||||
const dubLanguageCodesArray: string[] = [];
|
const dubLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.new_hd_locale)
|
if (language.new_hd_locale) dubLanguageCodesArray.push(language.code);
|
||||||
dubLanguageCodesArray.push(language.code);
|
}
|
||||||
}
|
return [...new Set(dubLanguageCodesArray)];
|
||||||
return [...new Set(dubLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async availableSubCodes(): Promise<string[]> {
|
public async availableSubCodes(): Promise<string[]> {
|
||||||
const subLanguageCodesArray: string[] = [];
|
const subLanguageCodesArray: string[] = [];
|
||||||
for(const language of languages){
|
for (const language of languages) {
|
||||||
if (language.new_hd_locale)
|
if (language.new_hd_locale) subLanguageCodesArray.push(language.locale);
|
||||||
subLanguageCodesArray.push(language.locale);
|
}
|
||||||
}
|
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
||||||
return ['all', 'none', ...new Set(subLanguageCodesArray)];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
public async resolveItems(data: ResolveItemsData): Promise<boolean> {
|
||||||
const parse = parseInt(data.id);
|
const parse = parseInt(data.id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return false;
|
||||||
return false;
|
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
||||||
console.debug(`Got resolve options: ${JSON.stringify(data)}`);
|
const res = await this.hidive.selectSeries(parseInt(data.id), data.e, data.but, data.all);
|
||||||
const res = await this.hidive.selectSeries(parseInt(data.id), data.e, data.but, data.all);
|
if (!res.isOk || !res.value) return res.isOk;
|
||||||
if (!res.isOk || !res.value)
|
this.addToQueue(
|
||||||
return res.isOk;
|
res.value.map((item) => {
|
||||||
this.addToQueue(res.value.map(item => {
|
return {
|
||||||
return {
|
...data,
|
||||||
...data,
|
ids: [item.id],
|
||||||
ids: [item.id],
|
title: item.title,
|
||||||
title: item.title,
|
parent: {
|
||||||
parent: {
|
title: item.seriesTitle,
|
||||||
title: item.seriesTitle,
|
season: item.episodeInformation.seasonNumber + ''
|
||||||
season: item.episodeInformation.seasonNumber+''
|
},
|
||||||
},
|
image: item.thumbnailUrl,
|
||||||
image: item.thumbnailUrl,
|
e: item.episodeInformation.episodeNumber + '',
|
||||||
e: item.episodeInformation.episodeNumber+'',
|
episode: item.episodeInformation.episodeNumber + ''
|
||||||
episode: item.episodeInformation.episodeNumber+'',
|
};
|
||||||
};
|
})
|
||||||
}));
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
public async listEpisodes(id: string): Promise<EpisodeListResponse> {
|
||||||
const parse = parseInt(id);
|
const parse = parseInt(id);
|
||||||
if (isNaN(parse) || parse <= 0)
|
if (isNaN(parse) || parse <= 0) return { isOk: false, reason: new Error('The ID is invalid') };
|
||||||
return { isOk: false, reason: new Error('The ID is invalid') };
|
|
||||||
|
|
||||||
const request = await this.hidive.listSeries(parse);
|
const request = await this.hidive.listSeries(parse);
|
||||||
if (!request.isOk || !request.value)
|
if (!request.isOk || !request.value) return { isOk: false, reason: new Error('Unknown upstream error, check for additional logs') };
|
||||||
return {isOk: false, reason: new Error('Unknown upstream error, check for additional logs')};
|
|
||||||
|
|
||||||
return { isOk: true, value: request.value.map(function(item) {
|
return {
|
||||||
const description = item.description.split('\r\n');
|
isOk: true,
|
||||||
return {
|
value: request.value.map(function (item) {
|
||||||
e: item.episodeInformation.episodeNumber+'',
|
const description = item.description.split('\r\n');
|
||||||
lang: [],
|
return {
|
||||||
name: item.title,
|
e: item.episodeInformation.episodeNumber + '',
|
||||||
season: item.episodeInformation.seasonNumber+'',
|
lang: [],
|
||||||
seasonTitle: request.series.seasons[item.episodeInformation.seasonNumber-1]?.title ?? request.series.title,
|
name: item.title,
|
||||||
episode: item.episodeInformation.episodeNumber+'',
|
season: item.episodeInformation.seasonNumber + '',
|
||||||
id: item.id+'',
|
seasonTitle: request.series.seasons[item.episodeInformation.seasonNumber - 1]?.title ?? request.series.title,
|
||||||
img: item.thumbnailUrl,
|
episode: item.episodeInformation.episodeNumber + '',
|
||||||
description: description ? description[0] : '',
|
id: item.id + '',
|
||||||
time: ''
|
img: item.thumbnailUrl,
|
||||||
};
|
description: description ? description[0] : '',
|
||||||
})};
|
time: ''
|
||||||
}
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async downloadItem(data: DownloadData) {
|
public async downloadItem(data: DownloadData) {
|
||||||
this.setDownloading(true);
|
this.setDownloading(true);
|
||||||
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
console.debug(`Got download options: ${JSON.stringify(data)}`);
|
||||||
const _default = yargs.appArgv(this.hidive.cfg.cli, true);
|
const _default = yargs.appArgv(this.hidive.cfg.cli, true);
|
||||||
const res = await this.hidive.selectSeries(parseInt(data.id), data.e, false, false);
|
const res = await this.hidive.selectSeries(parseInt(data.id), data.e, false, false);
|
||||||
if (!res.isOk || !res.showData)
|
if (!res.isOk || !res.showData) return this.alertError(new Error('Download failed upstream, check for additional logs'));
|
||||||
return this.alertError(new Error('Download failed upstream, check for additional logs'));
|
|
||||||
|
|
||||||
for (const ep of res.value) {
|
for (const ep of res.value) {
|
||||||
await this.hidive.downloadEpisode(ep, {..._default, callbackMaker: this.makeProgressHandler.bind(this), dubLang: data.dubLang, dlsubs: data.dlsubs, fileName: data.fileName, q: data.q, force: 'y', noaudio: data.noaudio, novids: data.novids });
|
await this.hidive.downloadEpisode(ep, {
|
||||||
}
|
..._default,
|
||||||
this.sendMessage({ name: 'finish', data: undefined });
|
callbackMaker: this.makeProgressHandler.bind(this),
|
||||||
this.setDownloading(false);
|
dubLang: data.dubLang,
|
||||||
this.onFinish();
|
dlsubs: data.dlsubs,
|
||||||
}
|
fileName: data.fileName,
|
||||||
|
q: data.q,
|
||||||
|
force: 'y',
|
||||||
|
noaudio: data.noaudio,
|
||||||
|
novids: data.novids
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.sendMessage({ name: 'finish', data: undefined });
|
||||||
|
this.setDownloading(false);
|
||||||
|
this.onFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HidiveHandler;
|
export default HidiveHandler;
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue