Show episode listing
This commit is contained in:
parent
ea9001d0b3
commit
14de1b243a
14 changed files with 196 additions and 38 deletions
2
@types/items.d.ts
vendored
2
@types/items.d.ts
vendored
|
|
@ -34,7 +34,7 @@ export interface Item {
|
|||
mostRecentSvodUs: MostRecent;
|
||||
item: Item;
|
||||
mostRecentSvodEngAllTerrStartTimestamp: number;
|
||||
audio: Audio[];
|
||||
audio: string[];
|
||||
mostRecentAvod: MostRecent;
|
||||
}
|
||||
|
||||
|
|
|
|||
14
@types/messageHandler.d.ts
vendored
14
@types/messageHandler.d.ts
vendored
|
|
@ -8,7 +8,8 @@ export interface MessageHandler {
|
|||
search: (data: SearchData) => Promise<SearchResponse>,
|
||||
availableDubCodes: () => Promise<string[]>,
|
||||
handleDefault: (name: string) => Promise<any>,
|
||||
resolveItems: (data: ResolveItemsData) => Promise<ResponseBase<QueueItem[]>>
|
||||
resolveItems: (data: ResolveItemsData) => Promise<ResponseBase<QueueItem[]>>,
|
||||
listEpisodes: (id: string) => Promise<EpisodeListResponse>
|
||||
}
|
||||
|
||||
export type QueueItem = {
|
||||
|
|
@ -42,7 +43,18 @@ export type SearchResponseItem = {
|
|||
rating: number
|
||||
};
|
||||
|
||||
export type Episode = {
|
||||
e: string,
|
||||
lang: string[],
|
||||
name: string,
|
||||
season: string,
|
||||
seasonTitle: string,
|
||||
episode: string,
|
||||
id: string
|
||||
}
|
||||
|
||||
export type SearchResponse = ResponseBase<SearchResponseItem[]>
|
||||
export type EpisodeListResponse = ResponseBase<Episode[]>
|
||||
|
||||
export type FuniEpisodeData = {
|
||||
title: string,
|
||||
|
|
|
|||
26
crunchy.ts
26
crunchy.ts
|
|
@ -38,7 +38,7 @@ import { PlaybackData } from './@types/playbackData';
|
|||
import { downloaded } from './modules/module.downloadArchive';
|
||||
import parseSelect from './modules/module.parseSelect';
|
||||
import { AvailableFilenameVars, getDefault } from './modules/module.args';
|
||||
import { AuthData, AuthResponse, ResponseBase, SearchData, SearchResponse, SearchResponseItem } from './@types/messageHandler';
|
||||
import { AuthData, AuthResponse, Episode, ResponseBase, SearchData, SearchResponse, SearchResponseItem } from './@types/messageHandler';
|
||||
import { ServiceClass } from './@types/serviceClassInterface';
|
||||
|
||||
export default class Crunchy implements ServiceClass {
|
||||
|
|
@ -1279,10 +1279,14 @@ export default class Crunchy implements ServiceClass {
|
|||
merger.cleanUp();
|
||||
}
|
||||
|
||||
public async downloadFromSeriesID(id: string, data: CurnchyMultiDownload) : Promise<ResponseBase<CrunchyEpMeta[]>> {
|
||||
public async listSeriesID(id: string): Promise<{ list: Episode[], data: Record<string, {
|
||||
items: Item[];
|
||||
langs: langsData.LanguageItem[];
|
||||
}>}> {
|
||||
await this.refreshToken();
|
||||
const parsed = await this.parseSeriesById(id);
|
||||
if (!parsed)
|
||||
return { isOk: false, reason: new Error('Parse Error') };
|
||||
throw new Error('Unable to parse')
|
||||
const result = this.parseSeriesResult(parsed);
|
||||
const episodes : Record<string, {
|
||||
items: Item[],
|
||||
|
|
@ -1331,6 +1335,22 @@ export default class Crunchy implements ServiceClass {
|
|||
}).join(', ')
|
||||
}]`);
|
||||
}
|
||||
|
||||
return { data: episodes, list: Object.entries(episodes).map(([key, value]) => {
|
||||
return {
|
||||
e: key.startsWith('E') ? key.slice(1) : key,
|
||||
lang: value.langs.map(a => a.code),
|
||||
name: value.items[0].title,
|
||||
season: value.items[0].season_number.toString(),
|
||||
seasonTitle: value.items[0].season_title.replace(/\(\w+ Dub\)/g, '').trimEnd(),
|
||||
episode: value.items[0].episode_number?.toString() ?? value.items[0].episode ?? '?',
|
||||
id: value.items[0].season_id
|
||||
}
|
||||
})};
|
||||
}
|
||||
|
||||
public async downloadFromSeriesID(id: string, data: CurnchyMultiDownload) : Promise<ResponseBase<CrunchyEpMeta[]>> {
|
||||
const { data: episodes } = await this.listSeriesID(id);
|
||||
console.log();
|
||||
console.log('-'.repeat(30));
|
||||
console.log();
|
||||
|
|
|
|||
45
funi.ts
45
funi.ts
|
|
@ -37,7 +37,7 @@ import { FunimationMediaDownload } from './@types/funiTypes';
|
|||
import * as langsData from './modules/module.langsData';
|
||||
import { TitleElement } from './@types/episode';
|
||||
import { AvailableFilenameVars } from './modules/module.args';
|
||||
import { AuthData, AuthResponse, CheckTokenResponse, FuniGetEpisodeData, FuniGetEpisodeResponse, FuniGetShowData, SearchData, FuniSearchReponse, FuniShowResponse, FuniStreamData, FuniSubsData, FuniEpisodeData } from './@types/messageHandler';
|
||||
import { AuthData, AuthResponse, CheckTokenResponse, FuniGetEpisodeData, FuniGetEpisodeResponse, FuniGetShowData, SearchData, FuniSearchReponse, FuniShowResponse, FuniStreamData, FuniSubsData, FuniEpisodeData, ResponseBase } from './@types/messageHandler';
|
||||
import { ServiceClass } from './@types/serviceClassInterface';
|
||||
// check page
|
||||
|
||||
|
|
@ -52,6 +52,9 @@ let fnEpNum: string|number = 0,
|
|||
stDlPath: Subtitle[] = [];
|
||||
|
||||
export default class Funi implements ServiceClass {
|
||||
public static epIdLen = 4;
|
||||
public static typeIdLen = 0;
|
||||
|
||||
public cfg: yamlCfg.ConfigObject;
|
||||
private token: string | boolean;
|
||||
|
||||
|
|
@ -170,10 +173,10 @@ export default class Funi implements ServiceClass {
|
|||
return { isOk: true, value: searchDataJSON };
|
||||
}
|
||||
|
||||
public async getShow(log: boolean, data: FuniGetShowData) : Promise<FuniShowResponse> {
|
||||
public async listShowItems(id: number) : Promise<ResponseBase<Item[]>> {
|
||||
const showData = await getData({
|
||||
baseUrl: api_host,
|
||||
url: `/source/catalog/title/${data.id}`,
|
||||
url: `/source/catalog/title/${id}`,
|
||||
token: this.token,
|
||||
useToken: true,
|
||||
debug: this.debug,
|
||||
|
|
@ -182,8 +185,7 @@ export default class Funi implements ServiceClass {
|
|||
if(!showData.ok || !showData.res){ return { isOk: false, reason: new Error('ShowData is not ok') }; }
|
||||
const showDataJSON = JSON.parse(showData.res.body);
|
||||
if(showDataJSON.status){
|
||||
if (log)
|
||||
console.log('[ERROR] Error #%d: %s\n', showDataJSON.status, showDataJSON.data.errors[0].detail);
|
||||
console.log('[ERROR] Error #%d: %s\n', showDataJSON.status, showDataJSON.data.errors[0].detail);
|
||||
return { isOk: false, reason: new Error(showDataJSON.data.errors[0].detail) };
|
||||
}
|
||||
else if(!showDataJSON.items || showDataJSON.items.length<1){
|
||||
|
|
@ -191,8 +193,7 @@ export default class Funi implements ServiceClass {
|
|||
return { isOk: false, reason: new Error('Show not found') };
|
||||
}
|
||||
const showDataItem = showDataJSON.items[0];
|
||||
if (log)
|
||||
console.log('[#%s] %s (%s)',showDataItem.id,showDataItem.title,showDataItem.releaseYear);
|
||||
console.log('[#%s] %s (%s)',showDataItem.id,showDataItem.title,showDataItem.releaseYear);
|
||||
// show episodes
|
||||
const qs: {
|
||||
limit: number,
|
||||
|
|
@ -200,7 +201,7 @@ export default class Funi implements ServiceClass {
|
|||
sort_direction: string,
|
||||
title_id: number,
|
||||
language?: string
|
||||
} = { limit: -1, sort: 'order', sort_direction: 'ASC', title_id: data.id };
|
||||
} = { limit: -1, sort: 'order', sort_direction: 'ASC', title_id: id };
|
||||
const episodesData = await getData({
|
||||
baseUrl: api_host,
|
||||
url: '/funimation/episodes/',
|
||||
|
|
@ -213,7 +214,6 @@ export default class Funi implements ServiceClass {
|
|||
|
||||
let epsDataArr: Item[] = JSON.parse(episodesData.res.body).items;
|
||||
const epNumRegex = /^([A-Z0-9]*[A-Z])?(\d+)$/i;
|
||||
const epSelEpsTxt = []; let typeIdLen = 0, epIdLen = 4;
|
||||
|
||||
const parseEpStr = (epStr: string) => {
|
||||
const match = epStr.match(epNumRegex);
|
||||
|
|
@ -234,23 +234,18 @@ export default class Funi implements ServiceClass {
|
|||
e.id = baseId.replace(new RegExp('^' + e.ids.externalShowId), '');
|
||||
if(e.id.match(epNumRegex)){
|
||||
const epMatch = parseEpStr(e.id);
|
||||
epIdLen = epMatch[1].length > epIdLen ? epMatch[1].length : epIdLen;
|
||||
typeIdLen = epMatch[0].length > typeIdLen ? epMatch[0].length : typeIdLen;
|
||||
Funi.epIdLen = epMatch[1].length > Funi.epIdLen ? epMatch[1].length : Funi.epIdLen;
|
||||
Funi.typeIdLen = epMatch[0].length > Funi.typeIdLen ? epMatch[0].length : Funi.typeIdLen;
|
||||
e.id_split = epMatch;
|
||||
}
|
||||
else{
|
||||
typeIdLen = 3 > typeIdLen? 3 : typeIdLen;
|
||||
Funi.typeIdLen = 3 > Funi.typeIdLen? 3 : Funi.typeIdLen;
|
||||
console.log('[ERROR] FAILED TO PARSE: ', e.id);
|
||||
e.id_split = [ 'ZZZ', 9999 ];
|
||||
}
|
||||
return e;
|
||||
});
|
||||
|
||||
const epSelList = parseSelect(data.e as string, data.but);
|
||||
|
||||
const fnSlug: FuniEpisodeData[] = []; let is_selected = false;
|
||||
|
||||
const eps = epsDataArr;
|
||||
epsDataArr.sort((a, b) => {
|
||||
if (a.item.seasonOrder < b.item.seasonOrder && a.id.localeCompare(b.id) < 0) {
|
||||
return -1;
|
||||
|
|
@ -260,9 +255,21 @@ export default class Funi implements ServiceClass {
|
|||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return { isOk: true, value: epsDataArr };
|
||||
}
|
||||
|
||||
public async getShow(log: boolean, data: FuniGetShowData) : Promise<FuniShowResponse> {
|
||||
const showList = await this.listShowItems(data.id);
|
||||
if (!showList.isOk)
|
||||
return showList;
|
||||
const eps = showList.value;
|
||||
const epSelList = parseSelect(data.e as string, data.but);
|
||||
const fnSlug: FuniEpisodeData[] = [], epSelEpsTxt = []; let is_selected = false;
|
||||
|
||||
|
||||
for(const e in eps){
|
||||
eps[e].id_split[1] = parseInt(eps[e].id_split[1].toString()).toString().padStart(epIdLen, '0');
|
||||
eps[e].id_split[1] = parseInt(eps[e].id_split[1].toString()).toString().padStart(Funi.epIdLen, '0');
|
||||
let epStrId = eps[e].id_split.join('');
|
||||
// select
|
||||
is_selected = false;
|
||||
|
|
@ -283,7 +290,7 @@ export default class Funi implements ServiceClass {
|
|||
const aud_str = eps[e].audio.length > 0 ? `, ${eps[e].audio.join(', ')}` : '';
|
||||
const rtm_str = eps[e].item.runtime !== '' ? eps[e].item.runtime : '??:??';
|
||||
// console string
|
||||
eps[e].id_split[0] = eps[e].id_split[0].toString().padStart(typeIdLen, ' ');
|
||||
eps[e].id_split[0] = eps[e].id_split[0].toString().padStart(Funi.typeIdLen, ' ');
|
||||
epStrId = eps[e].id_split.join('');
|
||||
let conOut = `[${epStrId}] `;
|
||||
conOut += `${eps[e].item.titleName+tx_snum} - ${tx_type+tx_enum} ${eps[e].item.episodeName} `;
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@ export default () => {
|
|||
ipcMain.handle('default', async (_, data) => handler?.handleDefault(data));
|
||||
ipcMain.handle('availableDubCodes', async () => handler?.availableDubCodes());
|
||||
ipcMain.handle('resolveItems', async (_, data) => handler?.resolveItems(data));
|
||||
ipcMain.handle('listEpisodes', async (_, data) => handler?.listEpisodes(data));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AuthData, CheckTokenResponse, MessageHandler, QueueItem, ResolveItemsData, ResponseBase, SearchData, SearchResponse } from '../../../../@types/messageHandler';
|
||||
import { AuthData, CheckTokenResponse, EpisodeListResponse, MessageHandler, QueueItem, ResolveItemsData, ResponseBase, SearchData, SearchResponse } from '../../../../@types/messageHandler';
|
||||
import Crunchy from '../../../../crunchy';
|
||||
import Funimation from '../../../../funi';
|
||||
import { getDefault } from '../../../../modules/module.args';
|
||||
|
|
@ -12,6 +12,10 @@ class CrunchyHandler extends Base implements MessageHandler {
|
|||
this.crunchy = new Crunchy();
|
||||
}
|
||||
|
||||
public async listEpisodes (id: string): Promise<EpisodeListResponse> {
|
||||
return { isOk: true, value: (await this.crunchy.listSeriesID(id)).list };
|
||||
}
|
||||
|
||||
public async handleDefault(name: string) {
|
||||
return getDefault(name, this.crunchy.cfg.cli);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AuthData, CheckTokenResponse, MessageHandler, QueueItem, ResolveItemsData, ResponseBase, SearchData, SearchResponse } from '../../../../@types/messageHandler';
|
||||
import { AuthData, CheckTokenResponse, EpisodeListResponse, MessageHandler, QueueItem, ResolveItemsData, ResponseBase, SearchData, SearchResponse } from '../../../../@types/messageHandler';
|
||||
import Funimation from '../../../../funi';
|
||||
import { getDefault } from '../../../../modules/module.args';
|
||||
import { dubLanguageCodes } from '../../../../modules/module.langsData';
|
||||
|
|
@ -10,6 +10,24 @@ class FunimationHandler extends Base implements MessageHandler {
|
|||
super();
|
||||
this.funi = new Funimation();
|
||||
}
|
||||
|
||||
public async listEpisodes (id: string) : Promise<EpisodeListResponse> {
|
||||
const parse = parseInt(id);
|
||||
if (isNaN(parse) || parse <= 0)
|
||||
return { isOk: false, reason: new Error('The ID is invalid') };
|
||||
const request = await this.funi.listShowItems(parse);
|
||||
if (!request.isOk)
|
||||
return request;
|
||||
return { isOk: true, value: request.value.map(item => ({
|
||||
e: item.id_split.join(''),
|
||||
lang: item.audio ?? [],
|
||||
name: item.episodeSlug,
|
||||
season: item.seasonNum,
|
||||
seasonTitle: item.seasonTitle,
|
||||
episode: item.episodeNum,
|
||||
id: item.id
|
||||
})) }
|
||||
}
|
||||
|
||||
public async handleDefault(name: string) {
|
||||
return getDefault(name, this.funi.cfg.cli);
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
import React from "react";
|
||||
|
||||
const Bottom: React.FC = () => {
|
||||
return <></>
|
||||
}
|
||||
|
||||
export default Bottom;
|
||||
11
gui/react/src/components/MainFrame/Bottom/Bottom.tsx
Normal file
11
gui/react/src/components/MainFrame/Bottom/Bottom.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import EpisodeListing from "./Listing/EpisodeListing";
|
||||
|
||||
const Bottom: React.FC = () => {
|
||||
return <Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
|
||||
<EpisodeListing />
|
||||
</Box>
|
||||
}
|
||||
|
||||
export default Bottom;
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import { Accordion, AccordionSummary, AccordionDetails, Box, List, ListItem, Typography } from "@mui/material";
|
||||
import { ExpandMore } from '@mui/icons-material'
|
||||
import React from "react";
|
||||
import useStore from "../../../../hooks/useStore";
|
||||
import { Episode } from "../../../../../../../@types/messageHandler";
|
||||
|
||||
const EpisodeListing: React.FC = () => {
|
||||
const [store] = useStore();
|
||||
|
||||
const [expended, setExpended] = React.useState('');
|
||||
|
||||
const [data, setData] = React.useState<{
|
||||
[seasonHeader: string]: Episode[]
|
||||
}>({});
|
||||
|
||||
React.useEffect(() => {
|
||||
const map: {
|
||||
[seasonHeader: string]: Episode[]
|
||||
} = {};
|
||||
|
||||
store.episodeListing.forEach(item => {
|
||||
const title = `S${item.season} - ${item.seasonTitle}`;
|
||||
if (Object.prototype.hasOwnProperty.call(map, title)) {
|
||||
map[title].push(item);
|
||||
} else {
|
||||
map[title] = [ item ];
|
||||
}
|
||||
})
|
||||
|
||||
setData(map);
|
||||
}, [store]);
|
||||
|
||||
return <Box>
|
||||
{Object.entries(data).map(([key, items], index) => {
|
||||
return <Accordion key={`Season_${index}`} expanded={expended === key} onChange={() => setExpended(key === expended ? '' : key)}>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMore />}
|
||||
aria-controls="panel1bh-content"
|
||||
id="panel1bh-header"
|
||||
>
|
||||
<Typography sx={{ width: '80%', flexShrink: 0 }}>
|
||||
{key}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{items.map((item, index) => {
|
||||
return <Typography key={`Season_Item_${index}`} sx={{ paddingBottom: 1 }}>
|
||||
{`[${item.e}] [S${item.season}E${item.episode}] ${item.name} ( ${item.lang.join(', ')} ) `}
|
||||
</Typography>
|
||||
})}
|
||||
</AccordionDetails>
|
||||
</Accordion>;
|
||||
})}
|
||||
</Box>
|
||||
}
|
||||
|
||||
export default EpisodeListing;
|
||||
|
|
@ -5,12 +5,14 @@ import MultiSelect from "../../MultiSelect";
|
|||
import { messageChannelContext } from "../../../provider/MessageChannel";
|
||||
import { Check, Close } from "@mui/icons-material";
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import { useSnackbar } from "notistack";
|
||||
|
||||
const DownloadSelector: React.FC = () => {
|
||||
const messageHandler = React.useContext(messageChannelContext);
|
||||
const [store, dispatch] = useStore();
|
||||
const [availableDubs, setAvailableDubs] = React.useState<string[]>([]);
|
||||
const [ loading, setLoading ] = React.useState(false);
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
|
|
@ -31,7 +33,11 @@ const DownloadSelector: React.FC = () => {
|
|||
setLoading(true);
|
||||
const res = await messageHandler?.resolveItems(store.downloadOptions);
|
||||
if (!res || !res.isOk) {
|
||||
window.alert(res?.reason.message ?? 'Unable to resolve data');
|
||||
console.error(res);
|
||||
setLoading(false);
|
||||
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
||||
variant: 'error'
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'queue',
|
||||
|
|
@ -41,6 +47,29 @@ const DownloadSelector: React.FC = () => {
|
|||
setLoading(false);
|
||||
}
|
||||
|
||||
const listEpisodes = async () => {
|
||||
if (!store.downloadOptions.id) {
|
||||
return enqueueSnackbar('Please enter a ID', {
|
||||
variant: 'error'
|
||||
});
|
||||
}
|
||||
setLoading(true);
|
||||
const res = await messageHandler?.listEpisodes(store.downloadOptions.id);
|
||||
if (!res || !res.isOk) {
|
||||
console.log(res);
|
||||
setLoading(false);
|
||||
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
|
||||
variant: 'error'
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'episodeListing',
|
||||
payload: res.value
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
console.log(store.queue);
|
||||
|
||||
return <Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
|
|
@ -87,7 +116,7 @@ const DownloadSelector: React.FC = () => {
|
|||
<Button onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, but: !store.downloadOptions.but } })} variant={store.downloadOptions.but ? 'contained' : 'outlined'}>Download all but</Button>
|
||||
</Box>
|
||||
<Box sx={{ gap: 2, flex: 0, m: 1, mb: 3, display: 'flex', justifyContent: 'center' }}>
|
||||
<LoadingButton loading={loading} onClick={addToQueue} variant='contained'>Search for episodes</LoadingButton>
|
||||
<LoadingButton loading={loading} onClick={listEpisodes} variant='contained'>Search for episodes</LoadingButton>
|
||||
<LoadingButton loading={loading} onClick={addToQueue} variant='contained'>Add to Queue</LoadingButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Box, Divider } from "@mui/material";
|
||||
import React from "react";
|
||||
import Bottom from "./Bottom/Bottom";
|
||||
import DownloadSelector from "./DownloadSelector/DownloadSelector";
|
||||
import './MainFrame.css';
|
||||
import SearchBox from "./SearchBox/SearchBox";
|
||||
|
|
@ -9,6 +10,8 @@ const MainFrame: React.FC = () => {
|
|||
<SearchBox />
|
||||
<Divider variant='middle' className="divider-width" light sx={{ color: 'text.primary', fontSize: '1.2rem' }}>Options</Divider>
|
||||
<DownloadSelector />
|
||||
<Divider variant='middle' className="divider-width" light />
|
||||
<Bottom />
|
||||
</Box>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ const MessageChannelProvider: React.FC = ({ children }) => {
|
|||
search: async (data) => await ipcRenderer.invoke('search', data),
|
||||
handleDefault: async (data) => await ipcRenderer.invoke('default', data),
|
||||
availableDubCodes: async () => await ipcRenderer.invoke('availableDubCodes'),
|
||||
resolveItems: async (data) => await ipcRenderer.invoke('resolveItems', data)
|
||||
resolveItems: async (data) => await ipcRenderer.invoke('resolveItems', data),
|
||||
listEpisodes: async (data) => await ipcRenderer.invoke('listEpisodes', data)
|
||||
}
|
||||
|
||||
return <messageChannelContext.Provider value={messageHandler}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { QueueItem } from '../../../../@types/messageHandler';
|
||||
import { Episode, QueueItem } from '../../../../@types/messageHandler';
|
||||
import { dubLanguageCodes } from '../../../../modules/module.langsData';
|
||||
|
||||
export type DownloadOptions = {
|
||||
|
|
@ -14,6 +14,7 @@ export type DownloadOptions = {
|
|||
|
||||
export type StoreState = {
|
||||
queue: QueueItem[],
|
||||
episodeListing: Episode[];
|
||||
downloadOptions: DownloadOptions,
|
||||
service: 'crunchy'|'funi'|undefined
|
||||
}
|
||||
|
|
@ -43,7 +44,8 @@ const initialState: StoreState = {
|
|||
all: false,
|
||||
but: false
|
||||
},
|
||||
service: undefined
|
||||
service: undefined,
|
||||
episodeListing: []
|
||||
};
|
||||
|
||||
const Store: React.FC = ({children}) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue