Initial commit

This commit is contained in:
admin1
2026-07-14 11:11:36 +08:00
commit 656499cf94
604 changed files with 119518 additions and 0 deletions
@@ -0,0 +1,29 @@
import '../../contracts/trakt/trakt_response.dart';
import '../../contracts/trakt/trakt_sync_job.dart';
abstract class AuthedTraktGateway {
Future<bool> isConnected();
Future<TraktScrobbleOutcome> scrobble(
TraktSyncJobType type,
Map<String, dynamic> body,
);
Future<TraktScrobbleOutcome> syncHistory(
TraktSyncJobType type,
Map<String, dynamic> body,
);
Future<List<Map<String, dynamic>>> fetchPlayback();
Future<List<Map<String, dynamic>>> fetchCalendarShows();
Future<List<Map<String, dynamic>>> fetchCalendarMovies();
}
@@ -0,0 +1,31 @@
import '../../contracts/danmaku.dart';
abstract class DanmakuGateway {
Future<List<DanmakuMatch>> match(
String baseUrl,
String fileName,
int durationSec,
);
Future<List<DanmakuMatch>> searchEpisodes(
String baseUrl,
String anime,
int? episode,
);
Future<List<DanmakuComment>> fetchComments(
String baseUrl,
int episodeId, {
int chConvert = 0,
});
Future<List<DanmakuBangumiEpisode>> getBangumiEpisodes(
String baseUrl,
int animeId,
);
}
@@ -0,0 +1,10 @@
import '../../contracts/danmaku.dart';
abstract class DanmakuSourcesStore {
Future<List<DanmakuSource>> list();
Future<void> replaceAll(List<DanmakuSource> sources);
}
+171
View File
@@ -0,0 +1,171 @@
import '../../contracts/cancellation.dart';
import '../../contracts/library.dart';
import '../../contracts/playback.dart';
import '../../contracts/server.dart';
class AuthedRequestContext {
final String baseUrl;
final String token;
final String userId;
const AuthedRequestContext({
required this.baseUrl,
required this.token,
required this.userId,
});
}
class EmbyAuthResult {
final String accessToken;
final String userId;
final String userName;
const EmbyAuthResult({
required this.accessToken,
required this.userId,
required this.userName,
});
}
abstract class EmbyGateway {
Future<ProbePublicInfoRes> probePublicInfo(String baseUrl);
Future<EmbyAuthResult> authenticateByName({
required String baseUrl,
required String username,
required String password,
});
Future<void> changePassword({
required AuthedRequestContext ctx,
required String currentPassword,
required String newPassword,
});
Future<EmbyRawLibraries> getUserViews(AuthedRequestContext ctx);
Future<LibraryLatestRes> getLatestItems(
AuthedRequestContext ctx,
String parentId, {
int? limit,
CancellationToken? cancelToken,
});
Future<LibraryResumeRes> getResumeItems(
AuthedRequestContext ctx, {
int? limit,
});
Future<List<EmbyRawItem>> getLibraryItems({
required AuthedRequestContext ctx,
String? parentId,
String? includeItemTypes,
List<String>? genreIds,
String? searchTerm,
String? anyProviderIdEquals,
List<String>? personIds,
String? fields,
String? enableImageTypes,
bool? groupProgramsBySeries,
int? imageTypeLimit,
int? startIndex,
int? limit,
bool? recursive,
String? sortBy,
SortOrder? sortOrder,
String? filters,
CancellationToken? cancelToken,
});
Future<List<EmbyRawItem>> getFavoriteItems({
required AuthedRequestContext ctx,
required String includeItemTypes,
required String sortBy,
SortOrder? sortOrder,
});
Future<ItemCountsRes> getItemCounts(AuthedRequestContext ctx);
Future<EmbyRawItem> getItemDetail(AuthedRequestContext ctx, String itemId);
Future<List<EmbyRawItem>> getSeriesNextUp(
AuthedRequestContext ctx,
String seriesId, {
int? limit,
});
Future<List<EmbyRawSeason>> getSeriesSeasons(
AuthedRequestContext ctx,
String seriesId, {
CancellationToken? cancelToken,
});
Future<List<EmbyRawItem>> getSeriesEpisodes(
AuthedRequestContext ctx,
String seriesId,
String seasonId, {
CancellationToken? cancelToken,
});
Future<List<EmbyRawItem>> getSimilarItems(
AuthedRequestContext ctx,
String itemId, {
int? limit,
});
Future<List<EmbyRawItem>> getAdditionalParts(
AuthedRequestContext ctx,
String itemId,
);
Future<List<EmbyRawItem>> getSpecialFeatures(
AuthedRequestContext ctx,
String itemId,
);
Future<bool> setFavoriteStatus({
required AuthedRequestContext ctx,
required String itemId,
required bool isFavorite,
});
Future<bool> setPlayedStatus({
required AuthedRequestContext ctx,
required String itemId,
required bool played,
});
Future<bool> hideFromResume({
required AuthedRequestContext ctx,
required String itemId,
required bool hide,
});
Future<void> reportPlaybackStarted({
required AuthedRequestContext ctx,
required PlaybackReportPayload payload,
});
Future<void> reportPlaybackProgress({
required AuthedRequestContext ctx,
required PlaybackReportPayload payload,
});
Future<void> reportPlaybackStopped({
required AuthedRequestContext ctx,
required PlaybackReportPayload payload,
});
Future<Map<String, dynamic>> fetchPlaybackInfo({
required AuthedRequestContext ctx,
required String itemId,
String? mediaSourceId,
int startTimeTicks = 0,
bool isPlayback = false,
required Map<String, dynamic> deviceProfile,
});
}
@@ -0,0 +1,3 @@
abstract class ScriptWidgetRemoteGateway {
Future<String> fetchText(String url);
}
@@ -0,0 +1,23 @@
import '../../contracts/script_widget.dart';
abstract class ScriptWidgetRepository {
Future<List<InstalledScriptWidget>> listWidgets();
Future<InstalledScriptWidget?> findWidget(String widgetId);
Future<void> upsertWidget(InstalledScriptWidget widget);
Future<void> deleteWidget(String widgetId);
Future<List<ScriptWidgetSubscription>> listSubscriptions();
Future<void> upsertSubscription(ScriptWidgetSubscription subscription);
Future<void> replaceAllWidgets(List<InstalledScriptWidget> widgets);
Future<void> replaceAllSubscriptions(
List<ScriptWidgetSubscription> subscriptions,
);
}
@@ -0,0 +1,19 @@
import '../../contracts/script_widget.dart';
abstract class ScriptWidgetRuntime {
Future<ScriptWidgetManifest> inspectWidget(String scriptSource);
Future<ScriptWidgetManifest> loadWidget(String scriptSource);
bool isWidgetLoaded(String widgetId);
Future<Object?> invokeModuleFunction(
String widgetId,
String functionName,
Map<String, Object?> params,
);
Future<void> unloadWidget(String widgetId);
Future<void> dispose();
}
@@ -0,0 +1,14 @@
import '../../contracts/server.dart';
abstract class ServerRepository {
Future<List<EmbyServer>> list();
Future<EmbyServer?> findById(String id);
Future<EmbyServer?> findByBaseUrl(String baseUrl);
Future<EmbyServer> create(EmbyServer server);
Future<EmbyServer> update(EmbyServer server);
Future<void> deleteById(String id);
Future<void> touchConnectedAt(String id, String updatedAt);
Future<void> replaceAll(List<EmbyServer> servers);
}
@@ -0,0 +1,28 @@
library;
class ServerSyncSnapshot {
final String? blob;
const ServerSyncSnapshot({this.blob});
bool get isEmpty => blob == null || blob!.trim().isEmpty;
}
abstract class ServerSyncGateway {
Future<ServerSyncSnapshot> pull({
required String baseUrl,
required String accessToken,
});
Future<void> push({
required String baseUrl,
required String accessToken,
required String blob,
});
}
@@ -0,0 +1,18 @@
import '../../contracts/auth.dart';
abstract class SessionRepository {
Future<SessionData> set(SessionData session);
Future<void> setMany(List<SessionData> sessions);
Future<void> replaceAll(List<SessionData> sessions, {String? activeServerId});
Future<SessionData?> getByServerId(String serverId);
Future<SessionData?> getActive();
Future<String?> getActiveServerId();
Future<List<SessionData>> listAll();
Future<void> setActive(String serverId);
Future<void> clear([String? serverId]);
}
@@ -0,0 +1,148 @@
library;
class SmLoginResult {
final bool ok;
final String email;
final String accessToken;
final String refreshToken;
final int expiresIn;
final bool isVip;
final int? vipExpiresAt;
final bool vipPermanent;
final bool needsVerification;
final String? message;
const SmLoginResult({
required this.ok,
this.email = '',
this.accessToken = '',
this.refreshToken = '',
this.expiresIn = 0,
this.isVip = false,
this.vipExpiresAt,
this.vipPermanent = false,
this.needsVerification = false,
this.message,
});
factory SmLoginResult.failure(
String message, {
bool needsVerification = false,
}) => SmLoginResult(
ok: false,
needsVerification: needsVerification,
message: message,
);
}
class SmTokenRefreshResult {
final bool ok;
final String accessToken;
final String refreshToken;
final int expiresIn;
final bool isVip;
final int? vipExpiresAt;
final bool vipPermanent;
final bool hasVipInfo;
final bool invalidRefreshToken;
final String? message;
const SmTokenRefreshResult({
required this.ok,
this.accessToken = '',
this.refreshToken = '',
this.expiresIn = 0,
this.isVip = false,
this.vipExpiresAt,
this.vipPermanent = false,
this.hasVipInfo = false,
this.invalidRefreshToken = false,
this.message,
});
factory SmTokenRefreshResult.failure(
String message, {
bool invalidRefreshToken = false,
}) => SmTokenRefreshResult(
ok: false,
invalidRefreshToken: invalidRefreshToken,
message: message,
);
}
class SmActionResult {
final bool ok;
final String? message;
const SmActionResult({required this.ok, this.message});
factory SmActionResult.success() => const SmActionResult(ok: true);
factory SmActionResult.failure(String message) =>
SmActionResult(ok: false, message: message);
}
abstract class SmAccountGateway {
Future<SmLoginResult> login({
required String baseUrl,
required String email,
required String password,
});
Future<SmActionResult> registerStart({
required String baseUrl,
required String email,
});
Future<SmLoginResult> registerVerify({
required String baseUrl,
required String email,
required String password,
required String code,
});
Future<SmActionResult> resendCode({
required String baseUrl,
required String email,
});
Future<void> logout({required String baseUrl, required String refreshToken});
Future<SmTokenRefreshResult> refreshAccessToken({
required String baseUrl,
required String refreshToken,
});
}
+126
View File
@@ -0,0 +1,126 @@
import '../../contracts/tmdb.dart';
class TmdbRequestConfig {
final String apiBaseUrl;
final String imageBaseUrl;
final String accessToken;
final String apiKey;
final Future<String?> Function()? onUnauthorized;
const TmdbRequestConfig({
required this.apiBaseUrl,
required this.imageBaseUrl,
this.accessToken = '',
this.apiKey = '',
this.onUnauthorized,
});
}
abstract class TmdbGateway {
Future<TmdbCreditsRes?> getCredits(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
});
Future<TmdbRecommendationsRes?> getRecommendations(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
});
Future<TmdbSeasonDetail?> getSeasonDetail(
TmdbRequestConfig config,
String tmdbId,
int seasonNumber, {
required String language,
});
Future<TmdbImageSet?> getImages(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
});
Future<TmdbEnrichedDetail?> getEnrichedDetail(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
List<String> appendToResponse,
});
Future<TmdbVideosRes?> getVideos(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
});
Future<TmdbPersonDetail?> getPersonDetail(
TmdbRequestConfig config,
int personId, {
required String language,
});
Future<TmdbPersonCreditsRes?> getPersonCredits(
TmdbRequestConfig config,
int personId, {
required String language,
});
Future<TmdbMediaDetail?> getMediaDetail(
TmdbRequestConfig config,
String tmdbId,
String mediaType, {
required String language,
});
Future<TmdbRecommendationsRes?> getTrending(
TmdbRequestConfig config, {
required String language,
String mediaType,
String timeWindow,
});
Future<TmdbRecommendationsRes?> getPopularMovies(
TmdbRequestConfig config, {
required String language,
});
Future<TmdbRecommendationsRes?> getPopularTv(
TmdbRequestConfig config, {
required String language,
});
Future<TmdbRecommendationsRes?> getAiringTodayTv(
TmdbRequestConfig config, {
required String language,
});
Future<TmdbRecommendationsRes?> getTopRatedMovies(
TmdbRequestConfig config, {
required String language,
});
Future<TmdbRecommendationsRes?> getDiscover(
TmdbRequestConfig config,
String mediaType, {
required String language,
String sortBy = 'popularity.desc',
String? withGenres,
String? voteCountGte,
});
Future<bool> testConnection(
TmdbRequestConfig config, {
required String language,
});
}
+14
View File
@@ -0,0 +1,14 @@
import '../../contracts/trakt/trakt_token.dart';
import '../../contracts/trakt/trakt_user.dart';
abstract class TraktGateway {
Future<TraktToken> exchangeCode(String code);
Future<TraktToken> refreshToken(String refreshToken);
Future<TraktUser> getMe(String accessToken);
}