mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-26 18:55:12 +02:00
feat: library page infinite scroll
This commit is contained in:
@@ -4,11 +4,16 @@ import {
|
||||
ExecutionContext,
|
||||
Type,
|
||||
} from '@nestjs/common';
|
||||
import { PaginatedResponseDto, PaginationParamsDto } from './common.dto';
|
||||
import { ApiExtraModels, ApiOkResponse, getSchemaPath } from '@nestjs/swagger';
|
||||
import { PaginatedResponseDto, PaginationDto } from './common.dto';
|
||||
import {
|
||||
ApiExtraModels,
|
||||
ApiOkResponse,
|
||||
ApiQuery,
|
||||
getSchemaPath,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
export const GetPaginationParams = createParamDecorator(
|
||||
(data: number | undefined, ctx: ExecutionContext): PaginationParamsDto => {
|
||||
(data: number | undefined, ctx: ExecutionContext): PaginationDto => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const page = parseInt(request.query.page, 10) || 1;
|
||||
const itemsPerPage = parseInt(request.query.itemsPerPage, 10) || data || 50;
|
||||
@@ -20,6 +25,20 @@ export const GetPaginationParams = createParamDecorator(
|
||||
},
|
||||
);
|
||||
|
||||
export const PaginationApiQuery = () =>
|
||||
applyDecorators(
|
||||
ApiQuery({
|
||||
name: 'page',
|
||||
required: false,
|
||||
type: 'number',
|
||||
}),
|
||||
ApiQuery({
|
||||
name: 'itemsPerPage',
|
||||
required: false,
|
||||
type: 'number',
|
||||
}),
|
||||
);
|
||||
|
||||
export const PaginatedApiOkResponse = <GenericType extends Type<unknown>>(
|
||||
data: GenericType,
|
||||
) =>
|
||||
|
||||
@@ -35,7 +35,7 @@ export class PaginatedResponseDto<T> implements PaginatedResponse<T> {
|
||||
items: T[];
|
||||
}
|
||||
|
||||
export class PaginationParamsDto implements PaginationParams {
|
||||
export class PaginationDto implements PaginationParams {
|
||||
@ApiProperty()
|
||||
page: number;
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@ import {
|
||||
import { ApiOkResponse, ApiQuery, ApiTags } from '@nestjs/swagger';
|
||||
import { GetAuthToken, UserAccessControl } from 'src/auth/auth.guard';
|
||||
import {
|
||||
GetPaginationParams,
|
||||
GetPaginationParams as GetPaginationQuery,
|
||||
PaginatedApiOkResponse,
|
||||
PaginationApiQuery,
|
||||
} from 'src/common/common.decorator';
|
||||
import {
|
||||
MediaType,
|
||||
PaginatedResponseDto,
|
||||
PaginationParamsDto,
|
||||
PaginationDto,
|
||||
SuccessResponseDto,
|
||||
} from 'src/common/common.dto';
|
||||
import {
|
||||
@@ -42,9 +43,10 @@ export class LibraryController {
|
||||
@ApiQuery({ name: 'type', enum: MyListTypeFilter, required: false })
|
||||
@ApiQuery({ name: 'order', enum: MyListOrder, required: false })
|
||||
@ApiQuery({ name: 'direction', enum: OrderDirection, required: false })
|
||||
@PaginationApiQuery()
|
||||
@PaginatedApiOkResponse(LibraryItemDto)
|
||||
async getMyList(
|
||||
@GetPaginationParams() pagination: PaginationParamsDto,
|
||||
@GetPaginationQuery() pagination: PaginationDto,
|
||||
@Param('userId') userId: string,
|
||||
@Query('status', new ParseEnumPipe(MyListStatusFilter, { optional: true }))
|
||||
status?: MyListStatusFilter,
|
||||
@@ -78,9 +80,10 @@ export class LibraryController {
|
||||
@ApiQuery({ name: 'type', enum: CatalogueTypeFilter, required: false })
|
||||
@ApiQuery({ name: 'order', required: false })
|
||||
@ApiQuery({ name: 'direction', required: false })
|
||||
@PaginationApiQuery()
|
||||
@PaginatedApiOkResponse(LibraryItemDto)
|
||||
async getCatalogue(
|
||||
@GetPaginationParams() pagination: PaginationParamsDto,
|
||||
@GetPaginationQuery() pagination: PaginationDto,
|
||||
@Param('userId') userId: string,
|
||||
@Param('sourceId') sourceId: string,
|
||||
@GetAuthToken() token: string,
|
||||
@@ -91,7 +94,7 @@ export class LibraryController {
|
||||
@Query('direction')
|
||||
direction?: string,
|
||||
): Promise<PaginatedResponseDto<LibraryItemDto>> {
|
||||
const items = this.libraryService.getCatalogueItems({
|
||||
const items = await this.libraryService.getCatalogueItems({
|
||||
sourceId,
|
||||
token,
|
||||
pagination,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
MediaType,
|
||||
PaginatedResponseDto,
|
||||
PaginationParamsDto,
|
||||
PaginationDto,
|
||||
} from 'src/common/common.dto';
|
||||
import { MetadataService } from 'src/metadata/metadata.service';
|
||||
import { MediaSourcesService } from 'src/users/media-sources/media-sources.service';
|
||||
@@ -42,7 +42,7 @@ export class LibraryService {
|
||||
/** TODO: decouple librayItem and movie/seriesItem */
|
||||
async getMyList(options: {
|
||||
userId: string;
|
||||
pagination: PaginationParamsDto;
|
||||
pagination: PaginationDto;
|
||||
type?: MyListTypeFilter;
|
||||
status?: MyListStatusFilter;
|
||||
order?: MyListOrder;
|
||||
@@ -244,7 +244,7 @@ export class LibraryService {
|
||||
async getCatalogueItems(options: {
|
||||
sourceId: string;
|
||||
token: string;
|
||||
pagination: PaginationParamsDto;
|
||||
pagination: PaginationDto;
|
||||
type?: CatalogueTypeFilter;
|
||||
order?: string;
|
||||
direction?: string;
|
||||
@@ -260,7 +260,12 @@ export class LibraryService {
|
||||
|
||||
const connection = await this.mediaSourceService.getConnection(sourceId);
|
||||
|
||||
if (!connection) return;
|
||||
if (!connection) {
|
||||
console.error(
|
||||
`No connection found for sourceId: ${sourceId}. Please check your media source configuration.`,
|
||||
);
|
||||
throw new Error('No connection found');
|
||||
}
|
||||
|
||||
const combined = connection.provider.catalogueProvider.getCatalogue;
|
||||
const movies = connection.provider.catalogueProvider.getMovieCatalogue;
|
||||
@@ -360,6 +365,10 @@ export class LibraryService {
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`No catalogue provider found for type: ${type}. Please check your media source configuration.`,
|
||||
);
|
||||
}
|
||||
|
||||
async findByTmdbId(
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
SourceProvider,
|
||||
ValidationResponse,
|
||||
} from '@aleksilassila/reiverr-plugin';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { SourceProvidersService } from 'src/source-providers/source-providers.service';
|
||||
import { User } from 'src/users/user.entity';
|
||||
import { UsersService } from 'src/users/users.service';
|
||||
import { Repository } from 'typeorm';
|
||||
import {
|
||||
MediaSourceDto,
|
||||
@@ -8,12 +12,6 @@ import {
|
||||
} from './media-source.dto';
|
||||
import { MediaSource } from './media-source.entity';
|
||||
import { MEIDA_SOURCE_REPOSITORY } from './media-source.providers';
|
||||
import { SourceProvidersService } from 'src/source-providers/source-providers.service';
|
||||
import {
|
||||
SourceProvider,
|
||||
ValidationResponse,
|
||||
} from '@aleksilassila/reiverr-plugin';
|
||||
import { PaginationParamsDto } from 'src/common/common.dto';
|
||||
|
||||
export enum MediaSourcesServiceError {
|
||||
SourceNotFound = 'SourceNotFound',
|
||||
|
||||
Reference in New Issue
Block a user