Skip to content

Commit 82c916e

Browse files
committed
Add support for triggering a library download via a URL
Updates #337
1 parent 10108a2 commit 82c916e

10 files changed

Lines changed: 106 additions & 74 deletions

src/Browser.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ function DiskContents({disk, onRun}: DiskContentsProps) {
289289
includeInfiniteHD: true,
290290
includeSavedHD: canSaveDisks(),
291291
includeLibrary: false,
292+
libraryDownloadURLs: [],
292293
machine: disk.machines[0],
293294
cdromURLs: [],
294295
diskFiles: [],

src/Custom.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function Custom({
6565
includeInfiniteHD: true,
6666
includeSavedHD: canSaveDisks(),
6767
includeLibrary: false,
68+
libraryDownloadURLs: [],
6869
isCustom: true,
6970
diskFiles: [],
7071
}

src/Mac.tsx

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ import {
4747
import {type ScreenSize} from "./run-def";
4848
import {viewTransitionNameForDisk} from "./view-transitions";
4949
import {DrawersContainer} from "./controls/Drawer";
50-
import {MacLibrary} from "./MacLibrary";
50+
import {handleLibraryURL, MacLibrary} from "./MacLibrary";
5151

5252
export type MacProps = {
5353
disks: SystemDiskDef[];
5454
includeInfiniteHD: boolean;
5555
includeSavedHD: boolean;
5656
includeLibrary: boolean;
57+
libraryDownloadURLs: string[];
5758
diskFiles: DiskFile[];
5859
cdroms: EmulatorCDROM[];
5960
initialErrorText?: string;
@@ -75,6 +76,7 @@ export default function Mac({
7576
includeInfiniteHD,
7677
includeSavedHD,
7778
includeLibrary,
79+
libraryDownloadURLs,
7880
diskFiles,
7981
cdroms,
8082
initialErrorText,
@@ -138,6 +140,35 @@ export default function Mac({
138140

139141
const hasSavedHD = includeSavedHD && canSaveDisks();
140142

143+
const handleMacLibraryProgress = useCallback(
144+
(name: string, fraction: number) => {
145+
setEmulatorFileLoadingProgress({
146+
name,
147+
fraction,
148+
});
149+
},
150+
[]
151+
);
152+
const handleMacLibraryRun = useCallback((file: File) => {
153+
const emulator = emulatorRef.current;
154+
if (emulator) {
155+
setEmulatorFileLoadingProgress({
156+
name: file.name,
157+
fraction: 1.0,
158+
linger: true,
159+
});
160+
uploadFiles(emulator, [file], undefined, true);
161+
setTimeout(
162+
() =>
163+
setEmulatorFileLoadingProgress({
164+
name: file.name,
165+
fraction: 1.0,
166+
}),
167+
1000
168+
);
169+
}
170+
}, []);
171+
141172
useEffect(() => {
142173
const emulatorDisks: EmulatorDiskDef[] = [...disks];
143174
const delayedDisks: EmulatorDiskDef[] = [];
@@ -199,6 +230,15 @@ export default function Mac({
199230
emulatorDidFinishLoading(emulator: Emulator) {
200231
setEmulatorLoaded(true);
201232
emulator.refreshSettings();
233+
if (emulatorSupportsDownloadsFolder(machine.emulatorType)) {
234+
libraryDownloadURLs.forEach(url =>
235+
handleLibraryURL(
236+
url,
237+
handleMacLibraryRun,
238+
handleMacLibraryProgress
239+
)
240+
);
241+
}
202242
},
203243
emulatorDidMakeLoadingProgress(
204244
emulator: Emulator,
@@ -721,36 +761,8 @@ export default function Mac({
721761
) && (
722762
<MacLibrary
723763
appearance={appearance}
724-
onLoadProgress={(name, fraction) => {
725-
setEmulatorFileLoadingProgress({
726-
name,
727-
fraction,
728-
});
729-
}}
730-
onRun={file => {
731-
const emulator = emulatorRef.current;
732-
if (emulator) {
733-
setEmulatorFileLoadingProgress({
734-
name: file.name,
735-
fraction: 1.0,
736-
linger: true,
737-
});
738-
uploadFiles(
739-
emulator,
740-
[file],
741-
undefined,
742-
true
743-
);
744-
setTimeout(
745-
() =>
746-
setEmulatorFileLoadingProgress({
747-
name: file.name,
748-
fraction: 1.0,
749-
}),
750-
1000
751-
);
752-
}
753-
}}
764+
onLoadProgress={handleMacLibraryProgress}
765+
onRun={handleMacLibraryRun}
754766
/>
755767
)}
756768
</DrawersContainer>

src/MacLibrary.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {Input} from "./controls/Input";
1212
import {useDebouncedCallback} from "use-debounce";
1313
import classNames from "classnames";
1414
import {type LibraryIndexItem} from "./library";
15+
import {proxyUrl} from "./library-urls";
1516

1617
export function MacLibrary({
1718
onRun,
@@ -49,19 +50,15 @@ export function MacLibrary({
4950
fileName,
5051
size
5152
) => {
52-
const progressName = fileName
53-
? `${name} (${fileName}}`
54-
: name;
5553
collapse();
56-
const blob = await fetchWithProgress(
54+
handleLibraryURL(
5755
url,
58-
(loadedBytes, totalBytes) =>
59-
onLoadProgress(
60-
progressName,
61-
loadedBytes / (size ?? totalBytes)
62-
)
56+
onRun,
57+
onLoadProgress,
58+
name,
59+
fileName,
60+
size
6361
);
64-
onRun(new File([blob], fileName ?? "Untitled"));
6562
}}
6663
appearance={appearance}
6764
/>
@@ -71,6 +68,25 @@ export function MacLibrary({
7168
);
7269
}
7370

71+
export async function handleLibraryURL(
72+
url: string,
73+
onRun: (file: File) => void,
74+
onLoadProgress: (name: string, fraction: number) => void,
75+
name?: string,
76+
fileName?: string,
77+
size?: number
78+
) {
79+
if (!fileName) {
80+
fileName = new URL(url).pathname.split("/").at(-1) ?? "Untitled";
81+
}
82+
const progressName = name ? `${name} (${fileName})` : fileName;
83+
const fetchURL = proxyUrl(url);
84+
const blob = await fetchWithProgress(fetchURL, (loadedBytes, totalBytes) =>
85+
onLoadProgress(progressName, loadedBytes / (size ?? totalBytes))
86+
);
87+
onRun(new File([blob], fileName));
88+
}
89+
7490
export function MacLibraryHeader({
7591
search,
7692
setSearch,

src/MacLibraryContents.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import {
1111
ARCHITECTURE_INDEX,
1212
CATEGORIES_INDEX,
1313
createSearchPredicate,
14-
downloadUrl,
1514
GAMES_INDEX,
1615
type LibraryDetailsItem,
1716
PERSPECTIVE_INDEX,
1817
SYSTEM_INDEX,
1918
useLibraryItemDetails,
2019
type LibraryIndexItem,
21-
proxyUrl,
2220
} from "./library";
21+
import {downloadUrl} from "./library-urls";
2322
import "./MacLibraryContents.css";
2423
import {memo, type ReactNode, useCallback, useMemo} from "react";
2524
import {Button} from "./controls/Button";
@@ -317,15 +316,14 @@ function MacLibraryItemDownloads({
317316
<ol>
318317
{Object.entries(details.files).map(([file, size]) => {
319318
const url = downloadUrl(file, item.type);
320-
const runUrl = proxyUrl(url);
321319
return (
322320
<li key={file}>
323321
<a
324322
href={url}
325323
onClick={e => {
326324
e.preventDefault();
327325
e.stopPropagation();
328-
onRun(runUrl, item.title, file, size);
326+
onRun(url, item.title, file, size);
329327
}}
330328
target="_blank">
331329
{file}

src/MacLibraryScreenshots.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import "./MacLibraryScreenshots.css";
22
import {useRef, useState} from "react";
3-
import {
4-
screenshotThumbnailUrl,
5-
screenshotUrl,
6-
type LibraryDetailsItem,
7-
type LibraryIndexItem,
8-
} from "./library";
3+
import {type LibraryDetailsItem, type LibraryIndexItem} from "./library";
4+
import {screenshotThumbnailUrl, screenshotUrl} from "./library-urls";
95
import classNames from "classnames";
106
import {type Appearance} from "./controls/Appearance";
117
import {Button} from "./controls/Button";

src/RunDefMac.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export default function RunDefMac({runDef, onDone}: RunDefMacProps) {
3333
includeInfiniteHD={runDef.includeInfiniteHD}
3434
includeSavedHD={runDef.includeSavedHD}
3535
includeLibrary={runDef.includeLibrary}
36+
libraryDownloadURLs={runDef.libraryDownloadURLs}
3637
diskFiles={runDef.diskFiles}
3738
cdroms={cdroms}
3839
initialErrorText={cdromErrorText}

src/library-urls.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {type LibraryItemType} from "./library";
2+
3+
export function proxyUrl(url: string): string {
4+
return `/Library/proxy?url=${encodeURIComponent(url)}`;
5+
}
6+
7+
export function screenshotThumbnailUrl(screenshot: string): string {
8+
return proxyUrl(
9+
`https://macintoshgarden.org/sites/macintoshgarden.org/files/imagecache/thumbnail/screenshots/${screenshot}`
10+
);
11+
}
12+
13+
export function screenshotUrl(screenshot: string): string {
14+
return proxyUrl(
15+
`https://macintoshgarden.org/sites/macintoshgarden.org/files/screenshots/${screenshot}`
16+
);
17+
}
18+
19+
export function downloadUrl(file: string, type: LibraryItemType): string {
20+
return `https://macintoshgarden.org/sites/macintoshgarden.org/files/${type}/${file}`;
21+
}

src/library.ts

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const GAMES_INDEX = unpackIndexItems(libraryIndex.games, "games");
66

77
export type LibraryIndexItem = {
88
id: number;
9-
type: ItemType;
9+
type: LibraryItemType;
1010
title: string;
1111
authors: string[];
1212
year?: number;
@@ -20,7 +20,7 @@ export type LibraryIndexItem = {
2020
index?: string[];
2121
};
2222

23-
type ItemType = "apps" | "games";
23+
export type LibraryItemType = "apps" | "games";
2424

2525
const enum System {
2626
SYSTEM_1 = 1,
@@ -141,7 +141,7 @@ export const PERSPECTIVE_INDEX = [
141141

142142
function unpackIndexItems(
143143
indexItems: any[],
144-
type: ItemType
144+
type: LibraryItemType
145145
): LibraryIndexItem[] {
146146
return indexItems.map((indexItem, i) => {
147147
const [
@@ -239,23 +239,3 @@ async function fetchItemDetails(
239239
}
240240

241241
const itemDetailsCache = new Map<string, LibraryDetailsItem>();
242-
243-
export function proxyUrl(url: string): string {
244-
return `/Library/proxy?url=${encodeURIComponent(url)}`;
245-
}
246-
247-
export function screenshotThumbnailUrl(screenshot: string): string {
248-
return proxyUrl(
249-
`https://macintoshgarden.org/sites/macintoshgarden.org/files/imagecache/thumbnail/screenshots/${screenshot}`
250-
);
251-
}
252-
253-
export function screenshotUrl(screenshot: string): string {
254-
return proxyUrl(
255-
`https://macintoshgarden.org/sites/macintoshgarden.org/files/screenshots/${screenshot}`
256-
);
257-
}
258-
259-
export function downloadUrl(file: string, type: ItemType): string {
260-
return `https://macintoshgarden.org/sites/macintoshgarden.org/files/${type}/${file}`;
261-
}

src/run-def.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export type RunDef = {
2626
includeInfiniteHD: boolean;
2727
includeSavedHD: boolean;
2828
includeLibrary: boolean;
29+
libraryDownloadURLs: string[];
2930
ethernetProvider?: EmulatorEthernetProvider;
3031
// Force non-SharedArrayBuffer mode for debugging
3132
debugFallback?: boolean;
@@ -57,6 +58,7 @@ export function runDefFromUrl(urlString: string): RunDef | undefined {
5758
let includeInfiniteHD;
5859
let includeSavedHD;
5960
const includeLibrary = searchParams.get("library") === "true"; // TODO: default to being on once launched
61+
const libraryDownloadURLs = [...searchParams.getAll("library_url")];
6062
const disks: SystemDiskDef[] = [];
6163
const yearDiskDef = diskFromYearPath(url.pathname);
6264
if (yearDiskDef) {
@@ -148,6 +150,7 @@ export function runDefFromUrl(urlString: string): RunDef | undefined {
148150
includeInfiniteHD,
149151
includeSavedHD,
150152
includeLibrary,
153+
libraryDownloadURLs,
151154
machine,
152155
ramSize,
153156
screenSize,
@@ -194,6 +197,9 @@ export function runDefToUrl(runDef: RunDef): string {
194197
if (runDef.includeLibrary) {
195198
url.searchParams.set("library", "true");
196199
}
200+
for (const libraryURL of runDef.libraryDownloadURLs) {
201+
url.searchParams.append("library_url", libraryURL);
202+
}
197203
for (const cdromURL of runDef.cdromURLs) {
198204
url.searchParams.append("cdrom", cdromURL);
199205
}

0 commit comments

Comments
 (0)