Add tracklist to audio player

This commit is contained in:
2024-03-15 13:59:34 +01:00
parent 13c5889a56
commit 7024648712
4 changed files with 98 additions and 63 deletions

View File

@@ -29,7 +29,7 @@ export const navigate = async (path, push_history) => {
console.debug("Navigating to path", path, push_history)
try {
let resp = await fs_get_node(path)
const resp = await fs_get_node(path)
open_node(resp, push_history)
} catch (err) {
if (err.value && err.value === "path_not_found") {
@@ -59,7 +59,7 @@ export const open_node = (node, push_history) => {
// to a 404 page when refreshing after renaming a file
if (history_enabled) {
window.document.title = node.path[node.base_index].name+" ~ pixeldrain"
let url = "/d"+ fs_encode_path(node.path[node.base_index].path)
const url = "/d"+ fs_encode_path(node.path[node.base_index].path)
if (push_history) {
window.history.pushState({}, window.document.title, url)
} else {
@@ -72,8 +72,8 @@ export const open_node = (node, push_history) => {
if (node.path.length > 1 && node.path[node.path.length-2].path === state.base.path) {
console.debug("Current parent path and new node path match. Saving siblings")
siblings_path = node.path[node.path.length-1].path
siblings = state.children
cached_siblings_path = node.path[node.path.length-1].path
cached_siblings = state.children
}
// Sort directory children
@@ -104,8 +104,25 @@ export const open_node = (node, push_history) => {
// directory. The siblings_path variable is used to verify that the parent
// directory is still the same. If it's sifferent the siblings array is not
// used
let siblings_path = ""
let siblings = null
let cached_siblings_path = ""
let cached_siblings = null
export const get_siblings = async () => {
// Check if we already have siblings cached
if (cached_siblings === null || cached_siblings_path !== state.path[state.path.length - 2].path) {
console.debug("Cached siblings not available. Fetching new")
const resp = await fs_get_node(state.path[state.path.length - 2].path)
// Sort directory children to make sure the order is consistent
sort_children(resp.children)
// Save new siblings in navigator state
cached_siblings_path = state.path[state.path.length - 2].path
cached_siblings = resp.children
}
return cached_siblings
}
// Opens a sibling of the currently open file. The offset is relative to the
// file which is currently open. Give a positive number to move forward and a
@@ -117,26 +134,14 @@ export const open_sibling = async offset => {
dispatch("loading", true)
// Check if we already have siblings cached
if (siblings != null && siblings_path == state.path[state.path.length - 2].path) {
console.debug("Using cached siblings", siblings)
} else {
console.debug("Cached siblings not available. Fetching new")
try {
let resp = await fs_get_node(state.path[state.path.length - 2].path)
// Sort directory children to make sure the order is consistent
sort_children(resp.children)
// Save new siblings in navigator state
siblings_path = state.path[state.path.length - 2].path
siblings = resp.children
} catch (err) {
console.error(err)
alert(err)
dispatch("loading", false)
return
}
let siblings
try {
siblings = await get_siblings()
} catch (err) {
console.error(err)
alert(err)
dispatch("loading", false)
return
}
let next_sibling = null
@@ -191,7 +196,7 @@ const sort_children = children => {
// Capture browser back and forward navigation buttons
window.onpopstate = (e) => {
// Get the part of the URL after the fs root and navigate to it
let path = document.location.pathname.replace("/d/", "")
const path = document.location.pathname.replace("/d/", "")
navigate(decodeURIComponent(path), false)
};
</script>

View File

@@ -83,7 +83,7 @@ export let large_icons = false
.node {
display: table-row;
text-decoration: none;
color: var(--text-color);
color: var(--body_text-color);
padding: 6px;
}
.node:not(:last-child) {

View File

@@ -1,58 +1,47 @@
<script>
import { createEventDispatcher, onMount } from 'svelte'
import { fs_path_url } from '../FilesystemUtil';
import { onMount } from 'svelte'
import { fs_encode_path, fs_node_icon, fs_path_url } from '../FilesystemUtil';
import FileTitle from '../../file_viewer/viewers/FileTitle.svelte';
let dispatch = createEventDispatcher()
import TextBlock from '../../file_viewer/viewers/TextBlock.svelte';
export let fs_navigator
export let state
let player
let playing = false
let media_session = false
let siblings = []
const toggle_play = () => playing ? player.pause() : player.play()
// Detect when the song changes
$: update_session_meta(state.base.name)
const update_session_meta = name => {
export const update = async () => {
if (media_session) {
navigator.mediaSession.metadata = new MediaMetadata({
title: name,
title: state.base.name,
artist: "pixeldrain",
album: "unknown",
});
}
siblings = await fs_navigator.get_siblings()
}
onMount(() => {
if ('mediaSession' in navigator) {
media_session = true
update_session_meta(state.base.name)
navigator.mediaSession.setActionHandler('play', () => player.play());
navigator.mediaSession.setActionHandler('pause', () => player.pause());
navigator.mediaSession.setActionHandler('stop', () => player.stop());
navigator.mediaSession.setActionHandler('previoustrack', () => dispatch("open_sibling", -1));
navigator.mediaSession.setActionHandler('nexttrack', () => dispatch("open_sibling", 1));
navigator.mediaSession.setActionHandler('previoustrack', () => fs_navigator.open_sibling(-1));
navigator.mediaSession.setActionHandler('nexttrack', () => fs_navigator.open_sibling(1));
}
})
</script>
<slot></slot>
<div class="container">
<FileTitle title={state.base.name}/>
<button on:click={() => dispatch("open_sibling", -1) }><i class="icon">skip_previous</i></button>
<button on:click={() => player.currentTime -= 10 }><i class="icon">replay_10</i></button>
<button on:click={toggle_play}>
{#if playing}
<i class="icon">pause</i>
{:else}
<i class="icon">play_arrow</i>
{/if}
</button>
<button on:click={() => player.currentTime += 10 }><i class="icon">forward_10</i></button>
<button on:click={() => dispatch("open_sibling", 1) }><i class="icon">skip_next</i></button>
<br/><br/>
<FileTitle title={state.base.name}/>
<TextBlock>
<audio
bind:this={player}
class="player"
@@ -61,18 +50,59 @@ onMount(() => {
controls="controls"
on:pause={() => playing = false }
on:play={() => playing = true }
on:ended={() => dispatch("open_sibling", 1) }>
on:ended={() => fs_navigator.open_sibling(1) }>
<track kind="captions"/>
</audio>
</div>
<div style="text-align: center;">
<button on:click={() => fs_navigator.open_sibling(-1) }><i class="icon">skip_previous</i></button>
<button on:click={() => player.currentTime -= 10 }><i class="icon">replay_10</i></button>
<button on:click={toggle_play}>
{#if playing}
<i class="icon">pause</i>
{:else}
<i class="icon">play_arrow</i>
{/if}
</button>
<button on:click={() => player.currentTime += 10 }><i class="icon">forward_10</i></button>
<button on:click={() => fs_navigator.open_sibling(1) }><i class="icon">skip_next</i></button>
</div>
<h2>Tracklist</h2>
{#each siblings as sibling (sibling.path)}
<a
href={"/d"+fs_encode_path(sibling.path)}
on:click|preventDefault={() => fs_navigator.navigate(sibling.path, true)}
class="node"
>
{#if sibling.path === state.base.path}
<i class="play_arrow icon">play_arrow</i>
{:else}
<img src={fs_node_icon(sibling, 64, 64)} class="node_icon" alt="icon"/>
{/if}
<span>{sibling.name}</span>
<br/>
</a>
{/each}
</TextBlock>
<style>
.container {
padding: 0;
overflow-y: auto;
text-align: center;
}
.player {
width: 90%;
width: 100%;
}
.node {
display: flex;
flex-direction: row;
color: var(--body_text_color);
text-decoration: none;
align-items: center;
border-bottom: 1px solid var(--separator);
}
.node_icon {
margin: 4px;
width: 1.5em;
height: 1.5em;
}
.play_arrow {
margin: 4px;
}
</style>

View File

@@ -56,7 +56,7 @@ const state_update = async (base) => {
<CustomBanner path={state.path}/>
</FileManager>
{:else if viewer_type === "audio"}
<Audio state={state} on:open_sibling>
<Audio bind:this={viewer} fs_navigator={fs_navigator} state={state}>
<CustomBanner path={state.path}/>
</Audio>
{:else if viewer_type === "image"}