Skip to content

Commit b5e3623

Browse files
authored
Merge pull request #24 from alexankitty/resource-loader
Implements static resource loading and separates out ejs files (nostly)
2 parents 872f962 + 2cc3168 commit b5e3623

File tree

16 files changed

+1182
-1122
lines changed

16 files changed

+1182
-1122
lines changed

views/pages/emulator.ejs

Lines changed: 22 additions & 346 deletions
Original file line numberDiff line numberDiff line change
@@ -51,360 +51,36 @@
5151
</div>
5252
</div>
5353

54-
<style>
55-
/* Only keep basic container styling */
56-
#game-wrapper {
57-
padding-top: 0;
58-
background: #222;
59-
border-radius: 8px;
60-
overflow: hidden;
61-
margin-bottom: 20px;
62-
max-width: 1024px;
63-
margin-left: auto;
64-
margin-right: auto;
65-
}
66-
67-
/* Keep only the aspect ratio for the game container */
68-
#game {
69-
aspect-ratio: 4/3;
70-
max-height: 700px;
71-
}
72-
73-
/* Keep alert styling for consistency */
74-
.alert-secondary {
75-
background-color: #2a2a2a;
76-
border-color: #3a3a3a;
77-
color: #999;
78-
display: inline-block;
79-
margin: 0 auto;
80-
padding: 0.75rem 1.25rem;
81-
}
82-
83-
.alert-secondary a.alert-link {
84-
color: #bbb;
85-
text-decoration: underline;
86-
}
87-
88-
.alert-secondary a.alert-link:hover {
89-
color: #fff;
90-
}
91-
92-
.progress-overlay {
93-
position: absolute;
94-
top: 0;
95-
left: 0;
96-
right: 0;
97-
bottom: 0;
98-
display: none; /* Hidden by default */
99-
justify-content: center;
100-
align-items: center;
101-
background-color: rgba(0, 0, 0, 0.8);
102-
z-index: 1000;
103-
}
104-
105-
.progress {
106-
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
107-
}
108-
109-
#progress-text {
110-
font-size: 14px;
111-
font-weight: bold;
112-
}
113-
114-
.alert-warning {
115-
display: inline-block;
116-
margin: 0 auto;
117-
padding: 0.75rem 1.25rem;
118-
}
119-
120-
/* Security Warning Styles */
121-
.security-alert {
122-
text-align: left;
123-
border: none;
124-
border-radius: 8px;
125-
margin-bottom: 1rem;
126-
padding: 0.75rem 1rem;
127-
box-shadow: 0 2px 10px rgba(220, 53, 69, 0.3);
128-
position: relative;
129-
overflow: hidden;
130-
font-size: 0.9rem;
131-
display: inline-block;
132-
line-height: 1.4;
133-
}
134-
135-
.security-alert::before {
136-
content: '';
137-
position: absolute;
138-
top: 0;
139-
left: 0;
140-
width: 4px;
141-
height: 100%;
142-
background: currentColor;
143-
opacity: 0.7;
144-
}
145-
146-
.security-alert.alert-danger {
147-
background-color: rgba(220, 53, 69, 0.1);
148-
color: #dc3545;
149-
}
150-
151-
.security-alert.alert-warning {
152-
background-color: rgba(255, 193, 7, 0.1);
153-
color: #ffc107;
154-
}
155-
156-
.security-alert i {
157-
vertical-align: middle;
158-
}
159-
160-
.security-alert strong {
161-
vertical-align: middle;
162-
}
163-
164-
.security-alert ul {
165-
margin-top: 0.75rem;
166-
margin-bottom: 0;
167-
padding-left: 2.5rem;
168-
color: #e9ecef;
169-
}
170-
171-
.security-alert ul li {
172-
margin: 0.5rem 0;
173-
line-height: 1.4;
174-
}
175-
176-
.security-alert small {
177-
display: block;
178-
margin-top: 1rem;
179-
padding-top: 1rem;
180-
border-top: 1px solid rgba(255, 255, 255, 0.1);
181-
color: #e9ecef;
182-
}
183-
184-
.security-alert pre {
185-
background: rgba(0, 0, 0, 0.2);
186-
border-radius: 4px;
187-
padding: 0.75rem;
188-
margin: 0.75rem 0 0;
189-
color: #e9ecef;
190-
font-size: 0.9rem;
191-
}
192-
</style>
193-
54+
<link rel="stylesheet" href="/public/css/emulator.css">
19455
<script src="https://code.jquery.com/jquery-3.7.1.min.js" crossorigin="anonymous"></script>
19556
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" crossorigin="anonymous"></script>
19657
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/js/bootstrap.min.js" crossorigin="anonymous"></script>
19758
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js" crossorigin="anonymous"></script>
19859
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script>
19960
<script>
200-
// Check if in a context that supports SharedArrayBuffer
201-
const isHttps = window.location.protocol === 'https:';
202-
const hasSharedArrayBuffer = typeof SharedArrayBuffer !== 'undefined';
203-
const isCrossOriginIsolated = window.crossOriginIsolated === true;
204-
const canUseThreads = hasSharedArrayBuffer && isCrossOriginIsolated;
205-
206-
// Display security warnings
207-
const warningsDiv = document.getElementById('security-warnings');
208-
209-
if (!isHttps) {
210-
warningsDiv.innerHTML += `
211-
<div class="alert security-alert alert-danger py-2">
212-
<i class="fas fa-exclamation-triangle mr-2"></i>
213-
<strong><%= __('emulator.warning.https').split(':')[0] %>:</strong>
214-
<%- __('emulator.warning.https').split(':')[1] %>
215-
</div>
216-
`;
217-
}
218-
219-
// Display important notice immediately
220-
console.log('%cAbout this Page', 'font-size: 20px; font-weight: bold; color: #4CAF50;');
221-
console.log(
222-
'%c<%= __("emulator.console.about") %>\n' +
223-
'<%= __("emulator.console.disclaimer") %>\n' +
224-
'<%= __("emulator.console.more_info") %>',
225-
'font-size: 14px; color: #90CAF9;'
226-
);
227-
console.log(`%c${window.location.origin}/about`, 'font-size: 14px; color: #90CAF9;');
228-
229-
// Configure EmulatorJS
230-
console.log('[Emulator] Starting emulator configuration');
231-
console.log('[Emulator] System:', '<%= emulatorConfig.system %>');
232-
console.log('[Emulator] Core:', '<%= emulatorConfig.core %>');
233-
234-
console.log('[Emulator] SharedArrayBuffer available:', hasSharedArrayBuffer);
235-
console.log('[Emulator] Cross-Origin-Isolation status:', isCrossOriginIsolated);
236-
console.log('[Emulator] Can use threads:', canUseThreads);
237-
238-
window.EJS_player = '#game';
239-
240-
window.EJS_core = '<%= emulatorConfig.core %>';
241-
window.EJS_gameUrl = '/proxy-rom/<%= romFile.id %>';
242-
window.EJS_pathtodata = '/emulatorjs/data/';
243-
window.EJS_startOnLoaded = true;
244-
window.EJS_gameID = 1
245-
246-
// Using threads improves performance by a lot
247-
// But also creates freezes, crashes and some emulators need to be reconfigured to work
248-
// This should be revisited in the future.
249-
// We're using threads only on PSP for now
250-
window.EJS_threads = '<%= emulatorConfig.system %>' === 'Sony PlayStation Portable' ? (navigator.hardwareConcurrency || 4) : false;
251-
window.EJS_gameName = '<%= romFile.filename.replace(/\.[^/.]+$/, "") %>';
252-
window.EJS_backgroundBlur = true;
253-
window.EJS_defaultOptions = {
254-
'save-state-slot': 1,
255-
'save-state-location': 'local'
256-
};
257-
258-
// BIOS configuration
259-
window.EJS_biosUrl = <% if (emulatorConfig.bios) { %>
260-
'/proxy-bios?url=' + encodeURIComponent(<%- JSON.stringify(Object.values(emulatorConfig.bios.files)[0].url) %>)
261-
<% } else { %>
262-
undefined
263-
<% } %>;
264-
265-
console.log('[Emulator] BIOS configuration:', window.EJS_biosUrl);
266-
267-
// Required for Sega CD ??
268-
window.EJS_loadStateURL = window.location.href;
269-
window.EJS_saveStateURL = window.location.href;
270-
window.EJS_cheats = true;
271-
272-
// Add error event listener for the emulator
273-
window.EJS_onGameStart = () => {
274-
console.log('[Emulator] Game started successfully');
275-
};
276-
277-
window.EJS_onLoadState = (state) => {
278-
console.log('[Emulator] Load state:', state);
279-
};
280-
281-
window.EJS_onSaveState = (state) => {
282-
console.log('[Emulator] Save state:', state);
283-
};
284-
285-
window.EJS_onLoadError = (error) => {
286-
console.error('[Emulator] Load error:', error);
287-
};
288-
289-
async function loadRom() {
290-
try {
291-
console.log('[Emulator] Starting ROM load process');
292-
const progressContainer = document.getElementById('progress-container');
293-
const progressBar = document.getElementById('download-progress');
294-
const progressText = document.getElementById('progress-text');
295-
progressContainer.style.display = 'flex';
296-
297-
const isCompressed = /\.(zip|7z)$/i.test('<%= romFile.filename %>');
298-
const shouldUnpack = <%= emulatorConfig.unpackRoms %>;
299-
console.log(`[Emulator] ROM compression status: ${isCompressed ? 'compressed' : 'uncompressed'}`);
300-
console.log(`[Emulator] Should unpack: ${shouldUnpack}`);
301-
302-
progressText.textContent = '<%= __("emulator.loading.downloading") %> (0%)';
303-
console.log('[Emulator] Initiating ROM download');
304-
305-
const response = await fetch(EJS_gameUrl);
306-
if (!response.ok) {
307-
throw new Error('<%= __("emulator.error.http_error", { status: "response.status" }) %>'.replace('response.status', response.status));
308-
}
309-
310-
// If we're not unpacking, still show download progress but return direct URL
311-
if (!isCompressed || !shouldUnpack) {
312-
const contentLength = response.headers.get('content-length');
313-
const total = parseInt(contentLength, 10);
314-
let loaded = 0;
315-
316-
const reader = response.body.getReader();
317-
const chunks = [];
318-
319-
while (true) {
320-
const { done, value } = await reader.read();
321-
if (done) break;
322-
323-
chunks.push(value);
324-
loaded += value.length;
325-
326-
const percent = Math.round((loaded / total) * 100);
327-
progressBar.style.width = percent + '%';
328-
progressText.textContent = `<%= __("emulator.loading.downloading") %> (${percent}%)`;
329-
}
330-
331-
console.log('[Emulator] Using direct URL for ROM');
332-
progressContainer.style.display = 'none';
333-
334-
// Create blob from chunks for direct loading
335-
const blob = new Blob(chunks);
336-
return URL.createObjectURL(blob);
337-
}
338-
339-
// For compressed files that need unpacking, continue with decompression
340-
const contentLength = response.headers.get('content-length');
341-
const total = parseInt(contentLength, 10);
342-
let loaded = 0;
343-
344-
const reader = response.body.getReader();
345-
const chunks = [];
346-
347-
while (true) {
348-
const { done, value } = await reader.read();
349-
if (done) break;
350-
351-
chunks.push(value);
352-
loaded += value.length;
353-
354-
const percent = Math.round((loaded / total) * 100);
355-
progressBar.style.width = percent + '%';
356-
progressText.textContent = `<%= __("emulator.loading.downloading") %> (${percent}%)`;
357-
}
358-
359-
// Decompression phase
360-
progressText.textContent = '<%= __("emulator.loading.decompressing") %>';
361-
console.log('[Emulator] Starting ZIP extraction');
362-
363-
const blob = new Blob(chunks);
364-
const zip = await JSZip.loadAsync(blob);
365-
const files = Object.keys(zip.files);
366-
console.log('[Emulator] ZIP contents:', files);
367-
368-
const romFile = files.find(f => !zip.files[f].dir);
369-
if (!romFile) {
370-
throw new Error('<%= __("emulator.error.no_rom") %>');
371-
}
372-
console.log('[Emulator] Found ROM file in ZIP:', romFile);
373-
374-
const romData = await zip.files[romFile].async('blob');
375-
console.log('[Emulator] ROM extraction complete');
376-
progressContainer.style.display = 'none';
377-
return URL.createObjectURL(romData);
378-
} catch (error) {
379-
console.error('[Emulator] Error in loadRom:', error);
380-
throw error;
61+
const emulatorConfig = <%- JSON.stringify(emulatorConfig) %>
62+
const romFile = <%- JSON.stringify(romFile) %>
63+
64+
const emuStrings = {
65+
console: {
66+
about: "<%= __("emulator.console.about") %>",
67+
disclaimer: "<%= __("emulator.console.disclaimer") %>",
68+
more_info: "<%= __("emulator.console.more_info") %>"
69+
},
70+
warning: {
71+
https: "<%= __("emulator.warning.https") %>"
72+
},
73+
loading: {
74+
downloading: "<%= __("emulator.loading.downloading") %>",
75+
decompressing: "<%= __("emulator.loading.decompressing") %>"
76+
},
77+
error: {
78+
http_error: "<%= __("emulator.error.http_error") %>",
79+
no_rom: "<%= __("emulator.error.no_rom") %>",
80+
loading: "<%= __("emulator.error.loading") %>"
38181
}
38282
}
383-
384-
loadRom()
385-
.then(romUrl => {
386-
console.log('[Emulator] ROM loaded successfully, initializing EmulatorJS');
387-
window.EJS_gameUrl = romUrl;
388-
389-
// We need to wait a moment to ensure cross-origin isolation is properly applied
390-
setTimeout(() => {
391-
const script = document.createElement('script');
392-
script.src = `${window.EJS_pathtodata}loader.js`;
393-
script.onerror = (error) => {
394-
const gameDiv = document.getElementById('game');
395-
gameDiv.innerHTML = `<div class="alert alert-danger">
396-
Failed to load EmulatorJS. Please refresh the page or try again later.
397-
</div>`;
398-
};
399-
document.body.appendChild(script);
400-
}, 500);
401-
})
402-
.catch(error => {
403-
const gameDiv = document.getElementById('game');
404-
gameDiv.innerHTML = `<div class="alert alert-danger">
405-
<%= __("emulator.error.loading") %>: ${error.message}
406-
</div>`;
407-
});
40883
</script>
84+
<script src="/public/js/emulator.js" defer></script>
40985
</body>
41086
</html>

0 commit comments

Comments
 (0)