add working player
All checks were successful
Deploy App / build (push) Successful in 1m20s
Deploy App / deploy (push) Successful in 16s

This commit is contained in:
valere
2025-10-04 00:49:12 +02:00
parent fef1a8c234
commit 96ffb4b10a
9 changed files with 242 additions and 153 deletions

View File

@@ -31,6 +31,8 @@ const props = withDefaults(
{ BoxState: 'list' } { BoxState: 'list' }
) )
const isDraggable = computed(() => !['list', 'hidden'].includes(BoxState.value()))
// --- Réfs --- // --- Réfs ---
const scene = ref<HTMLElement>() const scene = ref<HTMLElement>()
const box = ref<HTMLElement>() const box = ref<HTMLElement>()
@@ -123,61 +125,81 @@ function tickInertia() {
} }
// --- Pointer events --- // --- Pointer events ---
let listenersAttached = false
const down = (ev: PointerEvent) => {
ev.preventDefault()
dragging = true
box.value?.setPointerCapture(ev.pointerId)
lastPointer = { x: ev.clientX, y: ev.clientY, time: performance.now() }
velocity = { x: 0, y: 0 }
if (raf) { cancelAnimationFrame(raf); raf = null }
}
const move = (ev: PointerEvent) => {
if (!dragging) return
ev.preventDefault()
const now = performance.now()
const dx = ev.clientX - lastPointer.x
const dy = ev.clientY - lastPointer.y
const dt = Math.max(1, now - lastPointer.time)
rotateY.value += dx * sensitivity
rotateX.value -= dy * sensitivity
rotateX.value = Math.max(-80, Math.min(80, rotateX.value))
velocity.x = (dx / dt) * 16 * sensitivity
velocity.y = (-dy / dt) * 16 * sensitivity
lastPointer = { x: ev.clientX, y: ev.clientY, time: now }
applyTransform(0) // immédiat pendant drag
}
const end = (ev: PointerEvent) => {
if (!dragging) return
dragging = false
try { box.value?.releasePointerCapture(ev.pointerId) } catch { }
if (enableInertia && (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity)) {
if (!raf) raf = requestAnimationFrame(tickInertia)
}
}
function addListeners() {
if (!box.value || listenersAttached) return
box.value.addEventListener('pointerdown', down)
box.value.addEventListener('pointermove', move)
box.value.addEventListener('pointerup', end)
box.value.addEventListener('pointercancel', end)
box.value.addEventListener('pointerleave', end)
listenersAttached = true
}
function removeListeners() {
if (!box.value || !listenersAttached) return
box.value.removeEventListener('pointerdown', down)
box.value.removeEventListener('pointermove', move)
box.value.removeEventListener('pointerup', end)
box.value.removeEventListener('pointercancel', end)
box.value.removeEventListener('pointerleave', end)
listenersAttached = false
}
onMounted(() => { onMounted(() => {
applyColor() applyColor()
applyBoxState() applyBoxState()
if (isDraggable) addListeners()
})
const down = (ev: PointerEvent) => { onBeforeUnmount(() => {
ev.preventDefault() cancelAnimationFrame(raf!)
dragging = true removeListeners()
box.value?.setPointerCapture(ev.pointerId)
lastPointer = { x: ev.clientX, y: ev.clientY, time: performance.now() }
velocity = { x: 0, y: 0 }
if (raf) { cancelAnimationFrame(raf); raf = null }
}
const move = (ev: PointerEvent) => {
if (!dragging) return
ev.preventDefault()
const now = performance.now()
const dx = ev.clientX - lastPointer.x
const dy = ev.clientY - lastPointer.y
const dt = Math.max(1, now - lastPointer.time)
rotateY.value += dx * sensitivity
rotateX.value -= dy * sensitivity
rotateX.value = Math.max(-80, Math.min(80, rotateX.value))
velocity.x = (dx / dt) * 16 * sensitivity
velocity.y = (-dy / dt) * 16 * sensitivity
lastPointer = { x: ev.clientX, y: ev.clientY, time: now }
applyTransform(0) // immédiat pendant drag
}
const end = (ev: PointerEvent) => {
if (!dragging) return
dragging = false
try { box.value?.releasePointerCapture(ev.pointerId) } catch { }
if (enableInertia && (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity)) {
if (!raf) raf = requestAnimationFrame(tickInertia)
}
}
box.value?.addEventListener('pointerdown', down)
box.value?.addEventListener('pointermove', move)
box.value?.addEventListener('pointerup', end)
box.value?.addEventListener('pointercancel', end)
box.value?.addEventListener('pointerleave', end)
onBeforeUnmount(() => {
cancelAnimationFrame(raf!)
})
}) })
// --- Watchers --- // --- Watchers ---
watch(() => props.BoxState, () => applyBoxState()) watch(() => props.BoxState, () => applyBoxState())
watch(() => props.compilation, () => applyColor(), { deep: true }) watch(() => props.compilation, () => applyColor(), { deep: true })
watch(() => isDraggable, (enabled) => enabled ? addListeners() : removeListeners())
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,5 +1,5 @@
<template> <template>
<article class="flip-card w-56 h-80" :data-flipped="props.isflipped"> <article class="flip-card w-56 h-80">
<div class="flip-inner"> <div class="flip-inner">
<main <main
class="flip-front backdrop-blur-sm border-2 -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-40 hover:bg-opacity-80 hover:shadow-xl transition-all bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden"> class="flip-front backdrop-blur-sm border-2 -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-40 hover:bg-opacity-80 hover:shadow-xl transition-all bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden">
@@ -39,7 +39,7 @@
import type { Track } from '~~/types/types' import type { Track } from '~~/types/types'
import { usePlayerStore } from '~/store/player' import { usePlayerStore } from '~/store/player'
const props = defineProps<{ track: Track, isflipped: false }>() const props = defineProps<{ track: Track }>()
const playerStore = usePlayerStore() const playerStore = usePlayerStore()
const coverUrl = props.track.coverId.startsWith('http') const coverUrl = props.track.coverId.startsWith('http')
? props.track.coverId ? props.track.coverId
@@ -66,7 +66,7 @@ const coverUrl = props.track.coverId.startsWith('http')
transform-style: preserve-3d; transform-style: preserve-3d;
} }
.flip-card[data-flipped=false] .flip-inner { .flipped .flip-inner {
transform: rotateY(180deg); transform: rotateY(180deg);
} }

View File

@@ -1,7 +1,14 @@
<template> <template>
<audio ref="audioRef" class="fixed z-50 bottom-0 left-1/2 -translate-x-1/2 w-1/2" <div class="fixed left-0 bottom-0 opacity-1 z-50 w-full bg-white transition-all"
:src="playerStore.currentTrack ? playerStore.getCompilationUrlFromTrack(playerStore.currentTrack) : ''" controls :class="{ '-bottom-20 opacity-0': !playerStore.currentTrack }">
@timeupdate="updatePosition" @ended="onEnded" /> <!-- <p class="hidden">
{{ Math.round(currentTime) }}
{{ Math.round(currentProgression) }}%
</p> -->
<audio ref="audioRef" class="w-full"
:src="playerStore.currentTrack ? playerStore.getCompilationUrlFromTrack(playerStore.currentTrack) : ''"
controls />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -10,39 +17,36 @@ import { usePlayerStore } from '~/store/player'
const playerStore = usePlayerStore() const playerStore = usePlayerStore()
const audioRef = ref<HTMLAudioElement | null>(null) const audioRef = ref<HTMLAudioElement | null>(null)
const currentTime = ref(0)
const lastValidProgression = ref(0)
onMounted(() => { const currentProgression = computed(() => {
if (audioRef.value) playerStore.audio = audioRef.value if (!audioRef.value) return 0
const progression = (currentTime.value / audioRef.value.duration) * 100
if (!isNaN(progression)) {
lastValidProgression.value = progression
}
return lastValidProgression.value
}) })
// Mettre à jour la position function updateTime() {
function updatePosition() { if (audioRef.value) {
if (audioRef.value) playerStore.position = audioRef.value.currentTime currentTime.value = audioRef.value.currentTime
}
function onEnded() {
playerStore.isPlaying = false
}
// Si la track change, mettre à jour le src et le start
watch(
() => playerStore.currentTrack,
(newTrack) => {
if (newTrack && audioRef.value) {
audioRef.value.src = newTrack.url
audioRef.value.currentTime = newTrack.start || 0
if (playerStore.isPlaying) audioRef.value.play()
}
} }
) }
onMounted(() => {
if (audioRef.value) {
playerStore.audio = audioRef.value
audioRef.value.addEventListener("timeupdate", updateTime)
}
})
onUnmounted(() => {
if (audioRef.value) {
audioRef.value.removeEventListener("timeupdate", updateTime)
}
})
</script> </script>
<style scoped>
audio {
transition: all 1s;
}
audio[src=""] {
@apply -bottom-1.5 opacity-0
}
</style>

View File

@@ -9,7 +9,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useDataStore } from '~/store/data' import { useDataStore } from '~/store/data'
import type { BoxState } from '~~/types/types' import type { BoxState } from '~~/types/types'
import { useRouter } from 'vue-router'
const dataStore = useDataStore() const dataStore = useDataStore()
const boxStates = ref<Record<string, BoxState>>({}) const boxStates = ref<Record<string, BoxState>>({})
@@ -30,7 +29,6 @@ function closeCompilation(e: KeyboardEvent) {
} }
} }
onMounted(async () => { onMounted(async () => {
const dataStore = await useDataStore() const dataStore = await useDataStore()
await dataStore.loadData() await dataStore.loadData()

View File

@@ -1,7 +1,6 @@
<template> <template>
<div class="mt-8 p-8 w-full flex flex-wrap justify-around"> <div class="mt-8 p-8 w-full flex flex-wrap justify-around">
<MoleculeCard v-for="track in dataStore.getTracksByCompilationId(compilation.id)" :key="track.id" :track="track" <MoleculeCard v-for="track in dataStore.getTracksByCompilationId(compilation.id)" :key="track.id" :track="track" />
:isFlipped="true" />
</div> </div>
</template> </template>
@@ -14,4 +13,4 @@ const props = defineProps<{
}>() }>()
const dataStore = useDataStore() const dataStore = useDataStore()
</script> </script>

View File

@@ -18,4 +18,4 @@
.logo { .logo {
filter: drop-shadow(2px 2px 0 rgb(0 0 0 / 0.8)); filter: drop-shadow(2px 2px 0 rgb(0 0 0 / 0.8));
} }
</style> </style>

View File

@@ -54,5 +54,20 @@ export const useDataStore = defineStore('data', {
getTracksByArtistId: (state) => (artistId: number) => { getTracksByArtistId: (state) => (artistId: number) => {
return state.tracks.filter(track => track.artist.id === artistId) return state.tracks.filter(track => track.artist.id === artistId)
}, },
getNextTrack: (state) => {
return (track: Track) => {
// Récupérer toutes les tracks de la même compilation et les trier par ordre
const tracksInCompilation = state.tracks
.filter(t => t.compilationId === track.compilationId)
.sort((a, b) => a.order - b.order)
// Trouver lindex de la track courante
const index = tracksInCompilation.findIndex(t => t.id === track.id)
// Retourner la track suivante ou null si cest la dernière
return index >= 0 && index < tracksInCompilation.length - 1
? tracksInCompilation[index + 1]
: null
}
}
}, },
}) })

View File

@@ -1,62 +1,113 @@
// ~/store/player.ts // ~/store/player.ts
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { Track } from '~/types/types' import type { Track } from '~/../types/types'
import { useDataStore } from '~/store/data'
export const usePlayerStore = defineStore('player', { export const usePlayerStore = defineStore('player', {
state: () => ({ state: () => ({
currentTrack: null as Track | null, currentTrack: null as Track | null,
isPlaying: false,
position: 0, position: 0,
audio: null as HTMLAudioElement | null, audio: null as HTMLAudioElement | null,
}), }),
actions: { actions: {
setTrack(track: Track) { async playTrack(track: Track) {
this.currentTrack = track this.currentTrack = track
if (!this.audio) this.audio = new Audio(this.getCompilationUrlFromTrack(track))
else this.audio.src = this.getCompilationUrlFromTrack(track)
// Commencer à start secondes // toggle si on reclique sur la même
this.audio.currentTime = track.start || 0 if (this.isPlayingTrack(track)) {
}, this.togglePlay()
return
}
if (!this.audio) {
this.audio = new Audio()
}
playTrack(track?: Track) { // définir la source (fichier de la compilation entière)
// load compile if not allready loaded this.audio.src = this.getCompilationUrlFromTrack(track)
// play if track is not already played this.audio.load()
// else pause
// attendre que le player soit prêt avant de lire
await new Promise<void>((resolve, reject) => {
const onCanPlay = () => {
this.audio!.removeEventListener("canplay", onCanPlay)
resolve()
}
const onError = (e: Event) => {
this.audio!.removeEventListener("error", onError)
reject(e)
}
this.audio!.addEventListener("canplay", onCanPlay, { once: true })
this.audio!.addEventListener("error", onError, { once: true })
})
if (track) this.setTrack(track) // positionner le début
if (!this.currentTrack || !this.audio) return this.audio.currentTime = track.start ?? 0
this.audio.play() // lancer la lecture
this.isPlaying = true try {
}, await this.audio.play()
} catch (err) {
pauseTrack() { console.error("Impossible de lire la piste :", err)
if (this.audio) this.audio.pause()
this.isPlaying = false
},
togglePlay(track?: Track) {
if (track && (!this.currentTrack || track.id !== this.currentTrack.id)) {
this.playTrack(track)
} else {
this.isPlaying ? this.pauseTrack() : this.playTrack()
} }
}, },
setPosition(time: number) { togglePlay() {
if (this.audio) this.audio.currentTime = time if (!this.audio) return
this.position = time if (this.audio.paused) {
this.audio.play().catch(err => console.error(err))
} else {
this.audio.pause()
}
}, },
}, },
getters: { getters: {
isCurrentCompilation: (state) => {
return (compilationId: string) =>
compilationId === state.currentTrack?.compilationId
},
isPlayingTrack: (state) => {
return (track: Track) => {
if (!state.audio || !state.currentTrack) return false
const currentTime = state.audio.currentTime
if (!currentTime || isNaN(currentTime)) return false
const from = track.start ?? 0
const to = state.getTrackStop(track)
if (!to || isNaN(to)) return false
return currentTime >= from && currentTime < to
}
},
getCurrentTrack: (state) => state.currentTrack, getCurrentTrack: (state) => state.currentTrack,
getPlaying: (state) => state.isPlaying,
getCompilationUrlFromTrack: (state) => { getCompilationUrlFromTrack: () => {
return (track: Track) => `https://files.erudi.fr/evilspins/${track.compilationId}.mp3` return (track: Track) =>
`https://files.erudi.fr/evilspins/${track.compilationId}.mp3`
},
getCurrentCompilation: (state) => {
return state.currentTrack
? state.getCompilationUrlFromTrack(state.currentTrack)
: null
},
getTrackStop: (state) => {
return (track: Track) => {
if (!state.audio) return 0
if (track.order === 0) {
return Math.round(state.audio.duration)
} else {
const dataStore = useDataStore()
const nextTrack = dataStore.getNextTrack(track)
return nextTrack ? nextTrack.start : Math.round(state.audio.duration)
}
}
} }
}, },
}) })

View File

@@ -18,7 +18,7 @@ export default eventHandler(() => {
compilationId: 'ES00A', compilationId: 'ES00A',
title: 'Bleach', title: 'Bleach',
artist: 1, artist: 1,
start: 393, start: 392,
url: 'https://the-kundalini-genie.bandcamp.com/track/bleach-2', url: 'https://the-kundalini-genie.bandcamp.com/track/bleach-2',
coverId: 'a1714786533', coverId: 'a1714786533',
}, },
@@ -28,7 +28,7 @@ export default eventHandler(() => {
compilationId: 'ES00A', compilationId: 'ES00A',
title: 'Televised mind', title: 'Televised mind',
artist: 2, artist: 2,
start: 892, start: 896,
url: 'https://fontainesdc.bandcamp.com/track/televised-mind', url: 'https://fontainesdc.bandcamp.com/track/televised-mind',
coverId: 'a3772806156' coverId: 'a3772806156'
}, },
@@ -38,7 +38,7 @@ export default eventHandler(() => {
compilationId: 'ES00A', compilationId: 'ES00A',
title: 'In it', title: 'In it',
artist: 3, artist: 3,
start: 1138, start: 1139,
url: 'https://howlinbananarecords.bandcamp.com/track/in-it', url: 'https://howlinbananarecords.bandcamp.com/track/in-it',
coverId: 'a1720372066', coverId: 'a1720372066',
}, },
@@ -104,11 +104,11 @@ export default eventHandler(() => {
}, },
{ {
id: 10, id: 10,
order: 0, order: 11,
compilationId: 'ES00A', compilationId: 'ES00A',
title: 'Like in the movies', title: 'Like in the movies',
artist: 10, artist: 10,
start: 2559, start: 2560,
url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies-2', url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies-2',
coverId: 'a2203158939', coverId: 'a2203158939',
}, },
@@ -214,11 +214,11 @@ export default eventHandler(() => {
}, },
{ {
id: 21, id: 21,
order: 0, order: 11,
compilationId: 'ES00B', compilationId: 'ES00B',
title: 'Like in the movies', title: 'Like in the movies',
artist: 10, artist: 10,
start: 2185, start: 2186,
url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies', url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies',
coverId: 'a3647322740', coverId: 'a3647322740',
}, },
@@ -238,7 +238,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'The Third Wave', title: 'The Third Wave',
artist: 12, artist: 12,
start: 854, start: 841,
url: 'https://firefriend.bandcamp.com/track/the-third-wave', url: 'https://firefriend.bandcamp.com/track/the-third-wave',
coverId: 'a2803689859', coverId: 'a2803689859',
}, },
@@ -248,7 +248,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Broadcaster', title: 'Broadcaster',
artist: 13, artist: 13,
start: 0, start: 1104.5,
url: 'https://squiduk.bandcamp.com/track/broadcaster', url: 'https://squiduk.bandcamp.com/track/broadcaster',
coverId: 'a3391719769', coverId: 'a3391719769',
}, },
@@ -258,7 +258,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Mourn', title: 'Mourn',
artist: 14, artist: 14,
start: 0, start: 1441,
url: 'https://lysistrata.bandcamp.com/track/mourn-2', url: 'https://lysistrata.bandcamp.com/track/mourn-2',
coverId: 'a0872900041', coverId: 'a0872900041',
}, },
@@ -268,7 +268,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Let it Blow', title: 'Let it Blow',
artist: 15, artist: 15,
start: 0, start: 1844.8,
url: 'https://pabloxbroadcastingservices.bandcamp.com/track/let-it-blow', url: 'https://pabloxbroadcastingservices.bandcamp.com/track/let-it-blow',
coverId: 'a4000148031', coverId: 'a4000148031',
}, },
@@ -278,7 +278,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Sunday Mourning', title: 'Sunday Mourning',
artist: 16, artist: 16,
start: 0, start: 2091.7,
url: 'https://nightbeats.bandcamp.com/track/sunday-mourning', url: 'https://nightbeats.bandcamp.com/track/sunday-mourning',
coverId: 'a0031987121', coverId: 'a0031987121',
}, },
@@ -288,7 +288,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: '3030 Instrumental', title: '3030 Instrumental',
artist: 17, artist: 17,
start: 0, start: 2339.3,
url: 'https://delthefunkyhomosapien.bandcamp.com/track/3030', url: 'https://delthefunkyhomosapien.bandcamp.com/track/3030',
coverId: 'a1948146136', coverId: 'a1948146136',
}, },
@@ -298,7 +298,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Immortality Break', title: 'Immortality Break',
artist: 18, artist: 18,
start: 0, start: 2530.5,
url: 'https://theaa.bandcamp.com/track/immortality-break', url: 'https://theaa.bandcamp.com/track/immortality-break',
coverId: 'a2749250329', coverId: 'a2749250329',
}, },
@@ -308,7 +308,7 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Lazy Bones', title: 'Lazy Bones',
artist: 19, artist: 19,
start: 0, start: 2718,
url: 'https://woodenshjips.bandcamp.com/track/lazy-bones', url: 'https://woodenshjips.bandcamp.com/track/lazy-bones',
coverId: 'a1884221104', coverId: 'a1884221104',
}, },
@@ -318,17 +318,17 @@ export default eventHandler(() => {
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'On the Train of Aches', title: 'On the Train of Aches',
artist: 20, artist: 20,
start: 0, start: 2948,
url: 'https://silasjdirge.bandcamp.com/track/on-the-train-of-aches', url: 'https://silasjdirge.bandcamp.com/track/on-the-train-of-aches',
coverId: 'a1124177379', coverId: 'a1124177379',
}, },
{ {
id: 32, id: 32,
order: 0, order: 11,
compilationId: 'ES01A', compilationId: 'ES01A',
title: 'Me', title: 'Me',
artist: 21, artist: 21,
start: 0, start: 3265,
url: 'https://secretcolours.bandcamp.com/track/me', url: 'https://secretcolours.bandcamp.com/track/me',
coverId: 'a1497022499', coverId: 'a1497022499',
}, },
@@ -348,7 +348,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Dreamscapes', title: 'Dreamscapes',
artist: 12, artist: 12,
start: 0, start: 235,
url: 'https://littlecloudrecords.bandcamp.com/track/dreamscapes', url: 'https://littlecloudrecords.bandcamp.com/track/dreamscapes',
coverId: 'a3498981203', coverId: 'a3498981203',
}, },
@@ -358,7 +358,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Crispy Skin', title: 'Crispy Skin',
artist: 13, artist: 13,
start: 0, start: 644.2,
url: 'https://squiduk.bandcamp.com/track/crispy-skin-2', url: 'https://squiduk.bandcamp.com/track/crispy-skin-2',
coverId: 'a2516727021', coverId: 'a2516727021',
}, },
@@ -368,7 +368,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'The Boy Who Stood Above The Earth', title: 'The Boy Who Stood Above The Earth',
artist: 14, artist: 14,
start: 0, start: 1018,
url: 'https://lysistrata.bandcamp.com/track/the-boy-who-stood-above-the-earth-2', url: 'https://lysistrata.bandcamp.com/track/the-boy-who-stood-above-the-earth-2',
coverId: 'a0350933426', coverId: 'a0350933426',
}, },
@@ -378,7 +378,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Better Off Alone', title: 'Better Off Alone',
artist: 15, artist: 15,
start: 0, start: 1698,
url: 'https://pabloxbroadcastingservices.bandcamp.com/track/better-off-alone', url: 'https://pabloxbroadcastingservices.bandcamp.com/track/better-off-alone',
coverId: 'a4000148031', coverId: 'a4000148031',
}, },
@@ -388,7 +388,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Celebration #1', title: 'Celebration #1',
artist: 16, artist: 16,
start: 0, start: 2235,
url: 'https://nightbeats.bandcamp.com/track/celebration-1', url: 'https://nightbeats.bandcamp.com/track/celebration-1',
coverId: 'a0031987121', coverId: 'a0031987121',
}, },
@@ -398,7 +398,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: '3030 Instrumental', title: '3030 Instrumental',
artist: 17, artist: 17,
start: 0, start: 2458.3,
url: 'https://delthefunkyhomosapien.bandcamp.com/track/3030', url: 'https://delthefunkyhomosapien.bandcamp.com/track/3030',
coverId: 'a1948146136', coverId: 'a1948146136',
}, },
@@ -408,7 +408,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'The Emptiness Of Nothingness', title: 'The Emptiness Of Nothingness',
artist: 18, artist: 18,
start: 0, start: 2864.5,
url: 'https://theaa.bandcamp.com/track/the-emptiness-of-nothingness', url: 'https://theaa.bandcamp.com/track/the-emptiness-of-nothingness',
coverId: 'a1053923875', coverId: 'a1053923875',
}, },
@@ -418,7 +418,7 @@ export default eventHandler(() => {
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Rising', title: 'Rising',
artist: 19, artist: 19,
start: 0, start: 3145,
url: 'https://woodenshjips.bandcamp.com/track/rising', url: 'https://woodenshjips.bandcamp.com/track/rising',
coverId: 'a1884221104', coverId: 'a1884221104',
}, },
@@ -426,19 +426,19 @@ export default eventHandler(() => {
id: 42, id: 42,
order: 10, order: 10,
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'The Last Time / Jealous Woman', title: 'The Last Time',
artist: 22, artist: 22,
start: 0, start: 3447,
url: 'https://www.discogs.com/release/12110815-Larry-McNeil-And-The-Blue-Knights-Jealous-Woman', url: 'https://www.discogs.com/release/12110815-Larry-McNeil-And-The-Blue-Knights-Jealous-Woman',
coverId: 'https://i.discogs.com/Yr05_neEXwzPwKlDeV7dimmTG34atkAMgpxbMBhHBkI/rs:fit/g:sm/q:90/h:600/w:600/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEyMTEw/ODE1LTE1Mjg1NjU1/NzQtMjcyOC5qcGVn.jpeg', coverId: 'https://i.discogs.com/Yr05_neEXwzPwKlDeV7dimmTG34atkAMgpxbMBhHBkI/rs:fit/g:sm/q:90/h:600/w:600/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEyMTEw/ODE1LTE1Mjg1NjU1/NzQtMjcyOC5qcGVn.jpeg',
}, },
{ {
id: 43, id: 43,
order: 0, order: 11,
compilationId: 'ES01B', compilationId: 'ES01B',
title: 'Guajira Con Arpa', title: 'Guajira Con Arpa',
artist: 23, artist: 23,
start: 0, start: 3586,
url: 'https://elpalmasmusic.bandcamp.com/track/guajira-con-arpa', url: 'https://elpalmasmusic.bandcamp.com/track/guajira-con-arpa',
coverId: 'a3463036407', coverId: 'a3463036407',
}, },