Fetch titles from tags to show in playlist.

This commit is contained in:
Jean-Philip Desjardins 2022-12-25 15:16:12 -05:00
parent 2c6b76965b
commit dca9bf3531
4 changed files with 68 additions and 3 deletions

View file

@ -1,6 +1,6 @@
import { configureStore, createAsyncThunk, createReducer } from "@reduxjs/toolkit";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { PsfPlayerModule, initPsfPlayerModule, resumePsf, pausePsf, getPsfArchiveFileList, loadPsfFromArchive, getCurrentPsfTags } from "./PsfPlayerModule";
import { PsfPlayerModule, initPsfPlayerModule, resumePsf, pausePsf, getPsfArchiveFileList, getPsfArchiveItemTags, loadPsfFromArchive, getCurrentPsfTags } from "./PsfPlayerModule";
const invalidPlayingIndex = -1;
@ -26,6 +26,7 @@ export type AudioState = {
playing: boolean
playingIndex: number
archiveFileList : string[]
archiveItemTitles : string[]
archiveFileListVersion : number;
currentPsfTags : any | undefined
};
@ -41,6 +42,7 @@ let initialState : AudioState = {
playing: false,
playingIndex: invalidPlayingIndex,
archiveFileList: [],
archiveItemTitles: [],
archiveFileListVersion: 0,
currentPsfTags: undefined
};
@ -84,6 +86,20 @@ export const loadArchive = createAsyncThunk<string[] | undefined, File>('loadArc
}
);
export const fetchArchiveItemTitle = createAsyncThunk<string, number>('fetchArchiveItemTitle',
async (archiveFileIndex : number, thunkAPI) => {
let state = thunkAPI.getState() as RootState;
let psfFilePath = state.player.archiveFileList[archiveFileIndex] as string;
let tags = getPsfArchiveItemTags(archiveFilePath, psfFilePath);
let title = tags.get("title");
if(title) {
return title;
} else {
return psfFilePath;
}
}
);
export const loadPsf = createAsyncThunk<LoadPsfResult, number>('loadPsf',
async (archiveFileIndex : number, thunkAPI) => {
let state = thunkAPI.getState() as RootState;
@ -122,8 +138,10 @@ const reducer = createReducer(initialState, (builder) => (
state.currentPsfTags = undefined;
if(action.payload) {
state.archiveFileList = action.payload;
state.archiveItemTitles = [...action.payload];
} else {
state.archiveFileList = [];
state.archiveItemTitles = [];
}
state.archiveFileListVersion = state.archiveFileListVersion + 1;
return state;
@ -132,10 +150,15 @@ const reducer = createReducer(initialState, (builder) => (
state.playingIndex = invalidPlayingIndex;
state.currentPsfTags = undefined;
state.archiveFileList = [];
state.archiveItemTitles = [];
state.archiveFileListVersion = state.archiveFileListVersion + 1;
state.value = `loading failed: ${action.error.message}`;
return state;
})
.addCase(fetchArchiveItemTitle.fulfilled, (state, action) => {
state.archiveItemTitles[action.meta.arg] = action.payload;
return state;
})
.addCase(loadPsf.fulfilled, (state, action) => {
state.value = "psf loaded";
state.currentPsfTags = action.payload.tags;

View file

@ -2,7 +2,7 @@ import './App.css';
import { ChangeEvent, useEffect, useRef } from 'react';
import { FixedSizeList, ListChildComponentProps } from 'react-window';
import { ListItem, ListItemButton, ListItemText } from '@mui/material';
import { useAppDispatch, useAppSelector, loadArchive, loadPsf, play, pause } from "./Actions";
import { useAppDispatch, useAppSelector, loadArchive, fetchArchiveItemTitle, loadPsf, play, pause } from "./Actions";
import { PsfPlayerModule } from './PsfPlayerModule';
function RenderRow(props: ListChildComponentProps) {
@ -10,6 +10,7 @@ function RenderRow(props: ListChildComponentProps) {
const state = useAppSelector((state) => state.player);
let archiveFile = state.archiveFileList[index];
let archiveItemTitle = state.archiveItemTitles[index];
const dispatch = useAppDispatch();
const handleClick = function(archiveFileIndex : number) {
@ -24,7 +25,7 @@ function RenderRow(props: ListChildComponentProps) {
return (
<ListItem style={style} key={index} component="div" disablePadding>
<ListItemButton onClick={(e) => handleClick(index)}>
<ListItemText primary={archiveFile} primaryTypographyProps={{style: itemStyle}} />
<ListItemText primary={archiveItemTitle} primaryTypographyProps={{style: itemStyle}} />
</ListItemButton>
</ListItem>
);
@ -38,6 +39,8 @@ function usePrevious<Type>(value : Type) : Type | undefined {
return ref.current;
}
let fetchTitleAbortController = new AbortController();
export default function App() {
const dispatch = useAppDispatch();
const listRef = useRef<FixedSizeList>(null);
@ -82,13 +85,36 @@ export default function App() {
const handleChange = function(event : ChangeEvent<HTMLInputElement>) {
if(event.target && event.target.files && event.target.files.length !== 0) {
fetchTitleAbortController.abort();
dispatch(loadArchive(event.target.files[0]));
}
}
const fetchTitles = async function(signal : AbortSignal) {
function sleep(ms : number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let fetchPromiseAbortFunction : Function | null = null;
signal.addEventListener("abort", (ev: Event) => {
if(fetchPromiseAbortFunction) {
fetchPromiseAbortFunction();
}
});
for(let i = 0; i < state.archiveFileList.length; i++) {
await sleep(100);
if(signal.aborted) {
break;
}
let fetchPromise = dispatch(fetchArchiveItemTitle(i));
fetchPromiseAbortFunction = fetchPromise.abort;
}
}
useEffect(() => {
if(state.archiveFileListVersion !== prevArchiveFileListVersion) {
listRef.current?.scrollTo(0);
fetchTitleAbortController = new AbortController();
fetchTitles(fetchTitleAbortController.signal);
}
if(state.playing !== prevPlaying) {
if(state.playing) {

View file

@ -53,6 +53,11 @@ export let getPsfArchiveFileList = function(archivePath : string) {
return convertStringVectorToArray(fileList);
}
export let getPsfArchiveItemTags = function(archivePath : string, psfPath : string) {
let tags = convertStringMapToDictionary(PsfPlayerModule.getPsfArchiveItemTags(archivePath, psfPath));
return tags;
}
export let loadPsfFromArchive = async function(archivePath : string, psfPath : string) {
PsfPlayerModule.loadPsf(archivePath, psfPath);
}

View file

@ -2,6 +2,7 @@
#include <cstdio>
#include "filesystem_def.h"
#include "PsfArchive.h"
#include "PsfStreamProvider.h"
#include "SH_OpenALProxy.h"
#include "SH_FileOutput.h"
#include "../SH_OpenAL.h"
@ -79,6 +80,15 @@ std::vector<std::string> getPsfArchiveFileList(std::string rawArchivePath)
return result;
}
CPsfBase::TagMap getPsfArchiveItemTags(std::string rawArchivePath, std::string psfPath)
{
fs::path archivePath(rawArchivePath);
auto streamProvider = CreatePsfStreamProvider(archivePath);
std::unique_ptr<Framework::CStream> inputStream(streamProvider->GetStreamForPath(psfPath));
CPsfBase psfFile(*inputStream);
return CPsfBase::TagMap(psfFile.GetTagsBegin(), psfFile.GetTagsEnd());
}
CPsfBase::TagMap getCurrentPsfTags()
{
return g_tags;
@ -95,5 +105,6 @@ EMSCRIPTEN_BINDINGS(PsfPlayer)
function("resumePsf", &resumePsf);
function("loadPsf", &loadPsf);
function("getPsfArchiveFileList", &getPsfArchiveFileList);
function("getPsfArchiveItemTags", &getPsfArchiveItemTags);
function("getCurrentPsfTags", &getCurrentPsfTags);
}