Added Download file, play for homebrews and ZIP explorer.

This commit is contained in:
2026-06-16 18:35:01 +02:00
parent 7e1e26f20b
commit 279160c1cb
12 changed files with 215 additions and 24 deletions

View File

@@ -0,0 +1,43 @@
window.PlayOnline = function( filePath = "", emulatorJsConfig = {} ){
return {
fileUrl: filePath,
emuConfig: emulatorJsConfig,
init(){
this.launchEmulatorJs();
},
cleanEmulatorJsVars() {
['EJS_player','EJS_core','EJS_gameUrl','EJS_pathtodata',
'EJS_startOnLoaded','EJS_threads']
.forEach(k => delete window[k]);
},
prepareEmulatorJs(){
window.EJS_player = '#game';
window.EJS_core = this.emuConfig.core;
window.EJS_gameUrl = this.filePath;
window.EJS_pathtodata = "https://cdn.emulatorjs.org/stable/data/";
window.EJS_startOnLoaded = true;
window.EJS_threads = this.emuConfig.threads ?? false;
},
launchEmulatorJs(){
this.cleanEmulatorJsVars();
this.prepareEmulatorJs();
const script = document.createElement('script');
script.id = 'ejs-loader';
script.src = 'https://cdn.emulatorjs.org/stable/data/loader.js';
document.body.appendChild(script);
this.launchGame = true;
}
}
}

View File

@@ -1,6 +1,6 @@
/** @typedef { import('types/UploadchunkResponse.js').UploadchunkResponse} UploadchunkResponse */
export const CHUNK_SIZE = 8192;
export const CHUNK_SIZE = 8192 * 1024;
const PATCH_EXTENSIONS = new Set([
'ips', 'bps', 'ups', 'aps', 'ppf', 'xdelta', "zip"
@@ -72,6 +72,15 @@ export function FSFileData(name, totalChunks, rawFile ) {
*/
state: 'public',
file_explorer: null,
file_explorer_files: null,
/**
* For files already uploaded, download URL.
*/
download_url: null,
can_be_online_patched: PATCH_EXTENSIONS.has(extension),
/**

View File

@@ -105,6 +105,29 @@ export function FSUploader(){
},
handleDownloadFile( index ){
let download_url = this.files[index].download_url;
window.location.href = download_url;
},
async handleFileExplorer( index ){
if( this.files[index].file_explorer_files !== null )
return;
let file_explorer_url = this.files[index].file_explorer;
let response = await fetch(file_explorer_url, { method: 'GET', headers: { 'Content-Type': 'application/json' } });
let json = await response.json();
if( !json.files ){
this.files[index].file_explorer_files = [ "An error occurred during request" ];
return;
}
this.files[index].file_explorer_files = json.files;
},
/**
* Retry file uploading.
*
@@ -126,6 +149,8 @@ export function FSUploader(){
* @param {number} index FSFileData index in this.files.
*/
handleRemoveFile( index ){
if( this.files[index].state === 'archived')
return;
this.files.splice(index, 1);
},

View File

@@ -17,10 +17,13 @@
<div class="modal-body">
<div class="file-list">
@forelse( $files as $file )
@if( $file->state === 'private' )
@continue
@endif
<div class="file-item">
<div class="file-info">
<span class="file-name">{{ $file->filename }}</span>
<span class="file-meta">{{ $file->filesize }} - {{ $file->download_count }} downloads</span>
<span class="file-name">@if($file->state === 'archived')<i data-lucide="archive"></i> @endif{{ $file->filename }}</span>
<span class="file-meta">{{ $file->prettyFileSize() }} - {{ $file->download_count }} downloads</span>
</div>
<div style="display:flex;flex-direction:column;gap:15px;">
<a href="{{ route('fs.download', ['entry_id' => $entryId, 'file' => $file->file_uuid] ) }}" class="btn primary"><i data-lucide="download"></i> Download</a>

View File

@@ -100,7 +100,41 @@
</div>
</div>
@endif
<div class="upload-item-actions" x-data="{ showMetadata: false }">
<div class="upload-item-actions" x-data="{ showMetadata: false, showFileExplorer: false }">
<button type="button" class="btn" x-show="file.download_url" @click="handleDownloadFile(i)">
<i data-lucide="download"></i>
</button>
<button type="button" class="btn" x-show="file.file_explorer" @click="handleFileExplorer(i); showFileExplorer = true;">
<i data-lucide="package-open"></i>
</button>
<template x-if="file.file_explorer" x-teleport="body">
<div class="modal-overlay"
x-cloak
x-show="showFileExplorer"
x-transition.opacity.duration.300ms
@click.self="showFileExplorer = false"
@keydown.escape.window="showFileExplorer = false">
<div class="modal-window" x-show="showFileExplorer" x-transition>
<div class="modal-header">
<span class="modal-title" style="display: flex; align-items: center; gap: 8px;">
File explorer: <span x-text="file.name" style="color: var(--rhpz-orange);"></span>
</span>
<button type="button" class="modal-close" @click="showFileExplorer = false">
<i data-lucide="x" size="20"></i>
</button>
</div>
<div class="modal-content">
<ul>
<template x-for="(f,j) in file.file_explorer_files" :key="j">
<li><span x-text="f"></span></li>
</template>
</ul>
</div>
</div>
</div>
</template>
<button type="button" class="btn" x-show="file.error" @click="handleRetryFile(i)">
<i data-lucide="refresh-cw"></i>
</button>
@@ -109,7 +143,7 @@
<i data-lucide="settings"></i>
</button>
@endif
<button type="button" class="btn" x-show="file.done || file.error" @click="handleRemoveFile(i)">
<button type="button" class="btn" x-show="(file.done || file.error) && file.state !== 'archived'" @click="handleRemoveFile(i)">
<i data-lucide="x"></i>
</button>
<template x-teleport="body">

View File

@@ -0,0 +1,17 @@
@extends('layouts.app')
@section('page-title', "Play Online - " . config('app.name'))
@push('scripts')
@vite('resources/js/PlayOnline.js')
@endpush
@section('content')
<div class="page-title">
<span>Play Online</span>
</div>
<div id="rom-patcher-container" class="patcher-container" x-data="PlayOnline({{ Js::from($filePath) }}, {{ JS::from($emuConfig ?? [])}})">
<div id="game"></div>
</div>
@endsection