Removed MediaItem type
This commit is contained in:
32
src/app.d.ts
vendored
32
src/app.d.ts
vendored
@@ -24,8 +24,6 @@ declare global {
|
||||
passwordHash: string
|
||||
}
|
||||
|
||||
type serviceType = 'jellyfin' | 'youtube-music'
|
||||
|
||||
type ConnectionInfo = {
|
||||
id: string
|
||||
userId: string
|
||||
@@ -43,27 +41,24 @@ declare global {
|
||||
)
|
||||
|
||||
interface Connection {
|
||||
getRecommendations: () => Promise<MediaItem[]>
|
||||
getRecommendations: () => Promise<(Song | Album | Playlist)[]>
|
||||
getConnectionInfo: () => Promise<ConnectionInfo>
|
||||
search: (searchTerm: string) => Promise<MediaItem[]>
|
||||
search: (searchTerm: string) => Promise<(Song | Album | Playlist)[]>
|
||||
}
|
||||
// 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.
|
||||
// Big data should be fetched as needed in the app, these exist to ensure that the info necessary to fetch that data is there.
|
||||
interface MediaItem {
|
||||
type: 'song' | 'album' | 'playlist' | 'artist'
|
||||
id: string
|
||||
name: string
|
||||
thumbnail?: string
|
||||
}
|
||||
|
||||
interface Song extends MediaItem {
|
||||
type Song = {
|
||||
connection: {
|
||||
id: string
|
||||
type: serviceType
|
||||
}
|
||||
id: string
|
||||
name: string
|
||||
type: 'song'
|
||||
duration?: number
|
||||
thumbnail?: string
|
||||
artists?: {
|
||||
id: string
|
||||
name: string
|
||||
@@ -77,13 +72,16 @@ declare global {
|
||||
releaseDate?: string
|
||||
}
|
||||
|
||||
interface Album extends MediaItem {
|
||||
type Album = {
|
||||
connection: {
|
||||
id: string
|
||||
type: serviceType
|
||||
}
|
||||
id: string
|
||||
name: string
|
||||
type: 'album'
|
||||
duration?: number
|
||||
thumbnail?: string
|
||||
artists?: {
|
||||
// Album Artists
|
||||
id: string
|
||||
@@ -93,8 +91,11 @@ declare global {
|
||||
}
|
||||
|
||||
// IMPORTANT: This interface is for Lazuli created and stored playlists. Use service-specific interfaces when pulling playlists from services
|
||||
interface Playlist extends MediaItem {
|
||||
type Playlist = {
|
||||
id: string
|
||||
name: string
|
||||
type: 'playlist'
|
||||
thumbnail?: string
|
||||
description?: string
|
||||
items: {
|
||||
connectionId: string
|
||||
@@ -102,8 +103,11 @@ declare global {
|
||||
}[]
|
||||
}
|
||||
|
||||
interface Artist extends MediaItem {
|
||||
type Artist = {
|
||||
id: string
|
||||
name: string
|
||||
type: 'artist'
|
||||
thumbnail?: string
|
||||
}
|
||||
|
||||
namespace Jellyfin {
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
<script lang="ts">
|
||||
export let mediaItem: MediaItem
|
||||
export let mediaItem: Song | Album | Playlist
|
||||
|
||||
import IconButton from '$lib/components/util/iconButton.svelte'
|
||||
import { goto } from '$app/navigation'
|
||||
|
||||
let image: HTMLImageElement, captionText: HTMLDivElement
|
||||
|
||||
const checkSongOrAlbum = (item: MediaItem): item is Song | Album => {
|
||||
return item.type === 'song' || item.type === 'album'
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="card-wrapper" class="flex-shrink-0">
|
||||
@@ -29,7 +25,7 @@
|
||||
<div bind:this={captionText} class="w-56 p-1">
|
||||
<div class="mb-0.5 line-clamp-2 text-wrap text-sm" title={mediaItem.name}>{mediaItem.name}</div>
|
||||
<div class="leading-2 line-clamp-2 text-neutral-400" style="font-size: 0;">
|
||||
{#if checkSongOrAlbum(mediaItem) && 'artists' in mediaItem && mediaItem.artists}
|
||||
{#if 'artists' in mediaItem && mediaItem.artists}
|
||||
{#each mediaItem.artists as artist}
|
||||
{@const listIndex = mediaItem.artists.indexOf(artist)}
|
||||
<a class="text-sm hover:underline focus:underline" href="/details/artist?id={artist.id}&connection={mediaItem.connection.id}">{artist.name}</a>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
export let header: string
|
||||
export let cardDataList: MediaItem[]
|
||||
export let cardDataList: (Song | Album | Playlist)[]
|
||||
|
||||
import MediaCard from '$lib/components/media/mediaCard.svelte'
|
||||
import IconButton from '$lib/components/util/iconButton.svelte'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { generateUUID } from '$lib/utils'
|
||||
interface DBConnectionsTableSchema {
|
||||
id: string
|
||||
userId: string
|
||||
type: serviceType
|
||||
type: string
|
||||
service?: string
|
||||
tokens?: string
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class Storage {
|
||||
const { userId, type, service, tokens } = result
|
||||
const parsedService = service ? JSON.parse(service) : undefined
|
||||
const parsedTokens = tokens ? JSON.parse(tokens) : undefined
|
||||
connectionInfo.push({ id, userId, type, serviceInfo: parsedService, tokens: parsedTokens })
|
||||
connectionInfo.push({ id, userId, type: type as DBServiceInfo['type'], serviceInfo: parsedService, tokens: parsedTokens })
|
||||
}
|
||||
return connectionInfo
|
||||
}
|
||||
@@ -97,7 +97,7 @@ class Storage {
|
||||
for (const { id, type, service, tokens } of connectionRows) {
|
||||
const parsedService = service ? JSON.parse(service) : undefined
|
||||
const parsedTokens = tokens ? JSON.parse(tokens) : undefined
|
||||
connections.push({ id, userId, type, serviceInfo: parsedService, tokens: parsedTokens })
|
||||
connections.push({ id, userId, type: type as DBServiceInfo['type'], serviceInfo: parsedService, tokens: parsedTokens })
|
||||
}
|
||||
return connections
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export class Jellyfin implements Connection {
|
||||
}
|
||||
}
|
||||
|
||||
public getRecommendations = async (): Promise<MediaItem[]> => {
|
||||
public getRecommendations = async (): Promise<(Song | Album | Playlist)[]> => {
|
||||
const searchParams = new URLSearchParams({
|
||||
SortBy: 'PlayCount',
|
||||
SortOrder: 'Descending',
|
||||
@@ -69,7 +69,7 @@ export class Jellyfin implements Connection {
|
||||
return Array.from(mostPlayedData.Items as JellyfinAPI.Song[], (song) => this.parseSong(song))
|
||||
}
|
||||
|
||||
public search = async (searchTerm: string): Promise<MediaItem[]> => {
|
||||
public search = async (searchTerm: string): Promise<(Song | Album | Playlist)[]> => {
|
||||
const searchParams = new URLSearchParams({
|
||||
searchTerm,
|
||||
includeItemTypes: 'Audio,MusicAlbum', // Potentially add MusicArtist
|
||||
@@ -81,7 +81,7 @@ export class Jellyfin implements Connection {
|
||||
if (!searchResponse.ok) throw new JellyfinFetchError('Failed to search Jellyfin', searchResponse.status, searchURL)
|
||||
const searchResults = (await searchResponse.json()).Items as (JellyfinAPI.Song | JellyfinAPI.Album)[] // JellyfinAPI.Artist
|
||||
|
||||
const parsedResults: MediaItem[] = Array.from(searchResults, (result) => {
|
||||
const parsedResults: (Song | Album)[] = Array.from(searchResults, (result) => {
|
||||
switch (result.Type) {
|
||||
case 'Audio':
|
||||
return this.parseSong(result)
|
||||
|
||||
@@ -69,12 +69,12 @@ export class YouTubeMusic implements Connection {
|
||||
}
|
||||
}
|
||||
|
||||
public getRecommendations = async (): Promise<MediaItem[]> => {
|
||||
public getRecommendations = async (): Promise<(Song | Album | Playlist)[]> => {
|
||||
const { listenAgain, quickPicks } = await this.getHome()
|
||||
return listenAgain.concat(quickPicks)
|
||||
}
|
||||
|
||||
public search = async (searchTerm: string): Promise<MediaItem[]> => {
|
||||
public search = async (searchTerm: string): Promise<(Song | Album | Playlist)[]> => {
|
||||
const headers = Object.assign(this.BASEHEADERS, { authorization: `Bearer ${(await this.getTokens()).accessToken}`, 'X-Goog-Request-Time': `${Date.now()}` })
|
||||
|
||||
const response = await fetch(`https://music.youtube.com/youtubei/v1/search`, {
|
||||
@@ -127,7 +127,7 @@ export class YouTubeMusic implements Connection {
|
||||
const headerTitle = section.musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs[0].text
|
||||
const rawContents = section.musicCarouselShelfRenderer.contents
|
||||
|
||||
const parsedContent: MediaItem[] =
|
||||
const parsedContent: (Song | Album | Playlist)[] =
|
||||
'musicTwoRowItemRenderer' in rawContents[0]
|
||||
? this.parseTwoRowItemRenderer((rawContents as { musicTwoRowItemRenderer: InnerTube.musicTwoRowItemRenderer }[]).map((item) => item.musicTwoRowItemRenderer))
|
||||
: this.parseResponsiveListItemRenderer((rawContents as { musicResponsiveListItemRenderer: InnerTube.musicResponsiveListItemRenderer }[]).map((item) => item.musicResponsiveListItemRenderer))
|
||||
@@ -144,8 +144,8 @@ export class YouTubeMusic implements Connection {
|
||||
return homeItems
|
||||
}
|
||||
|
||||
private parseTwoRowItemRenderer = (rowContent: InnerTube.musicTwoRowItemRenderer[]): MediaItem[] => {
|
||||
const parsedContent: MediaItem[] = []
|
||||
private parseTwoRowItemRenderer = (rowContent: InnerTube.musicTwoRowItemRenderer[]): (Song | Album | Playlist)[] => {
|
||||
const parsedContent: (Song | Album | Playlist)[] = []
|
||||
for (const data of rowContent) {
|
||||
const title = data.title.runs[0].text
|
||||
const subtitles = data.subtitle.runs
|
||||
@@ -201,7 +201,7 @@ export class YouTubeMusic implements Connection {
|
||||
}
|
||||
}
|
||||
|
||||
const thumbnail: MediaItem['thumbnail'] = refineThumbnailUrl(data.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
||||
const thumbnail = refineThumbnailUrl(data.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails[0].url)
|
||||
|
||||
const song: Song = {
|
||||
connection: {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Connections } from '$lib/server/connections'
|
||||
export const GET: RequestHandler = async ({ params }) => {
|
||||
const userId = params.userId!
|
||||
|
||||
const recommendations: MediaItem[] = []
|
||||
const recommendations: (Song | Album | Playlist)[] = []
|
||||
for (const connection of Connections.getUserConnections(userId)) {
|
||||
await connection
|
||||
.getRecommendations()
|
||||
|
||||
Reference in New Issue
Block a user