perf(mal): parallelize library sync and fix movie scrobbling title fallback

This commit is contained in:
paregi12 2026-03-12 16:35:40 +05:30
parent c9fd5438b4
commit dad5beee67
4 changed files with 47 additions and 24 deletions

View file

@ -40,6 +40,7 @@ const MalSettingsScreen: React.FC = () => {
const [autoUpdateEnabled, setAutoUpdateEnabled] = useState(mmkvStorage.getBoolean('mal_auto_update') ?? true);
const [autoAddEnabled, setAutoAddEnabled] = useState(mmkvStorage.getBoolean('mal_auto_add') ?? true);
const [autoLibrarySyncEnabled, setAutoLibrarySyncEnabled] = useState(mmkvStorage.getBoolean('mal_auto_sync_to_library') ?? false);
const [includeNsfwEnabled, setIncludeNsfwEnabled] = useState(mmkvStorage.getBoolean('mal_include_nsfw') ?? true);
const [alertVisible, setAlertVisible] = useState(false);
const [alertTitle, setAlertTitle] = useState('');
@ -145,6 +146,11 @@ const MalSettingsScreen: React.FC = () => {
mmkvStorage.setBoolean('mal_auto_sync_to_library', val);
};
const toggleIncludeNsfw = (val: boolean) => {
setIncludeNsfwEnabled(val);
mmkvStorage.setBoolean('mal_include_nsfw', val);
};
return (
<SafeAreaView style={[
styles.container,
@ -411,6 +417,25 @@ const MalSettingsScreen: React.FC = () => {
/>
</View>
</View>
<View style={styles.settingItem}>
<View style={styles.settingContent}>
<View style={styles.settingTextContainer}>
<Text style={[styles.settingLabel, { color: currentTheme.colors.highEmphasis }]}>
Include NSFW Content
</Text>
<Text style={[styles.settingDescription, { color: currentTheme.colors.mediumEmphasis }]}>
Allow NSFW entries to be returned when fetching your MAL list.
</Text>
</View>
<Switch
value={includeNsfwEnabled}
onValueChange={toggleIncludeNsfw}
trackColor={{ false: currentTheme.colors.border, true: currentTheme.colors.primary + '80' }}
thumbColor={includeNsfwEnabled ? currentTheme.colors.white : currentTheme.colors.mediumEmphasis}
/>
</View>
</View>
</View>
</View>
)}

View file

@ -1,4 +1,5 @@
import axios from 'axios';
import { mmkvStorage } from '../mmkvStorage';
import { MalAuth } from './MalAuth';
import { MalAnimeNode, MalListStatus, MalUserListResponse, MalSearchResult, MalUser } from '../../types/mal';
@ -39,7 +40,7 @@ export const MalApiService = {
limit,
offset,
sort: 'list_updated_at',
nsfw: true // Ensure all content is returned
nsfw: mmkvStorage.getBoolean('mal_include_nsfw') ?? true
},
});
return response.data;

View file

@ -372,34 +372,31 @@ export const MalSync = {
const response = await MalApiService.getUserList('watching', 0, 50);
if (!response.data || response.data.length === 0) return;
for (const item of response.data) {
const currentLibrary = await catalogService.getLibraryItems();
const libraryIds = new Set(currentLibrary.map(l => l.id));
// Process items in parallel
await Promise.all(response.data.map(async (item) => {
const malId = item.node.id;
const { imdbId } = await MalSync.getIdsFromMalId(malId);
if (imdbId) {
if (imdbId && !libraryIds.has(imdbId)) {
const type = item.node.media_type === 'movie' ? 'movie' : 'series';
logger.log(`[MalSync] Auto-adding to library: ${item.node.title} (${imdbId})`);
// Check if already in library to avoid redundant calls
const currentLibrary = await catalogService.getLibraryItems();
const exists = currentLibrary.some(l => l.id === imdbId);
if (!exists) {
logger.log(`[MalSync] Auto-adding to library: ${item.node.title} (${imdbId})`);
await catalogService.addToLibrary({
id: imdbId,
type: type,
name: item.node.title,
poster: item.node.main_picture?.large || item.node.main_picture?.medium || '',
posterShape: 'poster',
year: item.node.start_season?.year,
description: '',
genres: [],
inLibrary: true,
});
}
await catalogService.addToLibrary({
id: imdbId,
type: type,
name: item.node.title,
poster: item.node.main_picture?.large || item.node.main_picture?.medium || '',
posterShape: 'poster',
year: item.node.start_season?.year,
description: '',
genres: [],
inLibrary: true,
});
}
}
}));
} catch (e) {
logger.error('[MalSync] syncMalWatchingToLibrary failed:', e);
}

View file

@ -221,7 +221,7 @@ class WatchedService {
const malToken = MalAuth.getToken();
if (malToken) {
MalSync.scrobbleEpisode(
imdbId,
'', // Don't use IMDb ID as title fallback (unlikely to match)
1,
1,
'movie',