fix(mal): enforce strict season-aware matching for episodes

- Removed the fallback to the show-level malId (which often points to Season 1) during scrobbling.
- Prioritized ARM/TMDB date-based mapping in watchedService and MalSync.
- Enabled tmdbId mapping when marking an entire season as watched in SeriesContent.tsx to ensure accurate season resolution on MyAnimeList.
This commit is contained in:
paregi12 2026-03-19 23:55:22 +05:30
parent 77ce6568d7
commit ea4ae8b421
3 changed files with 17 additions and 19 deletions

View file

@ -724,18 +724,21 @@ const SeriesContentComponent: React.FC<SeriesContentProps> = ({
const lastEp = Math.max(...episodeNumbers); const lastEp = Math.max(...episodeNumbers);
const lastEpisodeData = seasonEpisodes.find(e => e.episode_number === lastEp); const lastEpisodeData = seasonEpisodes.find(e => e.episode_number === lastEp);
const totalEpisodes = Object.values(groupedEpisodes).reduce((acc, curr) => acc + (curr?.length || 0), 0); const totalEpisodes = Object.values(groupedEpisodes).reduce((acc, curr) => acc + (curr?.length || 0), 0);
const showTmdbId = (metadata as any)?.tmdbId || (metadata as any)?.external_ids?.tmdb_id;
MalSync.scrobbleEpisode( MalSync.scrobbleEpisode(
metadata.name, metadata.name,
lastEp, lastEp,
totalEpisodes, totalEpisodes,
'series', 'series',
currentSeason, currentSeason,
imdbId, imdbId,
lastEpisodeData?.air_date // Pass release date for accuracy lastEpisodeData?.air_date, // Pass release date for accuracy
undefined, // Don't pass the base show malId, force it to resolve correct season
undefined, // No dayIndex for season completion
showTmdbId
); );
} }
// Re-sync with source of truth // Re-sync with source of truth
loadEpisodesProgress(); loadEpisodesProgress();

View file

@ -194,11 +194,11 @@ export const MalSync = {
return; return;
} }
let malId: number | null = providedMalId || null; let malId: number | null = null;
let finalEpisodeNumber = episodeNumber; let finalEpisodeNumber = episodeNumber;
// Strategy 1: TMDB-based Resolution (High Accuracy for Specials) // Strategy 1: TMDB-based Resolution (High Accuracy for Specials/Seasons)
if (!malId && tmdbId && releaseDate) { if (tmdbId && releaseDate) {
const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex); const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex);
if (tmdbResult) { if (tmdbResult) {
malId = tmdbResult.malId; malId = tmdbResult.malId;
@ -296,11 +296,11 @@ export const MalSync = {
try { try {
if (!MalAuth.isAuthenticated()) return; if (!MalAuth.isAuthenticated()) return;
let malId: number | null = providedMalId || null; let malId: number | null = null;
let finalEpisodeNumber = episodeNumber; let finalEpisodeNumber = episodeNumber;
// Resolve ID using same strategies as scrobbling // Resolve ID using same strategies as scrobbling
if (!malId && tmdbId && releaseDate) { if (tmdbId && releaseDate) {
const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex); const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex);
if (tmdbResult) { if (tmdbResult) {
malId = tmdbResult.malId; malId = tmdbResult.malId;

View file

@ -332,15 +332,10 @@ class WatchedService {
// Sync to MAL // Sync to MAL
if (MalAuth.isAuthenticated() && (showImdbId || malId || tmdbId)) { if (MalAuth.isAuthenticated() && (showImdbId || malId || tmdbId)) {
// Strategy 0: Direct Match (if malId is provided)
let synced = false; let synced = false;
if (malId) {
await MalSync.scrobbleDirect(malId, episode);
synced = true;
}
// Strategy 1: TMDB-based Resolution (High Accuracy for Specials) // Strategy 1: TMDB-based Resolution (High Accuracy for Specials)
if (!synced && releaseDate && tmdbId) { if (releaseDate && tmdbId) {
try { try {
const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex); const tmdbResult = await ArmSyncService.resolveByTmdb(tmdbId, releaseDate, dayIndex);
if (tmdbResult) { if (tmdbResult) {