import 'dart:async'; import 'dart:convert'; import 'package:venera/foundation/favorites.dart'; import 'package:venera/foundation/log.dart'; class ComicUpdateResult { final bool updated; final String? errorMessage; ComicUpdateResult(this.updated, this.errorMessage); } Future updateComic( FavoriteItemWithUpdateInfo c, String folder) async { int retries = 3; while (true) { try { var comicSource = c.type.comicSource; if (comicSource == null) { return ComicUpdateResult(false, "Comic source not found"); } var newInfo = (await comicSource.loadComicInfo!(c.id)).data; var newTags = []; for (var entry in newInfo.tags.entries) { const shouldIgnore = ['author', 'artist', 'time']; var namespace = entry.key; if (shouldIgnore.contains(namespace.toLowerCase())) { continue; } for (var tag in entry.value) { newTags.add("$namespace:$tag"); } } var item = FavoriteItem( id: c.id, name: newInfo.title, coverPath: newInfo.cover, author: newInfo.subTitle ?? newInfo.tags['author']?.firstOrNull ?? c.author, type: c.type, tags: newTags, ); LocalFavoritesManager().updateInfo(folder, item, false); var updated = false; var updateTime = newInfo.findUpdateTime(); if (updateTime != null && updateTime != c.updateTime) { LocalFavoritesManager().updateUpdateTime( folder, c.id, c.type, updateTime, ); updated = true; } else { LocalFavoritesManager().updateCheckTime(folder, c.id, c.type); } return ComicUpdateResult(updated, null); } catch (e, s) { Log.error("Check Updates", e, s); retries--; if (retries == 0) { return ComicUpdateResult(false, e.toString()); } } } } class UpdateProgress { final int total; final int current; final int errors; final int updated; final FavoriteItemWithUpdateInfo? comic; final String? errorMessage; UpdateProgress(this.total, this.current, this.errors, this.updated, [this.comic, this.errorMessage]); } void updateFolderBase( String folder, StreamController stream, bool ignoreCheckTime, ) async { var comics = LocalFavoritesManager().getComicsWithUpdatesInfo(folder); int total = comics.length; int current = 0; int errors = 0; int updated = 0; stream.add(UpdateProgress(total, current, errors, updated)); var comicsToUpdate = []; for (var comic in comics) { if (!ignoreCheckTime) { var lastCheckTime = comic.lastCheckTime; if (lastCheckTime != null && DateTime.now().difference(lastCheckTime).inDays < 1) { current++; stream.add(UpdateProgress(total, current, errors, updated)); continue; } } comicsToUpdate.add(comic); } total = comicsToUpdate.length; current = 0; stream.add(UpdateProgress(total, current, errors, updated)); var futures = []; for (var comic in comicsToUpdate) { var future = updateComic(comic, folder).then((result) { current++; if (result.updated) { updated++; } if (result.errorMessage != null) { errors++; } stream.add( UpdateProgress(total, current, errors, updated, comic, result.errorMessage)); }); futures.add(future); } await Future.wait(futures); if (updated > 0) { LocalFavoritesManager().notifyChanges(); } stream.close(); } Stream updateFolder(String folder, bool ignoreCheckTime) { var stream = StreamController(); updateFolderBase(folder, stream, ignoreCheckTime); return stream.stream; } Future getUpdatedComicsAsJson(String folder) async { var comics = LocalFavoritesManager().getComicsWithUpdatesInfo(folder); var updatedComics = comics.where((c) => c.hasNewUpdate).toList(); var jsonList = updatedComics.map((c) => { 'id': c.id, 'name': c.name, 'coverUrl': c.coverPath, 'author': c.author, 'type': c.type.sourceKey, 'updateTime': c.updateTime, 'tags': c.tags, }).toList(); return jsonEncode(jsonList); }