Implement queudtorrents, selecting files, hash rather than id
This commit is contained in:
parent
772631d47f
commit
fc9ea4c29a
3 changed files with 360 additions and 179 deletions
338
client/package-lock.json
generated
338
client/package-lock.json
generated
|
|
@ -35,7 +35,7 @@
|
|||
"@angular-eslint/eslint-plugin-template": "16.1.1",
|
||||
"@angular-eslint/schematics": "16.1.1",
|
||||
"@angular-eslint/template-parser": "16.1.1",
|
||||
"@angular/cli": "^16.2.1",
|
||||
"@angular/cli": "^16.2.14",
|
||||
"@angular/compiler-cli": "^16.2.3",
|
||||
"@angular/language-service": "^16.2.3",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
|
|
@ -352,12 +352,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.1.tgz",
|
||||
"integrity": "sha512-rXXO5zSI/iN6JtU3oU+vKfOB1N8n1iCH9aLudtJfO5zT9r29FIvV4YMmHO0iu78i4IhQAeJdr42cvrGPp8Y41A==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.14.tgz",
|
||||
"integrity": "sha512-B6LQKInCT8w5zx5Pbroext5eFFRTCJdTwHN8GhcVS8IeKCnkeqVTQLjB4lBUg7LEm8Y7UHXwzrVxmk+f+MBXhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"magic-string": "0.30.1",
|
||||
"ora": "5.4.1",
|
||||
|
|
@ -369,6 +369,55 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.10.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^3.5.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@angular-eslint/builder": {
|
||||
"version": "16.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-16.1.1.tgz",
|
||||
|
|
@ -544,15 +593,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@angular/cli": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.1.tgz",
|
||||
"integrity": "sha512-nuCc0VOGjuUFQo1Pu9CyFQ4VTy7OuwTiwxOG9qbut4FSGz2CO9NeqoamPUuy6rpKVu5JxVe+L6Y4OFaNKv2n3Q==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.14.tgz",
|
||||
"integrity": "sha512-0y71jtitigVolm4Rim1b8xPQ+B22cGp4Spef2Wunpqj67UowN6tsZaVuWBEQh4u5xauX8LAHKqsvy37ZPWCc4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/architect": "0.1602.1",
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/schematics": "16.2.1",
|
||||
"@schematics/angular": "16.2.1",
|
||||
"@angular-devkit/architect": "0.1602.14",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"@angular-devkit/schematics": "16.2.14",
|
||||
"@schematics/angular": "16.2.14",
|
||||
"@yarnpkg/lockfile": "1.1.0",
|
||||
"ansi-colors": "4.1.3",
|
||||
"ini": "4.1.1",
|
||||
|
|
@ -577,6 +626,70 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/@angular-devkit/architect": {
|
||||
"version": "0.1602.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz",
|
||||
"integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"rxjs": "7.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.10.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.10.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^3.5.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
|
|
@ -3665,13 +3778,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@schematics/angular": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.1.tgz",
|
||||
"integrity": "sha512-e3ckgvSv+OA+4xUBpOqVOvNM8FqY/yXaWqs/Ob0uQ/zPL1iVa/MCAoB25KqYQPnq21hEwE4zqIIQFKasKBIqMA==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.14.tgz",
|
||||
"integrity": "sha512-YqIv727l9Qze8/OL6H9mBHc2jVXzAGRNBYnxYWqWhLbfvuVbbldo6NNIIjgv6lrl2LJSdPAAMNOD5m/f6210ug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/schematics": "16.2.1",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"@angular-devkit/schematics": "16.2.14",
|
||||
"jsonc-parser": "3.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -3680,6 +3793,55 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.10.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^3.5.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sigstore/bundle": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz",
|
||||
|
|
@ -14563,16 +14725,50 @@
|
|||
}
|
||||
},
|
||||
"@angular-devkit/schematics": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.1.tgz",
|
||||
"integrity": "sha512-rXXO5zSI/iN6JtU3oU+vKfOB1N8n1iCH9aLudtJfO5zT9r29FIvV4YMmHO0iu78i4IhQAeJdr42cvrGPp8Y41A==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.14.tgz",
|
||||
"integrity": "sha512-B6LQKInCT8w5zx5Pbroext5eFFRTCJdTwHN8GhcVS8IeKCnkeqVTQLjB4lBUg7LEm8Y7UHXwzrVxmk+f+MBXhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"magic-string": "0.30.1",
|
||||
"ora": "5.4.1",
|
||||
"rxjs": "7.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@angular-eslint/builder": {
|
||||
|
|
@ -14708,15 +14904,15 @@
|
|||
}
|
||||
},
|
||||
"@angular/cli": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.1.tgz",
|
||||
"integrity": "sha512-nuCc0VOGjuUFQo1Pu9CyFQ4VTy7OuwTiwxOG9qbut4FSGz2CO9NeqoamPUuy6rpKVu5JxVe+L6Y4OFaNKv2n3Q==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.14.tgz",
|
||||
"integrity": "sha512-0y71jtitigVolm4Rim1b8xPQ+B22cGp4Spef2Wunpqj67UowN6tsZaVuWBEQh4u5xauX8LAHKqsvy37ZPWCc4A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/architect": "0.1602.1",
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/schematics": "16.2.1",
|
||||
"@schematics/angular": "16.2.1",
|
||||
"@angular-devkit/architect": "0.1602.14",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"@angular-devkit/schematics": "16.2.14",
|
||||
"@schematics/angular": "16.2.14",
|
||||
"@yarnpkg/lockfile": "1.1.0",
|
||||
"ansi-colors": "4.1.3",
|
||||
"ini": "4.1.1",
|
||||
|
|
@ -14733,6 +14929,48 @@
|
|||
"yargs": "17.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular-devkit/architect": {
|
||||
"version": "0.1602.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz",
|
||||
"integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"rxjs": "7.8.1"
|
||||
}
|
||||
},
|
||||
"@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
|
|
@ -16747,14 +16985,48 @@
|
|||
"optional": true
|
||||
},
|
||||
"@schematics/angular": {
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.1.tgz",
|
||||
"integrity": "sha512-e3ckgvSv+OA+4xUBpOqVOvNM8FqY/yXaWqs/Ob0uQ/zPL1iVa/MCAoB25KqYQPnq21hEwE4zqIIQFKasKBIqMA==",
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.14.tgz",
|
||||
"integrity": "sha512-YqIv727l9Qze8/OL6H9mBHc2jVXzAGRNBYnxYWqWhLbfvuVbbldo6NNIIjgv6lrl2LJSdPAAMNOD5m/f6210ug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "16.2.1",
|
||||
"@angular-devkit/schematics": "16.2.1",
|
||||
"@angular-devkit/core": "16.2.14",
|
||||
"@angular-devkit/schematics": "16.2.14",
|
||||
"jsonc-parser": "3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": {
|
||||
"version": "16.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
|
||||
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "8.12.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"picomatch": "2.3.1",
|
||||
"rxjs": "7.8.1",
|
||||
"source-map": "0.7.4"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sigstore/bundle": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"@angular-eslint/eslint-plugin-template": "16.1.1",
|
||||
"@angular-eslint/schematics": "16.1.1",
|
||||
"@angular-eslint/template-parser": "16.1.1",
|
||||
"@angular/cli": "^16.2.1",
|
||||
"@angular/cli": "^16.2.14",
|
||||
"@angular/compiler-cli": "^16.2.3",
|
||||
"@angular/language-service": "^16.2.3",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
|
|
@ -51,4 +51,4 @@
|
|||
"prettier": "^3.0.3",
|
||||
"typescript": "5.1.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using RdtClient.Data.Enums;
|
|||
using RdtClient.Data.Models.TorrentClient;
|
||||
using RdtClient.Service.Helpers;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
|
||||
namespace RdtClient.Service.Services.TorrentClients;
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
{
|
||||
logger.LogError(ex, $"The connection to RealDebrid has timed out: {ex.Message}");
|
||||
|
||||
throw;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
Hash = torrent.Hash,
|
||||
Bytes = torrent.Size,
|
||||
OriginalBytes = torrent.Size,
|
||||
Host = null,
|
||||
Host = torrent.DownloadPresent.ToString(),
|
||||
Split = 0,
|
||||
Progress = (Int64)((torrent.Progress) * 100.0),
|
||||
Status = torrent.DownloadState,
|
||||
|
|
@ -93,9 +94,22 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
|
||||
public async Task<IList<TorrentClientTorrent>> GetTorrents()
|
||||
{
|
||||
var results = await GetClient().Torrents.GetAsync(true);
|
||||
var torrents = new List<Torrent>();
|
||||
|
||||
return results!.Select(Map).ToList();
|
||||
var currentTorrents = await GetClient().Torrents.GetCurrentAsync(true);
|
||||
if (currentTorrents != null)
|
||||
{
|
||||
torrents.AddRange(currentTorrents);
|
||||
}
|
||||
|
||||
var queuedTorrents = await GetClient().Torrents.GetQueuedAsync(true);
|
||||
if (queuedTorrents != null)
|
||||
{
|
||||
torrents.AddRange(queuedTorrents);
|
||||
|
||||
}
|
||||
|
||||
return torrents!.Select(Map).ToList();
|
||||
}
|
||||
|
||||
public async Task<TorrentClientUser> GetUser()
|
||||
|
|
@ -105,7 +119,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
return new()
|
||||
{
|
||||
Username = user.Data!.Email,
|
||||
Expiration = user.Data!.Plan != 0 ? user.Data!.PremiumExpiresAt.Value : null
|
||||
Expiration = user.Data!.Plan != 0 ? user.Data!.PremiumExpiresAt!.Value : null
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -123,133 +137,20 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
return result.Data?.Torrent_ID.ToString()!;
|
||||
}
|
||||
|
||||
public async Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||
public Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||
{
|
||||
var result = await GetClient().Torrents.GetAvailableFiles(hash);
|
||||
|
||||
var files = result.SelectMany(m => m.Value).SelectMany(m => m.Value).SelectMany(m => m.Values);
|
||||
|
||||
var groups = files.Where(m => m.Filename != null).GroupBy(m => $"{m.Filename}-{m.Filesize}");
|
||||
|
||||
var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile
|
||||
{
|
||||
Filename = m.First().Filename!,
|
||||
Filesize = m.First().Filesize
|
||||
}).ToList();
|
||||
|
||||
return torrentClientAvailableFiles;
|
||||
var result = new List<TorrentClientAvailableFile>();
|
||||
return Task.FromResult<IList<TorrentClientAvailableFile>>(result);
|
||||
}
|
||||
|
||||
public async Task SelectFiles(Data.Models.Data.Torrent torrent)
|
||||
public Task SelectFiles(Data.Models.Data.Torrent torrent)
|
||||
{
|
||||
var files = torrent.Files;
|
||||
|
||||
Log("Seleting files", torrent);
|
||||
|
||||
if (torrent.DownloadAction == TorrentDownloadAction.DownloadAvailableFiles)
|
||||
{
|
||||
Log($"Determining which files are already available on RealDebrid", torrent);
|
||||
|
||||
var availableFiles = await GetAvailableFiles(torrent.Hash);
|
||||
|
||||
Log($"Found {files.Count}/{torrent.Files.Count} available files on RealDebrid", torrent);
|
||||
|
||||
files = torrent.Files.Where(m => availableFiles.Any(f => m.Path.EndsWith(f.Filename))).ToList();
|
||||
}
|
||||
else if (torrent.DownloadAction == TorrentDownloadAction.DownloadAll)
|
||||
{
|
||||
Log("Selecting all files", torrent);
|
||||
files = [.. torrent.Files];
|
||||
}
|
||||
else if (torrent.DownloadAction == TorrentDownloadAction.DownloadManual)
|
||||
{
|
||||
Log("Selecting manual selected files", torrent);
|
||||
files = torrent.Files.Where(m => torrent.ManualFiles.Any(f => m.Path.EndsWith(f))).ToList();
|
||||
}
|
||||
|
||||
Log($"Selecting {files.Count}/{torrent.Files.Count} files", torrent);
|
||||
|
||||
if (torrent.DownloadAction != TorrentDownloadAction.DownloadManual && torrent.DownloadMinSize > 0)
|
||||
{
|
||||
var minFileSize = torrent.DownloadMinSize * 1024 * 1024;
|
||||
|
||||
Log($"Determining which files are over {minFileSize} bytes", torrent);
|
||||
|
||||
files = files.Where(m => m.Bytes > minFileSize)
|
||||
.ToList();
|
||||
|
||||
Log($"Found {files.Count} files that match the minimum file size criterea", torrent);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.IncludeRegex))
|
||||
{
|
||||
Log($"Using regular expression {torrent.IncludeRegex} to include only files matching this regex", torrent);
|
||||
|
||||
var newFiles = new List<TorrentClientFile>();
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (Regex.IsMatch(file.Path, torrent.IncludeRegex))
|
||||
{
|
||||
Log($"* Including {file.Path}", torrent);
|
||||
newFiles.Add(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"* Excluding {file.Path}", torrent);
|
||||
}
|
||||
}
|
||||
|
||||
files = newFiles;
|
||||
|
||||
Log($"Found {files.Count} files that match the regex", torrent);
|
||||
}
|
||||
else if (!String.IsNullOrWhiteSpace(torrent.ExcludeRegex))
|
||||
{
|
||||
Log($"Using regular expression {torrent.IncludeRegex} to ignore files matching this regex", torrent);
|
||||
|
||||
var newFiles = new List<TorrentClientFile>();
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!Regex.IsMatch(file.Path, torrent.ExcludeRegex))
|
||||
{
|
||||
Log($"* Including {file.Path}", torrent);
|
||||
newFiles.Add(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"* Excluding {file.Path}", torrent);
|
||||
}
|
||||
}
|
||||
|
||||
files = newFiles;
|
||||
|
||||
Log($"Found {files.Count} files that match the regex", torrent);
|
||||
}
|
||||
|
||||
if (files.Count == 0)
|
||||
{
|
||||
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
|
||||
|
||||
files = torrent.Files;
|
||||
}
|
||||
|
||||
var fileIds = files.Select(m => m.Id.ToString()).ToArray();
|
||||
|
||||
Log($"Selecting files:");
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
Log($"{file.Id}: {file.Path} ({file.Bytes}b)");
|
||||
}
|
||||
|
||||
Log("", torrent);
|
||||
|
||||
await GetClient().Torrents.SelectFilesAsync(torrent.RdId!, [.. fileIds]);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Delete(String torrentId)
|
||||
{
|
||||
await GetClient().Torrents.DeleteAsync(torrentId);
|
||||
await GetClient().Torrents.ControlAsync(Convert.ToInt32(torrentId), "delete");
|
||||
}
|
||||
|
||||
public async Task<String> Unrestrict(String link)
|
||||
|
|
@ -273,7 +174,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
return torrent;
|
||||
}
|
||||
|
||||
var rdTorrent = await GetInfo(torrent.RdId) ?? throw new($"Resource not found");
|
||||
var rdTorrent = await GetInfo(torrent.Hash) ?? throw new($"Resource not found");
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(rdTorrent.Filename))
|
||||
{
|
||||
|
|
@ -308,21 +209,29 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
torrent.RdSeeders = rdTorrent.Seeders;
|
||||
torrent.RdStatusRaw = rdTorrent.Status;
|
||||
|
||||
torrent.RdStatus = rdTorrent.Status switch
|
||||
if (rdTorrent.Host == "true")
|
||||
{
|
||||
"magnet_error" => TorrentStatus.Error,
|
||||
"magnet_conversion" => TorrentStatus.Processing,
|
||||
"waiting_files_selection" => TorrentStatus.WaitingForFileSelection,
|
||||
"queued" => TorrentStatus.Downloading,
|
||||
"downloading" => TorrentStatus.Downloading,
|
||||
"downloaded" => TorrentStatus.Finished,
|
||||
"error" => TorrentStatus.Error,
|
||||
"virus" => TorrentStatus.Error,
|
||||
"compressing" => TorrentStatus.Downloading,
|
||||
"uploading" => TorrentStatus.Uploading,
|
||||
"dead" => TorrentStatus.Error,
|
||||
_ => TorrentStatus.Error
|
||||
};
|
||||
torrent.RdStatus = TorrentStatus.Finished;
|
||||
}
|
||||
else
|
||||
{
|
||||
torrent.RdStatus = rdTorrent.Status switch
|
||||
{
|
||||
"queued" => TorrentStatus.Processing,
|
||||
"metaDL" => TorrentStatus.Processing,
|
||||
"checkingResumeData" => TorrentStatus.Processing,
|
||||
"paused" => TorrentStatus.Downloading,
|
||||
"downloading" => TorrentStatus.Downloading,
|
||||
"completed" => TorrentStatus.Downloading,
|
||||
"uploading" => TorrentStatus.Downloading,
|
||||
"uploading (no peers)" => TorrentStatus.Downloading,
|
||||
"stalled" => TorrentStatus.Downloading,
|
||||
"stalled (no seeds)" => TorrentStatus.Downloading,
|
||||
"cached" => TorrentStatus.Finished,
|
||||
_ => TorrentStatus.Error
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -363,7 +272,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
}
|
||||
|
||||
Log($"Torrent has {torrent.Files.Count(m => m.Selected)} selected files out of {torrent.Files.Count} files, found {downloadLinks.Count} links, torrent ended: {torrent.RdEnded}", torrent);
|
||||
|
||||
|
||||
// Check if all the links are set that have been selected
|
||||
if (torrent.Files.Count(m => m.Selected) == downloadLinks.Count)
|
||||
{
|
||||
|
|
@ -396,7 +305,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
}
|
||||
|
||||
Log($"Did not find any suiteable download links", torrent);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -410,11 +319,11 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
|||
return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value);
|
||||
}
|
||||
|
||||
private async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||
private async Task<TorrentClientTorrent> GetInfo(String torrentHash)
|
||||
{
|
||||
var result = await GetClient().Torrents.GetInfoAsync(torrentId);
|
||||
var result = await GetClient().Torrents.GetInfoAsync(torrentHash);
|
||||
|
||||
return Map(result);
|
||||
return Map(result!);
|
||||
}
|
||||
|
||||
private void Log(String message, Data.Models.Data.Torrent? torrent = null)
|
||||
|
|
|
|||
Loading…
Reference in a new issue