diff --git a/package-lock.json b/package-lock.json index 6697a4d95c..bf88087474 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2513,6 +2513,17 @@ "string.prototype.matchall": "^4.0.6" } }, + "@thornbill/jellyfin-sdk": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@thornbill/jellyfin-sdk/-/jellyfin-sdk-0.4.1.tgz", + "integrity": "sha512-DuUeSiIvk1qcEYp9oxnKc/e4T0zj3LujXhITQ6L6TqGOo8miNiBgU8OjmidAUwPc2ibCLAK2rM5BcNVAEwaFmw==", + "dev": true, + "requires": { + "axios": "^0.26.0", + "compare-versions": "^4.0.0", + "normalize-url": "^6.1.0" + } + }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -3587,6 +3598,15 @@ "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", "dev": true }, + "axios": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz", + "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.8" + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -4199,6 +4219,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.3.tgz", + "integrity": "sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", diff --git a/package.json b/package.json index 39268a9568..d27e43887d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@babel/preset-env": "7.16.11", "@babel/preset-react": "7.16.7", "@babel/preset-typescript": "7.16.7", + "@thornbill/jellyfin-sdk": "0.4.1", "@types/lodash-es": "4.17.6", "@types/react": "17.0.39", "@types/react-dom": "17.0.11", diff --git a/src/apiclient.d.ts b/src/apiclient.d.ts new file mode 100644 index 0000000000..565ac35a83 --- /dev/null +++ b/src/apiclient.d.ts @@ -0,0 +1,350 @@ +// TODO: Move to jellyfin-apiclient +declare module 'jellyfin-apiclient' { + import { + AllThemeMediaResult, + AuthenticationResult, + BaseItemDto, + BaseItemDtoQueryResult, + BufferRequestDto, + ClientCapabilities, + CountryInfo, + CultureDto, + DeviceOptions, + DisplayPreferencesDto, + EndPointInfo, + FileSystemEntryInfo, + GeneralCommand, + GroupInfoDto, + GuideInfo, + IgnoreWaitRequestDto, + ImageInfo, + ImageProviderInfo, + ImageType, + ItemCounts, + LiveTvInfo, + MovePlaylistItemRequestDto, + NewGroupRequestDto, + NextItemRequestDto, + NotificationResultDto, + NotificationsSummaryDto, + ParentalRating, + PingRequestDto, + PlaybackInfoResponse, + PlaybackProgressInfo, + PlaybackStartInfo, + PlaybackStopInfo, + PlayCommand, + PlaystateCommand, + PluginInfo, + PluginSecurityInfo, + PreviousItemRequestDto, + QueryFiltersLegacy, + QueueRequestDto, + QuickConnectResult, + QuickConnectState, + ReadyRequestDto, + RecommendationDto, + RemoteImageResult, + RemoveFromPlaylistRequestDto, + SearchHintResult, + SeekRequestDto, + SeriesTimerInfoDto, + SeriesTimerInfoDtoQueryResult, + ServerConfiguration, + SessionInfo, + SetPlaylistItemRequestDto, + SetRepeatModeRequestDto, + SetShuffleModeRequestDto, + SystemInfo, + TaskInfo, + TaskTriggerInfo, + TimerInfoDto, + TimerInfoDtoQueryResult, + UserConfiguration, + UserDto, + UserItemDataDto, + UserPolicy, + UtcTimeResponse, + VirtualFolderInfo + } from '@thornbill/jellyfin-sdk/dist/generated-client'; + + class ApiClient { + constructor(serverAddress: string, appName: string, appVersion: string, deviceName: string, deviceId: string); + + accessToken(): string; + addMediaPath(virtualFolderName: string, mediaPath: string, networkSharePath: string, refreshLibrary?: boolean): Promise; + addVirtualFolder(name: string, type?: string, refreshLibrary?: boolean, libraryOptions?: any): Promise; + appName(): string; + appVersion(): string; + authenticateUserByName(name: string, password: string): Promise; + cancelLiveTvSeriesTimer(id: string): Promise; + cancelLiveTvTimer(id: string): Promise; + cancelSyncItems(itemIds: string[], targetId?: string): Promise; + clearAuthenticationInfo(): void; + clearUserItemRating(userId: string, itemId: string): Promise; + closeWebSocket(): void; + createLiveTvSeriesTimer(item: string): Promise; + createLiveTvTimer(item: string): Promise; + createPackageReview(review: any): Promise; + createSyncPlayGroup(options?: NewGroupRequestDto): Promise; + createUser(user: UserDto): Promise; + deleteDevice(deviceId: string): Promise; + deleteItemImage(itemId: string, imageType: ImageType, imageIndex?: number): Promise; + deleteItem(itemId: string): Promise; + deleteLiveTvRecording(id: string): Promise; + deleteUserImage(userId: string, imageType: ImageType, imageIndex?: number): Promise; + deleteUser(userId: string): Promise; + detectBitrate(force: boolean): Promise; + deviceId(): string; + deviceName(): string; + disablePlugin(id: string, version: string): Promise; + downloadRemoteImage(options: any): Promise; + enablePlugin(id: string, version: string): Promise; + encodeName(name: string): string; + ensureWebSocket(): void; + fetch(request: any, includeAuthorization?: boolean): Promise; + fetchWithFailover(request: any, enableReconnection?: boolean): Promise; + getAdditionalVideoParts(userId?: string, itemId: string): Promise; + getAlbumArtists(userId: string, options?: any): Promise; + getAncestorItems(itemId: string, userId?: string): Promise; + getArtist(name: string, userId?: string): Promise; + getArtists(userId: string, options?: any): Promise; + getAvailablePlugins(options?: any): Promise; + getAvailableRemoteImages(options: any): Promise; + getContentUploadHistory(): Promise; + getCountries(): Promise; + getCriticReviews(itemId: string, options?: any): Promise; + getCultures(): Promise; + getCurrentUserId(): string; + getDateParamValue(date: Date): string; + getDefaultImageQuality(imageType: ImageType): number; + getDevicesOptions(): Promise; + getDirectoryContents(path: string, options?: any): Promise; + getDisplayPreferences(id: string, userId: string, app: string): Promise; + getDownloadSpeed(byteSize: number): Promise; + getDrives(): Promise; + getEndpointInfo(): Promise; + getEpisodes(itemId: string, options?: any): Promise; + getFilters(options?: any): Promise; + getGenre(name: string, userId?: string): Promise; + getGenres(userId: string, options?: any): Promise; + getImageUrl(itemId: string, options?: any): string; + getInstalledPlugins(): Promise; + getInstantMixFromItem(itemId: string, options?: any): Promise; + getIntros(itemId: string): Promise; + getItemCounts(userId?: string): Promise; + getItemDownloadUrl(itemId: string): string; + getItemImageInfos(itemId: string): Promise; + getItems(userId: string, options?: any): Promise; + getItem(userId: string, itemId: string): Promise; + getJSON(url: string, includeAuthorization?: boolean): Promise; + getLatestItems(options?: any): Promise; + getLiveStreamMediaInfo(liveStreamId: string): Promise; + getLiveTvChannel(id: string, userId?: string): Promise; + getLiveTvChannels(options?: any): Promise; + getLiveTvGuideInfo(userId: string): Promise; + getLiveTvInfo(userId: string): Promise; + getLiveTvProgram(id: string, userId?: string): Promise; + getLiveTvPrograms(options?: any): Promise; + getLiveTvRecommendedPrograms(options?: any): Promise; + getLiveTvRecordingGroup(id: string): Promise; + getLiveTvRecordingGroups(options?: any): Promise; + getLiveTvRecording(id: string, userId?: string): Promise; + getLiveTvRecordingSeries(options?: any): Promise; + getLiveTvRecordings(options?: any): Promise; + getLiveTvSeriesTimer(id: string): Promise; + getLiveTvSeriesTimers(options?: any): Promise; + getLiveTvTimer(id: string): Promise; + getLiveTvTimers(options?: any): Promise; + getLocalTrailers(userId: string, itemId: string): Promise; + getMovieRecommendations(options?: any): Promise; + getMusicGenre(name: string, userId?: string): Promise; + getMusicGenres(userId: string, options?: any): Promise; + getNamedConfiguration(name: string): Promise; + getNetworkDevices(): Promise; + getNetworkShares(path: string): Promise; + getNewLiveTvTimerDefaults(options?: any): Promise; + getNextUpEpisodes(options?: any): Promise; + getNotificationSummary(userId: string): Promise; + getNotifications(userId: string, options?: any): Promise; + getPackageInfo(name: string, guid: string): Promise; + getPackageReviews(packageId: string, minRating?: string, maxRating?: string, limit?: string): Promise; + getParentalRatings(): Promise; + getParentPath(path: string): Promise; + getPeople(userId: string, options?: any): Promise; + getPerson(name: string, userId?: string): Promise; + getPhysicalPaths(): Promise; + getPlaybackInfo(itemId: string, options: any, deviceProfile: any): Promise; + getPluginConfiguration(id: string): Promise; + getPublicSystemInfo(): Promise; + getPublicUsers(): Promise; + getQuickConnect(verb: string): Promise; + getReadySyncItems(deviceId: string): Promise; + getRecordingFolders(userId: string): Promise; + getRegistrationInfo(feature: string): Promise; + getRemoteImageProviders(options: any): Promise; + getResumableItems(userId: string, options?: any): Promise; + getRootFolder(userId: string): Promise; + getSavedEndpointInfo(): EndPointInfo; + getScaledImageUrl(itemId: string, options?: any): string; + getScheduledTask(id: string): Promise; + getScheduledTasks(options?: any): Promise; + getSearchHints(options?: any): Promise; + getSeasons(itemId: string, options?: any): Promise; + getServerConfiguration(): Promise; + getServerTime(): Promise; + getSessions(options?: any): Promise; + getSimilarItems(itemId: string, options?: any): Promise; + getSpecialFeatures(userId: string, itemId: string): Promise; + getStudio(name: string, userId?: string): Promise; + getStudios(userId: string, options?: any): Promise; + getSyncPlayGroups(): Promise; + getSyncStatus(itemId: string): Promise; + getSystemInfo(): Promise; + getThemeMedia(userId?: string, itemId: string, inherit?: boolean): Promise; + getThumbImageUrl(item: BaseItemDto, options?: any): string; + getUpcomingEpisodes(options?: any): Promise; + getUrl(name: string, params?: any, serverAddress?: string): string; + get(url: string): Promise; + getUserImageUrl(userId: string, options?: any): string; + getUsers(options?: any): Promise; + getUser(userId: string): Promise; + getUserViews(options?: any, userId: string): Promise; + getVirtualFolders(): Promise; + handleMessageReceived(msg: any): void; + installPlugin(name: string, guid: string, version?: string): Promise; + isLoggedIn(): boolean; + isMessageChannelOpen(): boolean; + isMinServerVersion(version: string): boolean; + isWebSocketOpen(): boolean; + isWebSocketOpenOrConnecting(): boolean; + isWebSocketSupported(): boolean; + joinSyncPlayGroup(options?: any): Promise; + leaveSyncPlayGroup(): Promise; + logout(): Promise; + markNotificationsRead(userId: string, idList: string[], isRead: boolean): Promise; + markPlayed(userId: string, itemId: string, date: Date): Promise; + markUnplayed(userId: string, itemId: string, date: Date): Promise; + openWebSocket(): void; + quickConnect(secret: string): Promise; + refreshItem(itemId: string, options?: any): Promise; + removeMediaPath(virtualFolderName: string, mediaPath: string, refreshLibrary?: boolean): Promise; + removeVirtualFolder(name: string, refreshLibrary?: boolean): Promise; + renameVirtualFolder(name: string, newName: string, refreshLibrary?: boolean): Promise; + reportCapabilities(capabilities: ClientCapabilities): Promise; + reportOfflineActions(actions: any): Promise; + reportPlaybackProgress(options: PlaybackProgressInfo): Promise; + reportPlaybackStart(options: PlaybackStartInfo): Promise; + reportPlaybackStopped(options: PlaybackStopInfo): Promise; + reportSyncJobItemTransferred(syncJobItemId: string): Promise; + requestSyncPlayBuffering(options?: BufferRequestDto): Promise; + requestSyncPlayMovePlaylistItem(options?: MovePlaylistItemRequestDto): Promise; + requestSyncPlayNextItem(options?: NextItemRequestDto): Promise; + requestSyncPlayPause(): Promise; + requestSyncPlayPreviousItem(options?: PreviousItemRequestDto): Promise; + requestSyncPlayQueue(options?: QueueRequestDto): Promise; + requestSyncPlayReady(options?: ReadyRequestDto): Promise; + requestSyncPlayRemoveFromPlaylist(options?: RemoveFromPlaylistRequestDto): Promise; + requestSyncPlaySeek(options?: SeekRequestDto): Promise; + requestSyncPlaySetIgnoreWait(options?: IgnoreWaitRequestDto): Promise; + requestSyncPlaySetNewQueue(options?: NewGroupRequestDto): Promise; + requestSyncPlaySetPlaylistItem(options?: SetPlaylistItemRequestDto): Promise; + requestSyncPlaySetRepeatMode(options?: SetRepeatModeRequestDto): Promise; + requestSyncPlaySetShuffleMode(options?: SetShuffleModeRequestDto): Promise; + requestSyncPlayUnpause(): Promise; + resetEasyPassword(userId: string): Promise; + resetLiveTvTuner(id: string): Promise; + resetUserPassword(userId: string): Promise; + restartServer(): Promise; + sendCommand(sessionId: string, command: any): Promise; + sendMessageCommand(sessionId: string, options: GeneralCommand): Promise; + sendMessage(name: string, data: any): void; + sendPlayCommand(sessionId: string, options: PlayCommand): Promise; + sendPlayStateCommand(sessionId: string, command: PlaystateCommand, options?: any): Promise; + sendSyncPlayPing(options?: PingRequestDto): Promise; + sendWebSocketMessage(name: string, data: any): void; + serverAddress(val?: string): string; + serverId(): string; + serverVersion(): string + setAuthenticationInfo(accessKey?: string, userId?: string): void; + setRequestHeaders(headers: any): void; + setSystemInfo(info: SystemInfo): void; + shutdownServer(): Promise; + startScheduledTask(id: string): Promise; + stopActiveEncodings(playSessionId: string): Promise; + stopScheduledTask(id: string): Promise; + syncData(data: any): Promise; + uninstallPluginByVersion(id: string, version: string): Promise; + uninstallPlugin(id: string): Promise; + updateDisplayPreferences(id: string, obj: DisplayPreferencesDto, userId: string, app: string): Promise; + updateEasyPassword(userId: string, newPassword: string): Promise; + updateFavoriteStatus(userId: string, itemId: string, isFavorite: boolean): Promise; + updateItemImageIndex(itemId: string, imageType: ImageType, imageIndex: number, newIndex: number): Promise; + updateItem(item: BaseItemDto): Promise; + updateLiveTvSeriesTimer(item: SeriesTimerInfoDto): Promise; + updateLiveTvTimer(item: TimerInfoDto): Promise; + updateMediaPath(virtualFolderName: string, pathInfo: any): Promise; + updateNamedConfiguration(name: string, configuration: any): Promise; + updatePluginConfiguration(id: string, configuration: any): Promise; + updatePluginSecurityInfo(info: PluginSecurityInfo): Promise; + updateScheduledTaskTriggers(id: string, triggers: TaskTriggerInfo[]): Promise; + updateServerConfiguration(configuration: ServerConfiguration): Promise; + updateServerInfo(server: any, serverUrl: string): void; + updateUserConfiguration(userId: string, configuration: UserConfiguration): Promise; + updateUserItemRating(userId: string, itemId: string, likes: boolean): Promise; + updateUserPassword(userId: string, currentPassword: string, newPassword: string): Promise; + updateUserPolicy(userId: string, policy: UserPolicy): Promise; + updateUser(user: UserDto): Promise; + updateVirtualFolderOptions(id: string, libraryOptions?: any): Promise; + uploadItemImage(itemId: string, imageType: ImageType, file: File): Promise; + uploadItemSubtitle(itemId: string, language: string, isForced: boolean, file: File): Promise; + uploadUserImage(userId: string, imageType: ImageType, file: File): Promise; + } + + class AppStore { + constructor(); + + getItem(name: string): string|null; + removeItem(name: string): void; + setItem(name: string, value: string): void; + } + + class ConnectionManager { + constructor(credentialProvider: Credentials, appName: string, appVersion: string, deviceName: string, deviceId: string, capabilities: ClientCapabilities); + + addApiClient(apiClient: ApiClient): void; + clearData(): void; + connect(options?: any): Promise; + connectToAddress(address: string, options?: any): Promise; + connectToServer(server: any, options?: any): Promise; + connectToServers(servers: any[], options?: any): Promise; + deleteServer(serverId: string): Promise; + getApiClient(item: BaseItemDto|string): ApiClient; + getApiClients(): ApiClient[]; + getAvailableServers(): any[]; + getOrCreateApiClient(serverId: string): ApiClient; + getSavedServers(): any[]; + handleMessageReceived(msg: any): void; + logout(): Promise; + minServerVersion(val?: string): string; + user(apiClient: ApiClient): Promise; + } + + class Credentials { + constructor(key?: string); + + addOrUpdateServer(list: any[], server: any): any; + clear(): void; + credentials(data?: any): any; + } + + interface Event { + type: string; + } + + const Events: { + off(obj: any, eventName: string, fn: (e: Event, ...args: any[]) => void): void; + on(obj: any, eventName: string, fn: (e: Event, ...args: any[]) => void): void; + trigger(obj: any, eventName: string, ...args: any[]): void; + }; +} diff --git a/src/global.d.ts b/src/global.d.ts index e3243f505f..942f37b0cb 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,5 +1,8 @@ export declare global { + import { ApiClient, Events } from 'jellyfin-apiclient'; + interface Window { - ApiClient: any; + ApiClient: ApiClient; + Events: Events; } }