mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-20 09:47:31 +00:00
feat(intro): add date-based MAL ID resolution for accurate intro skipping
Implements robust season and episode mapping using ArmSyncService in introService. Updates SkipIntroButton and player components to pass releaseDate for precise AniSkip lookups, fixing mismatches for multi-season anime.
This commit is contained in:
parent
02da43e21c
commit
dd330a1786
4 changed files with 28 additions and 7 deletions
|
|
@ -1022,6 +1022,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
episode={episode}
|
||||
malId={(metadata as any)?.mal_id || (metadata as any)?.external_ids?.mal_id}
|
||||
kitsuId={id?.startsWith('kitsu:') ? id.split(':')[1] : undefined}
|
||||
releaseDate={releaseDate}
|
||||
currentTime={playerState.currentTime}
|
||||
onSkip={(endTime) => controlsHook.seekToTime(endTime)}
|
||||
controlsVisible={playerState.showControls}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
const {
|
||||
uri, title, episodeTitle, season, episode, id, type, quality, year,
|
||||
episodeId, imdbId, backdrop, availableStreams,
|
||||
headers, streamProvider, streamName,
|
||||
headers, streamProvider, streamName, releaseDate,
|
||||
initialPosition: routeInitialPosition
|
||||
} = params;
|
||||
|
||||
|
|
@ -998,6 +998,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
episode={episode}
|
||||
malId={(metadata as any)?.mal_id || (metadata as any)?.external_ids?.mal_id}
|
||||
kitsuId={id?.startsWith('kitsu:') ? id.split(':')[1] : undefined}
|
||||
releaseDate={releaseDate}
|
||||
currentTime={currentTime}
|
||||
onSkip={(endTime) => controls.seekToTime(endTime)}
|
||||
controlsVisible={showControls}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ interface SkipIntroButtonProps {
|
|||
episode?: number;
|
||||
malId?: string;
|
||||
kitsuId?: string;
|
||||
releaseDate?: string;
|
||||
currentTime: number;
|
||||
onSkip: (endTime: number) => void;
|
||||
controlsVisible?: boolean;
|
||||
|
|
@ -35,6 +36,7 @@ export const SkipIntroButton: React.FC<SkipIntroButtonProps> = ({
|
|||
episode,
|
||||
malId,
|
||||
kitsuId,
|
||||
releaseDate,
|
||||
currentTime,
|
||||
onSkip,
|
||||
controlsVisible = false,
|
||||
|
|
@ -96,7 +98,7 @@ export const SkipIntroButton: React.FC<SkipIntroButtonProps> = ({
|
|||
const fetchSkipData = async () => {
|
||||
logger.log(`[SkipIntroButton] Fetching skip data for S${season}E${episode} (IMDB: ${imdbId}, MAL: ${malId}, Kitsu: ${kitsuId})...`);
|
||||
try {
|
||||
const intervals = await introService.getSkipTimes(imdbId, season, episode, malId, kitsuId);
|
||||
const intervals = await introService.getSkipTimes(imdbId, season, episode, malId, kitsuId, releaseDate);
|
||||
setSkipIntervals(intervals);
|
||||
|
||||
if (intervals.length > 0) {
|
||||
|
|
@ -111,7 +113,7 @@ export const SkipIntroButton: React.FC<SkipIntroButtonProps> = ({
|
|||
};
|
||||
|
||||
fetchSkipData();
|
||||
}, [imdbId, type, season, episode, malId, kitsuId, skipIntroEnabled]);
|
||||
}, [imdbId, type, season, episode, malId, kitsuId, releaseDate, skipIntroEnabled]);
|
||||
|
||||
// Determine active interval based on current playback position
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import axios from 'axios';
|
||||
import { logger } from '../utils/logger';
|
||||
import { tmdbService } from './tmdbService';
|
||||
import { ArmSyncService } from './mal/ArmSyncService';
|
||||
|
||||
/**
|
||||
* IntroDB API service for fetching TV show intro timestamps
|
||||
|
|
@ -195,7 +196,8 @@ export async function getSkipTimes(
|
|||
season: number,
|
||||
episode: number,
|
||||
malId?: string,
|
||||
kitsuId?: string
|
||||
kitsuId?: string,
|
||||
releaseDate?: string
|
||||
): Promise<SkipInterval[]> {
|
||||
// 1. Try IntroDB (TV Shows) first
|
||||
if (imdbId) {
|
||||
|
|
@ -207,7 +209,22 @@ export async function getSkipTimes(
|
|||
|
||||
// 2. Try AniSkip (Anime) if we have MAL ID or Kitsu ID
|
||||
let finalMalId = malId;
|
||||
let finalEpisode = episode;
|
||||
|
||||
// If we have IMDb ID and Release Date, try ArmSyncService to resolve exact MAL ID and Episode
|
||||
if (!finalMalId && imdbId && releaseDate) {
|
||||
try {
|
||||
const armResult = await ArmSyncService.resolveByDate(imdbId, releaseDate);
|
||||
if (armResult) {
|
||||
finalMalId = armResult.malId.toString();
|
||||
finalEpisode = armResult.episode;
|
||||
logger.log(`[IntroService] ArmSync resolved: MAL ${finalMalId} Ep ${finalEpisode}`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn('[IntroService] ArmSync failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have Kitsu ID but no MAL ID, try to resolve it
|
||||
if (!finalMalId && kitsuId) {
|
||||
logger.log(`[IntroService] Resolving MAL ID from Kitsu ID: ${kitsuId}`);
|
||||
|
|
@ -228,8 +245,8 @@ export async function getSkipTimes(
|
|||
}
|
||||
|
||||
if (finalMalId) {
|
||||
logger.log(`[IntroService] Fetching AniSkip for MAL ID: ${finalMalId} Ep: ${episode}`);
|
||||
const aniSkipIntervals = await fetchFromAniSkip(finalMalId, episode);
|
||||
logger.log(`[IntroService] Fetching AniSkip for MAL ID: ${finalMalId} Ep: ${finalEpisode}`);
|
||||
const aniSkipIntervals = await fetchFromAniSkip(finalMalId, finalEpisode);
|
||||
if (aniSkipIntervals.length > 0) {
|
||||
logger.log(`[IntroService] Found ${aniSkipIntervals.length} skip intervals from AniSkip`);
|
||||
return aniSkipIntervals;
|
||||
|
|
@ -269,4 +286,4 @@ export const introService = {
|
|||
getSkipTimes
|
||||
};
|
||||
|
||||
export default introService;
|
||||
export default introService;
|
||||
Loading…
Reference in a new issue