mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-27 03:05:10 +02:00
feat: mark as watched, episode page uses userdata, progress etc
This commit is contained in:
@@ -22,19 +22,18 @@ export class PlayStateController {
|
||||
constructor(private playStateService: PlayStateService) {}
|
||||
|
||||
@Put('movie/tmdb/:tmdbId')
|
||||
@ApiQuery({ name: 'mediaType', enum: MediaType, required: false })
|
||||
// @ApiQuery({ name: 'mediaType', enum: MediaType, required: false })
|
||||
async updateMoviePlayStateByTmdbId(
|
||||
@Param('userId') userId: string,
|
||||
@Param('tmdbId') tmdbId: string,
|
||||
@Body() playState: UpdatePlayStateDto,
|
||||
@Query('mediaType', new ParseEnumPipe(MediaType, { optional: true }))
|
||||
mediaType?: MediaType,
|
||||
// @Query('mediaType', new ParseEnumPipe(MediaType, { optional: true }))
|
||||
// mediaType?: MediaType,
|
||||
) {
|
||||
return this.playStateService.updateOrCreateMoviePlayState(
|
||||
userId,
|
||||
tmdbId,
|
||||
playState,
|
||||
mediaType,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OmitType } from '@nestjs/swagger';
|
||||
import { OmitType, PartialType } from '@nestjs/swagger';
|
||||
import { PlayState } from './play-state.entity';
|
||||
|
||||
export class PlayStateDto extends PlayState {}
|
||||
@@ -21,12 +21,6 @@ export class PlayStateDto extends PlayState {}
|
||||
// }
|
||||
// }
|
||||
|
||||
export class UpdatePlayStateDto extends OmitType(PlayState, [
|
||||
'id',
|
||||
'tmdbId',
|
||||
'episode',
|
||||
'season',
|
||||
'user',
|
||||
'userId',
|
||||
'lastPlayedAt',
|
||||
]) {}
|
||||
export class UpdatePlayStateDto extends PartialType(
|
||||
OmitType(PlayStateDto, ['userId']),
|
||||
) {}
|
||||
|
||||
@@ -17,16 +17,16 @@ import { MediaType } from 'src/common/common.dto';
|
||||
@Entity()
|
||||
@Unique(['tmdbId', 'userId', 'season', 'episode'])
|
||||
export class PlayState {
|
||||
@ApiProperty({ required: false, type: 'string' })
|
||||
@ApiProperty({ type: 'string' })
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@ApiProperty({ required: true, type: 'number' })
|
||||
@Column({ unique: true })
|
||||
@Column()
|
||||
tmdbId: string;
|
||||
|
||||
@ApiProperty({ required: false, enum: MediaType })
|
||||
@Column({ nullable: true })
|
||||
@ApiProperty({ enum: MediaType })
|
||||
@Column()
|
||||
mediaType: MediaType;
|
||||
|
||||
@ApiProperty({ required: true, type: 'string' })
|
||||
@@ -47,7 +47,6 @@ export class PlayState {
|
||||
episode: number = 0;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the user has watched this media',
|
||||
@@ -56,7 +55,6 @@ export class PlayState {
|
||||
watched: boolean = false;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
default: false,
|
||||
example: 0.5,
|
||||
description: 'A number between 0 and 1',
|
||||
@@ -67,7 +65,6 @@ export class PlayState {
|
||||
@ApiProperty({
|
||||
type: 'string',
|
||||
description: 'Last time the user played this media',
|
||||
required: false,
|
||||
})
|
||||
@UpdateDateColumn()
|
||||
lastPlayedAt: Date;
|
||||
|
||||
@@ -18,12 +18,12 @@ export class PlayStateService {
|
||||
});
|
||||
}
|
||||
|
||||
async findShowPlayState(
|
||||
async findSeriesPlayStates(
|
||||
userId: string,
|
||||
tmdbId: string,
|
||||
season?: number,
|
||||
episode?: number,
|
||||
): Promise<PlayState | undefined> {
|
||||
): Promise<PlayState[]> {
|
||||
const playStates =
|
||||
(await this.playStateRepository.find({
|
||||
where: {
|
||||
@@ -42,14 +42,13 @@ export class PlayStateService {
|
||||
return a.episode - b.episode;
|
||||
});
|
||||
|
||||
return playStates[0];
|
||||
return playStates;
|
||||
}
|
||||
|
||||
async updateOrCreateMoviePlayState(
|
||||
userId: string,
|
||||
tmdbId: string,
|
||||
playState: UpdatePlayStateDto,
|
||||
mediaType?: MediaType,
|
||||
) {
|
||||
let state = await this.findMoviePlayState(userId, tmdbId);
|
||||
|
||||
@@ -57,9 +56,7 @@ export class PlayStateService {
|
||||
state = this.playStateRepository.create();
|
||||
state.userId = userId;
|
||||
state.tmdbId = tmdbId;
|
||||
if (mediaType) {
|
||||
state.mediaType = mediaType;
|
||||
}
|
||||
state.mediaType = MediaType.Movie;
|
||||
}
|
||||
|
||||
state.progress = playState.progress;
|
||||
@@ -75,7 +72,16 @@ export class PlayStateService {
|
||||
episode: number,
|
||||
playState: UpdatePlayStateDto,
|
||||
) {
|
||||
let state = await this.findShowPlayState(userId, tmdbId, season, episode);
|
||||
let state = await this.findSeriesPlayStates(
|
||||
userId,
|
||||
tmdbId,
|
||||
season,
|
||||
episode,
|
||||
).then((states) =>
|
||||
states.find(
|
||||
(state) => state.season === season && state.episode === episode,
|
||||
),
|
||||
);
|
||||
|
||||
if (!state) {
|
||||
state = this.playStateRepository.create();
|
||||
@@ -83,6 +89,7 @@ export class PlayStateService {
|
||||
state.tmdbId = tmdbId;
|
||||
state.season = season;
|
||||
state.episode = episode;
|
||||
state.mediaType = MediaType.Episode;
|
||||
}
|
||||
|
||||
state.progress = playState.progress;
|
||||
@@ -102,7 +109,12 @@ export class PlayStateService {
|
||||
season: number,
|
||||
episode: number,
|
||||
) {
|
||||
const state = await this.findShowPlayState(userId, tmdbId, season, episode);
|
||||
const state = await this.findSeriesPlayStates(
|
||||
userId,
|
||||
tmdbId,
|
||||
season,
|
||||
episode,
|
||||
);
|
||||
return await this.playStateRepository.remove(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ export class UpdateUserDto extends PartialType(
|
||||
|
||||
export class SignInDto extends PickType(User, ['name', 'password'] as const) {}
|
||||
|
||||
export class MediaUserDataDto {
|
||||
export class MovieUserDataDto {
|
||||
@ApiProperty()
|
||||
tmdbId: string;
|
||||
|
||||
@@ -68,3 +68,14 @@ export class MediaUserDataDto {
|
||||
@ApiProperty({ type: PlayStateDto, required: false })
|
||||
playState?: PlayStateDto;
|
||||
}
|
||||
|
||||
export class SeriesUserDataDto {
|
||||
@ApiProperty()
|
||||
tmdbId: string;
|
||||
|
||||
@ApiProperty()
|
||||
inLibrary: boolean;
|
||||
|
||||
@ApiProperty({ type: [PlayStateDto] })
|
||||
playStates: PlayStateDto[];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
CreateUserDto,
|
||||
MediaUserDataDto,
|
||||
MovieUserDataDto,
|
||||
SeriesUserDataDto,
|
||||
UpdateUserDto,
|
||||
UserDto,
|
||||
} from './user.dto';
|
||||
@@ -167,12 +168,12 @@ export class UsersController {
|
||||
@Get(':userId/user-data/movie/tmdb/:tmdbId')
|
||||
@ApiOkResponse({
|
||||
description: 'User movie data found',
|
||||
type: MediaUserDataDto,
|
||||
type: MovieUserDataDto,
|
||||
})
|
||||
async getUserMovieData(
|
||||
@Param('userId') userId: string,
|
||||
@Param('tmdbId') tmdbId: string,
|
||||
): Promise<MediaUserDataDto> {
|
||||
): Promise<MovieUserDataDto> {
|
||||
const libraryItem = await this.libraryService.findByTmdbId(userId, tmdbId);
|
||||
const playState = await this.playStateService.findMoviePlayState(
|
||||
userId,
|
||||
@@ -187,17 +188,17 @@ export class UsersController {
|
||||
}
|
||||
|
||||
@UseGuards(UserAccessControl)
|
||||
@Get(':userId/user-data/show/tmdb/:tmdbId')
|
||||
@Get(':userId/user-data/series/tmdb/:tmdbId')
|
||||
@ApiOkResponse({
|
||||
description: 'User show data found',
|
||||
type: MediaUserDataDto,
|
||||
description: 'User series data found',
|
||||
type: SeriesUserDataDto,
|
||||
})
|
||||
async getShowUserData(
|
||||
async getSeriesUserData(
|
||||
@Param('userId') userId: string,
|
||||
@Param('tmdbId') tmdbId: string,
|
||||
): Promise<MediaUserDataDto> {
|
||||
): Promise<SeriesUserDataDto> {
|
||||
const libraryItem = await this.libraryService.findByTmdbId(userId, tmdbId);
|
||||
const playState = await this.playStateService.findShowPlayState(
|
||||
const playState = await this.playStateService.findSeriesPlayStates(
|
||||
userId,
|
||||
tmdbId,
|
||||
);
|
||||
@@ -205,29 +206,28 @@ export class UsersController {
|
||||
return {
|
||||
tmdbId,
|
||||
inLibrary: !!libraryItem,
|
||||
playState: playState,
|
||||
playStates: playState,
|
||||
};
|
||||
}
|
||||
|
||||
@UseGuards(UserAccessControl)
|
||||
@Get(':userId/user-data/show/tmdb/:tmdbId/season/:season/episode/:episode')
|
||||
@Get(':userId/user-data/series/tmdb/:tmdbId/season/:season/episode/:episode')
|
||||
@ApiOkResponse({
|
||||
description: 'User show data found',
|
||||
type: MediaUserDataDto,
|
||||
description: 'User series data found',
|
||||
type: MovieUserDataDto,
|
||||
})
|
||||
async getEpisodeUserData(
|
||||
@Param('userId') userId: string,
|
||||
@Param('tmdbId') tmdbId: string,
|
||||
@Param('season', ParseIntPipe) season: number,
|
||||
@Param('episode', ParseIntPipe) episode: number,
|
||||
): Promise<MediaUserDataDto> {
|
||||
): Promise<MovieUserDataDto> {
|
||||
const libraryItem = await this.libraryService.findByTmdbId(userId, tmdbId);
|
||||
const playState = await this.playStateService.findShowPlayState(
|
||||
userId,
|
||||
tmdbId,
|
||||
season,
|
||||
episode,
|
||||
);
|
||||
const playState = await this.playStateService
|
||||
.findSeriesPlayStates(userId, tmdbId, season, episode)
|
||||
.then((states) =>
|
||||
states.find((s) => s.season === season && s.episode === episode),
|
||||
);
|
||||
|
||||
return {
|
||||
tmdbId,
|
||||
|
||||
Reference in New Issue
Block a user