Skip to content

Commit

Permalink
feat: use Audio object instead of audio tag
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackman99 committed Jun 5, 2023
1 parent 822f276 commit f272022
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 101 deletions.
4 changes: 2 additions & 2 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"fs": {
"scope": [
"/**/*"
"**"
],
"all": true
},
Expand All @@ -38,7 +38,7 @@
"protocol": {
"asset": true,
"assetScope": [
"/**/*"
"**"
]
},
"notification": {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/controls/AudioVisualizer.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { audioDom } from '$lib/store'
import { onMount } from 'svelte'
import visualizer from '../../utils/visualizer'
import { audioDom } from '$lib/store'
let canvas: HTMLCanvasElement
Expand Down
60 changes: 60 additions & 0 deletions src/lib/store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { liveQuery } from 'dexie'
import { derived, get, writable } from 'svelte/store'
import type { Readable } from 'svelte/store'
import { convertFileSrc } from '@tauri-apps/api/tauri'
import { db } from './db'
import type { Mode, Playlist, Song } from './types'
import { twoDigits } from './utils/format'
Expand Down Expand Up @@ -113,3 +114,62 @@ export const togglePlayOrPause = () => {
}

totalSongsNumber.subscribe(() => paginateSelectedPlaylistSongs())

const isFirst = writable(true)

const createAudio = (src: string) => {
const audio = new Audio(src)
audio.volume = get(volume)
audio.addEventListener('oncanplaythrough', () => {
if (get(isFirst)) {
isFirst.set(false)
audio.currentTime = Number(localStorage.getItem(CURRENT_TIME_KEY))
if (localStorage.getItem(PLAYING_KEY) === 'on') {
audio.load()
audio.play()
}
}
else {
audio.currentTime = 0
audio.load()
audio.play()
}
})

audio.addEventListener('ended', playNext)
audio.addEventListener('timeupdate', () => {
playedSeconds.set(audio.currentTime)
})
audio.addEventListener('play', () => {
paused.set(false)
})
audio.addEventListener('pause', () => {
paused.set(true)
})
audio.addEventListener('durationchange', () => {
duration.set(audio.duration)
})

return audio
}

playingSong.subscribe(ps => {
if (!ps) return
let audio = get(audioDom)
if (!audio) {
audio = createAudio(convertFileSrc(ps.path))
audioDom.set(audio)
}
else {
audio.src = convertFileSrc(ps.path)
audio.currentTime = 0
audio.load()
audio.play()
}
audio.title = `${ps.title} - ${ps.artist}`
})

volume.subscribe(vl => {
const audio = get(audioDom)
if (audio) audio.volume = Number(vl.toFixed(2))
})
3 changes: 1 addition & 2 deletions src/lib/utils/visualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const createVisualizer = (canvas: HTMLCanvasElement, audio: HTMLAudioElement) =>
const analyser = audioCtx.createAnalyser()
audioSource.connect(analyser)
analyser.connect(audioCtx.destination)
analyser.fftSize = 1024
analyser.fftSize = 128
const bufferLength = analyser.frequencyBinCount
const dataArray = new Uint8Array(bufferLength)
const barWidth = (canvas.width / bufferLength)
Expand Down Expand Up @@ -70,7 +70,6 @@ const createVisualizer = (canvas: HTMLCanvasElement, audio: HTMLAudioElement) =>
ctx.closePath()
requestAnimationFrame(drawWave)
}


return {
draw,
Expand Down
110 changes: 26 additions & 84 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { appWindow } from '@tauri-apps/api/window'
import { readDir } from '@tauri-apps/api/fs'
import { onDestroy, onMount } from 'svelte'
import { get } from 'svelte/store'
import DropZone from '$lib/components/layouts/DropZone.svelte'
import {
getSongInfoFromFile,
Expand All @@ -13,42 +14,33 @@
import { db } from '$lib/db'
import PlayerBottomBar from '$lib/components/controls/PlayerBottomBar.svelte'
import Sidebar from '$lib/components/layouts/Sidebar.svelte'
import { convertFileSrc } from '@tauri-apps/api/tauri'
import {
selectedPlaylistId,
SELECTED_PLAYLIST_ID_KEY,
PLAYING_SONG_ID_KEY,
COLOR_MODE_KEY,
CURRENT_SONGS_KEY,
CURRENT_TIME_KEY,
MODE_KEY,
PLAYING_KEY,
PLAYING_SONG_ID_KEY,
SELECTED_PLAYLIST_ID_KEY,
currentPlayingSongIds,
inWindow,
isDark,
mode,
paginateSelectedPlaylistSongs,
playlists,
paused,
playingSongId,
playedSeconds,
CURRENT_TIME_KEY,
playingSong,
currentPlayingSongIds,
CURRENT_SONGS_KEY,
playNext,
volume,
VOLUME_KEY,
audioDom,
mode,
PLAYING_KEY,
togglePlayOrPause,
duration,
COLOR_MODE_KEY,
isDark,
inWindow,
playingSongId,
playlists,
selectedPlaylistId,
selectedPlaylistSongsOffset,
selectedPlaylistSongsScrollTop,
togglePlayOrPause,
} from '$lib/store'
import { get } from 'svelte/store'
import type { Subscription } from 'dexie'
import CurrentPlayingSongs from '$lib/components/CurrentPlayingSongs.svelte'
import EditTagDialog from '$lib/components/lyrics/EditTagDialog.svelte'
import AppBar from '$lib/components/layouts/AppBar.svelte'
import { windowInnerWidth } from '$lib/layout'
import pageTransition from '$lib/page-transition'
// Mount global Buffer
globalThis.Buffer = Buffer
Expand All @@ -64,14 +56,18 @@
let unsubscribePlayingSongId: () => void
let unsubscribePlayedSeconds: () => void
let unsubscribePaused: () => void
let playlistSubscriber: Subscription
const handleSpaceKeyboard = (e: KeyboardEvent) => {
if (e.code === 'Space') {
e.preventDefault()
togglePlayOrPause()
}
}
const handleContextMenu = (e: any) => {
if (!import.meta.env.DEV) e.preventDefault()
}
onMount(async () => {
const currentSongIds = JSON.parse(
localStorage.getItem(CURRENT_SONGS_KEY) || '[]'
Expand Down Expand Up @@ -126,38 +122,17 @@
})
window.addEventListener('keyup', handleSpaceKeyboard)
window.addEventListener('contextmenu', handleContextMenu)
})
const handleContextMenu = (e: any) => {
if (!import.meta.env.DEV) {
e.preventDefault()
}
}
let isFirst = true
const handleLoadedMetadata = (e: any) => {
if (isFirst) {
e.target.currentTime = Number(localStorage.getItem(CURRENT_TIME_KEY))
isFirst = false
if (localStorage.getItem(PLAYING_KEY) === 'on') {
e.target.play()
}
} else {
e.target.currentTime = 0
e.target.play()
}
}
$: {
localStorage.setItem(PLAYING_KEY, $paused ? 'off' : 'on')
}
$: {
if ($isDark) {
document.querySelector('html')?.classList.add('dark')
} else {
document.querySelector('html')?.classList.remove('dark')
}
if ($isDark) document.querySelector('html')?.classList.add('dark')
else document.querySelector('html')?.classList.remove('dark')
localStorage.setItem(COLOR_MODE_KEY, $isDark ? 'on' : 'off')
}
Expand Down Expand Up @@ -190,45 +165,12 @@
unsubscribePlayingSongId?.()
unsubscribePlayedSeconds?.()
unsubscribePaused?.()
playlistSubscriber?.unsubscribe()
localStorage.setItem(CURRENT_TIME_KEY, get(playedSeconds).toString())
window.removeEventListener('keyup', handleSpaceKeyboard)
window.removeEventListener('contextmenu', handleContextMenu)
})
const setVolume = () => {
localStorage.setItem(VOLUME_KEY, $volume.toString())
if ($audioDom) {
$audioDom.volume = $volume
}
}
$: {
$volume
setVolume()
}
const handleTimeUpdate = () => {
$playedSeconds = $audioDom.currentTime
}
</script>

{#if $playingSong}
<audio
bind:this="{$audioDom}"
bind:duration="{$duration}"
src="{convertFileSrc($playingSong.path)}"
style="display: none;"
title="{$playingSong.title} - {$playingSong.artist}"
crossorigin="anonymous"
on:ended="{playNext}"
on:timeupdate="{handleTimeUpdate}"
on:play="{() => ($paused = false)}"
on:loadedmetadata="{handleLoadedMetadata}"
on:pause="{() => ($paused = true)}"
>
</audio>
{/if}

<svelte:head>
{@html `
<script>
Expand All @@ -248,7 +190,7 @@
<svelte:window bind:innerWidth="{$windowInnerWidth}" />

<AppBar />
<main class="j-main" on:contextmenu="{handleContextMenu}">
<main class="j-main">
<Sidebar />
<div class="j-content">
<slot />
Expand Down
13 changes: 5 additions & 8 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<script lang="ts">
import { ask, message } from '@tauri-apps/api/dialog'
import Songs from '$lib/components/Songs.svelte'
import {
currentPlaylistSongs,
paginateSelectedPlaylistSongs,
selectedPlaylistId,
selectedPlaylistSongsLimit,
selectedPlaylistSongNumber,
selectedPlaylistSongsLimit,
selectedPlaylistSongsOffset,
paginateSelectedPlaylistSongs,
selectedPlaylistSongsScrollTop,
} from '$lib/store'
import Playlists from '$lib/components/Playlists.svelte'
import { db } from '$lib/db'
import { message, ask } from '@tauri-apps/api/dialog'
import { fullscreen } from '$lib/components/lyrics/store'
let draggingSongId: number | null
Expand All @@ -29,14 +29,11 @@
if (playlist) {
if (draggingSongIds.length) {
draggingSongIds.forEach(id => {
if (!playlist.songIds.includes(id)) {
playlist.songIds.push(id)
}
if (!playlist.songIds.includes(id)) playlist.songIds.push(id)
})
} else if (draggingSongId) {
if (!playlist.songIds.includes(draggingSongId)) {
if (!playlist.songIds.includes(draggingSongId))
playlist.songIds.push(draggingSongId)
}
}
await db.playlists.update(playlist.id, playlist)
}
Expand Down
4 changes: 0 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,4 @@
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

0 comments on commit f272022

Please sign in to comment.