support media player api
This commit is contained in:
@@ -35,24 +35,18 @@ let state = {
|
||||
parents: initialNode.parents,
|
||||
base: initialNode.base,
|
||||
|
||||
// When navigating into a file or directory the siblings array will be
|
||||
// populated with the previous base's children
|
||||
siblings: [],
|
||||
|
||||
path_root: "/d/"+initialNode.bucket.id,
|
||||
loading: true,
|
||||
viewer_type: ""
|
||||
}
|
||||
|
||||
// Tallys
|
||||
$: total_directories = state.base.children.reduce((acc, cur) => {
|
||||
if (cur.type === "dir") {
|
||||
acc++
|
||||
}
|
||||
return acc
|
||||
}, 0)
|
||||
$: total_files = state.base.children.reduce((acc, cur) => {
|
||||
if (cur.type === "file") {
|
||||
acc++
|
||||
}
|
||||
return acc
|
||||
}, 0)
|
||||
$: total_directories = state.base.children.reduce((acc, cur) => cur.type === "dir" ? acc + 1 : acc, 0)
|
||||
$: total_files = state.base.children.reduce((acc, cur) => cur.type === "file" ? acc + 1 : acc, 0)
|
||||
$: total_file_size = state.base.children.reduce((acc, cur) => acc + cur.file_size, 0)
|
||||
|
||||
const navigate = (path, pushHist) => {
|
||||
@@ -77,16 +71,19 @@ const navigate = (path, pushHist) => {
|
||||
})
|
||||
}
|
||||
|
||||
const openNode = (node) => {
|
||||
// Sort directory children
|
||||
node.base.children.sort((a, b) => {
|
||||
const sort_children = children => {
|
||||
children.sort((a, b) => {
|
||||
// Sort directories before files
|
||||
console.log(a)
|
||||
if (a.type !== b.type) {
|
||||
return a.type === "file" ? 1 : -1
|
||||
return a.type === "dir" ? -1 : 1
|
||||
}
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
}
|
||||
|
||||
const openNode = (node) => {
|
||||
// Sort directory children
|
||||
sort_children(node.base.children)
|
||||
|
||||
// Update shared state
|
||||
state.bucket = node.bucket
|
||||
@@ -119,8 +116,50 @@ const openNode = (node) => {
|
||||
}
|
||||
onMount(() => openNode(initialNode))
|
||||
|
||||
// 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
|
||||
// negative number to move backward
|
||||
const open_sibling = offset => {
|
||||
state.loading = true
|
||||
|
||||
// Get the parent directory
|
||||
fs_get_node(
|
||||
state.bucket.id, state.parents[state.parents.length - 1].path,
|
||||
).then(resp => {
|
||||
// Sort directory children
|
||||
sort_children(resp.base.children)
|
||||
|
||||
// Loop over the parent node's children to find the one which is
|
||||
// currently open. Then, if possible, we save the one which comes before
|
||||
// or after it
|
||||
let next_sibling = null
|
||||
for (let i = 0; i < resp.base.children.length; i++) {
|
||||
if (
|
||||
resp.base.children[i].name === state.base.name &&
|
||||
i+offset >= 0 && // Prevent underflow
|
||||
i+offset < resp.base.children.length // Prevent overflow
|
||||
) {
|
||||
next_sibling = resp.base.children[i+offset]
|
||||
console.debug("Next sibling is", next_sibling)
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a sibling we open it
|
||||
if (next_sibling !== null) {
|
||||
navigate(next_sibling.path, true)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
alert(err)
|
||||
}).finally(() => {
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
// Capture browser back and forward navigation buttons
|
||||
window.onpopstate = (e) => {
|
||||
if(e.state){
|
||||
// Get the part of the URL after the bucket ID and navigate to it
|
||||
let locsplit = document.location.pathname.split(state.bucket.id+"/", 2)
|
||||
navigate(decodeURIComponent(locsplit[1]))
|
||||
}
|
||||
@@ -142,7 +181,7 @@ const download = () => {
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={keydown}/>
|
||||
<svelte:window on:keydown={keydown} on:/>
|
||||
|
||||
<div bind:this={file_viewer} class="file_viewer">
|
||||
{#if state.loading}
|
||||
@@ -205,11 +244,11 @@ const download = () => {
|
||||
{#if state.viewer_type === "dir"}
|
||||
<FileManager state={state} on:navigate={e => {navigate(e.detail, true)}} on:loading={e => {state.loading = e.detail}}></FileManager>
|
||||
{:else if state.viewer_type === "audio"}
|
||||
<Audio state={state}></Audio>
|
||||
<Audio state={state} on:open_sibling={e => {open_sibling(e.detail)}}></Audio>
|
||||
{:else if state.viewer_type === "image"}
|
||||
<Image state={state}></Image>
|
||||
<Image state={state} on:open_sibling={e => {open_sibling(e.detail)}}></Image>
|
||||
{:else if state.viewer_type === "video"}
|
||||
<Video state={state}></Video>
|
||||
<Video state={state} on:open_sibling={e => {open_sibling(e.detail)}}></Video>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,20 +1,64 @@
|
||||
<script>
|
||||
import { fs_get_file_url } from "../FilesystemAPI.svelte";
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let state;
|
||||
export let state
|
||||
let player
|
||||
let playing = false
|
||||
let media_session = false
|
||||
|
||||
const toggle_play = () => playing ? player.pause() : player.play()
|
||||
|
||||
// Detect when the song changes
|
||||
$: update_session_meta(state.base.name)
|
||||
|
||||
const update_session_meta = name => {
|
||||
if (media_session) {
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: name,
|
||||
artist: "unknown",
|
||||
album: "unknown",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
{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/>
|
||||
<audio
|
||||
bind:this={player}
|
||||
class="player"
|
||||
src={fs_get_file_url(state.bucket.id, state.base.path)}
|
||||
autoplay="autoplay"
|
||||
controls="controls"
|
||||
on:ended={() => { dispatch("next") }}>
|
||||
on:pause={() => playing = false }
|
||||
on:play={() => playing = true }
|
||||
on:ended={() => dispatch("open_sibling", 1) }>
|
||||
<track kind="captions"/>
|
||||
</audio>
|
||||
</div>
|
||||
|
@@ -12,7 +12,7 @@ export let state;
|
||||
src={fs_get_file_url(state.bucket.id, state.base.path)}
|
||||
autoplay="autoplay"
|
||||
controls="controls"
|
||||
on:ended={() => { dispatch("next") }}>
|
||||
on:ended={() => { dispatch("open_sibling", 1) }}>
|
||||
<track kind="captions"/>
|
||||
</video>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user