Add tracklist to audio player
This commit is contained in:
@@ -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>
|
||||
|
@@ -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) {
|
||||
|
@@ -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>
|
||||
|
@@ -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"}
|
||||
|
Reference in New Issue
Block a user