feature: full play function
This commit is contained in:
parent
10e7341a73
commit
6e50a7bdc3
22
src/app.css
22
src/app.css
@ -8,4 +8,24 @@ h1 {
|
||||
|
||||
h2 {
|
||||
@apply text-3xl font-medium leading-[3rem];
|
||||
}
|
||||
}
|
||||
|
||||
.text-shadow {
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.text-shadow-md {
|
||||
text-shadow:
|
||||
0 4px 8px rgba(0, 0, 0, 0.12),
|
||||
0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.text-shadow-lg {
|
||||
text-shadow:
|
||||
0 15px 30px rgba(0, 0, 0, 0.11),
|
||||
0 5px 15px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.text-shadow-none {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
@ -1,18 +1,15 @@
|
||||
<script lang="ts">
|
||||
import localforage from '$lib/storage';
|
||||
export let coverId;
|
||||
import type { Writable } from 'svelte/store';
|
||||
export let coverPath: Writable<string>;
|
||||
let path: string = "";
|
||||
|
||||
let coverPath = '';
|
||||
|
||||
localforage.getItem(`${coverId}-cover`, function (err, file) {
|
||||
if (file) {
|
||||
const path = URL.createObjectURL(file as File);
|
||||
coverPath = path;
|
||||
}
|
||||
coverPath.subscribe((p) => {
|
||||
if (p) path = p;
|
||||
});
|
||||
</script>
|
||||
|
||||
<img class="cover" src={coverPath} alt="封面" />
|
||||
<img class="cover" src={path} alt="封面" />
|
||||
|
||||
<style>
|
||||
.cover {
|
||||
|
@ -1,38 +1,39 @@
|
||||
<script lang="ts">
|
||||
import formatDuration from "$lib/formatDuration";
|
||||
import formatDuration from '$lib/formatDuration';
|
||||
|
||||
export let name: string;
|
||||
export let singer: string = "";
|
||||
export let singer: string = '';
|
||||
export let duration: number = 0;
|
||||
export let progress: number = 0;
|
||||
export let paused: boolean;
|
||||
export let clickPlay: Function;
|
||||
</script>
|
||||
|
||||
<div class="interactive-box">
|
||||
<div class="song-info">
|
||||
<span class="song-name">{name}</span><br/>
|
||||
<span class="song-name text-shadow">{name}</span><br />
|
||||
<span class="song-author">{singer}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="time-indicator time-current">{formatDuration(progress)}</div>
|
||||
<div id="progress-bar" class="progress-bar">
|
||||
<div class="bar" style={`width: ${progress/(duration+0.001)*100}%;`}></div>
|
||||
<div class="time-indicator text-shadow-md time-current">{formatDuration(progress)}</div>
|
||||
<div class="progress-bar shadow-md">
|
||||
<div class="bar" style={`width: ${(progress / (duration + 0.001)) * 100}%;`}></div>
|
||||
</div>
|
||||
<div class="time-indicator time-total">{formatDuration(duration)}</div>
|
||||
<div class="time-indicator text-shadow-md time-total">{formatDuration(duration)}</div>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div id="previous" class="control-btn previous">
|
||||
<div style="filter: drop-shadow( 0 4px 8px rgba(0, 0, 0, 0.12) );" class="control-btn previous">
|
||||
<img class="control-img switch-song-img" src="/previous.svg" alt="上一曲" />
|
||||
</div>
|
||||
<div id="play" class="control-btn play-btn">
|
||||
<img id="play-img" class="control-img" src="/play.svg" alt="暂停或播放" />
|
||||
<div style="filter: drop-shadow( 0 4px 8px rgba(0, 0, 0, 0.12) );" class="control-btn play-btn" on:click={() => clickPlay()}>
|
||||
<img class="control-img" src={paused ? '/play.svg' : '/pause.svg'} alt="暂停或播放" />
|
||||
</div>
|
||||
<div id="right" class="control-btn next">
|
||||
<div style="filter: drop-shadow( 0 4px 8px rgba(0, 0, 0, 0.12) );" class="control-btn next">
|
||||
<img class="control-img switch-song-img" src="/next.svg" alt="下一曲" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.controls {
|
||||
position: absolute;
|
||||
@ -110,13 +111,13 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0.3rem;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.bar {
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
content: "";
|
||||
content: '';
|
||||
height: 0.3rem;
|
||||
display: inline-block;
|
||||
border-radius: 1.5rem;
|
||||
@ -127,7 +128,6 @@
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-family: sans-serif;
|
||||
display: inline-block;
|
||||
top: 0.2rem;
|
||||
}
|
||||
|
@ -6,25 +6,138 @@
|
||||
import InteractiveBox from '$lib/components/interactiveBox.svelte';
|
||||
import extractFileName from '$lib/extractFileName';
|
||||
import localforage from 'localforage';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const audioId = $page.params.id;
|
||||
let name = "";
|
||||
let singer = "";
|
||||
let audioPlayer: HTMLAudioElement;
|
||||
let name = '';
|
||||
let singer = '';
|
||||
let duration = 0;
|
||||
let currentProgress = 0;
|
||||
let audioFile: File;
|
||||
let paused: boolean = true;
|
||||
let launched = false;
|
||||
let prepared: string[] = [];
|
||||
const coverPath = writable('');
|
||||
let mainInterval: ReturnType<typeof setInterval>;
|
||||
|
||||
localforage.getItem(`${audioId}-file`, function (err, file) {
|
||||
if (file) {
|
||||
const f = file as File;
|
||||
name = extractFileName(f.name);
|
||||
function setMediaSession() {
|
||||
if ('mediaSession' in navigator === false) return;
|
||||
const ms = navigator.mediaSession;
|
||||
ms.metadata = new MediaMetadata({
|
||||
title: name,
|
||||
artist: singer,
|
||||
artwork: [
|
||||
{
|
||||
src: $coverPath
|
||||
}
|
||||
]
|
||||
});
|
||||
ms.setActionHandler('play', function () {
|
||||
audioPlayer.play();
|
||||
paused = false;
|
||||
});
|
||||
|
||||
ms.setActionHandler('pause', function () {
|
||||
audioPlayer.pause();
|
||||
paused = true;
|
||||
});
|
||||
|
||||
ms.setActionHandler('seekbackward', function () {
|
||||
if (audioPlayer.currentTime > 4) {
|
||||
audioPlayer.currentTime = 0;
|
||||
}
|
||||
});
|
||||
|
||||
ms.setActionHandler('previoustrack', function () {
|
||||
if (audioPlayer.currentTime > 4) {
|
||||
audioPlayer.currentTime = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function readDB() {
|
||||
getAudioIDMetadata(audioId, (metadata: any) => {
|
||||
duration = metadata.format.duration ? metadata.format.duration : 0;
|
||||
prepared.push('duration');
|
||||
});
|
||||
localforage.getItem(`${audioId}-cover`, function (err, file) {
|
||||
if (file) {
|
||||
const path = URL.createObjectURL(file as File);
|
||||
coverPath.set(path);
|
||||
}
|
||||
prepared.push('cover');
|
||||
});
|
||||
localforage.getItem(`${audioId}-file`, function (err, file) {
|
||||
if (file) {
|
||||
const f = file as File;
|
||||
audioFile = f;
|
||||
audioPlayer.src = URL.createObjectURL(audioFile);
|
||||
name = extractFileName(f.name);
|
||||
prepared.push('name');
|
||||
prepared.push('file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function playAudio() {
|
||||
if (audioPlayer.duration) {
|
||||
duration = audioPlayer.duration;
|
||||
}
|
||||
});
|
||||
getAudioIDMetadata(audioId, (metadata: any) => {
|
||||
console.log(metadata);
|
||||
duration = metadata.format.duration ? metadata.format.duration : 0;
|
||||
})
|
||||
audioPlayer.paused ? audioPlayer.play() : audioPlayer.pause();
|
||||
paused = audioPlayer.paused;
|
||||
setMediaSession();
|
||||
}
|
||||
|
||||
$: {
|
||||
if (!launched) {
|
||||
console.log('launch?');
|
||||
const requirements = ['name', 'file', 'cover'];
|
||||
let flag = true;
|
||||
for (const r of requirements) {
|
||||
if (!prepared.includes(r)) {
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
console.log(prepared, flag);
|
||||
if (flag) {
|
||||
launched = true;
|
||||
console.log('launch!');
|
||||
setMediaSession();
|
||||
audioPlayer.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
clearInterval(mainInterval);
|
||||
mainInterval = setInterval(() => {
|
||||
if (audioPlayer !== null && audioPlayer.currentTime !== undefined) {
|
||||
currentProgress = audioPlayer.currentTime;
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
$: {
|
||||
if (audioPlayer) {
|
||||
paused = audioPlayer.paused;
|
||||
if (audioPlayer.ended) {
|
||||
paused = true;
|
||||
audioPlayer.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
readDB();
|
||||
</script>
|
||||
|
||||
<Background coverId={audioId} />
|
||||
<Cover coverId={audioId} />
|
||||
<InteractiveBox name={name} singer={singer} duration={duration} progress={currentProgress}/>
|
||||
<Cover {coverPath} />
|
||||
<InteractiveBox
|
||||
{name}
|
||||
{singer}
|
||||
{duration}
|
||||
progress={currentProgress}
|
||||
clickPlay={playAudio}
|
||||
{paused}
|
||||
/>
|
||||
<audio bind:this={audioPlayer} controls style="display: none"></audio>
|
||||
|
Loading…
Reference in New Issue
Block a user