Duration
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import {Track} from './Track';
|
import {Track} from './Track';
|
||||||
|
import {Signal, signal, WritableSignal} from '@angular/core';
|
||||||
|
|
||||||
enum STATE {
|
enum STATE {
|
||||||
Playing,
|
Playing,
|
||||||
@@ -7,46 +8,71 @@ enum STATE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PlaylistItem {
|
export class PlaylistItem {
|
||||||
protected element: HTMLAudioElement;
|
protected element: HTMLAudioElement | null = null;
|
||||||
protected state: STATE = STATE.Stopped;
|
protected state: STATE = STATE.Stopped;
|
||||||
|
protected initialised: boolean = false;
|
||||||
|
public currentTime: WritableSignal<number> = signal(0);
|
||||||
|
public duration: WritableSignal<number> = signal(0);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public track: Track,
|
public track: Track,
|
||||||
protected context: AudioContext
|
protected context: AudioContext
|
||||||
) {
|
) {
|
||||||
this.element = this.createElement(this.track.file.filepath, this.track.getMimeType())
|
|
||||||
context.createMediaElementSource(this.element).connect(context.destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createElement(filename: string, type: string) {
|
public initialise(): void {
|
||||||
const element = document.createElement('audio');
|
if (this.initialised) return;
|
||||||
|
|
||||||
|
this.initialised = true;
|
||||||
|
this.element = document.createElement('audio');
|
||||||
const source = document.createElement('source');
|
const source = document.createElement('source');
|
||||||
source.src = filename;
|
source.src = this.track.file.filepath;
|
||||||
source.type = type;
|
source.type = this.track.getMimeType();
|
||||||
element.appendChild(source);
|
this.element.appendChild(source);
|
||||||
return element;
|
for (const eventType of ['progress', 'durationchange', 'ended', 'loadeddata', 'pause', 'play', 'seeking', 'seeked', 'stalled', 'volumechange']) {
|
||||||
|
this.element.addEventListener(eventType, (event) => {
|
||||||
|
console.log(eventType, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.addEventListener('timeupdate', () => {
|
||||||
|
this.currentTime.set(this.element?.currentTime || 0);
|
||||||
|
})
|
||||||
|
this.element.addEventListener('durationchange', () => {
|
||||||
|
this.duration.set(this.element?.duration || 0);
|
||||||
|
})
|
||||||
|
this.context.createMediaElementSource(this.element).connect(this.context.destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async play() {
|
public async play() {
|
||||||
|
this.initialise();
|
||||||
if (this.state === STATE.Stopped || this.state === STATE.Paused) {
|
if (this.state === STATE.Stopped || this.state === STATE.Paused) {
|
||||||
await this.element.play();
|
await this.element?.play();
|
||||||
this.state = STATE.Playing;
|
this.state = STATE.Playing;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async stop() {
|
public async stop() {
|
||||||
this.element.currentTime = 0;
|
this.initialise();
|
||||||
this.element.pause();
|
this.element?.pause();
|
||||||
|
this.setTime();
|
||||||
this.state = STATE.Stopped;
|
this.state = STATE.Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setTime() {
|
||||||
|
if (this.element) {
|
||||||
|
this.element.currentTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async pause() {
|
public async pause() {
|
||||||
|
this.initialise();
|
||||||
if (this.state === STATE.Paused) {
|
if (this.state === STATE.Paused) {
|
||||||
return this.play();
|
return this.play();
|
||||||
}
|
}
|
||||||
if (this.state === STATE.Playing) {
|
if (this.state === STATE.Playing) {
|
||||||
this.element.pause();
|
this.element?.pause();
|
||||||
this.state = STATE.Paused;
|
this.state = STATE.Paused;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ Home
|
|||||||
{{ item.track.file.filename }}
|
{{ item.track.file.filename }}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<div>{{ audio.current()?.currentTime()}} / {{audio.current()?.duration()}} -> {{ audio.progress()}} %</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {FileSystemFile, Track, TrackMeta, PlaylistItem} from '../models';
|
import {FileSystemFile, Track, TrackMeta, PlaylistItem} from '../models';
|
||||||
import {Signal} from '@angular/core';
|
import {computed, Signal} from '@angular/core';
|
||||||
import {IndexedArray} from '../lib';
|
import {IndexedArray} from '../lib';
|
||||||
|
|
||||||
export class AudioService {
|
export class AudioService {
|
||||||
@@ -8,6 +8,12 @@ export class AudioService {
|
|||||||
public list: Signal<PlaylistItem[]> = this.playlist.playlist;
|
public list: Signal<PlaylistItem[]> = this.playlist.playlist;
|
||||||
public current: Signal<PlaylistItem|null> = this.playlist.current;
|
public current: Signal<PlaylistItem|null> = this.playlist.current;
|
||||||
public index: Signal<number> = this.playlist.index;
|
public index: Signal<number> = this.playlist.index;
|
||||||
|
public progress: Signal<number> = computed(() => {
|
||||||
|
const current = this.current();
|
||||||
|
if (!current) return 0;
|
||||||
|
if (current.duration() === 0) return 0;
|
||||||
|
return current.currentTime() / current.duration();
|
||||||
|
})
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.context = new AudioContext();
|
this.context = new AudioContext();
|
||||||
|
|||||||
Reference in New Issue
Block a user