CP!!! Some changes top trakt

This commit is contained in:
tapframe 2025-07-07 16:27:21 +05:30
parent 6d661f6c85
commit fde8904c3b
3 changed files with 126 additions and 4 deletions

View file

@ -254,6 +254,62 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
// Wait for all content to be processed
await Promise.all(contentPromises);
// -------------------- TRAKT HISTORY INTEGRATION --------------------
try {
const traktService = TraktService.getInstance();
const isAuthed = await traktService.isAuthenticated();
if (isAuthed) {
const historyItems = await traktService.getWatchedEpisodesHistory(1, 200);
const latestWatchedByShow: Record<string, { season: number; episode: number; watchedAt: number }> = {};
for (const item of historyItems) {
if (item.type !== 'episode') continue;
const showImdb = item.show?.ids?.imdb ? `tt${item.show.ids.imdb.replace(/^tt/, '')}` : null;
if (!showImdb) continue;
const season = item.episode?.season;
const epNum = item.episode?.number;
if (season === undefined || epNum === undefined) continue;
const watchedAt = new Date(item.watched_at).getTime();
const existing = latestWatchedByShow[showImdb];
if (!existing || existing.watchedAt < watchedAt) {
latestWatchedByShow[showImdb] = { season, episode: epNum, watchedAt };
}
}
// Create placeholders for each show if not already present
for (const [showId, info] of Object.entries(latestWatchedByShow)) {
if (latestEpisodes[showId]) continue; // already handled via progress
const nextEpisode = info.episode + 1;
const nextEpisodeId = `${showId}:${info.season}:${nextEpisode}`;
try {
const basicContent = await catalogService.getBasicContentDetails('series', showId);
if (!basicContent) continue;
const placeholder: ContinueWatchingItem = {
...basicContent,
id: showId,
type: 'series',
progress: 0,
lastUpdated: info.watchedAt,
season: info.season,
episode: nextEpisode,
episodeTitle: `Episode ${nextEpisode}`,
} as ContinueWatchingItem;
latestEpisodes[showId] = placeholder;
} catch (err) {
logger.error('Failed to build placeholder from history:', err);
}
}
}
} catch (err) {
logger.error('Error merging Trakt history:', err);
}
// Add the latest episodes for each series to the items list
progressItems.push(...Object.values(latestEpisodes));

View file

@ -10,6 +10,8 @@ import { tmdbService } from '../../services/tmdbService';
import { storageService } from '../../services/storageService';
import { useFocusEffect } from '@react-navigation/native';
import Animated, { FadeIn } from 'react-native-reanimated';
import { TraktService } from '../../services/traktService';
import { logger } from '../../utils/logger';
interface SeriesContentProps {
episodes: Episode[];
@ -66,6 +68,46 @@ export const SeriesContent: React.FC<SeriesContentProps> = ({
}
});
// ---------------- Trakt watched-history integration ----------------
try {
const traktService = TraktService.getInstance();
const isAuthed = await traktService.isAuthenticated();
if (isAuthed && metadata?.id) {
const historyItems = await traktService.getWatchedEpisodesHistory(1, 400);
historyItems.forEach(item => {
if (item.type !== 'episode') return;
const showImdb = item.show?.ids?.imdb ? `tt${item.show.ids.imdb.replace(/^tt/, '')}` : null;
if (!showImdb || showImdb !== metadata.id) return;
const season = item.episode?.season;
const epNum = item.episode?.number;
if (season === undefined || epNum === undefined) return;
const episodeId = `${metadata.id}:${season}:${epNum}`;
const watchedAt = new Date(item.watched_at).getTime();
// Mark as 100% completed (use 1/1 to avoid divide-by-zero)
const traktProgressEntry = {
currentTime: 1,
duration: 1,
lastUpdated: watchedAt,
};
const existing = progress[episodeId];
const existingPercent = existing ? (existing.currentTime / existing.duration) * 100 : 0;
// Prefer local progress if it is already >=85%; otherwise use Trakt data
if (!existing || existingPercent < 85) {
progress[episodeId] = traktProgressEntry;
}
});
}
} catch (err) {
logger.error('[SeriesContent] Failed to merge Trakt history:', err);
}
setEpisodeProgress(progress);
};
@ -799,8 +841,8 @@ const styles = StyleSheet.create({
},
completedBadge: {
position: 'absolute',
bottom: 8,
right: 8,
top: 8,
left: 8,
width: 20,
height: 20,
borderRadius: 10,
@ -808,6 +850,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.3)',
zIndex: 2,
},
// Horizontal Layout Styles
@ -935,8 +978,8 @@ const styles = StyleSheet.create({
},
completedBadgeHorizontal: {
position: 'absolute',
bottom: 12,
right: 12,
top: 12,
left: 12,
width: 24,
height: 24,
borderRadius: 12,

View file

@ -1562,6 +1562,29 @@ export class TraktService {
return false;
}
}
public async getWatchedEpisodesHistory(page: number = 1, limit: number = 100): Promise<any[]> {
await this.ensureInitialized();
const cacheKey = `history_episodes_${page}_${limit}`;
const lastSync = this.lastSyncTimes.get(cacheKey) || 0;
const now = Date.now();
if (now - lastSync < this.SYNC_DEBOUNCE_MS) {
// Return cached result if we fetched recently
return (this as any)[cacheKey] || [];
}
const endpoint = `/sync/history/episodes?page=${page}&limit=${limit}`;
try {
const data = await this.apiRequest<any[]>(endpoint, 'GET');
(this as any)[cacheKey] = data;
this.lastSyncTimes.set(cacheKey, now);
return data;
} catch (error) {
logger.error('[TraktService] Failed to fetch watched episodes history:', error);
return [];
}
}
}
// Export a singleton instance