Skip to content

Instantly share code, notes, and snippets.

@Nyaasu66
Created March 11, 2026 08:50
Show Gist options
  • Select an option

  • Save Nyaasu66/7d2c9757e5c8632416b03b3fb1720a41 to your computer and use it in GitHub Desktop.

Select an option

Save Nyaasu66/7d2c9757e5c8632416b03b3fb1720a41 to your computer and use it in GitHub Desktop.
Flash Player
<!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