add music-ibrary n test
This commit is contained in:
parent
decce4a910
commit
d269605f55
20 changed files with 801 additions and 65 deletions
|
@ -3,8 +3,9 @@
|
|||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"publish-player": "cd dist/packages/player && npm publish --access=public",
|
||||
"publish-visualizer": "cd dist/packages/visualizer && npm publish --access=public"
|
||||
"publish-player": "nx build player && cd dist/packages/player && npm publish --access=public",
|
||||
"publish-visualizer": "nx build visualizer && cd dist/packages/visualizer && npm publish --access=public",
|
||||
"publish-library": "nx build music-library && cd dist/packages/music-library && npm publish --access=public"
|
||||
},
|
||||
"private": false,
|
||||
"devDependencies": {
|
||||
|
|
33
packages/music-library-web-test/.eslintrc.json
Normal file
33
packages/music-library-web-test/.eslintrc.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"extends": [
|
||||
"../../.eslintrc.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
43
packages/music-library-web-test/index.html
Normal file
43
packages/music-library-web-test/index.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>MusicLibraryTest</title>
|
||||
<base href="/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="/src/styles.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="name-wrapper">
|
||||
<p>playing:
|
||||
<p id="text-playing"> ID</p>
|
||||
</p>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
|
||||
<audio src="" id="audio"></audio>
|
||||
<button id="previous">Previous Song</button>
|
||||
<button id="play">Play</button>
|
||||
<button id="pause">Pause</button>
|
||||
<button id="toggle-play">Toggle Pause/Play</button>
|
||||
<button id="next">Next Song</button>
|
||||
<p id="current">-:--</p>
|
||||
<input type="range" min="0" max="10" value="0" id="seek" step="0.01">
|
||||
<p id="duration">-:--</p>
|
||||
<span>
|
||||
<input type="range" min="0" max="1" value="1" id="volume" step="0.01">
|
||||
</span>
|
||||
<button id="mute">Mute</button>
|
||||
<button id="unmute">Unmute</button>
|
||||
<button id="toggle-mute">Toggle Mute</button>
|
||||
|
||||
</div>
|
||||
<script type="module" src="/src/db.ts"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
70
packages/music-library-web-test/project.json
Normal file
70
packages/music-library-web-test/project.json
Normal file
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "music-library-web-test",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "packages/music-library-web-test/src",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/vite:build",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"outputPath": "dist/packages/music-library-web-test"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"mode": "development"
|
||||
},
|
||||
"production": {
|
||||
"mode": "production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx/vite:dev-server",
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"buildTarget": "music-library-web-test:build"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "music-library-web-test:build:development",
|
||||
"hmr": true
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "music-library-web-test:build:production",
|
||||
"hmr": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"executor": "@nx/vite:preview-server",
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"buildTarget": "music-library-web-test:build"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "music-library-web-test:build:development"
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "music-library-web-test:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
],
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"packages/music-library-web-test/**/*.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
packages/music-library-web-test/public/favicon.ico
Normal file
BIN
packages/music-library-web-test/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
packages/music-library-web-test/public/janz - wish.mp3
Normal file
BIN
packages/music-library-web-test/public/janz - wish.mp3
Normal file
Binary file not shown.
0
packages/music-library-web-test/src/assets/.gitkeep
Normal file
0
packages/music-library-web-test/src/assets/.gitkeep
Normal file
50
packages/music-library-web-test/src/db.ts
Normal file
50
packages/music-library-web-test/src/db.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { DB, Artist, Song, RefTo, Ref, Platforms } from "@euterpe/music-library";
|
||||
export const db = new DB
|
||||
|
||||
db.add([
|
||||
//The IDs are added incrementally & are 0 based., so first artists ID added is 0, next 1 etc...
|
||||
//You can specify the ID manually if you want
|
||||
new Artist({
|
||||
name: "Jamie xx",
|
||||
}),
|
||||
new Artist({
|
||||
name: "janz",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Machinedrum",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Tanerélle",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Mono/Poly",
|
||||
}),
|
||||
new Artist({
|
||||
name: "IMANU",
|
||||
links: [
|
||||
[Platforms.Spotify, new URL("https://open.spotify.com/artist/5Y7rFm0tiJTVDzGLMzz0W1?si=DRaZyugTTIqlBHDkMGKVqA&nd=1")]
|
||||
]
|
||||
})])
|
||||
db.add([
|
||||
new Song({
|
||||
//Refrences are constructed as such. This allows to get to the artist from either collection or song
|
||||
artists: [new Ref(RefTo.Artists, 2), new Ref(RefTo.Artists, 3), new Ref(RefTo.Artists, 4)],
|
||||
duration: 252,
|
||||
name: "Star",
|
||||
remix_artists: [new Ref(RefTo.Artists, 5)],
|
||||
url: new URL("http://127.0.0.1:4200/Machinedrum, Tanerelle & Mono Poly - Star (IMANU Remix) final.mp3")
|
||||
}),
|
||||
new Song({
|
||||
//If you don't like guessing the IDs, then this is also a way to do it
|
||||
artists: [new Ref(RefTo.Artists, db.artists.find((a) => a.name == "Jamie xx")!.id!)],
|
||||
duration: 331,
|
||||
name: "Sleep Sound",
|
||||
url: new URL("http://127.0.0.1:4200/Jamie xx - Sleep Sound.mp3")
|
||||
}),
|
||||
new Song({
|
||||
artists: [new Ref(RefTo.Artists, 1)],
|
||||
duration: 75,
|
||||
name: "wish",
|
||||
url: new URL("http://127.0.0.1:4200/janz - wish.mp3")
|
||||
})
|
||||
])
|
116
packages/music-library-web-test/src/main.ts
Normal file
116
packages/music-library-web-test/src/main.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { MusicPlayerBuilder } from "@euterpe/player";
|
||||
import { db } from "./db";
|
||||
import { Artist } from "@euterpe/music-library";
|
||||
import { DB, Platforms } from "@euterpe/music-library";
|
||||
const audio_el = document.querySelector("#audio") as HTMLAudioElement
|
||||
const music_player_builder = MusicPlayerBuilder(audio_el)
|
||||
music_player_builder.start()
|
||||
const music_player = music_player_builder.build()
|
||||
music_player.change_volume(1)
|
||||
|
||||
let curr_song_id = 1;
|
||||
const elem_curr_song = document.querySelector("#text-playing")
|
||||
|
||||
music_player.try_new_song_async(db.songs[curr_song_id].url.pathname)
|
||||
.then(() => {
|
||||
let is_seeking = false
|
||||
change_current_song_text(db)
|
||||
|
||||
document.querySelector("#previous")?.addEventListener("click", () => {
|
||||
curr_song_id--
|
||||
if (curr_song_id < 0) curr_song_id = 2
|
||||
music_player.try_new_song_async(db.songs[curr_song_id].url.pathname).then((s) => {
|
||||
change_current_song_text(db)
|
||||
music_player.play_async().catch((err) => { console.log(err) })
|
||||
}, (e) => { console.log(e) })
|
||||
})
|
||||
document.querySelector("#next")?.addEventListener("click", () => {
|
||||
curr_song_id++
|
||||
if (curr_song_id > 2) curr_song_id = 0
|
||||
music_player.try_new_song_async(db.songs[curr_song_id].url.pathname).then((s) => {
|
||||
change_current_song_text(db)
|
||||
music_player.play_async().catch((err) => { console.log(err) })
|
||||
}, (e) => { console.log(e) })
|
||||
})
|
||||
|
||||
document.querySelector("#play")?.addEventListener("click", () => {
|
||||
music_player.play_async()
|
||||
.then(() => { console.log("Playing!") }, (e) => alert("Failed to play, " + e))
|
||||
})
|
||||
document.querySelector("#pause")?.addEventListener("click", () => {
|
||||
music_player.pause()
|
||||
})
|
||||
document.querySelector("#mute")?.addEventListener("click", () => {
|
||||
music_player.mute()
|
||||
})
|
||||
document.querySelector("#unmute")?.addEventListener("click", () => {
|
||||
music_player.unmute()
|
||||
})
|
||||
document.querySelector("#toggle-mute")?.addEventListener("click", () => {
|
||||
music_player.mute_toggle()
|
||||
})
|
||||
document.querySelector("#toggle-play")?.addEventListener("click", () => {
|
||||
music_player.play_toggle_async().then((s) => console.log("toggled play/pause"), (e) => alert("failed to toggle pause/play!" + e))
|
||||
})
|
||||
document.querySelector("#volume")?.addEventListener("input", (e) => {
|
||||
music_player.change_volume(e.target?.valueAsNumber)
|
||||
})
|
||||
document.querySelector("#seek")?.addEventListener("mousedown", (e) => {
|
||||
is_seeking = true;
|
||||
})
|
||||
document.querySelector("#seek")?.addEventListener("mouseup", (e) => {
|
||||
music_player.try_seek_async(e.target?.valueAsNumber).then(() => { console.log("seeked to " + e.target?.valueAsNumber) }, () => {
|
||||
alert("Failed seeking! " + e)
|
||||
})
|
||||
is_seeking = false
|
||||
})
|
||||
// Subscriptions to AudioContext changes, eg. time..
|
||||
music_player.subscribe_to_formatted_duration_time((time) => {
|
||||
document.querySelector("#duration").innerHTML = time
|
||||
document.querySelector("#seek").max = "" + music_player.get_current_duration()
|
||||
})
|
||||
music_player.subscribe_to_formatted_current_time_tick((time) => {
|
||||
document.querySelector("#current").innerHTML = time
|
||||
})
|
||||
music_player.subscribe_to_time_tick((time) => {
|
||||
if (is_seeking) return
|
||||
document.querySelector("#seek").value = "" + time
|
||||
})
|
||||
|
||||
}, (e) => console.log(e))
|
||||
|
||||
|
||||
function change_current_song_text(db: DB) {
|
||||
const curr_song = db.songs[curr_song_id]
|
||||
let final_text = ""
|
||||
|
||||
for (const artist of curr_song.artists) {
|
||||
const curr_artist = artist.get(db) as Artist
|
||||
final_text += curr_artist.name + ", "
|
||||
}
|
||||
|
||||
final_text = final_text.slice(0, final_text.length - 2) // remove trailing ", "
|
||||
final_text += " - " + curr_song.name
|
||||
|
||||
if (curr_song.remix_artists.length > 0) {
|
||||
final_text += " ("
|
||||
|
||||
for (const artist of curr_song.remix_artists) {
|
||||
const curr_artist = artist.get(db) as Artist
|
||||
if (curr_artist.links && curr_artist.links.length > 0) {
|
||||
//returns "found a link! Spotify"
|
||||
console.log("found a link! " + Platforms[curr_artist.links[0][0]])
|
||||
|
||||
const url = curr_artist.links[0][1]
|
||||
final_text += `<a href=${url}>${curr_artist.name}</a>, `
|
||||
} else {
|
||||
final_text += curr_artist.name + ", "
|
||||
}
|
||||
}
|
||||
|
||||
final_text = final_text.slice(0, final_text.length - 2) // remove trailing ", "
|
||||
final_text += " Remix)"
|
||||
}
|
||||
|
||||
elem_curr_song!.innerHTML = final_text
|
||||
}
|
23
packages/music-library-web-test/src/styles.css
Normal file
23
packages/music-library-web-test/src/styles.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
#volume{
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
body {
|
||||
width: 100vw;
|
||||
height:100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.wrapper{
|
||||
width:80vw;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.name-wrapper{
|
||||
width:80vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
29
packages/music-library-web-test/tsconfig.json
Normal file
29
packages/music-library-web-test/tsconfig.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"noEmit": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vite/client"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
}
|
33
packages/music-library-web-test/vite.config.ts
Normal file
33
packages/music-library-web-test/vite.config.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/// <reference types="vitest" />
|
||||
import { defineConfig } from "vite"
|
||||
|
||||
import viteTsConfigPaths from "vite-tsconfig-paths"
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: "../../node_modules/.vite/music-library-web-test",
|
||||
|
||||
server: {
|
||||
port: 4200,
|
||||
host: "localhost"
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: "localhost"
|
||||
},
|
||||
|
||||
plugins: [
|
||||
viteTsConfigPaths({
|
||||
root: "../../"
|
||||
})
|
||||
]
|
||||
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [
|
||||
// viteTsConfigPaths({
|
||||
// root: '../../',
|
||||
// }),
|
||||
// ],
|
||||
// },
|
||||
})
|
|
@ -1,13 +1,154 @@
|
|||
# music-library
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
A simple music library, acting as a Local DB as JS Object. Contains everything a person would need to store their music data for website playback.
|
||||
|
||||
## How to use:
|
||||
|
||||
#### Simple demo using euterpe player [here](https://github.com/euterpe-js/euterpe-source/tree/master/packages/music-library-web-test)
|
||||
|
||||
## Building
|
||||
Recommended to make a db.ts file where one instanciates their database, then exports it for use elsewhere.
|
||||
|
||||
Run `nx build music-library` to build the library.
|
||||
`db.ts`
|
||||
```ts
|
||||
import { DB, Artist, Song, RefTo, Ref, Platforms } from "@euterpe/music-library";
|
||||
export const db = new DB
|
||||
|
||||
db.add([
|
||||
//The IDs are added incrementally & are 0 based., so first artists ID added is 0, next 1 etc...
|
||||
//You can specify the ID manually if you want
|
||||
new Artist({
|
||||
name: "Jamie xx",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Machinedrum",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Tanerélle",
|
||||
}),
|
||||
new Artist({
|
||||
name: "Mono/Poly",
|
||||
}),
|
||||
new Artist({
|
||||
name: "IMANU",
|
||||
links: [
|
||||
[Platforms.Spotify, new URL("https://open.spotify.com/artist/5Y7rFm0tiJTVDzGLMzz0W1?si=DRaZyugTTIqlBHDkMGKVqA&nd=1")]
|
||||
]
|
||||
})])
|
||||
db.add([
|
||||
new Song({
|
||||
//Refrences are constructed as such. This allows to get to the artist from either collection or song
|
||||
artists: [new Ref(RefTo.Artists, 2), new Ref(RefTo.Artists, 3), new Ref(RefTo.Artists, 4)],
|
||||
duration: 252,
|
||||
name: "Star",
|
||||
remix_artists: [new Ref(RefTo.Artists, 5)],
|
||||
url: new URL("http://127.0.0.1:4200/Machinedrum, Tanerelle & Mono Poly - Star (IMANU Remix) final.mp3")
|
||||
}),
|
||||
new Song({
|
||||
//If you don't like guessing the IDs, then this is also a way to do it
|
||||
artists: [new Ref(RefTo.Artists, db.artists.find((a) => a.name == "Jamie xx")!.id!)],
|
||||
duration: 331,
|
||||
name: "Sleep Sound",
|
||||
url: new URL("http://127.0.0.1:4200/Jamie xx - Sleep Sound.mp3")
|
||||
}),
|
||||
])
|
||||
```
|
||||
And then we can easily get any data we want elsewhere, like:
|
||||
`main.ts`
|
||||
```ts
|
||||
import { db } from "./db";
|
||||
|
||||
let curr_song_id = 1;
|
||||
// Some buttons in the DOM to act on the library, snippet is using euterpe-js/player
|
||||
document.querySelector("#previous")?.addEventListener("click", () => {
|
||||
curr_song_id--
|
||||
if (curr_song_id < 0) curr_song_id = 2
|
||||
music_player.try_new_song_async(db.songs[curr_song_id].url.pathname).then((s) => {
|
||||
change_current_song_text(db)
|
||||
music_player.play_async().catch((err) => { console.log(err) })
|
||||
}, (e) => { console.log(e) })
|
||||
})
|
||||
document.querySelector("#next")?.addEventListener("click", () => {
|
||||
curr_song_id++
|
||||
if (curr_song_id > 2) curr_song_id = 0
|
||||
music_player.try_new_song_async(db.songs[curr_song_id].url.pathname).then((s) => {
|
||||
change_current_song_text(db)
|
||||
music_player.play_async().catch((err) => { console.log(err) })
|
||||
}, (e) => { console.log(e) })
|
||||
})
|
||||
```
|
||||
Example on how to produce final titles:
|
||||
* If the current song has multiple titles, add them with `, ` between, then append " - " and song name.
|
||||
* If the song has remix artists, we add a " (", add all artists with ", " between, and even make them link to artists' links if there are some.
|
||||
* Results with given db:
|
||||
- `Machinedrum, Tanerélle, Mono/Poly - Star (<a href="{{spotify link}}">IMANU</a> Remix)`
|
||||
- `Jamie xx - Sleep Sound`
|
||||
```ts
|
||||
function change_current_song_text(db: DB) {
|
||||
const curr_song = db.songs[curr_song_id]
|
||||
let final_text = ""
|
||||
|
||||
for (const artist of curr_song.artists) {
|
||||
const curr_artist = artist.get(db) as Artist
|
||||
final_text += curr_artist.name + ", "
|
||||
}
|
||||
|
||||
final_text = final_text.slice(0, final_text.length - 2) // remove trailing ", "
|
||||
final_text += " - " + curr_song.name
|
||||
|
||||
if (curr_song.remix_artists.length > 0) {
|
||||
final_text += " ("
|
||||
|
||||
for (const artist of curr_song.remix_artists) {
|
||||
const curr_artist = artist.get(db) as Artist
|
||||
if (curr_artist.links && curr_artist.links.length > 0) {
|
||||
//returns "found a link! Spotify"
|
||||
console.log("found a link! " + Platforms[curr_artist.links[0][0]])
|
||||
|
||||
const url = curr_artist.links[0][1]
|
||||
final_text += `<a href=${url}>${curr_artist.name}</a>, `
|
||||
} else {
|
||||
final_text += curr_artist.name + ", "
|
||||
}
|
||||
}
|
||||
|
||||
final_text = final_text.slice(0, final_text.length - 2) // remove trailing ", "
|
||||
final_text += " Remix)"
|
||||
}
|
||||
|
||||
elem_curr_song!.innerHTML = final_text
|
||||
}
|
||||
```
|
||||
What data this database stores right now:
|
||||
```ts
|
||||
class Song {
|
||||
name: string
|
||||
artists: Ref[] //Ref(RefTo.Artist, {ID})
|
||||
url: URL
|
||||
duration: number
|
||||
remix_artists: Ref[] //Ref(RefTo.Artist, {ID})
|
||||
publish_date?: Date
|
||||
in_collection?: Ref //Ref(RefTo.Collection, {ID})
|
||||
cover?: URL
|
||||
bpm?: number
|
||||
key?: string
|
||||
fft_data?: number[]
|
||||
id?: ID
|
||||
}
|
||||
class Artist {
|
||||
name = ""
|
||||
pfp?: URL
|
||||
songs: Ref[] //Ref(RefTo.Song, {ID})
|
||||
collections: Ref[] //Ref(RefTo.Collection, {ID})
|
||||
links?: [Platforms, URL][]
|
||||
id?: ID
|
||||
}
|
||||
//can be used as EP, Album etc...
|
||||
class Collection {
|
||||
artists: Ref[] //Ref(RefTo.Artist, {ID})
|
||||
songs: Ref[] //Ref(RefTo.Song, {ID})
|
||||
cover: URL
|
||||
duration: number
|
||||
publish_date?: Date
|
||||
id?: ID
|
||||
}
|
||||
```
|
|
@ -1,5 +1,33 @@
|
|||
{
|
||||
"name": "@euterpe-js/music-library",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs"
|
||||
}
|
||||
"name": "@euterpe.js/music-library",
|
||||
"version": "1.0.1",
|
||||
"type": "module",
|
||||
"description": "A simple music library, acting as a Local DB as JS Object. Contains everything a person would need to store their music data for website playback.",
|
||||
"main": "./src/index.js",
|
||||
"author": {
|
||||
"name": "Djkáťo",
|
||||
"email": "djkatovfx@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/euterpe-js/euterpe-source.git"
|
||||
},
|
||||
"homepage": "https://github.com/euterpe-js/euterpe-source/tree/master/packages/music-library#readme",
|
||||
"keywords": [
|
||||
"audio",
|
||||
"library",
|
||||
"music-database",
|
||||
"audio-player",
|
||||
"webaudio",
|
||||
"database",
|
||||
"db"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.d.ts",
|
||||
"import": "./src/index.js",
|
||||
"require": "./src/lib/music-library.js"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,13 @@
|
|||
"packages/music-library/**/*.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"run": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"command": "node ./dist/packages/music-library/src/index.js"
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
}
|
|
@ -1,65 +1,227 @@
|
|||
import { writeFile, readFile } from "node:fs"
|
||||
export {
|
||||
RefTo,
|
||||
Ref,
|
||||
Song,
|
||||
Collection,
|
||||
DB,
|
||||
Artist,
|
||||
Platforms
|
||||
}
|
||||
type ID = number
|
||||
type URL = string
|
||||
enum RefTo {
|
||||
Artists,
|
||||
Songs,
|
||||
Collections
|
||||
}
|
||||
enum Platforms {
|
||||
Youtube,
|
||||
Linktree,
|
||||
Bandcamp,
|
||||
Spotify,
|
||||
Portfolio,
|
||||
BeatPort,
|
||||
SoundCloud,
|
||||
Youtube = "Youtube",
|
||||
Linktree = "Linktree",
|
||||
Bandcamp = "Bandcamp",
|
||||
Spotify = "Spotify",
|
||||
Portfolio = "Portfolio",
|
||||
BeatPort = "BeatPort",
|
||||
SoundCloud = "SoundCloud",
|
||||
Instagram = "Instagram",
|
||||
Patreon = "Patreon",
|
||||
Twitter = "Twitter",
|
||||
Facebook = "Facebook",
|
||||
}
|
||||
type Ref<T> = [T, ID]
|
||||
|
||||
type Song = {
|
||||
id: ID,
|
||||
name: string,
|
||||
artists: Ref<RefTo.Artists>[],
|
||||
url: URL,
|
||||
publish_date?: Date,
|
||||
remix_artists?: Ref<RefTo.Artists>[],
|
||||
in_collection?: Ref<RefTo.Collections>,
|
||||
cover?: URL,
|
||||
duration: number,
|
||||
bpm?: number,
|
||||
key?: string,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
type Artist = {
|
||||
id: ID,
|
||||
name: string,
|
||||
pfp?: URL,
|
||||
songs?: Ref<RefTo.Songs>[],
|
||||
collections?: Ref<RefTo.Collections>[],
|
||||
links: [Platforms, URL][],
|
||||
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[]
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
type Collection = {
|
||||
id: ID,
|
||||
publish_date?: Date,
|
||||
artists: Ref<RefTo.Artists>[],
|
||||
songs: Ref<RefTo.Songs>[],
|
||||
cover: URL,
|
||||
duration: number,
|
||||
}
|
||||
type DB = {
|
||||
artists?: Artist[],
|
||||
songs?: Song[],
|
||||
Collections?: Collection[],
|
||||
}
|
||||
const db: DB = {}
|
||||
db.songs?.push(
|
||||
{
|
||||
id: 0,
|
||||
artists: [RefTo.Artists, 0] as Ref<RefTo.Artists>,
|
||||
duration: 13,
|
||||
songs: [RefTo.Songs, 0] as Ref<RefTo.Songs>,
|
||||
name: "Just the two of us",
|
||||
url: "Huehue" as URL,
|
||||
|
||||
} as Song)
|
||||
interface ArtistConstructor {
|
||||
name: string,
|
||||
pfp?: URL
|
||||
songs?: Ref[]
|
||||
collections?: Ref[]
|
||||
links?: [Platforms, URL][]
|
||||
id?: ID
|
||||
}
|
||||
class Artist {
|
||||
name = ""
|
||||
pfp?: URL
|
||||
songs: Ref[]
|
||||
collections: Ref[]
|
||||
links?: [Platforms, URL][]
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
interface CollectionConstructor {
|
||||
artists: Ref[]
|
||||
songs: Ref[]
|
||||
cover: URL
|
||||
duration: number
|
||||
publish_date?: Date
|
||||
id?: ID
|
||||
}
|
||||
class Collection {
|
||||
artists: Ref[]
|
||||
songs: Ref[]
|
||||
cover: URL
|
||||
duration: number
|
||||
publish_date?: Date
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
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
|
||||
*/
|
||||
for (const input of stuff) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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!`)
|
|
@ -292,7 +292,7 @@ export const MusicPlayer = (audio_context_i: AudioContext, audio_element_i: HTML
|
|||
controller.abort()
|
||||
reject(e)
|
||||
}, { signal: controller.signal })
|
||||
|
||||
/*
|
||||
audio_element.addEventListener("abort", function abort_listener(e) {
|
||||
controller.abort()
|
||||
reject(e)
|
||||
|
@ -302,6 +302,7 @@ export const MusicPlayer = (audio_context_i: AudioContext, audio_element_i: HTML
|
|||
controller.abort()
|
||||
reject(e)
|
||||
}, { signal: controller.signal })
|
||||
*/
|
||||
is_playing = false
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"skipDefaultLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@euterpe-js/music-library": [
|
||||
"@euterpe/music-library": [
|
||||
"packages/music-library/src/index.ts"
|
||||
],
|
||||
"@euterpe/player": [
|
||||
|
@ -33,4 +33,4 @@
|
|||
"node_modules",
|
||||
"tmp"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue