chore: init repository with project sources

This commit is contained in:
2025-10-30 10:29:33 +01:00
commit 65f1175ba7
97 changed files with 7762 additions and 0 deletions
@@ -0,0 +1,57 @@
import '../../../core/status.dart';
class EpisodeItem {
final int id;
final int episodeNumber;
final int seasonNumber;
final String showName;
final String? name;
final ItemStatus status;
final String? resolution;
final int? firstAirYear;
final String? showJson;
final String? showStatus;
final bool? showCliffhanger;
final String? posterPath;
EpisodeItem({
required this.id,
required this.episodeNumber,
required this.seasonNumber,
required this.showName,
this.name,
required this.status,
this.resolution,
this.firstAirYear,
this.showJson,
this.showStatus,
this.showCliffhanger,
this.posterPath,
});
factory EpisodeItem.fromJson(Map<String, dynamic> j) => EpisodeItem(
id: j['id'] as int,
episodeNumber: j['episode_number'] as int,
seasonNumber: j['season_number'] as int,
showName: j['show_name'] as String,
name: j['name'] as String?,
status: statusFromString(j['status'] as String?),
resolution: j['resolution'] as String?,
firstAirYear: j['first_air_year'] as int?,
showJson: j['show_json'] as String?,
showStatus: j['show_status'] as String?,
showCliffhanger: _parseBool(j['show_cliffhanger']),
posterPath: j['poster_path'] as String?,
);
static bool? _parseBool(dynamic v) {
if (v == null) return null;
if (v is bool) return v;
if (v is num) return v != 0;
if (v is String) {
final s = v.toLowerCase();
return s == '1' || s == 'true' || s == 'yes';
}
return null;
}
}
@@ -0,0 +1,40 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../shared/providers.dart';
import '../../../core/status.dart';
import 'episode_model.dart';
final episodeFilterProvider = StateProvider<ItemStatus?>((_) => null);
final seriesGroupedProvider =
FutureProvider.autoDispose<SeriesGroupedData>((ref) async {
final backend = ref.watch(backendApiProvider);
final st = ref.watch(episodeFilterProvider);
final rows = await backend.getEpisodes(status: st?.name, limit: 5000);
final items = rows
.map(EpisodeItem.fromJson)
.where((e) => e.seasonNumber > 0)
.toList();
return SeriesGroupedData.fromEpisodes(items);
});
class SeriesGroupedData {
final Map<String, Map<int, List<EpisodeItem>>>
data; // showName -> season -> episodes
SeriesGroupedData(this.data);
factory SeriesGroupedData.fromEpisodes(List<EpisodeItem> items) {
final map = <String, Map<int, List<EpisodeItem>>>{};
for (final e in items) {
final bySeason =
map.putIfAbsent(e.showName, () => <int, List<EpisodeItem>>{});
final list = bySeason.putIfAbsent(e.seasonNumber, () => <EpisodeItem>[]);
list.add(e);
}
for (final bySeason in map.values) {
for (final eps in bySeason.values) {
eps.sort((a, b) => a.episodeNumber.compareTo(b.episodeNumber));
}
}
return SeriesGroupedData(map);
}
}