fix: add type safety to PlaybackPositionService and clarify watched state logic

- Move PlaybackPositionData interface to shared-interfaces lib
- Replace all `any` types with proper PlaybackPositionData typing
- Add comment clarifying position=duration semantics for watched episodes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 4.5 committed 2026-01-22 13:25:10 +01:00
1 parent adb89145a3
commit 0219d3253e
5 files changed
+29 -20

No files matched your search

@@ -1,10 +1,14 @@
import { InjectionToken } from '@angular/core';
import {
PlaybackPositionData,
XtreamCategory,
XtreamLiveStream,
XtreamSerieItem,
XtreamVodStream,
} from 'shared-interfaces';
// Re-export for backward compatibility
export { PlaybackPositionData };
import { XtreamCredentials, CategoryType, StreamType } from '../services/xtream-api.service';
/**
@@ -75,21 +79,6 @@ export interface RecentlyViewedItem extends XtreamContentItem {
viewed_at: string;
}
/**
* Playback position data for resume functionality
*/
export interface PlaybackPositionData {
contentXtreamId: number;
contentType: 'vod' | 'episode';
seriesXtreamId?: number;
seasonNumber?: number;
episodeNumber?: number;
positionSeconds: number;
durationSeconds?: number;
playlistId?: string;
updatedAt?: string;
}
/**
* Database category type mapping (differs from API type)
*/
@@ -318,6 +318,7 @@ export function withPlaybackPositions() {
if (duration === 0) duration = 1; // Fallback
// Setting position = duration indicates episode is fully watched
const data: PlaybackPositionData = {
contentXtreamId: id,
contentType: 'episode',
@@ -1,10 +1,14 @@
import { Injectable } from '@angular/core';
import { PlaybackPositionData } from 'shared-interfaces';
@Injectable({
providedIn: 'root',
})
export class PlaybackPositionService {
async savePlaybackPosition(playlistId: string, data: any): Promise<void> {
async savePlaybackPosition(
playlistId: string,
data: PlaybackPositionData
): Promise<void> {
try {
await window.electron.dbSavePlaybackPosition(playlistId, data);
} catch (error) {
@@ -16,7 +20,7 @@ export class PlaybackPositionService {
playlistId: string,
contentXtreamId: number,
contentType: 'vod' | 'episode'
): Promise<any | null> {
): Promise<PlaybackPositionData | null> {
try {
return await window.electron.dbGetPlaybackPosition(
playlistId,
@@ -32,7 +36,7 @@ export class PlaybackPositionService {
async getSeriesPlaybackPositions(
playlistId: string,
seriesXtreamId: number
): Promise<any[]> {
): Promise<PlaybackPositionData[]> {
try {
return await window.electron.dbGetSeriesPlaybackPositions(
playlistId,
@@ -47,7 +51,7 @@ export class PlaybackPositionService {
async getRecentPlaybackPositions(
playlistId: string,
limit?: number
): Promise<any[]> {
): Promise<PlaybackPositionData[]> {
try {
return await window.electron.dbGetRecentPlaybackPositions(
playlistId,
@@ -59,7 +63,7 @@ export class PlaybackPositionService {
}
}
async getAllPlaybackPositions(playlistId: string): Promise<any[]> {
async getAllPlaybackPositions(playlistId: string): Promise<PlaybackPositionData[]> {
try {
return await window.electron.dbGetAllPlaybackPositions(playlistId);
} catch (error) {
+1
View File
@@ -10,6 +10,7 @@ export * from './lib/ipc-command.class';
export * from './lib/ipc-commands';
export * from './lib/language.enum';
export * from './lib/parsed-playlist.interface';
export * from './lib/playback-position.interface';
export * from './lib/playlist-meta.type';
export * from './lib/playlist.interface';
export * from './lib/settings.interface';
@@ -0,0 +1,14 @@
/**
* Playback position data for resume functionality
*/
export interface PlaybackPositionData {
contentXtreamId: number;
contentType: 'vod' | 'episode';
seriesXtreamId?: number;
seasonNumber?: number;
episodeNumber?: number;
positionSeconds: number;
durationSeconds?: number;
playlistId?: string;
updatedAt?: string;
}