import 'package:freezed_annotation/freezed_annotation.dart'; part 'script_widget.freezed.dart'; part 'script_widget.g.dart'; @freezed abstract class ScriptWidgetOption with _$ScriptWidgetOption { const factory ScriptWidgetOption({ @Default('') String title, @JsonKey(fromJson: _stringFromAny) @Default('') String value, }) = _ScriptWidgetOption; factory ScriptWidgetOption.fromJson(Map json) => _$ScriptWidgetOptionFromJson(json); } @freezed abstract class ScriptWidgetBelongTo with _$ScriptWidgetBelongTo { const factory ScriptWidgetBelongTo({ @Default('') String paramName, @JsonKey(fromJson: _stringListFromAny) @Default([]) List value, }) = _ScriptWidgetBelongTo; factory ScriptWidgetBelongTo.fromJson(Map json) => _$ScriptWidgetBelongToFromJson(json); } @freezed abstract class ScriptWidgetParam with _$ScriptWidgetParam { const factory ScriptWidgetParam({ required String name, @Default('') String title, @Default('input') String type, @Default('') String description, Object? value, ScriptWidgetBelongTo? belongTo, @Default([]) List placeholders, @Default([]) List enumOptions, }) = _ScriptWidgetParam; factory ScriptWidgetParam.fromJson(Map json) => _$ScriptWidgetParamFromJson(json); } Map buildScriptWidgetParameterDefaults( List parameters, ) { return { for (final parameter in parameters) parameter.name: _resolveScriptWidgetParameterDefault(parameter), }; } Object? _resolveScriptWidgetParameterDefault(ScriptWidgetParam parameter) { if (parameter.value != null) return parameter.value; if (parameter.enumOptions.isNotEmpty) { return parameter.enumOptions.first.value; } if (parameter.placeholders.isNotEmpty) { return parameter.placeholders.first.value; } return ''; } @freezed abstract class ScriptWidgetModule with _$ScriptWidgetModule { const factory ScriptWidgetModule({ @Default('') String id, required String title, @Default('') String description, @Default(false) bool requiresWebView, required String functionName, @Default(false) bool sectionMode, @Default(3600) int cacheDuration, @Default('list') String type, @Default([]) List params, }) = _ScriptWidgetModule; factory ScriptWidgetModule.fromJson(Map json) => _$ScriptWidgetModuleFromJson(json); } @freezed abstract class ScriptWidgetManifest with _$ScriptWidgetManifest { const factory ScriptWidgetManifest({ required String id, required String title, @Default('') String description, @Default('') String author, @Default('') String site, @Default('0.0.0') String version, @Default('0.0.1') String requiredVersion, @Default(60) int detailCacheDuration, @Default([]) List globalParams, @Default([]) List modules, ScriptWidgetModule? search, }) = _ScriptWidgetManifest; factory ScriptWidgetManifest.fromJson(Map json) => _$ScriptWidgetManifestFromJson(json); } @freezed abstract class ScriptVideoPerson with _$ScriptVideoPerson { const factory ScriptVideoPerson({ @JsonKey(fromJson: _stringFromAny) @Default('') String id, @Default('') String title, @Default('') String avatar, @Default('') String role, }) = _ScriptVideoPerson; factory ScriptVideoPerson.fromJson(Map json) => _$ScriptVideoPersonFromJson(json); } @freezed abstract class ScriptVideoGenre with _$ScriptVideoGenre { const factory ScriptVideoGenre({ @JsonKey(fromJson: _stringFromAny) @Default('') String id, @Default('') String title, }) = _ScriptVideoGenre; factory ScriptVideoGenre.fromJson(Map json) => _$ScriptVideoGenreFromJson(json); } @freezed abstract class ScriptVideoTrailer with _$ScriptVideoTrailer { const factory ScriptVideoTrailer({ @Default('') String coverUrl, @Default('') String url, }) = _ScriptVideoTrailer; factory ScriptVideoTrailer.fromJson(Map json) => _$ScriptVideoTrailerFromJson(json); } @freezed abstract class ScriptVideoItem with _$ScriptVideoItem { const factory ScriptVideoItem({ @JsonKey(fromJson: _stringFromAny) required String id, @Default('link') String type, @Default('') String title, @Default('') String coverUrl, @JsonKey(readValue: _readPosterPath) @Default('') String posterPath, @Default('') String detailPoster, @Default('') String backdropPath, @Default([]) List backdropPaths, @Default('') String releaseDate, @Default('') String mediaType, @JsonKey(fromJson: _doubleFromAny) double? rating, @Default('') String genreTitle, @Default([]) List genreItems, @Default([]) List peoples, @JsonKey(fromJson: _intFromAny) int? duration, @Default('') String durationText, @Default('') String previewUrl, @Default([]) List trailers, @Default('') String videoUrl, @Default('') String link, @JsonKey(fromJson: _intFromAny) int? episode, @Default('') String description, @Default('app') String playerType, @Default([]) List childItems, @Default([]) List episodeItems, @Default([]) List relatedItems, }) = _ScriptVideoItem; factory ScriptVideoItem.fromJson(Map json) => _$ScriptVideoItemFromJson(json); } @freezed abstract class ScriptVideoResource with _$ScriptVideoResource { const factory ScriptVideoResource({ @Default('') String name, @Default('') String description, required String url, @JsonKey(readValue: _readResourceHeaders) @Default({}) Map customHeaders, @Default('app') String playerType, }) = _ScriptVideoResource; factory ScriptVideoResource.fromJson(Map json) => _$ScriptVideoResourceFromJson(json); } @freezed abstract class InstalledScriptWidget with _$InstalledScriptWidget { const factory InstalledScriptWidget({ required ScriptWidgetManifest manifest, required String scriptSource, @Default('') String sourceUrl, @Default(true) bool enabled, @Default({}) Map globalParams, required DateTime installedAt, required DateTime updatedAt, }) = _InstalledScriptWidget; factory InstalledScriptWidget.fromJson(Map json) => _$InstalledScriptWidgetFromJson(json); } @freezed abstract class ScriptWidgetCatalogEntry with _$ScriptWidgetCatalogEntry { const factory ScriptWidgetCatalogEntry({ required String id, required String title, @Default('') String description, @Default('') String requiredVersion, @Default('') String version, @Default('') String author, required String url, }) = _ScriptWidgetCatalogEntry; factory ScriptWidgetCatalogEntry.fromJson(Map json) => _$ScriptWidgetCatalogEntryFromJson(json); } @freezed abstract class ScriptWidgetCatalog with _$ScriptWidgetCatalog { const factory ScriptWidgetCatalog({ required String title, @Default('') String description, @Default('') String icon, @Default([]) List widgets, }) = _ScriptWidgetCatalog; factory ScriptWidgetCatalog.fromJson(Map json) => _$ScriptWidgetCatalogFromJson(json); } @freezed abstract class ScriptWidgetSubscription with _$ScriptWidgetSubscription { const factory ScriptWidgetSubscription({ required String url, required ScriptWidgetCatalog catalog, required DateTime refreshedAt, }) = _ScriptWidgetSubscription; factory ScriptWidgetSubscription.fromJson(Map json) => _$ScriptWidgetSubscriptionFromJson(json); } String _stringFromAny(Object? value) => value?.toString() ?? ''; int? _intFromAny(Object? value) { if (value is num) return value.toInt(); return int.tryParse(value?.toString() ?? ''); } double? _doubleFromAny(Object? value) { if (value is num) return value.toDouble(); return double.tryParse(value?.toString() ?? ''); } List _stringListFromAny(Object? value) { if (value is List) { return value.map((item) => item.toString()).toList(growable: false); } if (value == null) return const []; return [value.toString()]; } Object? _readPosterPath(Map json, String key) { return json[key] ?? json['posterUrl'] ?? json['poster_url']; } Object? _readResourceHeaders(Map json, String key) { final value = json[key] ?? json['headers']; if (value is! Map) return const {}; return { for (final entry in value.entries) entry.key.toString(): entry.value.toString(), }; }