Implement queudtorrents, selecting files, hash rather than id

This commit is contained in:
Sam Heinz 2024-08-27 11:06:33 +10:00
parent 772631d47f
commit fc9ea4c29a
3 changed files with 360 additions and 179 deletions

338
client/package-lock.json generated
View file

@ -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": {

View file

@ -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"
}
}
}

View file

@ -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)