Skip to content

Commit

Permalink
Fix m3u loader.
Browse files Browse the repository at this point in the history
  • Loading branch information
okaxaki committed Dec 17, 2023
1 parent feb20bb commit 128dc74
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 39 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "m3disp",
"private": true,
"version": "0.11.1",
"version": "0.11.2",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
26 changes: 11 additions & 15 deletions src/contexts/PlayerContext.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useContext, useEffect, useRef, useState } from "react";
import { AudioPlayerState } from "webaudio-stream-player";
import { KSSChannelMask } from "../kss/kss-device";
import { KSSPlayer } from "../kss/kss-player";
import { BinaryDataStorage } from "../utils/binary-data-storage";
import { loadUrls } from "../utils/load-urls";
import { loadEntriesFromUrl } from "../utils/load-urls";
import { isIOS, isSafari } from "../utils/platform-detect";
import { unmuteAudio } from "../utils/unmute";
import AppGlobal from "./AppGlobal";
import { PlayerContextReducer } from "./PlayerContextReducer";
import { AppProgressContext } from "./AppProgressContext";

export type PlayListEntry = {
title?: string | null;
Expand Down Expand Up @@ -148,6 +149,7 @@ async function applyPlayStateChange(
export function PlayerContextProvider(props: React.PropsWithChildren) {
const [state, setState] = useState(defaultContextState);
const oldState = usePrevious(state);
const p = useContext(AppProgressContext);

useEffect(() => {
applyPlayStateChange(oldState, state);
Expand Down Expand Up @@ -184,19 +186,13 @@ export function PlayerContextProvider(props: React.PropsWithChildren) {
const params = AppGlobal.getQueryParamsOnce();
const openUrl = params.get("open");
if (openUrl) {
const [newEntry] = await loadUrls([openUrl], state.storage);
if (newEntry != null) {
setState((oldState) => {
const newEntries = [...oldState.entries];
if (newEntry?.dataId != newEntries[0]?.dataId) {
newEntries.unshift(newEntry);
}
return {
...oldState,
entries: newEntries,
};
});
}
const entries = await loadEntriesFromUrl(openUrl, state.storage, p.setProgress);
setState((oldState) => {
return {
...oldState,
entries,
};
});
}
} catch (e) {
console.error(e);
Expand Down
11 changes: 3 additions & 8 deletions src/kss/kss-decoder-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ class KSSDecoderWorker extends AudioDecoderWorker {
private _kss: KSS | null = null;
private _kssplay: KSSPlay | null = null;



private _duration = 60 * 1000 * 5;
private _fadeDuration = 5 * 1000;
private _decodeFrames = 0;
Expand Down Expand Up @@ -86,7 +84,7 @@ class KSSDecoderWorker extends AudioDecoderWorker {
this._kssplay.setSilentLimit(15 * 1000);

this._fadeDuration = args.fadeDuration ?? defaultFadeDuration;
this._duration = (args.duration ?? defaultDuration);
this._duration = args.duration ?? defaultDuration;
this._hasDebugMarker = args.debug ?? false;
this._maxLoop = args.loop ?? defaultLoop;
this._decodeFrames = 0;
Expand Down Expand Up @@ -186,16 +184,13 @@ class KSSDecoderWorker extends AudioDecoderWorker {

const currentTimeInMs = (this._decodeFrames / this.sampleRate) * 1000;

if (
this._kssplay.getLoopCount() >= this._maxLoop ||
this._duration <= currentTimeInMs
) {
if (this._kssplay.getLoopCount() >= this._maxLoop || this._duration <= currentTimeInMs) {
if (this._kssplay.getFadeFlag() == 0) {
this._kssplay.fadeStart(this._fadeDuration);
}
}

if ((this._duration + this._fadeDuration) < currentTimeInMs) {
if (this._duration + this._fadeDuration <= currentTimeInMs) {
return null;
}

Expand Down
37 changes: 35 additions & 2 deletions src/utils/load-urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,47 @@ import { MGSC, TextDecoderEncoding, detectEncoding } from "mgsc-js";
import { parseM3U } from "./m3u-parser";

export const convertUrlIfRequired = (url: string) => {
const m = url.match(/^(https:\/\/)?f\.msxplay\.com\/([0-9a-z]+)/i);
// MSXplay.com
let m = url.match(/^(https:\/\/)?f\.msxplay\.com\/([0-9a-z]+)/i);
if (m != null) {
return `https://firebasestorage.googleapis.com/v0/b/msxplay-63a7a.appspot.com/o/pastebin%2F${m[2]}?alt=media`;
}

// github.com (blob or raw URL)
m = url.match(/^(?:https:\/\/)?github\.com\/(.+)\/(?:blob|raw)\/(.*)/);
if (m != null) {
return `https://raw.githubusercontent.com/${m[1]}/${m[2]}`;
}

return url;
};

export const loadUrls = async (
export async function loadEntriesFromUrl(
url: string, // m3u, pls or single data file.
storage: BinaryDataStorage,
progressCallback?: (value: number | null) => void
): Promise<PlayListEntry[]> {
const targetUrl = convertUrlIfRequired(url);
const fileUrls = [];

if (/[^/]*\.(m3u|pls)/i.test(url)) {
const baseUrl = targetUrl.replace(/[^/]*\.(m3u|pls)/i, "");
const res = await fetch(targetUrl);
const items = parseM3U(await res.text());
for (const item of items) {
if (/https?:\/\//.test(item.filename)) {
fileUrls.push(item.filename);
} else {
fileUrls.push(`${baseUrl}${item.filename}`);
}
}
} else {
fileUrls.push(targetUrl);
}
return loadFilesFromUrls(fileUrls, storage, progressCallback);
}

export const loadFilesFromUrls = async (
urls: string[],
storage: BinaryDataStorage,
setProgress?: (value: number | null) => void
Expand Down
6 changes: 4 additions & 2 deletions src/utils/m3u-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ export function parseM3U(text: string): PlayListEntry[] {
let durationInMs = mainDurationInMs;

if (durationInMs != null && loopDurationInMs != null) {
if (loopDurationInMs >= 0) {
if (loopDurationInMs > 0) {
durationInMs += loopDurationInMs;
} else {
} else if (loopDurationInMs < 0 || loopDurationInMs == -0) {
durationInMs += durationInMs + loopDurationInMs;
} else {
// do nothind
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/views/OpenUrlDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { ChangeEvent, useContext, useState } from "react";
import { AppContext } from "../contexts/AppContext";
import { Box, Button, Dialog, DialogActions, DialogContent, TextField } from "@mui/material";
import { PlayerContext } from "../contexts/PlayerContext";
import { loadUrls } from "../utils/load-urls";
import { loadEntriesFromUrl } from "../utils/load-urls";
import { AppProgressContext } from "../contexts/AppProgressContext";

export function OpenUrlDialog() {
const app = useContext(AppContext);
const progress = useContext(AppProgressContext);
const context = useContext(PlayerContext);
const id = "open-url-dialog";

Expand All @@ -17,7 +19,7 @@ export function OpenUrlDialog() {
const onOk = async () => {
app.closeDialog(id);
if (url != null) {
const entries = await loadUrls([url], context.storage);
const entries = await loadEntriesFromUrl(url, context.storage, progress.setProgress);
context.reducer.setEntries(entries);
}
};
Expand Down
11 changes: 4 additions & 7 deletions src/views/SampleDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Album, Close, LibraryMusic } from "@mui/icons-material";
import { Close, LibraryMusic } from "@mui/icons-material";
import {
AppBar,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Divider,
IconButton,
List,
Expand All @@ -17,13 +14,13 @@ import {
Toolbar,
Typography,
useMediaQuery,
useTheme,
useTheme
} from "@mui/material";
import { useContext } from "react";
import { AppContext } from "../contexts/AppContext";
import { AppProgressContext } from "../contexts/AppProgressContext";
import { PlayerContext } from "../contexts/PlayerContext";
import { loadUrls } from "../utils/load-urls";
import { loadFilesFromUrls } from "../utils/load-urls";

function getUrls(id: string) {
const res: string[] = [];
Expand Down Expand Up @@ -110,7 +107,7 @@ export function SampleDialog() {
const onClickItem = async (id: string) => {
await context.unmute();
app.closeDialog("sample-dialog");
const entries = await loadUrls(getUrls(id), context.storage, p.setProgress);
const entries = await loadFilesFromUrls(getUrls(id), context.storage, p.setProgress);
context.reducer.stop();
context.reducer.setEntries(entries);
context.reducer.play(0);
Expand Down

0 comments on commit 128dc74

Please sign in to comment.