Schedule: remove the per-user follow (bookmark, Following filter, AnimeFlow follow calls)
Personal tracking will come from the user's AniList lists; AnimeFlow keeps downloads, availability and requests only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
473c82ec0a
commit
f23cc7b311
8 files changed
+22
-130
No files matched your search
@@ -29,7 +29,6 @@ final seriesJson = {
|
||||
'jellyfin_series_id': 'jf7',
|
||||
'state': 'released',
|
||||
'monitored': true,
|
||||
'followed': true,
|
||||
'episodes_total': 24,
|
||||
'episodes_available': 20,
|
||||
'next_air_date': null,
|
||||
@@ -110,7 +109,7 @@ void main() {
|
||||
'to': req.uri.queryParameters['to'],
|
||||
'items': [
|
||||
{...episodeJson, 'series_id': 7, 'title': 'Show', 'anidb_id': 70, 'tvdb_id': 700,
|
||||
'jellyfin_series_id': 'jf7', 'followed': true},
|
||||
'jellyfin_series_id': 'jf7'},
|
||||
],
|
||||
}, etag: 'W/"s1"');
|
||||
},
|
||||
@@ -126,7 +125,6 @@ void main() {
|
||||
expect(it.anidbId, 70);
|
||||
expect(it.tvdbId, 700);
|
||||
expect(it.jellyfinSeriesId, 'jf7');
|
||||
expect(it.followed, isTrue);
|
||||
final e = it.episode;
|
||||
expect((e.season, e.episode, e.absolute, e.title, e.anilistId), (2, 3, 15, 'Three', 222));
|
||||
expect(e.airDate, DateTime.utc(2026, 10, 8, 19, 36, 32));
|
||||
@@ -146,7 +144,7 @@ void main() {
|
||||
expect(server.seen, isEmpty);
|
||||
});
|
||||
|
||||
test('/series, /series/{id} with episodes, follow/unfollow', () async {
|
||||
test('/series, /series/{id} with episodes', () async {
|
||||
await serve({
|
||||
'GET /series': (req, res) async => json(res, {'items': [seriesJson]}, etag: 'W/"a"'),
|
||||
'GET /series/7': (req, res) async => json(res, {
|
||||
@@ -156,24 +154,18 @@ void main() {
|
||||
{'season': 1, 'episode': 1, 'status': 'failed', 'reason': 'No release'},
|
||||
],
|
||||
}),
|
||||
'PUT /series/7/follow': (req, res) async => res.statusCode = 204,
|
||||
'DELETE /series/7/follow': (req, res) async => res.statusCode = 204,
|
||||
});
|
||||
final c = client();
|
||||
final s = (await c.series()).single;
|
||||
expect(s.seriesId, 7);
|
||||
expect(s.anilistId, 111);
|
||||
expect(s.state, SeriesState.released);
|
||||
expect(s.monitored && s.followed, isTrue);
|
||||
expect(s.monitored, isTrue);
|
||||
expect((s.episodesTotal, s.episodesAvailable, s.nextAirDate), (24, 20, null));
|
||||
final d = await c.seriesDetail(7);
|
||||
expect(d.episodes.map((e) => e.season), [0, 1]);
|
||||
expect(d.episodes.last.status, EpisodeStatus.failed);
|
||||
expect(d.episodes.last.reason, 'No release');
|
||||
await c.setFollowed(7, true);
|
||||
await c.setFollowed(7, false);
|
||||
expect(server.seen.skip(2).map((r) => '${r.method} ${r.uri.path}'),
|
||||
['PUT /api/app/v1/series/7/follow', 'DELETE /api/app/v1/series/7/follow']);
|
||||
});
|
||||
|
||||
test('/search and the three request bodies', () async {
|
||||
|
||||
@@ -20,7 +20,7 @@ Airing airing(int id, int ep, DateTime local) => Airing(
|
||||
);
|
||||
|
||||
AnimeFlowScheduleItem item(int? anilistId, int ep, EpisodeStatus status,
|
||||
{int season = 1, int? absolute, DateTime? air, int seriesId = 7, bool followed = false,
|
||||
{int season = 1, int? absolute, DateTime? air, int seriesId = 7,
|
||||
double? progress, String? reason}) =>
|
||||
AnimeFlowScheduleItem(
|
||||
episode: AnimeFlowEpisode(
|
||||
@@ -36,7 +36,6 @@ AnimeFlowScheduleItem item(int? anilistId, int ep, EpisodeStatus status,
|
||||
seriesId: seriesId,
|
||||
title: 'Show',
|
||||
jellyfinSeriesId: 'jf$seriesId',
|
||||
followed: followed,
|
||||
);
|
||||
|
||||
void main() {
|
||||
@@ -150,7 +149,7 @@ void main() {
|
||||
[airing(100, 3, DateTime(2026, 10, 1, 20)), airing(200, 3, DateTime(2026, 10, 9, 20))],
|
||||
schedule: [
|
||||
item(100, 3, EpisodeStatus.available, season: 1),
|
||||
item(200, 3, EpisodeStatus.downloading, season: 2, progress: 0.4, followed: true),
|
||||
item(200, 3, EpisodeStatus.downloading, season: 2, progress: 0.4),
|
||||
],
|
||||
series: [const AnimeFlowSeries(seriesId: 7, title: 'Show', anilistId: 100, jellyfinSeriesId: 'jf7')],
|
||||
now: now,
|
||||
@@ -158,7 +157,6 @@ void main() {
|
||||
expect(out.map((e) => e.status), [ScheduleStatus.available, ScheduleStatus.downloading]);
|
||||
expect(out.map((e) => e.season), [1, 2]);
|
||||
expect(out[1].progress, 0.4);
|
||||
expect(out[1].followed, isTrue);
|
||||
expect(out.every((e) => e.tracked && e.seriesId == 7 && e.jellyfinSeriesId == 'jf7'), isTrue);
|
||||
});
|
||||
|
||||
@@ -205,11 +203,11 @@ void main() {
|
||||
final out = matchSchedule(
|
||||
[airing(500, 2, DateTime(2026, 10, 7, 20)), airing(500, 3, DateTime(2026, 10, 14, 20))],
|
||||
schedule: const [],
|
||||
series: [const AnimeFlowSeries(seriesId: 9, title: 'S', anilistId: 500, followed: true)],
|
||||
series: [const AnimeFlowSeries(seriesId: 9, title: 'S', anilistId: 500)],
|
||||
now: now,
|
||||
);
|
||||
expect(out.map((e) => e.status), [ScheduleStatus.missing, ScheduleStatus.upcoming]);
|
||||
expect(out.every((e) => e.followed && e.seriesId == 9), isTrue);
|
||||
expect(out.every((e) => e.seriesId == 9), isTrue);
|
||||
});
|
||||
|
||||
test('progress only while downloading, reason only when failed', () {
|
||||
@@ -271,7 +269,7 @@ void main() {
|
||||
return json(res, {
|
||||
'items': [
|
||||
{'season': 1, 'episode': 3, 'anilist_id': 100, 'status': 'available', 'series_id': 7,
|
||||
'title': 'Show', 'followed': false},
|
||||
'title': 'Show'},
|
||||
],
|
||||
});
|
||||
case '/flow/series':
|
||||
|
||||
@@ -88,7 +88,6 @@ List<ScheduleEntry> entries() => [
|
||||
airing: airing(111, 'Avail Show', 3, day(0, 9)),
|
||||
status: ScheduleStatus.available,
|
||||
tracked: true,
|
||||
followed: true,
|
||||
seriesId: 7,
|
||||
season: 1,
|
||||
jellyfinSeriesId: 'jf7',
|
||||
@@ -201,8 +200,6 @@ void main() {
|
||||
});
|
||||
case ('GET', '/search'):
|
||||
json(res, {'items': searchHits});
|
||||
case ('PUT' || 'DELETE', '/series/7/follow'):
|
||||
res.statusCode = 204;
|
||||
case ('POST', '/requests/1/approve' || '/requests/2/reject'):
|
||||
json(res, {});
|
||||
default:
|
||||
@@ -298,13 +295,9 @@ void main() {
|
||||
await done(tester);
|
||||
});
|
||||
|
||||
testWidgets('filters: following, all airing, niche too, compact', (tester) async {
|
||||
testWidgets('filters: all airing, niche too, compact', (tester) async {
|
||||
await pumpPage(tester);
|
||||
await tester.tap(find.text('Following'));
|
||||
await tester.pump();
|
||||
expect(card(111, 3), findsOneWidget);
|
||||
expect(card(222, 5), findsNothing);
|
||||
|
||||
expect(find.text('Following'), findsNothing);
|
||||
await tester.tap(find.text('All airing'));
|
||||
await tester.pump();
|
||||
expect(card(444, 1), findsOneWidget);
|
||||
@@ -398,15 +391,6 @@ void main() {
|
||||
await done(tester);
|
||||
});
|
||||
|
||||
testWidgets('follow toggles through AnimeFlow', (tester) async {
|
||||
final repo = await pumpPage(tester);
|
||||
await tester.tap(find.byKey(const ValueKey('follow-111-3')));
|
||||
await io(tester);
|
||||
expect(server.seen.where((r) => r.method == 'DELETE' && r.uri.path.endsWith('/series/7/follow')), hasLength(1));
|
||||
expect(repo.forced.length, greaterThanOrEqualTo(2)); // reloaded
|
||||
await done(tester);
|
||||
});
|
||||
|
||||
testWidgets('put it up resolves the Jellyfin episode', (tester) async {
|
||||
final jf = FakeJf();
|
||||
final accounts = JellyfinAccounts(
|
||||
|
||||
Reference in new issue
Block a user