diff --git a/.prettierignore b/.prettierignore index 33affff..76e12cd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,3 +12,24 @@ node_modules pnpm-lock.yaml package-lock.json yarn.lock + +.github +.husky +**/.DS_Store +**/.env +**/.env.* +**/build/ +**/coverage/ +**/dist/ +**/docker-compose.* +**/node_modules/ + +# Ignore files for PNPM, NPM and YARN +package-lock.json +package.json +pnpm-lock.yaml +yarn.lock + +backend\packages\jellyfin.plugin\src\jellyfin.openapi.ts +backend\swagger-spec.json +**/*.generated.d.ts diff --git a/backend/migrations/1739650446621-add-library-item-created-at.ts b/backend/migrations/1739650446621-add-library-item-created-at.ts index 4c55df5..f4517f3 100644 --- a/backend/migrations/1739650446621-add-library-item-created-at.ts +++ b/backend/migrations/1739650446621-add-library-item-created-at.ts @@ -1,28 +1,53 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; -export class AddLibraryItemCreatedAt1739650446621 implements MigrationInterface { - name = 'AddLibraryItemCreatedAt1739650446621' +export class AddLibraryItemCreatedAt1739650446621 + implements MigrationInterface +{ + name = 'AddLibraryItemCreatedAt1739650446621'; - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "temporary_library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`); - await queryRunner.query(`INSERT INTO "temporary_library_item"("id", "tmdbId", "userId", "mediaType") SELECT "id", "tmdbId", "userId", "mediaType" FROM "library_item"`); - await queryRunner.query(`DROP TABLE "library_item"`); - await queryRunner.query(`ALTER TABLE "temporary_library_item" RENAME TO "library_item"`); - await queryRunner.query(`CREATE TABLE "temporary_library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "UQ_97081ef9b13ccb55daec682da1a" UNIQUE ("tmdbId", "userId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`); - await queryRunner.query(`INSERT INTO "temporary_library_item"("id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt") SELECT "id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt" FROM "library_item"`); - await queryRunner.query(`DROP TABLE "library_item"`); - await queryRunner.query(`ALTER TABLE "temporary_library_item" RENAME TO "library_item"`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "library_item" RENAME TO "temporary_library_item"`); - await queryRunner.query(`CREATE TABLE "library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`); - await queryRunner.query(`INSERT INTO "library_item"("id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt") SELECT "id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt" FROM "temporary_library_item"`); - await queryRunner.query(`DROP TABLE "temporary_library_item"`); - await queryRunner.query(`ALTER TABLE "library_item" RENAME TO "temporary_library_item"`); - await queryRunner.query(`CREATE TABLE "library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`); - await queryRunner.query(`INSERT INTO "library_item"("id", "tmdbId", "userId", "mediaType") SELECT "id", "tmdbId", "userId", "mediaType" FROM "temporary_library_item"`); - await queryRunner.query(`DROP TABLE "temporary_library_item"`); - } + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "temporary_library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`, + ); + await queryRunner.query( + `INSERT INTO "temporary_library_item"("id", "tmdbId", "userId", "mediaType") SELECT "id", "tmdbId", "userId", "mediaType" FROM "library_item"`, + ); + await queryRunner.query(`DROP TABLE "library_item"`); + await queryRunner.query( + `ALTER TABLE "temporary_library_item" RENAME TO "library_item"`, + ); + await queryRunner.query( + `CREATE TABLE "temporary_library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "UQ_97081ef9b13ccb55daec682da1a" UNIQUE ("tmdbId", "userId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`, + ); + await queryRunner.query( + `INSERT INTO "temporary_library_item"("id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt") SELECT "id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt" FROM "library_item"`, + ); + await queryRunner.query(`DROP TABLE "library_item"`); + await queryRunner.query( + `ALTER TABLE "temporary_library_item" RENAME TO "library_item"`, + ); + } + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "library_item" RENAME TO "temporary_library_item"`, + ); + await queryRunner.query( + `CREATE TABLE "library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, "updatedAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "createdAt" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`, + ); + await queryRunner.query( + `INSERT INTO "library_item"("id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt") SELECT "id", "tmdbId", "userId", "mediaType", "updatedAt", "createdAt" FROM "temporary_library_item"`, + ); + await queryRunner.query(`DROP TABLE "temporary_library_item"`); + await queryRunner.query( + `ALTER TABLE "library_item" RENAME TO "temporary_library_item"`, + ); + await queryRunner.query( + `CREATE TABLE "library_item" ("id" varchar NOT NULL, "tmdbId" varchar NOT NULL, "userId" varchar NOT NULL, "mediaType" varchar NOT NULL, CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId", "userId"), CONSTRAINT "UQ_d1794fd0082c98017895ea6afa4" UNIQUE ("tmdbId"), CONSTRAINT "FK_44e2a69f2788510e190dd3ac5ec" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("id", "userId"))`, + ); + await queryRunner.query( + `INSERT INTO "library_item"("id", "tmdbId", "userId", "mediaType") SELECT "id", "tmdbId", "userId", "mediaType" FROM "temporary_library_item"`, + ); + await queryRunner.query(`DROP TABLE "temporary_library_item"`); + } } diff --git a/backend/packages/torrent-stream.plugin/src/index.ts b/backend/packages/torrent-stream.plugin/src/index.ts index bc57b3f..b38b616 100644 --- a/backend/packages/torrent-stream.plugin/src/index.ts +++ b/backend/packages/torrent-stream.plugin/src/index.ts @@ -136,7 +136,11 @@ class TorrentProvider extends SourceProvider { throw new Error('Torrent not found'); } - const src = `${this.getProxyUrl(context.sourceId)}/magnet?link=${encodeURIComponent(torrent?.link)}&reiverr_token=${context.token}`; + const src = `${this.getProxyUrl( + context.sourceId, + )}/magnet?link=${encodeURIComponent(torrent?.link)}&reiverr_token=${ + context.token + }`; const files = await getFiles(context.userId, torrent.link); @@ -146,7 +150,11 @@ class TorrentProvider extends SourceProvider { .filter((f) => subtitleExtensions.some((ext) => f.name.endsWith(ext))) .map((f) => ({ kind: 'subtitles', - src: `${this.getProxyUrl(context.sourceId)}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${context.token}&file=${f.name}`, + src: `${this.getProxyUrl( + context.sourceId, + )}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${ + context.token + }&file=${f.name}`, label: f.name, lang: 'unknown', })); @@ -193,7 +201,11 @@ class TorrentProvider extends SourceProvider { throw new Error('Torrent not found'); } - const src = `${this.getProxyUrl(context.sourceId)}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${context.token}&season=${metadata.season}&episode=${metadata.episode}`; + const src = `${this.getProxyUrl( + context.sourceId, + )}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${ + context.token + }&season=${metadata.season}&episode=${metadata.episode}`; const files = await getFiles(context.userId, torrent.link); @@ -201,7 +213,11 @@ class TorrentProvider extends SourceProvider { .filter((f) => subtitleExtensions.some((ext) => f.name.endsWith(ext))) .map((f) => ({ kind: 'subtitles', - src: `${this.getProxyUrl(context.sourceId)}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${context.token}&file=${f.name}`, + src: `${this.getProxyUrl( + context.sourceId, + )}/magnet?link=${encodeURIComponent(torrent.link)}&reiverr_token=${ + context.token + }&file=${f.name}`, label: f.name, lang: 'unknown', })); @@ -259,7 +275,9 @@ class TorrentProvider extends SourceProvider { const name = f.name.toUpperCase(); return ( name.includes( - `S${season.toString().padStart(2, '0')}E${episode.toString().padStart(2, '0')}`, + `S${season.toString().padStart(2, '0')}E${episode + .toString() + .padStart(2, '0')}`, ) || name.includes(`S${season.toString()}E${episode.toString()}`) ); diff --git a/backend/packages/torrent-stream.plugin/src/lib/jackett.api.ts b/backend/packages/torrent-stream.plugin/src/lib/jackett.api.ts index fdb9695..977e882 100644 --- a/backend/packages/torrent-stream.plugin/src/lib/jackett.api.ts +++ b/backend/packages/torrent-stream.plugin/src/lib/jackett.api.ts @@ -91,7 +91,9 @@ export const getEpisodeTorrents = ( params: { apikey: settings.apiKey, t: 'tvsearch', - q: `${series} S${season.toString().padStart(2, '0')}E${episode.toString().padStart(2, '0')}`, + q: `${series} S${season.toString().padStart(2, '0')}E${episode + .toString() + .padStart(2, '0')}`, // q: `${series}`, // `${series} S${season.toString().padStart(2, '0')}E${episode.toString().padStart(2, '0')}` // season: season, // episode: episode, diff --git a/backend/packages/torrent-stream.plugin/src/lib/torrent-manager.ts b/backend/packages/torrent-stream.plugin/src/lib/torrent-manager.ts index 0a3c59a..6a548e7 100644 --- a/backend/packages/torrent-stream.plugin/src/lib/torrent-manager.ts +++ b/backend/packages/torrent-stream.plugin/src/lib/torrent-manager.ts @@ -5,10 +5,7 @@ import * as torrentStream from 'torrent-stream'; class FileCache { private cache: T; - constructor( - private cacheFile: string, - private defaultValue: T, - ) { + constructor(private cacheFile: string, private defaultValue: T) { this.cache = this.readStreamCache(); } diff --git a/backend/packages/torrent-stream.plugin/src/utils.ts b/backend/packages/torrent-stream.plugin/src/utils.ts index 6f7666b..d361c99 100644 --- a/backend/packages/torrent-stream.plugin/src/utils.ts +++ b/backend/packages/torrent-stream.plugin/src/utils.ts @@ -207,4 +207,4 @@ function convertSrtCue(caption: string) { cue += s[line] + '\n\n'; } return cue; -} \ No newline at end of file +} diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index b965825..a7ad279 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -21,7 +21,7 @@ export class SignInResponse { @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} - + @HttpCode(HttpStatus.OK) @Post() @ApiOkResponse({ description: 'User found', type: SignInResponse }) diff --git a/backend/src/common/common.dto.ts b/backend/src/common/common.dto.ts index 0e1b297..c984b95 100644 --- a/backend/src/common/common.dto.ts +++ b/backend/src/common/common.dto.ts @@ -6,7 +6,10 @@ import { PartialType, PickType, } from '@nestjs/swagger'; -import { PaginatedResponse, PaginationParams } from '@aleksilassila/reiverr-plugin'; +import { + PaginatedResponse, + PaginationParams, +} from '@aleksilassila/reiverr-plugin'; export const PickAndPartial = ( clazz: Type, diff --git a/backend/src/media-sources/media-sources.controller.ts b/backend/src/media-sources/media-sources.controller.ts index 10b1d07..bec3c82 100644 --- a/backend/src/media-sources/media-sources.controller.ts +++ b/backend/src/media-sources/media-sources.controller.ts @@ -69,8 +69,9 @@ export class ServiceOwnershipValidator implements CanActivate { if (!sourceId) return true; - const mediaSource = - await this.mediaSourcesService.findMediaSource(sourceId); + const mediaSource = await this.mediaSourcesService.findMediaSource( + sourceId, + ); if (!mediaSource) throw new NotFoundException('Source not found'); @@ -302,8 +303,9 @@ export class MediaSourcesController { @GetAuthToken() token: string, ) { const sourceId = params.sourceId; - const mediaSource = - await this.mediaSourcesService.findMediaSource(sourceId); + const mediaSource = await this.mediaSourcesService.findMediaSource( + sourceId, + ); if (!mediaSource) throw new NotFoundException('Source not found'); @@ -368,8 +370,9 @@ export class MediaSourcesController { } async getConnection(sourceId: string) { - const mediaSource = - await this.mediaSourcesService.findMediaSource(sourceId); + const mediaSource = await this.mediaSourcesService.findMediaSource( + sourceId, + ); if (!mediaSource.pluginId || !mediaSource.enabled) { throw new BadRequestException('Source not configured'); diff --git a/backend/src/source-providers/source-providers.service.ts b/backend/src/source-providers/source-providers.service.ts index 443ab68..9825923 100644 --- a/backend/src/source-providers/source-providers.service.ts +++ b/backend/src/source-providers/source-providers.service.ts @@ -59,7 +59,9 @@ export class SourceProvidersService { plugins[plugin.name] = plugin; } else { this.logger.warn( - `Plugin ${plugin.name}@${plugin._getPluginVersion()} is not compatible with Reiverr plugin API version ${supportedPluginVersion}`, + `Plugin ${ + plugin.name + }@${plugin._getPluginVersion()} is not compatible with Reiverr plugin API version ${supportedPluginVersion}`, ); } }); diff --git a/src/lib/apis/tmdb/tmdb-api.ts b/src/lib/apis/tmdb/tmdb-api.ts index 8f26041..12cbdd2 100644 --- a/src/lib/apis/tmdb/tmdb-api.ts +++ b/src/lib/apis/tmdb/tmdb-api.ts @@ -313,7 +313,7 @@ export class TmdbApi implements Api { movie_id: tmdbId }, query: { - language: get(settings)?.language || 'en', + language: get(settings)?.language || 'en' } } }) @@ -327,7 +327,7 @@ export class TmdbApi implements Api { series_id: tmdbId }, query: { - language: get(settings)?.language || 'en', + language: get(settings)?.language || 'en' } } }) diff --git a/src/lib/components/Container.type.ts b/src/lib/components/Container.type.ts index 7e74049..8738157 100644 --- a/src/lib/components/Container.type.ts +++ b/src/lib/components/Container.type.ts @@ -7,19 +7,19 @@ // export let focusOnClick = false; // export let focusedChild = false; -import type { SvelteHTMLElements } from "svelte/elements"; +import type { SvelteHTMLElements } from 'svelte/elements'; // export let disabled = false; export type ContainerProps = SvelteHTMLElements['div'] & { - name?: string; - direction?: 'vertical' | 'horizontal' | 'grid'; - gridCols?: number; - focusOnMount?: boolean; - trapFocus?: boolean; - debugOutline?: boolean; - focusOnClick?: boolean; - focusedChild?: boolean; - disabled?: boolean; - tag?: string; + name?: string; + direction?: 'vertical' | 'horizontal' | 'grid'; + gridCols?: number; + focusOnMount?: boolean; + trapFocus?: boolean; + debugOutline?: boolean; + focusOnClick?: boolean; + focusedChild?: boolean; + disabled?: boolean; + tag?: string; }; diff --git a/src/lib/components/Notifications/NotificationStack.svelte b/src/lib/components/Notifications/NotificationStack.svelte index 02b088a..0b852f0 100644 --- a/src/lib/components/Notifications/NotificationStack.svelte +++ b/src/lib/components/Notifications/NotificationStack.svelte @@ -7,8 +7,8 @@ export let persistent = false; onDestroy(() => { - notificationStack.destroy([]); - }) + notificationStack.destroy([]); + });
diff --git a/src/lib/components/ScrollHelper.svelte b/src/lib/components/ScrollHelper.svelte index c46e533..da1b4e7 100644 --- a/src/lib/components/ScrollHelper.svelte +++ b/src/lib/components/ScrollHelper.svelte @@ -7,7 +7,8 @@ export let scrollLeft: number = 0; const scrollStore = getScrollContext(); - if (!scrollStore.scrollLeft || !scrollStore.scrollTop) console.error('ScrollHelper requires ScrollStore'); + if (!scrollStore.scrollLeft || !scrollStore.scrollTop) + console.error('ScrollHelper requires ScrollStore'); $: scrollStore.scrollTop?.set(scrollTop); $: scrollStore.scrollLeft?.set(scrollLeft); diff --git a/tailwind.config.js b/tailwind.config.js index e5c42b7..e5c3615 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,4 +1,4 @@ -import scrollbarHide from 'tailwind-scrollbar-hide' +import scrollbarHide from 'tailwind-scrollbar-hide'; /** * https://huemint.com/website-monochrome/#palette=353633-fbfdff