mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
945 lines
28 KiB
Dart
945 lines
28 KiB
Dart
import 'dart:developer';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:chopper/chopper.dart';
|
|
import 'package:collection/collection.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:path/path.dart';
|
|
|
|
import 'package:fladder/fake/fake_jellyfin_open_api.dart';
|
|
import 'package:fladder/jellyfin/enum_models.dart';
|
|
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
|
import 'package:fladder/models/account_model.dart';
|
|
import 'package:fladder/models/credentials_model.dart';
|
|
import 'package:fladder/models/item_base_model.dart';
|
|
import 'package:fladder/models/items/media_segments_model.dart';
|
|
import 'package:fladder/models/items/trick_play_model.dart';
|
|
import 'package:fladder/providers/auth_provider.dart';
|
|
import 'package:fladder/providers/image_provider.dart';
|
|
import 'package:fladder/providers/user_provider.dart';
|
|
import 'package:fladder/util/jellyfin_extension.dart';
|
|
|
|
class ServerQueryResult {
|
|
final List<BaseItemDto> original;
|
|
final List<ItemBaseModel> items;
|
|
final int? totalRecordCount;
|
|
final int? startIndex;
|
|
ServerQueryResult({
|
|
required this.original,
|
|
required this.items,
|
|
this.totalRecordCount,
|
|
this.startIndex,
|
|
});
|
|
|
|
factory ServerQueryResult.fromBaseQuery(
|
|
BaseItemDtoQueryResult baseQuery,
|
|
Ref ref,
|
|
) {
|
|
return ServerQueryResult(
|
|
original: baseQuery.items ?? [],
|
|
items: baseQuery.items
|
|
?.map(
|
|
(e) => ItemBaseModel.fromBaseDto(e, ref),
|
|
)
|
|
.toList() ??
|
|
[],
|
|
totalRecordCount: baseQuery.totalRecordCount,
|
|
startIndex: baseQuery.startIndex,
|
|
);
|
|
}
|
|
|
|
ServerQueryResult copyWith({
|
|
List<BaseItemDto>? original,
|
|
List<ItemBaseModel>? items,
|
|
int? totalRecordCount,
|
|
int? startIndex,
|
|
}) {
|
|
return ServerQueryResult(
|
|
original: original ?? this.original,
|
|
items: items ?? this.items,
|
|
totalRecordCount: totalRecordCount ?? this.totalRecordCount,
|
|
startIndex: startIndex ?? this.startIndex,
|
|
);
|
|
}
|
|
}
|
|
|
|
class JellyService {
|
|
JellyService(this.ref, this._api);
|
|
|
|
final JellyfinOpenApi _api;
|
|
|
|
JellyfinOpenApi get api {
|
|
var authServer = ref.read(authProvider).tempCredentials.server;
|
|
var currentServer = ref.read(userProvider)?.credentials.server;
|
|
if ((authServer.isNotEmpty ? authServer : currentServer) == FakeHelper.fakeTestServerUrl) {
|
|
return FakeJellyfinOpenApi();
|
|
} else {
|
|
return _api;
|
|
}
|
|
}
|
|
|
|
final Ref ref;
|
|
AccountModel? get account => ref.read(userProvider);
|
|
|
|
Future<Response<ItemBaseModel>> usersUserIdItemsItemIdGet({
|
|
String? itemId,
|
|
}) async {
|
|
final response = await api.itemsItemIdGet(
|
|
userId: account?.id,
|
|
itemId: itemId,
|
|
);
|
|
return response.copyWith(body: ItemBaseModel.fromBaseDto(response.bodyOrThrow, ref));
|
|
}
|
|
|
|
Future<Response<BaseItemDto>> usersUserIdItemsItemIdGetBaseItem({
|
|
String? itemId,
|
|
}) async {
|
|
final response = await api.itemsItemIdGet(
|
|
userId: account?.id,
|
|
itemId: itemId,
|
|
);
|
|
return response;
|
|
}
|
|
|
|
Future<Response<ServerQueryResult>> itemsGet({
|
|
String? maxOfficialRating,
|
|
bool? hasThemeSong,
|
|
bool? hasThemeVideo,
|
|
bool? hasSubtitles,
|
|
bool? hasSpecialFeature,
|
|
bool? hasTrailer,
|
|
String? adjacentTo,
|
|
int? parentIndexNumber,
|
|
bool? hasParentalRating,
|
|
bool? isHd,
|
|
bool? is4K,
|
|
List<LocationType>? locationTypes,
|
|
List<LocationType>? excludeLocationTypes,
|
|
bool? isMissing,
|
|
bool? isUnaired,
|
|
num? minCommunityRating,
|
|
num? minCriticRating,
|
|
DateTime? minPremiereDate,
|
|
DateTime? minDateLastSaved,
|
|
DateTime? minDateLastSavedForUser,
|
|
DateTime? maxPremiereDate,
|
|
bool? hasOverview,
|
|
bool? hasImdbId,
|
|
bool? hasTmdbId,
|
|
bool? hasTvdbId,
|
|
bool? isMovie,
|
|
bool? isSeries,
|
|
bool? isNews,
|
|
bool? isKids,
|
|
bool? isSports,
|
|
List<String>? excludeItemIds,
|
|
int? startIndex,
|
|
int? limit,
|
|
bool? recursive,
|
|
String? searchTerm,
|
|
List<SortOrder>? sortOrder,
|
|
String? parentId,
|
|
List<ItemFields>? fields,
|
|
List<BaseItemKind>? excludeItemTypes,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
List<ItemFilter>? filters,
|
|
bool? isFavorite,
|
|
List<MediaType>? mediaTypes,
|
|
List<ImageType>? imageTypes,
|
|
List<ItemSortBy>? sortBy,
|
|
bool? isPlayed,
|
|
List<String>? genres,
|
|
List<String>? officialRatings,
|
|
List<String>? tags,
|
|
List<int>? years,
|
|
bool? enableUserData,
|
|
int? imageTypeLimit,
|
|
List<ImageType>? enableImageTypes,
|
|
String? person,
|
|
List<String>? personIds,
|
|
List<String>? personTypes,
|
|
List<String>? studios,
|
|
List<String>? artists,
|
|
List<String>? excludeArtistIds,
|
|
List<String>? artistIds,
|
|
List<String>? albumArtistIds,
|
|
List<String>? contributingArtistIds,
|
|
List<String>? albums,
|
|
List<String>? albumIds,
|
|
List<String>? ids,
|
|
List<VideoType>? videoTypes,
|
|
String? minOfficialRating,
|
|
bool? isLocked,
|
|
bool? isPlaceHolder,
|
|
bool? hasOfficialRating,
|
|
bool? collapseBoxSetItems,
|
|
int? minWidth,
|
|
int? minHeight,
|
|
int? maxWidth,
|
|
int? maxHeight,
|
|
bool? is3D,
|
|
List<SeriesStatus>? seriesStatus,
|
|
String? nameStartsWithOrGreater,
|
|
String? nameStartsWith,
|
|
String? nameLessThan,
|
|
List<String>? studioIds,
|
|
List<String>? genreIds,
|
|
bool? enableTotalRecordCount,
|
|
bool? enableImages,
|
|
}) async {
|
|
final response = await api.itemsGet(
|
|
userId: account?.id,
|
|
maxOfficialRating: maxOfficialRating,
|
|
hasThemeSong: hasThemeSong,
|
|
hasThemeVideo: hasThemeVideo,
|
|
hasSubtitles: hasSubtitles,
|
|
hasSpecialFeature: hasSpecialFeature,
|
|
hasTrailer: hasTrailer,
|
|
adjacentTo: adjacentTo,
|
|
parentIndexNumber: parentIndexNumber,
|
|
hasParentalRating: hasParentalRating,
|
|
isHd: isHd,
|
|
is4K: is4K,
|
|
locationTypes: locationTypes,
|
|
excludeLocationTypes: excludeLocationTypes,
|
|
isMissing: isMissing,
|
|
isUnaired: isUnaired,
|
|
minCommunityRating: minCommunityRating,
|
|
minCriticRating: minCriticRating,
|
|
minPremiereDate: minPremiereDate,
|
|
minDateLastSaved: minDateLastSaved,
|
|
minDateLastSavedForUser: minDateLastSavedForUser,
|
|
maxPremiereDate: maxPremiereDate,
|
|
hasOverview: hasOverview,
|
|
hasImdbId: hasImdbId,
|
|
hasTmdbId: hasTmdbId,
|
|
hasTvdbId: hasTvdbId,
|
|
isMovie: isMovie,
|
|
isSeries: isSeries,
|
|
isNews: isNews,
|
|
isKids: isKids,
|
|
isSports: isSports,
|
|
excludeItemIds: excludeItemIds,
|
|
startIndex: startIndex,
|
|
limit: limit,
|
|
recursive: recursive,
|
|
searchTerm: searchTerm,
|
|
sortOrder: sortOrder,
|
|
sortBy: sortBy,
|
|
parentId: parentId,
|
|
fields: {...?fields, ItemFields.candelete, ItemFields.candownload}.toList(),
|
|
excludeItemTypes: excludeItemTypes,
|
|
includeItemTypes: includeItemTypes,
|
|
filters: filters,
|
|
isFavorite: isFavorite,
|
|
mediaTypes: mediaTypes,
|
|
imageTypes: imageTypes,
|
|
isPlayed: isPlayed,
|
|
genres: genres,
|
|
officialRatings: officialRatings,
|
|
tags: tags,
|
|
years: years,
|
|
enableUserData: enableUserData,
|
|
imageTypeLimit: imageTypeLimit,
|
|
enableImageTypes: enableImageTypes,
|
|
person: person,
|
|
personIds: personIds,
|
|
personTypes: personTypes,
|
|
studios: studios,
|
|
artists: artists,
|
|
excludeArtistIds: excludeArtistIds,
|
|
artistIds: artistIds,
|
|
albumArtistIds: albumArtistIds,
|
|
contributingArtistIds: contributingArtistIds,
|
|
albums: albums,
|
|
albumIds: albumIds,
|
|
ids: ids,
|
|
videoTypes: videoTypes,
|
|
minOfficialRating: minOfficialRating,
|
|
isLocked: isLocked,
|
|
isPlaceHolder: isPlaceHolder,
|
|
hasOfficialRating: hasOfficialRating,
|
|
collapseBoxSetItems: collapseBoxSetItems,
|
|
minWidth: minWidth,
|
|
minHeight: minHeight,
|
|
maxWidth: maxWidth,
|
|
maxHeight: maxHeight,
|
|
is3D: is3D,
|
|
seriesStatus: seriesStatus,
|
|
nameStartsWithOrGreater: nameStartsWithOrGreater,
|
|
nameStartsWith: nameStartsWith,
|
|
nameLessThan: nameLessThan,
|
|
studioIds: studioIds,
|
|
genreIds: genreIds,
|
|
enableTotalRecordCount: enableTotalRecordCount,
|
|
enableImages: enableImages,
|
|
);
|
|
|
|
return response.copyWith(
|
|
body: ServerQueryResult.fromBaseQuery(response.bodyOrThrow, ref),
|
|
);
|
|
}
|
|
|
|
Future<Response<List<ItemBaseModel>>> personsGet({
|
|
String? searchTerm,
|
|
int? limit,
|
|
bool? isFavorite,
|
|
}) async {
|
|
final response = await api.personsGet(
|
|
userId: account?.id,
|
|
limit: limit,
|
|
isFavorite: isFavorite,
|
|
);
|
|
return response.copyWith(
|
|
body: response.body?.items
|
|
?.map(
|
|
(e) => ItemBaseModel.fromBaseDto(e, ref),
|
|
)
|
|
.toList() ??
|
|
[],
|
|
);
|
|
}
|
|
|
|
Future<Response<List<ImageInfo>>> itemsItemIdImagesGet({
|
|
String? itemId,
|
|
bool? isFavorite,
|
|
}) async {
|
|
final response = await api.itemsItemIdImagesGet(itemId: itemId);
|
|
return response;
|
|
}
|
|
|
|
Future<Response<MetadataEditorInfo>> itemsItemIdMetadataEditorGet({
|
|
String? itemId,
|
|
}) async {
|
|
return api.itemsItemIdMetadataEditorGet(itemId: itemId);
|
|
}
|
|
|
|
Future<Response<RemoteImageResult>> itemsItemIdRemoteImagesGet({
|
|
String? itemId,
|
|
ImageType? type,
|
|
bool? includeAllLanguages,
|
|
}) async {
|
|
return api.itemsItemIdRemoteImagesGet(
|
|
itemId: itemId,
|
|
type: ItemsItemIdRemoteImagesGetType.values.firstWhereOrNull(
|
|
(element) => element.value == type?.value,
|
|
),
|
|
includeAllLanguages: includeAllLanguages,
|
|
);
|
|
}
|
|
|
|
Future<Response> itemsItemIdPost({
|
|
String? itemId,
|
|
required BaseItemDto? body,
|
|
}) async {
|
|
return api.itemsItemIdPost(
|
|
itemId: itemId,
|
|
body: body,
|
|
);
|
|
}
|
|
|
|
Future<Response<dynamic>?> itemIdImagesImageTypePost(
|
|
ImageType type,
|
|
String itemId,
|
|
Uint8List data,
|
|
) async {
|
|
return api.itemIdImagesImageTypePost(
|
|
type,
|
|
itemId,
|
|
data,
|
|
);
|
|
}
|
|
|
|
Future<Response> itemsItemIdRemoteImagesDownloadPost({
|
|
required String? itemId,
|
|
required ImageType? type,
|
|
String? imageUrl,
|
|
}) async {
|
|
return api.itemsItemIdRemoteImagesDownloadPost(
|
|
itemId: itemId,
|
|
type: ItemsItemIdRemoteImagesDownloadPostType.values.firstWhereOrNull(
|
|
(element) => element.value == type?.value,
|
|
),
|
|
imageUrl: imageUrl,
|
|
);
|
|
}
|
|
|
|
Future<Response> itemsItemIdImagesImageTypeDelete({
|
|
required String? itemId,
|
|
required ImageType? imageType,
|
|
int? imageIndex,
|
|
}) async {
|
|
return api.itemsItemIdImagesImageTypeDelete(
|
|
itemId: itemId,
|
|
imageType: ItemsItemIdImagesImageTypeDeleteImageType.values.firstWhereOrNull(
|
|
(element) => element.value == imageType?.value,
|
|
),
|
|
imageIndex: imageIndex,
|
|
);
|
|
}
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> usersUserIdItemsResumeGet({
|
|
int? startIndex,
|
|
int? limit,
|
|
String? searchTerm,
|
|
String? parentId,
|
|
List<ItemFields>? fields,
|
|
List<MediaType>? mediaTypes,
|
|
bool? enableUserData,
|
|
bool? enableTotalRecordCount,
|
|
List<ImageType>? enableImageTypes,
|
|
List<BaseItemKind>? excludeItemTypes,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
}) async {
|
|
return api.userItemsResumeGet(
|
|
userId: account?.id,
|
|
searchTerm: searchTerm,
|
|
parentId: parentId,
|
|
limit: limit,
|
|
fields: fields,
|
|
mediaTypes: mediaTypes,
|
|
enableTotalRecordCount: enableTotalRecordCount,
|
|
enableImageTypes: enableImageTypes,
|
|
enableUserData: enableUserData,
|
|
includeItemTypes: includeItemTypes,
|
|
excludeItemTypes: excludeItemTypes,
|
|
);
|
|
}
|
|
|
|
Future<Response<List<BaseItemDto>>> usersUserIdItemsLatestGet({
|
|
String? parentId,
|
|
List<ItemFields>? fields,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
bool? isPlayed,
|
|
bool? enableImages,
|
|
int? imageTypeLimit,
|
|
List<ImageType>? enableImageTypes,
|
|
bool? enableUserData,
|
|
int? limit,
|
|
bool? groupItems,
|
|
}) async {
|
|
return api.itemsLatestGet(
|
|
parentId: parentId,
|
|
userId: account?.id,
|
|
fields: fields,
|
|
includeItemTypes: includeItemTypes,
|
|
isPlayed: isPlayed,
|
|
enableImages: enableImages,
|
|
imageTypeLimit: imageTypeLimit,
|
|
enableImageTypes: enableImageTypes,
|
|
enableUserData: enableUserData,
|
|
limit: limit,
|
|
groupItems: groupItems,
|
|
);
|
|
}
|
|
|
|
Future<Response<List<RecommendationDto>>> moviesRecommendationsGet({
|
|
String? parentId,
|
|
List<ItemFields>? fields,
|
|
int? categoryLimit,
|
|
int? itemLimit,
|
|
}) async {
|
|
return api.moviesRecommendationsGet(
|
|
userId: account?.id,
|
|
parentId: parentId,
|
|
fields: fields,
|
|
categoryLimit: categoryLimit,
|
|
itemLimit: itemLimit,
|
|
);
|
|
}
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> showsNextUpGet({
|
|
int? startIndex,
|
|
int? limit,
|
|
String? parentId,
|
|
DateTime? nextUpDateCutoff,
|
|
List<ItemFields>? fields,
|
|
bool? enableUserData,
|
|
List<ImageType>? enableImageTypes,
|
|
int? imageTypeLimit,
|
|
}) async {
|
|
return api.showsNextUpGet(
|
|
userId: account?.id,
|
|
parentId: parentId,
|
|
limit: limit,
|
|
fields: fields,
|
|
enableResumable: false,
|
|
enableRewatching: false,
|
|
disableFirstEpisode: false,
|
|
nextUpDateCutoff: nextUpDateCutoff,
|
|
enableImageTypes: enableImageTypes,
|
|
enableUserData: enableUserData,
|
|
imageTypeLimit: imageTypeLimit,
|
|
);
|
|
}
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> genresGet({
|
|
String? parentId,
|
|
List<ItemSortBy>? sortBy,
|
|
List<SortOrder>? sortOrder,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
}) async {
|
|
return api.genresGet(
|
|
parentId: parentId,
|
|
userId: account?.id,
|
|
sortBy: sortBy,
|
|
sortOrder: sortOrder,
|
|
);
|
|
}
|
|
|
|
Future<Response> sessionsPlayingPost({required PlaybackStartInfo? body}) async => api.sessionsPlayingPost(body: body);
|
|
|
|
Future<Response> sessionsPlayingStoppedPost({
|
|
required PlaybackStopInfo? body,
|
|
}) =>
|
|
api.sessionsPlayingStoppedPost(body: body);
|
|
|
|
Future<Response> sessionsPlayingProgressPost({required PlaybackProgressInfo? body}) async =>
|
|
api.sessionsPlayingProgressPost(body: body);
|
|
|
|
Future<Response<PlaybackInfoResponse>> itemsItemIdPlaybackInfoPost({
|
|
required String? itemId,
|
|
required PlaybackInfoDto? body,
|
|
}) async =>
|
|
api.itemsItemIdPlaybackInfoPost(
|
|
itemId: itemId,
|
|
userId: account?.id,
|
|
enableDirectPlay: body?.enableDirectPlay,
|
|
enableDirectStream: body?.enableDirectStream,
|
|
enableTranscoding: body?.enableTranscoding,
|
|
autoOpenLiveStream: body?.autoOpenLiveStream,
|
|
maxStreamingBitrate: body?.maxStreamingBitrate,
|
|
liveStreamId: body?.liveStreamId,
|
|
startTimeTicks: body?.startTimeTicks,
|
|
mediaSourceId: body?.mediaSourceId,
|
|
audioStreamIndex: body?.audioStreamIndex,
|
|
subtitleStreamIndex: body?.subtitleStreamIndex,
|
|
body: body,
|
|
);
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> showsSeriesIdEpisodesGet({
|
|
required String? seriesId,
|
|
List<ItemFields>? fields,
|
|
int? season,
|
|
String? seasonId,
|
|
bool? isMissing,
|
|
String? adjacentTo,
|
|
String? startItemId,
|
|
int? startIndex,
|
|
int? limit,
|
|
bool? enableImages,
|
|
int? imageTypeLimit,
|
|
List<ImageType>? enableImageTypes,
|
|
bool? enableUserData,
|
|
ShowsSeriesIdEpisodesGetSortBy? sortBy,
|
|
}) async {
|
|
return api.showsSeriesIdEpisodesGet(
|
|
seriesId: seriesId,
|
|
userId: account?.id,
|
|
fields: [
|
|
...?fields,
|
|
ItemFields.parentid,
|
|
],
|
|
isMissing: isMissing,
|
|
limit: limit,
|
|
sortBy: sortBy,
|
|
enableUserData: enableUserData,
|
|
startIndex: startIndex,
|
|
adjacentTo: adjacentTo,
|
|
startItemId: startItemId,
|
|
season: season,
|
|
seasonId: seasonId,
|
|
enableImages: enableImages,
|
|
enableImageTypes: enableImageTypes,
|
|
);
|
|
}
|
|
|
|
Future<List<ItemBaseModel>> fetchEpisodeFromShow({
|
|
required String? seriesId,
|
|
String? seasonId,
|
|
}) async {
|
|
final response = await showsSeriesIdEpisodesGet(seriesId: seriesId, seasonId: seasonId);
|
|
return response.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [];
|
|
}
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> itemsItemIdSimilarGet({
|
|
String? itemId,
|
|
int? limit,
|
|
}) async {
|
|
return api.itemsItemIdSimilarGet(
|
|
userId: account?.id,
|
|
itemId: itemId,
|
|
limit: limit,
|
|
);
|
|
}
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> usersUserIdItemsGet({
|
|
String? parentId,
|
|
bool? recursive,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
}) async {
|
|
return api.itemsGet(
|
|
parentId: parentId,
|
|
userId: account?.id,
|
|
recursive: recursive,
|
|
includeItemTypes: includeItemTypes,
|
|
);
|
|
}
|
|
|
|
Future<Response<dynamic>> playlistsPlaylistIdItemsPost({
|
|
String? playlistId,
|
|
List<String>? ids,
|
|
}) async {
|
|
return api.playlistsPlaylistIdItemsPost(
|
|
playlistId: playlistId,
|
|
ids: ids,
|
|
userId: account?.id,
|
|
);
|
|
}
|
|
|
|
Future<Response<dynamic>> playlistsPost({
|
|
String? name,
|
|
List<String>? ids,
|
|
required CreatePlaylistDto? body,
|
|
}) async {
|
|
return api.playlistsPost(
|
|
name: name,
|
|
ids: ids,
|
|
userId: account?.id,
|
|
body: body,
|
|
);
|
|
}
|
|
|
|
Future<Response<List<AccountModel>>> usersPublicGet(
|
|
CredentialsModel credentials,
|
|
) async {
|
|
final response = await api.usersPublicGet();
|
|
return response.copyWith(
|
|
body: response.body?.map(
|
|
(e) {
|
|
var imageUrl = ref.read(imageUtilityProvider).getUserImageUrl(e.id ?? "");
|
|
return AccountModel(
|
|
name: e.name ?? "",
|
|
credentials: credentials,
|
|
id: e.id ?? "",
|
|
avatar: imageUrl,
|
|
lastUsed: DateTime.now(),
|
|
);
|
|
},
|
|
).toList(),
|
|
);
|
|
}
|
|
|
|
Future<Response<AuthenticationResult>> usersAuthenticateByNamePost({
|
|
required String userName,
|
|
required String password,
|
|
}) async {
|
|
return api.usersAuthenticateByNamePost(body: AuthenticateUserByName(username: userName, pw: password));
|
|
}
|
|
|
|
Future<Response<ServerConfiguration>> systemConfigurationGet() => api.systemConfigurationGet();
|
|
Future<Response<PublicSystemInfo>> systemInfoPublicGet() => api.systemInfoPublicGet();
|
|
|
|
Future<Response> sessionsLogoutPost() => api.sessionsLogoutPost();
|
|
|
|
Future<Response<String>> itemsItemIdDownloadGet({
|
|
String? itemId,
|
|
}) =>
|
|
api.itemsItemIdDownloadGet(itemId: itemId);
|
|
|
|
Future<Response> collectionsCollectionIdItemsPost({required String? collectionId, required List<String>? ids}) =>
|
|
api.collectionsCollectionIdItemsPost(collectionId: collectionId, ids: ids);
|
|
Future<Response> collectionsCollectionIdItemsDelete({required String? collectionId, required List<String>? ids}) =>
|
|
api.collectionsCollectionIdItemsDelete(collectionId: collectionId, ids: ids);
|
|
|
|
Future<Response> collectionsPost({String? name, List<String>? ids, String? parentId, bool? isLocked}) =>
|
|
api.collectionsPost(name: name, ids: ids, parentId: parentId, isLocked: isLocked);
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> usersUserIdViewsGet({
|
|
bool? includeExternalContent,
|
|
List<CollectionType>? presetViews,
|
|
bool? includeHidden,
|
|
}) =>
|
|
api.userViewsGet(
|
|
userId: account?.id,
|
|
includeExternalContent: includeExternalContent,
|
|
presetViews: presetViews,
|
|
includeHidden: includeHidden);
|
|
|
|
Future<Response<List<ExternalIdInfo>>> itemsItemIdExternalIdInfosGet({required String? itemId}) =>
|
|
api.itemsItemIdExternalIdInfosGet(itemId: itemId);
|
|
|
|
Future<Response<List<RemoteSearchResult>>> itemsRemoteSearchSeriesPost(
|
|
{required SeriesInfoRemoteSearchQuery? body}) =>
|
|
api.itemsRemoteSearchSeriesPost(body: body);
|
|
|
|
Future<Response<List<RemoteSearchResult>>> itemsRemoteSearchMoviePost({required MovieInfoRemoteSearchQuery? body}) =>
|
|
api.itemsRemoteSearchMoviePost(body: body);
|
|
|
|
Future<Response<dynamic>> itemsRemoteSearchApplyItemIdPost({
|
|
required String? itemId,
|
|
bool? replaceAllImages,
|
|
required RemoteSearchResult? body,
|
|
}) =>
|
|
api.itemsRemoteSearchApplyItemIdPost(
|
|
itemId: itemId,
|
|
replaceAllImages: replaceAllImages,
|
|
body: body,
|
|
);
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> showsSeriesIdSeasonsGet({
|
|
required String? seriesId,
|
|
bool? enableUserData,
|
|
bool? isMissing,
|
|
List<ItemFields>? fields,
|
|
}) =>
|
|
api.showsSeriesIdSeasonsGet(
|
|
seriesId: seriesId,
|
|
isMissing: isMissing,
|
|
enableUserData: enableUserData,
|
|
fields: [
|
|
...?fields,
|
|
ItemFields.parentid,
|
|
],
|
|
);
|
|
|
|
Future<Response<QueryFilters>> itemsFilters2Get({
|
|
String? parentId,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
bool? isAiring,
|
|
bool? isMovie,
|
|
bool? isSports,
|
|
bool? isKids,
|
|
bool? isNews,
|
|
bool? isSeries,
|
|
bool? recursive,
|
|
}) =>
|
|
api.itemsFilters2Get(
|
|
parentId: parentId,
|
|
includeItemTypes: includeItemTypes,
|
|
isAiring: isAiring,
|
|
isMovie: isMovie,
|
|
isSports: isSports,
|
|
isKids: isKids,
|
|
isNews: isNews,
|
|
isSeries: isSeries,
|
|
recursive: recursive,
|
|
);
|
|
|
|
Future<Response<BaseItemDtoQueryResult>> studiosGet({
|
|
int? startIndex,
|
|
int? limit,
|
|
String? searchTerm,
|
|
String? parentId,
|
|
List<ItemFields>? fields,
|
|
List<BaseItemKind>? excludeItemTypes,
|
|
List<BaseItemKind>? includeItemTypes,
|
|
bool? isFavorite,
|
|
bool? enableUserData,
|
|
int? imageTypeLimit,
|
|
List<ImageType>? enableImageTypes,
|
|
String? userId,
|
|
String? nameStartsWithOrGreater,
|
|
String? nameStartsWith,
|
|
String? nameLessThan,
|
|
bool? enableImages,
|
|
bool? enableTotalRecordCount,
|
|
}) =>
|
|
api.studiosGet(
|
|
startIndex: startIndex,
|
|
limit: limit,
|
|
searchTerm: searchTerm,
|
|
parentId: parentId,
|
|
fields: fields,
|
|
excludeItemTypes: excludeItemTypes,
|
|
includeItemTypes: includeItemTypes,
|
|
isFavorite: isFavorite,
|
|
enableUserData: enableUserData,
|
|
imageTypeLimit: imageTypeLimit,
|
|
enableImageTypes: enableImageTypes,
|
|
nameStartsWithOrGreater: nameStartsWithOrGreater,
|
|
nameStartsWith: nameStartsWith,
|
|
nameLessThan: nameLessThan,
|
|
enableImages: enableImages,
|
|
enableTotalRecordCount: enableTotalRecordCount,
|
|
);
|
|
|
|
Future<Response<ServerQueryResult>> playlistsPlaylistIdItemsGet({
|
|
required String? playlistId,
|
|
int? startIndex,
|
|
int? limit,
|
|
List<ItemFields>? fields,
|
|
bool? enableImages,
|
|
bool? enableUserData,
|
|
int? imageTypeLimit,
|
|
List<ImageType>? enableImageTypes,
|
|
}) async {
|
|
final response = await api.playlistsPlaylistIdItemsGet(
|
|
playlistId: playlistId,
|
|
userId: account?.id,
|
|
startIndex: startIndex,
|
|
limit: limit,
|
|
fields: fields,
|
|
enableImages: enableImages,
|
|
enableUserData: enableUserData,
|
|
imageTypeLimit: imageTypeLimit,
|
|
enableImageTypes: enableImageTypes,
|
|
);
|
|
return response.copyWith(
|
|
body: ServerQueryResult.fromBaseQuery(response.bodyOrThrow, ref),
|
|
);
|
|
}
|
|
|
|
Future<Response> playlistsPlaylistIdItemsDelete({required String? playlistId, List<String>? entryIds}) =>
|
|
api.playlistsPlaylistIdItemsDelete(
|
|
playlistId: playlistId,
|
|
entryIds: entryIds,
|
|
);
|
|
|
|
Future<Response<UserDto>> usersMeGet() => api.usersMeGet();
|
|
|
|
Future<Response> configuration() => api.systemConfigurationGet();
|
|
|
|
Future<Response> itemsItemIdRefreshPost({
|
|
required String? itemId,
|
|
MetadataRefresh? metadataRefreshMode,
|
|
MetadataRefresh? imageRefreshMode,
|
|
bool? replaceAllMetadata,
|
|
bool? replaceAllImages,
|
|
}) =>
|
|
api.itemsItemIdRefreshPost(
|
|
itemId: itemId,
|
|
metadataRefreshMode: metadataRefreshMode?.metadataRefreshMode,
|
|
imageRefreshMode: imageRefreshMode?.imageRefreshMode,
|
|
replaceAllMetadata: replaceAllMetadata,
|
|
replaceAllImages: replaceAllImages,
|
|
);
|
|
|
|
Future<Response<UserItemDataDto>> usersUserIdFavoriteItemsItemIdPost({
|
|
required String? itemId,
|
|
}) =>
|
|
api.userFavoriteItemsItemIdPost(
|
|
itemId: itemId,
|
|
userId: account?.id,
|
|
);
|
|
|
|
Future<Response<UserItemDataDto>> usersUserIdFavoriteItemsItemIdDelete({
|
|
required String? itemId,
|
|
}) =>
|
|
api.userFavoriteItemsItemIdDelete(
|
|
itemId: itemId,
|
|
userId: account?.id,
|
|
);
|
|
|
|
Future<Response<UserItemDataDto>> usersUserIdPlayedItemsItemIdPost({
|
|
required String? itemId,
|
|
DateTime? datePlayed,
|
|
}) =>
|
|
api.userPlayedItemsItemIdPost(itemId: itemId, userId: account?.id, datePlayed: datePlayed);
|
|
|
|
Future<Response<UserItemDataDto>> usersUserIdPlayedItemsItemIdDelete({
|
|
required String? itemId,
|
|
}) =>
|
|
api.userPlayedItemsItemIdDelete(
|
|
itemId: itemId,
|
|
userId: account?.id,
|
|
);
|
|
|
|
Future<Response<MediaSegmentsModel>?> mediaSegmentsGet({
|
|
required String id,
|
|
}) async {
|
|
try {
|
|
final response = await api.mediaSegmentsItemIdGet(itemId: id);
|
|
final newSegments = response.body?.items?.map((e) => e.toSegment).toList() ?? [];
|
|
return response.copyWith(
|
|
body: MediaSegmentsModel(segments: newSegments),
|
|
);
|
|
} catch (e) {
|
|
log(e.toString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<Response<TrickPlayModel>?> getTrickPlay({
|
|
required ItemBaseModel? item,
|
|
int? width,
|
|
required Ref ref,
|
|
}) async {
|
|
try {
|
|
if (item == null) return null;
|
|
if (item.overview.trickPlayInfo?.isEmpty == true) {
|
|
return null;
|
|
}
|
|
final trickPlayModel = item.overview.trickPlayInfo?.values.lastOrNull;
|
|
if (trickPlayModel == null) return null;
|
|
final response = await api.videosItemIdTrickplayWidthTilesM3u8Get(
|
|
itemId: item.id,
|
|
width: trickPlayModel.width,
|
|
);
|
|
|
|
final server = ref.read(userProvider)?.server;
|
|
|
|
if (server == null) return null;
|
|
|
|
final sanitizedUrls = response.bodyString
|
|
.split('\n')
|
|
.where((line) => line.isNotEmpty && !line.startsWith('#'))
|
|
.map((line) => line.trim())
|
|
.map((line) => Uri.parse(line).toString())
|
|
.toList();
|
|
|
|
return response.copyWith(
|
|
body: trickPlayModel.copyWith(
|
|
images: sanitizedUrls
|
|
.map(
|
|
(e) => joinAll([server, 'Videos/${item.id}/Trickplay/${trickPlayModel.width}', e]),
|
|
)
|
|
.toList()));
|
|
} catch (e) {
|
|
log(e.toString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<Response<List<SessionInfoDto>>> sessionsInfo(String deviceId) async => api.sessionsGet(deviceId: deviceId);
|
|
|
|
Future<Response<bool>> quickConnect(String code) async => api.quickConnectAuthorizePost(code: code);
|
|
|
|
Future<Response<bool>> quickConnectEnabled() async => api.quickConnectEnabledGet();
|
|
|
|
Future<Response<dynamic>> deleteItem(String itemId) => api.itemsItemIdDelete(itemId: itemId);
|
|
|
|
Future<UserConfiguration?> _updateUserConfiguration(UserConfiguration newUserConfiguration) async {
|
|
if (account?.id == null) return null;
|
|
|
|
final response = await api.usersConfigurationPost(
|
|
userId: account!.id,
|
|
body: newUserConfiguration,
|
|
);
|
|
|
|
if (response.isSuccessful) {
|
|
return newUserConfiguration;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<UserConfiguration?> updateRememberAudioSelections() {
|
|
final currentUserConfiguration = account?.userConfiguration;
|
|
if (currentUserConfiguration == null) return Future.value(null);
|
|
|
|
final updated = currentUserConfiguration.copyWith(
|
|
rememberAudioSelections: !(currentUserConfiguration.rememberAudioSelections ?? false),
|
|
);
|
|
return _updateUserConfiguration(updated);
|
|
}
|
|
|
|
Future<UserConfiguration?> updateRememberSubtitleSelections() {
|
|
final current = account?.userConfiguration;
|
|
if (current == null) return Future.value(null);
|
|
|
|
final updated = current.copyWith(
|
|
rememberSubtitleSelections: !(current.rememberSubtitleSelections ?? false),
|
|
);
|
|
return _updateUserConfiguration(updated);
|
|
}
|
|
}
|