Schedule: "waiting · searched N min ago" and "release rejected" (with AnimeFlow's reason) from its new episode fields
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a407d3cbb0
commit
572104f49e
5 files changed
+37
-7
No files matched your search
@@ -210,7 +210,8 @@ marked with what the Jellyfin server has of it when AnimeFlow is
|
|||||||
connected (Settings, Jellyfin & integrations): **on Jellyfin** (Put it
|
connected (Settings, Jellyfin & integrations): **on Jellyfin** (Put it
|
||||||
up, right-click to queue), **downloading**, **waiting for release**
|
up, right-click to queue), **downloading**, **waiting for release**
|
||||||
(aired in Japan, AnimeFlow downloads it by itself once a release
|
(aired in Japan, AnimeFlow downloads it by itself once a release
|
||||||
appears), **failed**, **not monitored** (Request asks AnimeFlow for it),
|
appears; with when AnimeFlow last searched, or **release rejected** when
|
||||||
|
it found releases it won't take, the reason on hover), **failed**, **not monitored** (Request asks AnimeFlow for it),
|
||||||
or the time left until it airs. A show AnimeFlow does not follow can be asked for with **Request
|
or the time left until it airs. A show AnimeFlow does not follow can be asked for with **Request
|
||||||
series**. Episodes you already watched on Jellyfin carry a check on the
|
series**. Episodes you already watched on Jellyfin carry a check on the
|
||||||
cover; one you started shows how far you got.
|
cover; one you started shows how far you got.
|
||||||
|
|||||||
@@ -210,8 +210,11 @@ class AnimeFlowEpisode {
|
|||||||
final EpisodeStatus status;
|
final EpisodeStatus status;
|
||||||
/// 0..1, only while downloading.
|
/// 0..1, only while downloading.
|
||||||
final double? progress;
|
final double? progress;
|
||||||
/// Only when failed.
|
/// Why it failed; for a missing one with rejected releases, a
|
||||||
|
/// ready-to-show sentence ("2 release(s) found, rejected: …").
|
||||||
final String? reason;
|
final String? reason;
|
||||||
|
/// Last search for a monitored, not yet downloaded episode.
|
||||||
|
final DateTime? lastSearchedAt;
|
||||||
|
|
||||||
const AnimeFlowEpisode({
|
const AnimeFlowEpisode({
|
||||||
required this.season,
|
required this.season,
|
||||||
@@ -224,6 +227,7 @@ class AnimeFlowEpisode {
|
|||||||
required this.status,
|
required this.status,
|
||||||
this.progress,
|
this.progress,
|
||||||
this.reason,
|
this.reason,
|
||||||
|
this.lastSearchedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
static AnimeFlowEpisode fromJson(Map j) => AnimeFlowEpisode(
|
static AnimeFlowEpisode fromJson(Map j) => AnimeFlowEpisode(
|
||||||
@@ -239,6 +243,7 @@ class AnimeFlowEpisode {
|
|||||||
status: EpisodeStatus.parse(j['status']),
|
status: EpisodeStatus.parse(j['status']),
|
||||||
progress: (j['progress'] as num?)?.toDouble(),
|
progress: (j['progress'] as num?)?.toDouble(),
|
||||||
reason: _str(j['reason']),
|
reason: _str(j['reason']),
|
||||||
|
lastSearchedAt: _time(j['last_searched_at']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,10 @@ class ScheduleEntry {
|
|||||||
final ScheduleStatus status;
|
final ScheduleStatus status;
|
||||||
/// 0..1 while downloading.
|
/// 0..1 while downloading.
|
||||||
final double? progress;
|
final double? progress;
|
||||||
/// Why it failed.
|
/// Why it failed, or (missing) why the releases found were rejected.
|
||||||
final String? reason;
|
final String? reason;
|
||||||
|
/// AnimeFlow's last search for it (missing).
|
||||||
|
final DateTime? lastSearchedAt;
|
||||||
/// AnimeFlow tracks the series.
|
/// AnimeFlow tracks the series.
|
||||||
final bool tracked;
|
final bool tracked;
|
||||||
/// AnimeFlow's series id (requests).
|
/// AnimeFlow's series id (requests).
|
||||||
@@ -74,6 +76,7 @@ class ScheduleEntry {
|
|||||||
required this.status,
|
required this.status,
|
||||||
this.progress,
|
this.progress,
|
||||||
this.reason,
|
this.reason,
|
||||||
|
this.lastSearchedAt,
|
||||||
this.tracked = false,
|
this.tracked = false,
|
||||||
this.seriesId,
|
this.seriesId,
|
||||||
this.season,
|
this.season,
|
||||||
@@ -87,6 +90,7 @@ class ScheduleEntry {
|
|||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
reason: reason,
|
reason: reason,
|
||||||
|
lastSearchedAt: lastSearchedAt,
|
||||||
tracked: tracked,
|
tracked: tracked,
|
||||||
seriesId: seriesId,
|
seriesId: seriesId,
|
||||||
season: season,
|
season: season,
|
||||||
@@ -231,7 +235,8 @@ List<ScheduleEntry> matchSchedule(
|
|||||||
airing: a,
|
airing: a,
|
||||||
status: ScheduleStatus.of(e.status),
|
status: ScheduleStatus.of(e.status),
|
||||||
progress: e.status == EpisodeStatus.downloading ? e.progress : null,
|
progress: e.status == EpisodeStatus.downloading ? e.progress : null,
|
||||||
reason: e.status == EpisodeStatus.failed ? e.reason : null,
|
reason: e.status == EpisodeStatus.failed || e.status == EpisodeStatus.missing ? e.reason : null,
|
||||||
|
lastSearchedAt: e.lastSearchedAt,
|
||||||
tracked: true,
|
tracked: true,
|
||||||
seriesId: it.seriesId,
|
seriesId: it.seriesId,
|
||||||
season: e.season,
|
season: e.season,
|
||||||
|
|||||||
@@ -42,9 +42,21 @@ bool _waiting(ScheduleEntry e, DateTime now) =>
|
|||||||
|
|
||||||
const waitingHint = 'Aired in Japan; downloads automatically when a release appears';
|
const waitingHint = 'Aired in Japan; downloads automatically when a release appears';
|
||||||
|
|
||||||
|
String _ago(DateTime t, DateTime now) {
|
||||||
|
final m = now.difference(t).inMinutes;
|
||||||
|
return m < 1 ? 'just now' : m < 60 ? '$m min ago' : '${m ~/ 60} h ago';
|
||||||
|
}
|
||||||
|
|
||||||
/// Status line: text, colour, icon.
|
/// Status line: text, colour, icon.
|
||||||
(String, Color, IconData) statusBadge(ScheduleEntry e, DateTime now) => _waiting(e, now)
|
(String, Color, IconData) statusBadge(ScheduleEntry e, DateTime now) => _waiting(e, now)
|
||||||
? ('waiting for release', Colors.amber.shade200, Icons.hourglass_top)
|
? e.reason != null
|
||||||
|
// Releases exist but AnimeFlow rejected them (the hint says why).
|
||||||
|
? ('release rejected', Colors.orangeAccent, Icons.block)
|
||||||
|
: (
|
||||||
|
e.lastSearchedAt == null ? 'waiting for release' : 'waiting · searched ${_ago(e.lastSearchedAt!, now)}',
|
||||||
|
Colors.amber.shade200,
|
||||||
|
Icons.hourglass_top,
|
||||||
|
)
|
||||||
: switch (e.status) {
|
: switch (e.status) {
|
||||||
ScheduleStatus.available => ('on Jellyfin', Colors.greenAccent, Icons.check_circle),
|
ScheduleStatus.available => ('on Jellyfin', Colors.greenAccent, Icons.check_circle),
|
||||||
ScheduleStatus.downloading => (
|
ScheduleStatus.downloading => (
|
||||||
@@ -67,7 +79,11 @@ const waitingHint = 'Aired in Japan; downloads automatically when a release appe
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// What the status line means, when its text alone does not say.
|
/// What the status line means, when its text alone does not say.
|
||||||
String? statusHint(ScheduleEntry e, DateTime now) => _waiting(e, now) ? waitingHint : null;
|
String? statusHint(ScheduleEntry e, DateTime now) => !_waiting(e, now)
|
||||||
|
? null
|
||||||
|
: e.reason != null
|
||||||
|
? '${e.reason}${e.lastSearchedAt == null ? '' : ' · searched ${_ago(e.lastSearchedAt!, now)}'}'
|
||||||
|
: waitingHint;
|
||||||
|
|
||||||
class DayColumn extends StatelessWidget {
|
class DayColumn extends StatelessWidget {
|
||||||
final DateTime day;
|
final DateTime day;
|
||||||
|
|||||||
@@ -1188,7 +1188,10 @@ panel) and chat messages (Copy message, and a link in it).
|
|||||||
episode (`schedule_model.dart`). AnimeFlow's `missing` (aired,
|
episode (`schedule_model.dart`). AnimeFlow's `missing` (aired,
|
||||||
monitored, no release grabbed yet; AnimeFlow grabs it by itself once
|
monitored, no release grabbed yet; AnimeFlow grabs it by itself once
|
||||||
one appears), and its `upcoming` past the AniList air time, read
|
one appears), and its `upcoming` past the AniList air time, read
|
||||||
"waiting for release"; Request is offered only for an `unmonitored`
|
"waiting for release" (with "searched N min ago" from the episode's
|
||||||
|
`last_searched_at`, or "release rejected" with AnimeFlow's `reason`
|
||||||
|
sentence on hover when it found releases it won't take); Request is
|
||||||
|
offered only for an `unmonitored`
|
||||||
episode (and "Request series" for a show AnimeFlow does not track).
|
episode (and "Request series" for a show AnimeFlow does not track).
|
||||||
Air dates (AnimeFlow's `air_date`, midnight Japan time; Jellyfin's
|
Air dates (AnimeFlow's `air_date`, midnight Japan time; Jellyfin's
|
||||||
premiere date)
|
premiere date)
|
||||||
|
|||||||
Reference in new issue
Block a user