Started on jellyfin search

This commit is contained in:
Eclypsed
2024-03-25 12:29:22 -04:00
parent cd8360851f
commit a05796dbd6
2 changed files with 52 additions and 8 deletions

1
src/app.d.ts vendored
View File

@@ -45,6 +45,7 @@ declare global {
interface Connection {
getRecommendations: () => Promise<MediaItem[]>
getConnectionInfo: () => Promise<ConnectionInfo>
search: (searchTerm: string) => Promise<MediaItem[]>
}
// These Schemas should only contain general info data that is necessary for data fetching purposes.
// They are NOT meant to be stores for large amounts of data, i.e. Don't include the data for every single song the Playlist type.

View File

@@ -5,12 +5,16 @@ export class Jellyfin implements Connection {
private serverUrl: string
private accessToken: string
private readonly BASEHEADERS: Headers
constructor(id: string, userId: string, jellyfinUserId: string, serverUrl: string, accessToken: string) {
this.id = id
this.userId = userId
this.jfUserId = jellyfinUserId
this.serverUrl = serverUrl
this.accessToken = accessToken
this.BASEHEADERS = new Headers({ Authorization: `MediaBrowser Token="${this.accessToken}"` })
}
// const audoSearchParams = new URLSearchParams({
@@ -23,13 +27,11 @@ export class Jellyfin implements Connection {
// })
public getConnectionInfo = async (): Promise<Extract<ConnectionInfo, { type: 'jellyfin' }>> => {
const reqHeaders = new Headers({ Authorization: `MediaBrowser Token="${this.accessToken}"` })
const userUrl = new URL(`Users/${this.jfUserId}`, this.serverUrl).href
const systemUrl = new URL('System/Info', this.serverUrl).href
const userResponse = await fetch(userUrl, { headers: reqHeaders })
const systemResponse = await fetch(systemUrl, { headers: reqHeaders })
const userResponse = await fetch(userUrl, { headers: this.BASEHEADERS })
const systemResponse = await fetch(systemUrl, { headers: this.BASEHEADERS })
const userData: JellyfinAPI.User = await userResponse.json()
const systemData: JellyfinAPI.System = await systemResponse.json()
@@ -51,7 +53,7 @@ export class Jellyfin implements Connection {
}
public getRecommendations = async (): Promise<MediaItem[]> => {
const mostPlayedSongsSearchParams = new URLSearchParams({
const searchParams = new URLSearchParams({
SortBy: 'PlayCount',
SortOrder: 'Descending',
IncludeItemTypes: 'Audio',
@@ -59,15 +61,34 @@ export class Jellyfin implements Connection {
limit: '10',
})
const mostPlayedSongsURL = new URL(`/Users/${this.jfUserId}/Items?${mostPlayedSongsSearchParams.toString()}`, this.serverUrl).href
const requestHeaders = new Headers({ Authorization: `MediaBrowser Token="${this.accessToken}"` })
const mostPlayedSongsURL = new URL(`/Users/${this.jfUserId}/Items?${searchParams.toString()}`, this.serverUrl).toString()
const mostPlayedResponse = await fetch(mostPlayedSongsURL, { headers: requestHeaders })
const mostPlayedResponse = await fetch(mostPlayedSongsURL, { headers: this.BASEHEADERS })
const mostPlayedData = await mostPlayedResponse.json()
return Array.from(mostPlayedData.Items as JellyfinAPI.Song[], (song) => this.songFactory(song))
}
public search = async (searchTerm: string): Promise<MediaItem[]> => {
const searchParams = new URLSearchParams({
userId: this.jfUserId,
searchTerm,
includeItemTypes: 'Audio,MusicAlbum,MusicArtist',
})
const searchURL = new URL(`Search/Hints?${searchParams.toString()}`, this.serverUrl).toString()
const searchResponse = await fetch(searchURL, { headers: this.BASEHEADERS })
if (!searchResponse.ok) throw new JellyfinFetchError('Failed to search Jellyfin', searchResponse.status, searchURL)
const searchResults = (await searchResponse.json()).SearchHints as JellyfinAPI.SearchHint[]
}
private mediaItemFactory = (mediaItem: JellyfinAPI.MediaItem): MediaItem => {
const thumbnail = mediaItem.ImageTags?.Primary
? new URL(`Items/${mediaItem.Id}/Images/Primary`, this.serverUrl).toString()
: mediaItem.
}
private songFactory = (song: JellyfinAPI.Song): Song => {
const thumbnail = song.ImageTags?.Primary
? new URL(`Items/${song.Id}/Images/Primary`, this.serverUrl).href
@@ -196,4 +217,26 @@ declare namespace JellyfinAPI {
interface Artist extends JellyfinAPI.MediaItem {
Type: 'MusicArtist'
}
type SearchHint = {
Id: string
Name: string
PrimaryImageTag?: string
} & ({
Type: 'Audio'
RunTimeTicks: number
ProductionYear?: number
AlbumId: string // When no album exists, the id defaults to: "00000000000000000000000000000000"
Album?: string
Artists: {
[key: number]: string
}[]
} | {
Type: 'MusicArtist'
} | {
Type: 'MusicAlbum'
RunTimeTicks: number
ProductionYear?: number
AlbumArtist: string
})
}