@audiowalk/sdk 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -4
- package/.github/workflows/publish.yml +0 -36
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -17
- package/dist/main.d.ts +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js +0 -1
- package/dist/player/player-controller.d.ts +0 -34
- package/dist/player/player-controller.d.ts.map +0 -1
- package/dist/player/player-controller.js +0 -145
- package/dist/service-worker.d.ts +0 -5
- package/dist/service-worker.d.ts.map +0 -1
- package/dist/service-worker.js +0 -58
- package/src/index.ts +0 -1
- package/src/player/player-controller.ts +0 -169
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audiowalk/sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/audiowalk-cz/components.git"
|
|
7
|
+
},
|
|
5
8
|
"main": "dist/index.js",
|
|
6
9
|
"scripts": {
|
|
7
10
|
"dev": "tsc -w",
|
|
8
|
-
"build": "tsc"
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"release:patch": "npm version patch && git push && npm publish --access public"
|
|
9
13
|
},
|
|
10
14
|
"author": "",
|
|
11
15
|
"license": "ISC",
|
|
@@ -15,4 +19,4 @@
|
|
|
15
19
|
"dependencies": {
|
|
16
20
|
"rxjs": "^7.8.1"
|
|
17
21
|
}
|
|
18
|
-
}
|
|
22
|
+
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
name: Publish NPM package
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- release
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
publish:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
packages: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- name: Setup Node.js
|
|
20
|
-
uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: "22.x"
|
|
23
|
-
registry-url: "https://registry.npmjs.org"
|
|
24
|
-
cache: "npm"
|
|
25
|
-
cache-dependency-path: package-lock.json
|
|
26
|
-
|
|
27
|
-
- name: Install dependencies
|
|
28
|
-
run: npm ci
|
|
29
|
-
|
|
30
|
-
- name: Build
|
|
31
|
-
run: npm run build
|
|
32
|
-
|
|
33
|
-
- name: Publish
|
|
34
|
-
run: npm publish --access public
|
|
35
|
-
env:
|
|
36
|
-
NODE_AUTH_TOKEN: ${{secrets.NPM_PUBLISH_TOKEN}}
|
package/dist/index.d.ts
DELETED
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./player/player-controller"), exports);
|
package/dist/main.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=main.d.ts.map
|
package/dist/main.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
|
package/dist/main.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject, Subject } from "rxjs";
|
|
2
|
-
export interface PlayerControllerOptions {
|
|
3
|
-
playOnInit?: boolean;
|
|
4
|
-
autoSave?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare enum PlayerStatus {
|
|
7
|
-
"playing" = "playing",
|
|
8
|
-
"paused" = "paused",
|
|
9
|
-
"ended" = "ended"
|
|
10
|
-
}
|
|
11
|
-
export declare class PlayerController {
|
|
12
|
-
private readonly playerElement;
|
|
13
|
-
private options;
|
|
14
|
-
readonly onPlay: Subject<void>;
|
|
15
|
-
readonly onPause: Subject<void>;
|
|
16
|
-
readonly onStop: Subject<void>;
|
|
17
|
-
readonly currentTime: BehaviorSubject<number>;
|
|
18
|
-
readonly totalTime: BehaviorSubject<number>;
|
|
19
|
-
readonly progress: import("rxjs").Observable<number>;
|
|
20
|
-
readonly status: BehaviorSubject<PlayerStatus | null>;
|
|
21
|
-
readonly playing: import("rxjs").Observable<boolean>;
|
|
22
|
-
private file?;
|
|
23
|
-
constructor(playerElement: HTMLAudioElement, options?: PlayerControllerOptions);
|
|
24
|
-
open(file: string, metadata: MediaMetadataInit): void;
|
|
25
|
-
close(): void;
|
|
26
|
-
play(): void;
|
|
27
|
-
pause(): void;
|
|
28
|
-
seekTo(seconds: number): void;
|
|
29
|
-
back(): void;
|
|
30
|
-
forward(): void;
|
|
31
|
-
private savePosition;
|
|
32
|
-
private log;
|
|
33
|
-
}
|
|
34
|
-
//# sourceMappingURL=player-controller.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"player-controller.d.ts","sourceRoot":"","sources":["../../src/player/player-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAsB,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpE,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,oBAAY,YAAY;IACtB,SAAS,YAAY;IACrB,QAAQ,WAAW;IACnB,OAAO,UAAU;CAClB;AAED,qBAAa,gBAAgB;IAiBf,OAAO,CAAC,QAAQ,CAAC,aAAa;IAAoB,OAAO,CAAC,OAAO;IAhB7E,SAAgB,MAAM,gBAAuB;IAC7C,SAAgB,OAAO,gBAAuB;IAC9C,SAAgB,MAAM,gBAAuB;IAE7C,SAAgB,WAAW,0BAAkC;IAC7D,SAAgB,SAAS,0BAAkC;IAC3D,SAAgB,QAAQ,oCAEtB;IAEF,SAAgB,MAAM,uCAAkD;IAExE,SAAgB,OAAO,qCAA2D;IAElF,OAAO,CAAC,IAAI,CAAC,CAAS;gBAEO,aAAa,EAAE,gBAAgB,EAAU,OAAO,GAAE,uBAA4B;IAmE3G,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB;IAW9C,KAAK;IAaL,IAAI;IAOJ,KAAK;IAML,MAAM,CAAC,OAAO,EAAE,MAAM;IAOtB,IAAI;IAOJ,OAAO;IAQP,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,GAAG;CAOZ"}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PlayerController = exports.PlayerStatus = void 0;
|
|
4
|
-
const rxjs_1 = require("rxjs");
|
|
5
|
-
var PlayerStatus;
|
|
6
|
-
(function (PlayerStatus) {
|
|
7
|
-
PlayerStatus["playing"] = "playing";
|
|
8
|
-
PlayerStatus["paused"] = "paused";
|
|
9
|
-
PlayerStatus["ended"] = "ended";
|
|
10
|
-
})(PlayerStatus || (exports.PlayerStatus = PlayerStatus = {}));
|
|
11
|
-
class PlayerController {
|
|
12
|
-
constructor(playerElement, options = {}) {
|
|
13
|
-
this.playerElement = playerElement;
|
|
14
|
-
this.options = options;
|
|
15
|
-
this.onPlay = new rxjs_1.Subject();
|
|
16
|
-
this.onPause = new rxjs_1.Subject();
|
|
17
|
-
this.onStop = new rxjs_1.Subject();
|
|
18
|
-
this.currentTime = new rxjs_1.BehaviorSubject(0);
|
|
19
|
-
this.totalTime = new rxjs_1.BehaviorSubject(0);
|
|
20
|
-
this.progress = (0, rxjs_1.combineLatest)([this.currentTime, this.totalTime]).pipe((0, rxjs_1.map)(([currentTime, totalTime]) => currentTime / totalTime));
|
|
21
|
-
this.status = new rxjs_1.BehaviorSubject(null);
|
|
22
|
-
this.playing = this.status.pipe((0, rxjs_1.map)((status) => status === "playing"));
|
|
23
|
-
navigator.mediaSession.setActionHandler("play", () => this.play());
|
|
24
|
-
navigator.mediaSession.setActionHandler("pause", () => this.pause());
|
|
25
|
-
navigator.mediaSession.setActionHandler("seekbackward", () => this.back());
|
|
26
|
-
navigator.mediaSession.setActionHandler("seekforward", () => this.forward());
|
|
27
|
-
navigator.mediaSession.setActionHandler("previoustrack", () => this.back());
|
|
28
|
-
navigator.mediaSession.setActionHandler("nexttrack", () => this.forward());
|
|
29
|
-
navigator.mediaSession.setActionHandler("seekto", (details) => {
|
|
30
|
-
// The fastSeek dictionary member will be true if the seek action is being called
|
|
31
|
-
// multiple times as part of a sequence and this is not the last call in that sequence.
|
|
32
|
-
if (details.fastSeek !== true && details.seekTime)
|
|
33
|
-
this.seekTo(details.seekTime);
|
|
34
|
-
});
|
|
35
|
-
this.status.subscribe((status) => {
|
|
36
|
-
switch (status) {
|
|
37
|
-
case "playing":
|
|
38
|
-
navigator.mediaSession.playbackState = "playing";
|
|
39
|
-
break;
|
|
40
|
-
case "paused":
|
|
41
|
-
navigator.mediaSession.playbackState = "paused";
|
|
42
|
-
break;
|
|
43
|
-
default:
|
|
44
|
-
case "ended":
|
|
45
|
-
navigator.mediaSession.playbackState = "none";
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
this.playerElement.addEventListener("play", () => {
|
|
50
|
-
this.onPlay.next();
|
|
51
|
-
this.status.next(PlayerStatus.playing);
|
|
52
|
-
});
|
|
53
|
-
this.playerElement.addEventListener("pause", () => {
|
|
54
|
-
this.onPause.next();
|
|
55
|
-
this.status.next(PlayerStatus.paused);
|
|
56
|
-
});
|
|
57
|
-
this.playerElement.addEventListener("ended", () => {
|
|
58
|
-
this.onStop.next();
|
|
59
|
-
this.status.next(PlayerStatus.ended);
|
|
60
|
-
});
|
|
61
|
-
this.playerElement.addEventListener("loadedmetadata", (event) => {
|
|
62
|
-
if (this.playerElement.duration) {
|
|
63
|
-
this.totalTime.next(this.playerElement.duration);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
this.playerElement.addEventListener("timeupdate", () => {
|
|
67
|
-
navigator.mediaSession.setPositionState({
|
|
68
|
-
duration: this.playerElement.duration,
|
|
69
|
-
playbackRate: this.playerElement.playbackRate,
|
|
70
|
-
position: this.playerElement.currentTime,
|
|
71
|
-
});
|
|
72
|
-
this.currentTime.next(this.playerElement.currentTime);
|
|
73
|
-
if (this.playerElement.duration) {
|
|
74
|
-
this.totalTime.next(this.playerElement.duration);
|
|
75
|
-
}
|
|
76
|
-
this.savePosition(this.playerElement.currentTime);
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
open(file, metadata) {
|
|
80
|
-
this.file = file;
|
|
81
|
-
navigator.mediaSession.metadata = new MediaMetadata(metadata);
|
|
82
|
-
const position = localStorage.getItem(`progress-${this.file}`);
|
|
83
|
-
if (position && this.options.autoSave)
|
|
84
|
-
this.playerElement.currentTime = parseFloat(position);
|
|
85
|
-
if (this.options.playOnInit)
|
|
86
|
-
this.playerElement.play();
|
|
87
|
-
}
|
|
88
|
-
close() {
|
|
89
|
-
this.file = undefined;
|
|
90
|
-
this.playerElement.pause();
|
|
91
|
-
this.playerElement.src = "";
|
|
92
|
-
navigator.mediaSession.setActionHandler("play", null);
|
|
93
|
-
navigator.mediaSession.setActionHandler("pause", null);
|
|
94
|
-
navigator.mediaSession.setActionHandler("previoustrack", null);
|
|
95
|
-
navigator.mediaSession.setActionHandler("nexttrack", null);
|
|
96
|
-
navigator.mediaSession.playbackState = "none";
|
|
97
|
-
navigator.mediaSession.metadata = null;
|
|
98
|
-
}
|
|
99
|
-
play() {
|
|
100
|
-
var _a;
|
|
101
|
-
if (!this.file)
|
|
102
|
-
throw new Error("No file opened");
|
|
103
|
-
this.log("Called play");
|
|
104
|
-
(_a = this.playerElement) === null || _a === void 0 ? void 0 : _a.play();
|
|
105
|
-
}
|
|
106
|
-
pause() {
|
|
107
|
-
var _a;
|
|
108
|
-
if (!this.file)
|
|
109
|
-
throw new Error("No file opened");
|
|
110
|
-
this.log("Called pause");
|
|
111
|
-
(_a = this.playerElement) === null || _a === void 0 ? void 0 : _a.pause();
|
|
112
|
-
}
|
|
113
|
-
seekTo(seconds) {
|
|
114
|
-
if (!this.file)
|
|
115
|
-
throw new Error("No file opened");
|
|
116
|
-
this.log("Called seekTo");
|
|
117
|
-
this.playerElement.currentTime = seconds;
|
|
118
|
-
}
|
|
119
|
-
back() {
|
|
120
|
-
if (!this.file)
|
|
121
|
-
throw new Error("No file opened");
|
|
122
|
-
const position = this.playerElement.currentTime;
|
|
123
|
-
this.seekTo(Math.max(position - 10, 0));
|
|
124
|
-
}
|
|
125
|
-
forward() {
|
|
126
|
-
if (!this.file)
|
|
127
|
-
throw new Error("No file opened");
|
|
128
|
-
const position = this.playerElement.currentTime;
|
|
129
|
-
const duration = this.playerElement.duration;
|
|
130
|
-
this.seekTo(duration && duration > 0 ? Math.min(position + 10, duration) : position + 10);
|
|
131
|
-
}
|
|
132
|
-
savePosition(currentTime) {
|
|
133
|
-
if (!this.file)
|
|
134
|
-
return;
|
|
135
|
-
localStorage.setItem(`progress-${this.file}`, String(currentTime));
|
|
136
|
-
}
|
|
137
|
-
log(message) {
|
|
138
|
-
var _a, _b;
|
|
139
|
-
const time = ((_a = this.playerElement) === null || _a === void 0 ? void 0 : _a.currentTime) ? Math.round((_b = this.playerElement) === null || _b === void 0 ? void 0 : _b.currentTime) : null;
|
|
140
|
-
if (time)
|
|
141
|
-
message += ` @${time}s`;
|
|
142
|
-
console.log(`[PlayerController] ${message}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports.PlayerController = PlayerController;
|
package/dist/service-worker.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service-worker.d.ts","sourceRoot":"","sources":["../src/service-worker.ts"],"names":[],"mappings":";;;AAIA,YAAY,EAAE,CAAC"}
|
package/dist/service-worker.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/// <reference lib="esnext" />
|
|
3
|
-
/// <reference lib="webworker" />
|
|
4
|
-
/// <reference no-default-lib="true"/>
|
|
5
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
function install() {
|
|
16
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
const res = yield fetch("audiowalk.json");
|
|
18
|
-
const config = yield res.json();
|
|
19
|
-
const cache = yield caches.open(`audiowalk-v${config.version}`);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function clearCache() {
|
|
23
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
const keys = yield caches.keys();
|
|
25
|
-
yield Promise.all(keys.map((key) => caches.delete(key)));
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
function updateCache() {
|
|
29
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
const res = yield fetch("audiowalk.json");
|
|
31
|
-
const config = yield res.json();
|
|
32
|
-
const cache = yield caches.open(`audiowalk-v${config.version}`);
|
|
33
|
-
const keys = yield cache.keys();
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
function checkUpdate() {
|
|
37
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
-
const res = yield fetch("audiowalk.json");
|
|
39
|
-
const config = yield res.json();
|
|
40
|
-
const cache = yield caches.open(`audiowalk-v${config.version}`);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
function checkCache() {
|
|
44
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
-
return false;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
self.addEventListener("install", (event) => { });
|
|
49
|
-
self.addEventListener("fetch", (event) => {
|
|
50
|
-
const request = event.request;
|
|
51
|
-
event.respondWith(caches.match(request).then((response) => {
|
|
52
|
-
return response || fetch(request);
|
|
53
|
-
}));
|
|
54
|
-
});
|
|
55
|
-
self.addEventListener("activate", (event) => { });
|
|
56
|
-
self.addEventListener("message", (event) => {
|
|
57
|
-
// TODO: Implement message handler
|
|
58
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./player/player-controller";
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject, combineLatest, map, Subject } from "rxjs";
|
|
2
|
-
|
|
3
|
-
export interface PlayerControllerOptions {
|
|
4
|
-
playOnInit?: boolean;
|
|
5
|
-
autoSave?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export enum PlayerStatus {
|
|
9
|
-
"playing" = "playing",
|
|
10
|
-
"paused" = "paused",
|
|
11
|
-
"ended" = "ended",
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class PlayerController {
|
|
15
|
-
public readonly onPlay = new Subject<void>();
|
|
16
|
-
public readonly onPause = new Subject<void>();
|
|
17
|
-
public readonly onStop = new Subject<void>();
|
|
18
|
-
|
|
19
|
-
public readonly currentTime = new BehaviorSubject<number>(0);
|
|
20
|
-
public readonly totalTime = new BehaviorSubject<number>(0);
|
|
21
|
-
public readonly progress = combineLatest([this.currentTime, this.totalTime]).pipe(
|
|
22
|
-
map(([currentTime, totalTime]) => currentTime / totalTime)
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
public readonly status = new BehaviorSubject<PlayerStatus | null>(null);
|
|
26
|
-
|
|
27
|
-
public readonly playing = this.status.pipe(map((status) => status === "playing"));
|
|
28
|
-
|
|
29
|
-
private file?: string;
|
|
30
|
-
|
|
31
|
-
constructor(private readonly playerElement: HTMLAudioElement, private options: PlayerControllerOptions = {}) {
|
|
32
|
-
navigator.mediaSession.setActionHandler("play", () => this.play());
|
|
33
|
-
navigator.mediaSession.setActionHandler("pause", () => this.pause());
|
|
34
|
-
navigator.mediaSession.setActionHandler("seekbackward", () => this.back());
|
|
35
|
-
navigator.mediaSession.setActionHandler("seekforward", () => this.forward());
|
|
36
|
-
navigator.mediaSession.setActionHandler("previoustrack", () => this.back());
|
|
37
|
-
navigator.mediaSession.setActionHandler("nexttrack", () => this.forward());
|
|
38
|
-
navigator.mediaSession.setActionHandler("seekto", (details) => {
|
|
39
|
-
// The fastSeek dictionary member will be true if the seek action is being called
|
|
40
|
-
// multiple times as part of a sequence and this is not the last call in that sequence.
|
|
41
|
-
if (details.fastSeek !== true && details.seekTime) this.seekTo(details.seekTime);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
this.status.subscribe((status) => {
|
|
45
|
-
switch (status) {
|
|
46
|
-
case "playing":
|
|
47
|
-
navigator.mediaSession.playbackState = "playing";
|
|
48
|
-
break;
|
|
49
|
-
case "paused":
|
|
50
|
-
navigator.mediaSession.playbackState = "paused";
|
|
51
|
-
break;
|
|
52
|
-
|
|
53
|
-
default:
|
|
54
|
-
case "ended":
|
|
55
|
-
navigator.mediaSession.playbackState = "none";
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
this.playerElement.addEventListener("play", () => {
|
|
61
|
-
this.onPlay.next();
|
|
62
|
-
this.status.next(PlayerStatus.playing);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
this.playerElement.addEventListener("pause", () => {
|
|
66
|
-
this.onPause.next();
|
|
67
|
-
this.status.next(PlayerStatus.paused);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
this.playerElement.addEventListener("ended", () => {
|
|
71
|
-
this.onStop.next();
|
|
72
|
-
this.status.next(PlayerStatus.ended);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
this.playerElement.addEventListener("loadedmetadata", (event) => {
|
|
76
|
-
if (this.playerElement.duration) {
|
|
77
|
-
this.totalTime.next(this.playerElement.duration);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
this.playerElement.addEventListener("timeupdate", () => {
|
|
82
|
-
navigator.mediaSession.setPositionState({
|
|
83
|
-
duration: this.playerElement.duration,
|
|
84
|
-
playbackRate: this.playerElement.playbackRate,
|
|
85
|
-
position: this.playerElement.currentTime,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
this.currentTime.next(this.playerElement.currentTime);
|
|
89
|
-
|
|
90
|
-
if (this.playerElement.duration) {
|
|
91
|
-
this.totalTime.next(this.playerElement.duration);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
this.savePosition(this.playerElement.currentTime);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
open(file: string, metadata: MediaMetadataInit) {
|
|
99
|
-
this.file = file;
|
|
100
|
-
|
|
101
|
-
navigator.mediaSession.metadata = new MediaMetadata(metadata);
|
|
102
|
-
|
|
103
|
-
const position = localStorage.getItem(`progress-${this.file}`);
|
|
104
|
-
if (position && this.options.autoSave) this.playerElement.currentTime = parseFloat(position);
|
|
105
|
-
|
|
106
|
-
if (this.options.playOnInit) this.playerElement.play();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
close() {
|
|
110
|
-
this.file = undefined;
|
|
111
|
-
this.playerElement.pause();
|
|
112
|
-
this.playerElement.src = "";
|
|
113
|
-
|
|
114
|
-
navigator.mediaSession.setActionHandler("play", null);
|
|
115
|
-
navigator.mediaSession.setActionHandler("pause", null);
|
|
116
|
-
navigator.mediaSession.setActionHandler("previoustrack", null);
|
|
117
|
-
navigator.mediaSession.setActionHandler("nexttrack", null);
|
|
118
|
-
navigator.mediaSession.playbackState = "none";
|
|
119
|
-
navigator.mediaSession.metadata = null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
play() {
|
|
123
|
-
if (!this.file) throw new Error("No file opened");
|
|
124
|
-
|
|
125
|
-
this.log("Called play");
|
|
126
|
-
this.playerElement?.play();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
pause() {
|
|
130
|
-
if (!this.file) throw new Error("No file opened");
|
|
131
|
-
this.log("Called pause");
|
|
132
|
-
this.playerElement?.pause();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
seekTo(seconds: number) {
|
|
136
|
-
if (!this.file) throw new Error("No file opened");
|
|
137
|
-
|
|
138
|
-
this.log("Called seekTo");
|
|
139
|
-
this.playerElement.currentTime = seconds;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
back() {
|
|
143
|
-
if (!this.file) throw new Error("No file opened");
|
|
144
|
-
|
|
145
|
-
const position = this.playerElement.currentTime;
|
|
146
|
-
this.seekTo(Math.max(position - 10, 0));
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
forward() {
|
|
150
|
-
if (!this.file) throw new Error("No file opened");
|
|
151
|
-
|
|
152
|
-
const position = this.playerElement.currentTime;
|
|
153
|
-
const duration = this.playerElement.duration;
|
|
154
|
-
this.seekTo(duration && duration > 0 ? Math.min(position + 10, duration) : position + 10);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private savePosition(currentTime: number) {
|
|
158
|
-
if (!this.file) return;
|
|
159
|
-
localStorage.setItem(`progress-${this.file}`, String(currentTime));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private log(message: string) {
|
|
163
|
-
const time = this.playerElement?.currentTime ? Math.round(this.playerElement?.currentTime) : null;
|
|
164
|
-
|
|
165
|
-
if (time) message += ` @${time}s`;
|
|
166
|
-
|
|
167
|
-
console.log(`[PlayerController] ${message}`);
|
|
168
|
-
}
|
|
169
|
-
}
|