diff --git a/.gitignore b/.gitignore index 3b94e6a2a..f1541252e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ npm-debug.log.* # Temp /temp +/*.cpuprofile # Launcher files (created during testing) /config.json diff --git a/src/back/responses.ts b/src/back/responses.ts index 914749828..0634885ff 100644 --- a/src/back/responses.ts +++ b/src/back/responses.ts @@ -1,7 +1,7 @@ import { LogLevel } from '@shared/Log/interface'; import { MetaEditFile, MetaEditMeta } from '@shared/MetaEdit'; import { deepCopy, downloadFile, padEnd } from '@shared/Util'; -import { BackIn, BackInit, BackOut, ComponentState, CurationImageEnum, DownloadDetails, GetRendererLoadedDataResponse } from '@shared/back/types'; +import { BackIn, BackInit, BackOut, ComponentState, CurationImageEnum, DownloadDetails, GameOfTheDay, GetRendererLoadedDataResponse } from '@shared/back/types'; import { overwriteConfigData } from '@shared/config/util'; import { CURATIONS_FOLDER_EXPORTED, CURATIONS_FOLDER_TEMP, CURATIONS_FOLDER_WORKING, LOGOS, SCREENSHOTS, VIEW_PAGE_SIZE } from '@shared/constants'; import { convertGameToCurationMetaFile } from '@shared/curate/metaToMeta'; @@ -143,16 +143,14 @@ export function registerRequestCallbacks(state: BackState, init: () => Promise { const libraries = await fpDatabase.findAllGameLibraries(); - // Fetch update feed - let updateFeedMarkdown = ''; + // Fetch update feed in background if (state.preferences.updateFeedUrl) { - updateFeedMarkdown = await axios.get(state.preferences.updateFeedUrl, { timeout: 3000 }) + axios.get(state.preferences.updateFeedUrl, { timeout: 3000 }) .then((res) => { - return res.data; + state.socketServer.broadcast(BackOut.UPDATE_FEED, res.data); }) .catch((err) => { log.debug('Launcher', `Failed to fetch news feed from ${state.preferences.updateFeedUrl}, ERROR: ${err}`); - return ''; }); } else { log.debug('Launcher', 'No Update Feed URL specified'); @@ -161,7 +159,7 @@ export function registerRequestCallbacks(state: BackState, init: () => Promise { + const gotdDownload = new Promise((resolve, reject) => { const thumbnailWriter = fs.createWriteStream(gotdPath); axios.get(gotdUrl, { responseType: 'stream' }) .then((res) => { @@ -180,15 +178,51 @@ export function registerRequestCallbacks(state: BackState, init: () => Promise g.id !== ''); + gotdList = (gotdList as GameOfTheDay[]).filter((g: any) => g.id !== ''); + + // Now let the download update in its own time + gotdDownload.then(() => { + try { + gotdList = JSON.parse(fs.readFileSync(gotdPath, { encoding: 'utf8' })).games || []; + gotdList = (gotdList as GameOfTheDay[]).filter((g: any) => g.id !== ''); + state.socketServer.broadcast(BackOut.UPDATE_GOTD, gotdList); + } catch { + /** Bad download, ignore */ + } + }) + .catch(() => { + /** Bad download, ignore */ + }); } catch { - /** Ignore */ + // File doesn't exist, or broken, lets wait for a new one before trying again and returning + gotdList = await gotdDownload + .then(() => { + // Try loading again + let list = []; + try { + list = JSON.parse(fs.readFileSync(gotdPath, { encoding: 'utf8' })).games || []; + list = list.filter((g: any) => g.id !== ''); + return list; + } catch { + /** Neither local or remote, give up */ + return []; + } + }) + .catch(() => { + /** Neither local or remote, give up */ + return []; + }); } - state.platformAppPaths = processPlatformAppPaths(await fpDatabase.findPlatformAppPaths()); + fpDatabase.findPlatformAppPaths().then((paths) => { + paths = processPlatformAppPaths(paths); + state.platformAppPaths = paths; + state.socketServer.broadcast(BackOut.UPDATE_PLATFORM_APP_PATHS, paths); + }); const res: GetRendererLoadedDataResponse = { gotdList: gotdList, @@ -199,7 +233,6 @@ export function registerRequestCallbacks(state: BackState, init: () => Promise s.mad4fp === true) !== -1) : false, componentStatuses: state.componentStatuses, shortcuts: state.shortcuts, diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index 0b2096077..aee4e784e 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -241,25 +241,16 @@ export class App extends React.Component { for (const index of data.done) { switch (+index) { // Conversion to number, type safe bug case BackInit.DATABASE: { - if (this.props.preferencesData.gameMetadataSources.length > 0) { - window.Shared.back.request(BackIn.PRE_UPDATE_INFO, this.props.preferencesData.gameMetadataSources[0]) - .then((total) => { - this.props.dispatchMain({ - type: MainActionType.UPDATE_UPDATE_INFO, - total - }); - }); - } window.Shared.back.request(BackIn.GET_PLAYLISTS) .then(data => { if (data) { + this.props.dispatchMain({ + type: MainActionType.ADD_LOADED, + loaded: [BackInit.PLAYLISTS], + }); this.props.setMainState({ playlists: data }); this.cachePlaylistIcons(data); } - this.props.dispatchMain({ - type: MainActionType.ADD_LOADED, - loaded: [BackInit.PLAYLISTS], - }); }); window.Shared.back.request(BackIn.GET_RENDERER_LOADED_DATA) .then(data => { @@ -290,6 +281,13 @@ export class App extends React.Component { }); this.props.setTagCategories(data.tagCategories); }) + .then(() => { + console.log('fired db'); + this.props.dispatchMain({ + type: MainActionType.ADD_LOADED, + loaded: [index], + }); + }) .then(async () => { const data = await window.Shared.back.request(BackIn.GET_GAMES_TOTAL); if (data) { @@ -300,13 +298,20 @@ export class App extends React.Component { } }) .then(() => { - if (this.props.main.randomGames.length < RANDOM_GAME_ROW_COUNT) { this.rollRandomGames(true); } + if (this.props.main.randomGames.length < RANDOM_GAME_ROW_COUNT) { + this.rollRandomGames(true); + } }) .then(() => { - this.props.dispatchMain({ - type: MainActionType.ADD_LOADED, - loaded: [index], - }); + if (this.props.preferencesData.gameMetadataSources.length > 0) { + window.Shared.back.request(BackIn.PRE_UPDATE_INFO, this.props.preferencesData.gameMetadataSources[0]) + .then((total) => { + this.props.dispatchMain({ + type: MainActionType.UPDATE_UPDATE_INFO, + total + }); + }); + } }); break; } @@ -594,6 +599,24 @@ export class App extends React.Component { }); }); + window.Shared.back.register(BackOut.UPDATE_GOTD, (event, gotd) => { + this.props.setMainState({ + gotdList: gotd + }); + }); + + window.Shared.back.register(BackOut.UPDATE_FEED, (event, feed) => { + this.props.setMainState({ + updateFeedMarkdown: feed + }); + }); + + window.Shared.back.register(BackOut.UPDATE_PLATFORM_APP_PATHS, (event, paths) => { + this.props.setMainState({ + platformAppPaths: paths + }); + }); + window.Shared.back.register(BackOut.POST_SYNC_CHANGES, (event, libraries, suggestions, platformAppPaths, cats, total) => { this.props.dispatchMain({ type: MainActionType.POST_FPFSS_SYNC, @@ -1813,8 +1836,9 @@ export class App extends React.Component { alert(strings.dialog.unableToDeleteGame + '\n\n' + error); }); }; - cachePlaylistIcons(playlists: Playlist[]): void { - Promise.all(playlists.map(p => (async () => { + + async cachePlaylistIcons(playlists: Playlist[]) { + return Promise.all(playlists.map(p => (async () => { if (p.icon) { return cacheIcon(p.icon); } })())) .then(urls => { diff --git a/src/renderer/components/pages/HomePage.tsx b/src/renderer/components/pages/HomePage.tsx index 9c267432e..dbd36da59 100644 --- a/src/renderer/components/pages/HomePage.tsx +++ b/src/renderer/components/pages/HomePage.tsx @@ -26,7 +26,7 @@ import { SimpleButton } from '../SimpleButton'; import { SizeProvider } from '../SizeProvider'; type OwnProps = { - gotdList: GameOfTheDay[]; + gotdList: GameOfTheDay[] | undefined; platforms: string[]; playlists: Playlist[]; /** Generator for game context menu */ @@ -59,7 +59,7 @@ export function HomePage(props: HomePageProps) { const [updating, setUpdating] = React.useState(false); const parsedGotdList = React.useMemo(() => { - return props.gotdList.map(g => { + return props.gotdList ? props.gotdList.map(g => { const parts = g.date.split('-'); const year = parseInt(parts[0], 10); const month = parseInt(parts[1], 10); @@ -69,7 +69,7 @@ export function HomePage(props: HomePageProps) { ...g, date: newDate }; - }).sort((a, b) => { return a.date.getTime() - b.date.getTime(); }); + }).sort((a, b) => { return a.date.getTime() - b.date.getTime(); }) : []; }, [props.gotdList]); const [selectedGotd, setSelectedGotd] = React.useState(() => { @@ -286,6 +286,9 @@ export function HomePage(props: HomePageProps) { const extremeIconPath = React.useMemo(() => getExtremeIconURL(props.logoVersion), [props.logoVersion]); const renderedGotd = React.useMemo(() => { + if (props.gotdList === undefined) { + return <>; // No GOTD to display yet + } const extremeTags = props.preferencesData.tagFilters.filter(t => !t.enabled && t.extreme).reduce((prev, cur) => prev.concat(cur.tags), []); return ( void; diff --git a/src/renderer/store/main/types.ts b/src/renderer/store/main/types.ts index 3818d8fc4..983c9cdca 100644 --- a/src/renderer/store/main/types.ts +++ b/src/renderer/store/main/types.ts @@ -53,7 +53,7 @@ export type View = { export type ViewPageStates = Partial> export type MainState = { - gotdList: GameOfTheDay[]; + gotdList: GameOfTheDay[] | undefined; views: Record; // views[id] = view libraries: string[]; serverNames: string[]; diff --git a/src/shared/back/types.ts b/src/shared/back/types.ts index 529302eb6..ab09a639a 100644 --- a/src/shared/back/types.ts +++ b/src/shared/back/types.ts @@ -216,6 +216,11 @@ export enum BackOut { UPDATE_COMPONENT_STATUSES, SET_VIEW_SEARCH_STATUS, + // Updates? + UPDATE_GOTD, + UPDATE_FEED, + UPDATE_PLATFORM_APP_PATHS, + // Metadata Sync POST_SYNC_CHANGES, @@ -444,6 +449,11 @@ export type BackOutTemplate = SocketTemplate void; [BackOut.SET_VIEW_SEARCH_STATUS]: (viewId: string, status: string | null) => void; + // Updates? + [BackOut.UPDATE_GOTD]: (gotd: GameOfTheDay[]) => void; + [BackOut.UPDATE_FEED]: (markdown: string) => void; + [BackOut.UPDATE_PLATFORM_APP_PATHS]: (paths: PlatformAppPathSuggestions) => void; + // Metadata Sync [BackOut.POST_SYNC_CHANGES]: (libraries: string[], suggestions: GamePropSuggestions, platformAppPaths: PlatformAppPathSuggestions, cats: TagCategory[], total: number) => void; @@ -535,7 +545,7 @@ export type GameOfTheDay = { } export type GetRendererLoadedDataResponse = { - gotdList: GameOfTheDay[], + gotdList: GameOfTheDay[] | undefined, services: IService[]; libraries: string[]; suggestions: GamePropSuggestions; @@ -544,7 +554,6 @@ export type GetRendererLoadedDataResponse = { tagCategories: TagCategory[]; logoSets: LogoSet[]; platformAppPaths: PlatformAppPathSuggestions; - updateFeedMarkdown: string; componentStatuses: ComponentStatus[]; shortcuts: Record; }