Created
March 11, 2026 08:50
-
-
Save Nyaasu66/7d2c9757e5c8632416b03b3fb1720a41 to your computer and use it in GitHub Desktop.
Flash Player
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>SWF Flash Player</title> | |
| <style> | |
| :root { | |
| --bg: #f5f5f7; | |
| --surface: #fff; | |
| --text: #1d1d1f; | |
| --muted: #6e6e73; | |
| --accent: #0071e3; | |
| --border: #d2d2d7; | |
| --radius: 10px; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| background: var(--bg); | |
| color: var(--text); | |
| font: 14px / 1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | |
| padding: 32px 24px; | |
| } | |
| .page-header { | |
| text-align: center; | |
| font-size: 22px; | |
| font-weight: 700; | |
| letter-spacing: -0.3px; | |
| margin-bottom: 20px; | |
| } | |
| .controls { | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| padding: 20px 24px; | |
| max-width: 820px; | |
| margin: 0 auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| } | |
| .hint-text { | |
| color: var(--muted); | |
| font-size: 13px; | |
| text-align: center; | |
| } | |
| .file-picker input[type="file"] { | |
| display: block; | |
| width: 100%; | |
| padding: 10px 12px; | |
| border: 2px dashed var(--border); | |
| border-radius: var(--radius); | |
| background: var(--bg); | |
| cursor: pointer; | |
| font-size: 13px; | |
| color: var(--muted); | |
| transition: border-color 0.2s; | |
| } | |
| .file-picker input[type="file"]:hover { | |
| border-color: var(--accent); | |
| } | |
| /* ── Size controls ── */ | |
| .size-controls { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| } | |
| .size-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .size-group label { | |
| color: var(--muted); | |
| font-size: 13px; | |
| } | |
| .size-slider { | |
| width: 120px; | |
| accent-color: var(--accent); | |
| cursor: pointer; | |
| } | |
| .size-number { | |
| width: 64px; | |
| padding: 4px 8px; | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| font-size: 13px; | |
| color: var(--text); | |
| background: var(--bg); | |
| } | |
| .size-number:focus { | |
| outline: 2px solid var(--accent); | |
| border-color: transparent; | |
| } | |
| .btn-group { | |
| display: flex; | |
| gap: 6px; | |
| margin-left: 4px; | |
| } | |
| button { | |
| padding: 5px 14px; | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| background: var(--surface); | |
| color: var(--text); | |
| font-size: 13px; | |
| cursor: pointer; | |
| transition: background 0.15s, border-color 0.15s, color 0.15s; | |
| } | |
| button:disabled { | |
| opacity: 0.38; | |
| cursor: default; | |
| } | |
| button:not(:disabled):hover { | |
| border-color: var(--accent); | |
| color: var(--accent); | |
| } | |
| #btn_save:not(:disabled) { | |
| background: var(--accent); | |
| color: #fff; | |
| border-color: var(--accent); | |
| } | |
| #btn_save:not(:disabled):hover { | |
| background: #005bbf; | |
| border-color: #005bbf; | |
| color: #fff; | |
| } | |
| /* ── Flash embed area ── */ | |
| #codearea { | |
| text-align: center; | |
| } | |
| .flash-warning { | |
| color: #f0a500; | |
| font-size: 13px; | |
| margin-bottom: 8px; | |
| } | |
| /* ── Toast ── */ | |
| .toast { | |
| position: fixed; | |
| bottom: 24px; | |
| right: 24px; | |
| background: #1d1d1f; | |
| color: #f5f5f7; | |
| padding: 9px 18px; | |
| border-radius: 8px; | |
| font-size: 13px; | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, .18); | |
| display: none; | |
| z-index: 10001; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1 class="page-header">SWF Flash Player</h1> | |
| <div class="controls"> | |
| <p class="hint-text">Select a local SWF file or drag and drop it onto this page to play.</p> | |
| <p class="hint-text">Since modern browsers no longer support Flash Player, it is recommended to install the browser | |
| extension <a href="https://ruffle.rs/" target="_blank" rel="noopener noreferrer" | |
| style="color:var(--accent)">Ruffle Emulator</a>.<br>Please refresh the page after installation to properly | |
| display SWF files.</p> | |
| <div class="file-picker"> | |
| <input type="file" id="fileload1" name="files[]"> | |
| </div> | |
| <div class="size-controls"> | |
| <div class="size-group"> | |
| <label for="size_width">Width</label> | |
| <input type="range" id="size_width" class="size-slider" min="100" max="1000" step="1" value="600"> | |
| <input type="number" id="size_width_n" class="size-number" min="100" max="1000" value="600"> | |
| </div> | |
| <div class="size-group"> | |
| <label for="size_height">Height</label> | |
| <input type="range" id="size_height" class="size-slider" min="100" max="900" step="1" value="400"> | |
| <input type="number" id="size_height_n" class="size-number" min="100" max="900" value="400"> | |
| </div> | |
| <div class="btn-group"> | |
| <button id="btn_save" disabled title="Save and keep this size">Save Size</button> | |
| <button id="btn_refresh" disabled>Refresh</button> | |
| <button id="btn_close" disabled>Close</button> | |
| </div> | |
| </div> | |
| <div id="codearea"></div> | |
| </div> | |
| <div id="layer_message" class="toast"></div> | |
| <script> | |
| 'use strict'; | |
| // ── Constants ──────────────────────────────────────────────────────────── | |
| const MAX_FILE_SIZE_MB = 60; | |
| const MAX_HISTORY_SIZE = 5; | |
| const MAX_SAVED_SIZES = 30; | |
| const TOAST_DURATION_MS = 2000; | |
| const STORAGE_KEY = 'drive_data'; | |
| const SIZE_LIMITS = { | |
| width: { min: 100, max: 1000 }, | |
| height: { min: 100, max: 900 }, | |
| }; | |
| // ── State ──────────────────────────────────────────────────────────────── | |
| window.URL = window.URL || window.webkitURL; | |
| let isFlashAvailable = null; | |
| let currentEntry = null; // { url, resp } — last loaded file | |
| let recentHistory = []; // up to MAX_HISTORY_SIZE entries | |
| let pendingFiles = null; | |
| let toastTimer = null; | |
| // ── DOM helpers ────────────────────────────────────────────────────────── | |
| function $(id) { return document.getElementById(id); } | |
| // ── LocalStorage helpers ───────────────────────────────────────────────── | |
| function saveToStorage(key, value) { | |
| if (window.localStorage) localStorage[key] = String(value); | |
| } | |
| function loadFromStorage(key) { | |
| return window.localStorage ? localStorage[key] : undefined; | |
| } | |
| // ── Toast notification ─────────────────────────────────────────────────── | |
| function showToast(message, duration = TOAST_DURATION_MS) { | |
| const el = $('layer_message'); | |
| el.innerHTML = `<label>${message}</label>`; | |
| el.style.display = ''; | |
| if (toastTimer) clearTimeout(toastTimer); | |
| toastTimer = setTimeout(() => { el.style.display = 'none'; }, duration); | |
| } | |
| // ── Size controls ──────────────────────────────────────────────────────── | |
| function clamp(value, min, max) { | |
| return Math.min(Math.max(Number(value), min), max); | |
| } | |
| /** Read slider values, clamp them, and sync the number inputs. */ | |
| function onSliderChange() { | |
| const w = clamp($('size_width').value, SIZE_LIMITS.width.min, SIZE_LIMITS.width.max); | |
| const h = clamp($('size_height').value, SIZE_LIMITS.height.min, SIZE_LIMITS.height.max); | |
| $('size_width_n').value = w; | |
| $('size_height_n').value = h; | |
| applyEmbedSize(w, h); | |
| } | |
| /** Read number inputs, clamp them, sync sliders, then resize the embed. */ | |
| function onNumberInputChange() { | |
| const w = clamp($('size_width_n').value, SIZE_LIMITS.width.min, SIZE_LIMITS.width.max); | |
| const h = clamp($('size_height_n').value, SIZE_LIMITS.height.min, SIZE_LIMITS.height.max); | |
| $('size_width').value = w; | |
| $('size_height').value = h; | |
| applyEmbedSize(w, h); | |
| } | |
| /** Resize any EMBED / OBJECT elements inside the code area. */ | |
| function applyEmbedSize(width, height) { | |
| const elements = $('codearea').getElementsByTagName('*'); | |
| for (const el of elements) { | |
| const tag = el.tagName; | |
| if (tag === 'EMBED' || tag === 'OBJECT') { | |
| el.width = width; | |
| el.height = height; | |
| } | |
| } | |
| } | |
| // ── Saved-size persistence ─────────────────────────────────────────────── | |
| function getSavedSizes() { | |
| const raw = loadFromStorage(STORAGE_KEY) || '[]'; | |
| try { return JSON.parse(raw) || []; } catch { return []; } | |
| } | |
| function persistSavedSizes(sizes) { | |
| if (window.JSON) saveToStorage(STORAGE_KEY, JSON.stringify(sizes)); | |
| } | |
| // ── Flash detection ────────────────────────────────────────────────────── | |
| function detectFlash() { | |
| if (isFlashAvailable !== null) return; | |
| isFlashAvailable = false; | |
| try { | |
| if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) isFlashAvailable = true; | |
| } catch { | |
| const mimeTypes = navigator.mimeTypes; | |
| const swfMime = mimeTypes && mimeTypes['application/x-shockwave-flash']; | |
| if (swfMime && swfMime.enabledPlugin) isFlashAvailable = true; | |
| } | |
| } | |
| // ── Flash embed ────────────────────────────────────────────────────────── | |
| /** | |
| * Load (or reload) a SWF into the embed area. | |
| * @param {string} url - Object URL pointing to the SWF blob. | |
| * @param {{ id: string, title: string }} meta - File metadata. | |
| * @param {boolean} isReload - True when called by Refresh (skip history update). | |
| */ | |
| function loadSwf(url, meta, isReload = false) { | |
| currentEntry = { url, resp: meta }; | |
| if (!isReload) { | |
| updateHistory(url, meta); | |
| } | |
| const { width, height } = resolveDisplaySize(meta.id); | |
| renderEmbed(url, width, height, meta.id); | |
| setPlayerButtonsEnabled(true); | |
| } | |
| /** Maintain a bounded history list, revoking oldest blob URLs. */ | |
| function updateHistory(url, meta) { | |
| // Remove any existing entry for this file id. | |
| const existing = recentHistory.findIndex(e => e.resp.id === meta.id); | |
| if (existing !== -1) { | |
| if (recentHistory[existing].url) window.URL.revokeObjectURL(recentHistory[existing].url); | |
| recentHistory.splice(existing, 1); | |
| } | |
| recentHistory.push({ id: Date.now(), url, resp: meta }); | |
| if (recentHistory.length > MAX_HISTORY_SIZE) { | |
| const oldest = recentHistory.shift(); | |
| if (oldest.url) window.URL.revokeObjectURL(oldest.url); | |
| } | |
| } | |
| /** | |
| * Look up a previously saved width/height for a file id. | |
| * Falls back to the current slider values. | |
| */ | |
| function resolveDisplaySize(fileId) { | |
| const saved = getSavedSizes().find(entry => entry.id === fileId); | |
| if (saved) { | |
| $('size_width').value = saved.width; | |
| $('size_height').value = saved.height; | |
| $('size_width_n').value = saved.width; | |
| $('size_height_n').value = saved.height; | |
| return { width: saved.width, height: saved.height }; | |
| } | |
| $('btn_save').style.color = ''; | |
| return { | |
| width: $('size_width').value, | |
| height: $('size_height').value, | |
| }; | |
| } | |
| /** Build and inject the <embed> HTML into the code area. */ | |
| function renderEmbed(url, width, height, fileId) { | |
| const codearea = $('codearea'); | |
| const warning = isFlashAvailable | |
| ? '' | |
| : '<div class="flash-warning">Adobe Flash Player is required. Please check it is installed.</div>'; | |
| codearea.innerHTML = | |
| warning + | |
| `<embed width="${width}" height="${height}" src="${url}" | |
| quality="high" | |
| type="application/x-shockwave-flash" | |
| allowfullscreen="true" | |
| allowScriptAccess="never">`; | |
| codearea.dataset.fileId = fileId; | |
| } | |
| // ── Button handlers ────────────────────────────────────────────────────── | |
| function setPlayerButtonsEnabled(enabled) { | |
| $('btn_save').disabled = !enabled; | |
| $('btn_refresh').disabled = !enabled; | |
| $('btn_close').disabled = !enabled; | |
| } | |
| function handleClose() { | |
| $('codearea').innerHTML = ''; | |
| setPlayerButtonsEnabled(false); | |
| } | |
| function handleRefresh() { | |
| if (currentEntry) loadSwf(currentEntry.url, currentEntry.resp, true); | |
| } | |
| function handleSaveSize() { | |
| const fileId = $('codearea').dataset.fileId; | |
| if (!fileId) return; | |
| const sizes = getSavedSizes(); | |
| if (sizes.length >= MAX_SAVED_SIZES) sizes.splice(0, 1); | |
| const existingIdx = sizes.findIndex(e => e.id === fileId); | |
| if (existingIdx !== -1) sizes.splice(existingIdx, 1); | |
| sizes.push({ | |
| id: fileId, | |
| width: $('size_width').value, | |
| height: $('size_height').value, | |
| }); | |
| persistSavedSizes(sizes); | |
| showToast('Saved.'); | |
| $('btn_save').style.color = 'green'; | |
| } | |
| // ── File loading ───────────────────────────────────────────────────────── | |
| function handleFileSelect(files) { | |
| if (!window.FileReader) { alert('This browser does not support FileReader.'); return; } | |
| if (files) pendingFiles = files; | |
| if (!pendingFiles || pendingFiles.length === 0) return; | |
| const file = pendingFiles[0]; | |
| const maxBytes = MAX_FILE_SIZE_MB * 1024 * 1024; | |
| if (file.size > maxBytes) { | |
| alert(`File is too large. Limit: ~${MAX_FILE_SIZE_MB} MB`); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| const blob = new Blob([e.target.result]); | |
| const blobUrl = window.URL.createObjectURL(blob); | |
| const label = `(Local) ${file.name}`; | |
| loadSwf(blobUrl, { id: label, title: label }); | |
| }; | |
| reader.onerror = () => alert(`Read Error: ${file.name}`); | |
| reader.readAsArrayBuffer(file); | |
| } | |
| // ── Initialisation ─────────────────────────────────────────────────────── | |
| function init() { | |
| // Restrict file picker to .swf on Windows (where accept works reliably). | |
| const isWindows = navigator.userAgent.toLowerCase().includes('windows'); | |
| if (isWindows) $('fileload1').setAttribute('accept', '.swf'); | |
| $('fileload1').addEventListener('change', (e) => { | |
| if (!e || !e.target) { alert('This browser does not support.'); return; } | |
| handleFileSelect(e.target.files); | |
| }); | |
| $('size_width').addEventListener('change', onSliderChange); | |
| $('size_height').addEventListener('change', onSliderChange); | |
| $('size_width_n').addEventListener('change', onNumberInputChange); | |
| $('size_height_n').addEventListener('change', onNumberInputChange); | |
| $('btn_save').addEventListener('click', handleSaveSize); | |
| $('btn_refresh').addEventListener('click', handleRefresh); | |
| $('btn_close').addEventListener('click', handleClose); | |
| document.addEventListener('dragover', (e) => e.preventDefault()); | |
| document.addEventListener('dragend', (e) => e.preventDefault()); | |
| document.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| handleFileSelect(e.dataTransfer.files); | |
| }); | |
| window.addEventListener('beforeunload', () => { | |
| recentHistory.forEach(entry => { | |
| if (entry.url) window.URL.revokeObjectURL(entry.url); | |
| }); | |
| }); | |
| detectFlash(); | |
| } | |
| init(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment