export { RefTo, Ref, Song, Collection, DB, Artist, Platforms, CollectionType, from_json } type ID = number enum RefTo { Artists, Songs, Collections } enum CollectionType { Album = "Album", EP = "EP", Single = "Single", Playlist = "Playlist", Release = "Release", } enum Platforms { Youtube = "Youtube", Linktree = "Linktree", Bandcamp = "Bandcamp", Spotify = "Spotify", Portfolio = "Portfolio", BeatPort = "BeatPort", SoundCloud = "SoundCloud", Instagram = "Instagram", Patreon = "Patreon", Twitter = "Twitter", Facebook = "Facebook", } class Ref { constructor(public to: RefTo, public id: ID) { } get(from: DB) { switch (this.to) { case RefTo.Artists: { return from.artists.find((artist) => artist.id == this.id) } case RefTo.Songs: { return from.songs.find((song) => song.id == this.id) } case RefTo.Collections: { return from.collections.find((col) => col.id = this.id) } } } } function ref_from_json(ref: any): Ref { return new Ref(ref.to, ref.id) } interface SongConstructor { name: string artists: Ref[] url: URL duration: number publish_date?: Date remix_artists?: Ref[] in_collection?: Ref cover?: URL bpm?: number key?: string fft_data?: number[] id?: ID, metadata: any } class Song { name: string artists: Ref[] url: URL duration: number remix_artists: Ref[] publish_date?: Date in_collection?: Ref cover?: URL bpm?: number key?: string fft_data?: number[] metadata: any /** * The ID is always there, don't worry :) */ id?: ID constructor(data: SongConstructor) { this.name = data.name this.artists = data.artists || [] this.url = data.url this.duration = data.duration this.publish_date = data.publish_date this.remix_artists = data.remix_artists || [] this.in_collection = data.in_collection this.cover = data.cover this.bpm = data.bpm this.key = data.key this.fft_data = data.fft_data this.id = data.id this.metadata = data.metadata } } interface ArtistConstructor { name: string, pfp?: URL songs?: Ref[] collections?: Ref[] links?: [Platforms, URL][] id?: ID metadata: any } class Artist { name = "" pfp?: URL | string songs: Ref[] collections: Ref[] links?: [Platforms, URL][] metadata: any /** * The ID is always there, don't worry :) */ id?: ID constructor(data: ArtistConstructor) { this.name = data.name this.pfp = data.pfp this.songs = data.songs || [] this.collections = data.collections || [] this.links = data.links this.id = data.id this.metadata = data.metadata } } interface CollectionConstructor { artists: Ref[] songs: Ref[] cover: URL duration: number publish_date?: Date id?: ID metadata: any name?: string type?: CollectionType } class Collection { name?: string type?: CollectionType artists: Ref[] songs: Ref[] cover: URL duration: number publish_date?: Date metadata: any /** * The ID is always there, don't worry :) */ id?: ID constructor(data: CollectionConstructor) { this.artists = data.artists this.songs = data.songs this.cover = data.cover this.duration = data.duration this.publish_date = data.publish_date this.id = data.id this.name = data.name this.metadata = data.metadata } } class DB { artists: Artist[] = [] songs: Song[] = [] collections: Collection[] = [] add(song: Song[]): void add(artist: Artist[]): void add(collection: Collection[]): void add(mix: (Song | Artist | Collection)[]): void add(stuff: Artist[] | Collection[] | Song[] | (Song | Artist | Collection)[]) { /** All of this adds refrences to the other side of whatever is being added. * eg. adding song with refrence to artist, adds refrence of song to artist * and adds incremental ids */ let inputs if (typeof stuff[Symbol.iterator] != "function") { inputs = [stuff] } else { inputs = stuff } for (const input of inputs) { if (input instanceof Artist) { const artist = input as Artist if (!artist.id) artist.id = this.artists.length this.artists.push(artist) for (const song_ref of artist.songs) { const curr_song = song_ref.get(this) as Song curr_song?.artists.push(new Ref(RefTo.Artists, artist.id)) } for (const col_ref of artist.collections) { const curr_col = col_ref.get(this) as Collection curr_col?.artists.push(new Ref(RefTo.Artists, artist.id)) } } else if (input instanceof Collection) { const col = input as Collection if (!col.id) col.id = this.collections.length this.collections.push(col) for (const song_ref of col.songs) { const curr_song = song_ref.get(this) as Song curr_song.in_collection = new Ref(RefTo.Collections, col.id) } for (const artist_ref of col.artists) { const curr_artist = artist_ref.get(this) as Artist curr_artist.collections.push(new Ref(RefTo.Collections, col.id)) } } else if (input instanceof Song) { const song = input as Song if (!song.id) song.id = this.songs.length this.songs.push(song) if (song.in_collection) { const curr_col = song.in_collection.get(this) as Collection curr_col?.songs.push(new Ref(RefTo.Songs, song.id)) } for (const artist_ref of song.artists) { const curr_artist = artist_ref.get(this) as Artist curr_artist.songs.push(new Ref(RefTo.Songs, song.id)) } } } this.songs.sort((a, b) => a.id! - b.id!) this.collections.sort((a, b) => a.id! - b.id!) this.artists.sort((a, b) => a.id! - b.id!) } } function from_json(db_stringified: { artists?: any, songs?: any, collections?: any }): DB { const db = new DB if (db_stringified.artists) { for (const artist of db_stringified.artists) { if (artist.songs) artist.songs = artist.songs.map((e: any) => ref_from_json(e)) if (artist.collections) artist.collections = artist.collections.map((e: any) => ref_from_json(e)) if (artist.links) artist.links = artist.links.map((e: any) => { try { [e[0] as Platforms, new URL(e[1])] } catch (e) { console.log(e) } }) if (artist.publish_date) artist.publish_date = new Date(JSON.parse(artist.publish_date)) if (artist.id) artist.id = artist.id as ID try { if (artist.pfp) artist.pfp = new URL(artist.pfp) } catch (e) { console.error(e), console.error("failed to parse artist URL") } db.artists.push(artist) } } if (db_stringified.songs) { for (const song of db_stringified.songs) { if (song.artists) song.artists = song.artists.map((e: any) => ref_from_json(e)) if (song.remix_artists) song.remix_artists = song.remix_artists.map((e: any) => ref_from_json(e)) if (song.in_collection) song.in_collection = ref_from_json(song.in_collection) try { if (song.cover) song.cover = new URL(song.cover) } catch (e) { console.error(e), console.error("failed to parse artist URL") } try { if (song.publish_date) song.publish_date = new Date(JSON.parse(song.publish_date)) } catch (e) { console.error(e), console.error("Failed to song cover url") } if (song.id) song.id = song.id as ID db.songs.push(song) } } if (db_stringified.collections) { for (const collection of db_stringified.collections) { if (collection.artists) collection.artists = collection.artists.map((e: any) => ref_from_json(e)) if (collection.songs) collection.songs = collection.songs.map((e: any) => ref_from_json(e)) if (collection.type) collection.type = collection.type.map((e: any) => e as CollectionType) try { if (collection.publish_date) collection.publish_date = new Date(JSON.parse(collection.publish_date)) } catch (e) { console.error(e), console.error("Failed to parse date") } try { if (collection.cover) collection.cover = new URL(collection.cover) } catch (e) { console.error(e), console.error("failed to parse collection cover url") } if (collection.id) collection.id = collection.id as ID db.collections.push(collection) } } return db } // const db = new DB // db.add( // new Artist({ // name: "djkato", // }) // ) // db.add( // new Song({ // name: "Hihaa", // artists: [new Ref(RefTo.Artists, db.artists.find((a) => a.name == "djkato")!.id!)], // duration: 123, // url: new URL("http://Smt.com/efsse.mp3") // }) // ) // console.dir(db, { depth: null }) // const res = db.artists[0].songs[0].get(db) as Song // console.log(`${db.artists[0].name} has song ${db.songs[0].name}? : ${res.name} is there!`)