Files
venera/lib/foundation/follow_updates.dart
2025-09-01 20:54:11 +08:00

163 lines
4.2 KiB
Dart

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<ComicUpdateResult> 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 = <String>[];
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<UpdateProgress> 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 = <FavoriteItemWithUpdateInfo>[];
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 = <Future>[];
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<UpdateProgress> updateFolder(String folder, bool ignoreCheckTime) {
var stream = StreamController<UpdateProgress>();
updateFolderBase(folder, stream, ignoreCheckTime);
return stream.stream;
}
Future<String> 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);
}