mirror of
https://activitypub.software/TransFem-org/Sharkey.git
synced 2024-12-27 12:10:17 +01:00
Merge branch 'develop' into feature/2024.10
This commit is contained in:
commit
9937ff39be
32 changed files with 1958 additions and 274 deletions
38
locales/index.d.ts
vendored
38
locales/index.d.ts
vendored
|
@ -11134,6 +11134,44 @@ export interface Locale extends ILocale {
|
|||
* Show warning when opening external URLs
|
||||
*/
|
||||
"warnExternalUrl": string;
|
||||
/**
|
||||
* Flash
|
||||
*/
|
||||
"flash": string;
|
||||
"_flash": {
|
||||
/**
|
||||
* Flash Content Hidden
|
||||
*/
|
||||
"contentHidden": string;
|
||||
/**
|
||||
* Powered by Ruffle.
|
||||
*/
|
||||
"poweredByRuffle": string;
|
||||
/**
|
||||
* Always be wary of arbitrary code execution!
|
||||
*/
|
||||
"arbitraryCodeExecutionWarning": string;
|
||||
/**
|
||||
* Flash Content Failed To Load:
|
||||
*/
|
||||
"failedToLoad": string;
|
||||
/**
|
||||
* Flash Content Is Loading
|
||||
*/
|
||||
"isLoading": string;
|
||||
/**
|
||||
* Loading Ruffle player
|
||||
*/
|
||||
"loadingRufflePlayer": string;
|
||||
/**
|
||||
* Loading Flash file
|
||||
*/
|
||||
"loadingFlashFile": string;
|
||||
/**
|
||||
* raw.esm.sh could not be accessed, meaning this instance's Content Security Policy is likely out of date. Please contact your instance administrators.
|
||||
*/
|
||||
"cspError": string;
|
||||
};
|
||||
"_mfm": {
|
||||
/**
|
||||
* This is not a widespread feature, it may not display properly on most other fedi software, including other Misskey forks
|
||||
|
|
|
@ -886,7 +886,7 @@ export class ClientServerService {
|
|||
});
|
||||
|
||||
if (note == null) return;
|
||||
if (note.visibility !== 'public') return;
|
||||
if (['specified', 'followers'].includes(note.visibility)) return;
|
||||
if (note.userHost != null) return;
|
||||
|
||||
const _note = await this.noteEntityService.pack(note, null, { detail: true });
|
||||
|
|
1
packages/frontend-embed/@types/global.d.ts
vendored
1
packages/frontend-embed/@types/global.d.ts
vendored
|
@ -14,6 +14,7 @@ declare const _PERF_PREFIX_: string;
|
|||
declare const _DATA_TRANSFER_DRIVE_FILE_: string;
|
||||
declare const _DATA_TRANSFER_DRIVE_FOLDER_: string;
|
||||
declare const _DATA_TRANSFER_DECK_COLUMN_: string;
|
||||
declare const _RUFFLE_VERSION_: string;
|
||||
|
||||
// for dev-mode
|
||||
declare const _LANGS_FULL_: string[][];
|
||||
|
|
|
@ -30,6 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
rotate: getDecorationAngle(decoration),
|
||||
scale: getDecorationScale(decoration),
|
||||
translate: getDecorationOffset(decoration),
|
||||
zIndex: getDecorationZIndex(decoration),
|
||||
}"
|
||||
alt=""
|
||||
>
|
||||
|
@ -86,6 +87,10 @@ function getDecorationOffset(decoration: Omit<Misskey.entities.UserDetailed['ava
|
|||
const offsetY = decoration.offsetY ?? 0;
|
||||
return offsetX === 0 && offsetY === 0 ? undefined : `${offsetX * 100}% ${offsetY * 100}%`;
|
||||
}
|
||||
|
||||
function getDecorationZIndex(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
||||
return decoration.showBelow ? '-1' : undefined;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<a :href="href" target="_blank" :class="$style.root">
|
||||
<div :class="$style.label">
|
||||
<template v-if="media.type.startsWith('audio')"><i class="ti ti-music"></i> {{ i18n.ts.audio }}</template>
|
||||
<template v-else-if="media.type.startsWith('application') && media.type.includes('flash')"><i class="ti ti-bolt"></i> {{ i18n.ts.flash }}</template>
|
||||
<template v-else><i class="ti ti-file"></i> {{ i18n.ts.file }}</template>
|
||||
</div>
|
||||
<div :class="$style.go">
|
||||
|
|
1
packages/frontend-shared/@types/global.d.ts
vendored
1
packages/frontend-shared/@types/global.d.ts
vendored
|
@ -15,6 +15,7 @@ declare const _PERF_PREFIX_: string;
|
|||
declare const _DATA_TRANSFER_DRIVE_FILE_: string;
|
||||
declare const _DATA_TRANSFER_DRIVE_FOLDER_: string;
|
||||
declare const _DATA_TRANSFER_DECK_COLUMN_: string;
|
||||
declare const _RUFFLE_VERSION_: string;
|
||||
|
||||
// for dev-mode
|
||||
declare const _LANGS_FULL_: string[][];
|
||||
|
|
|
@ -99,6 +99,15 @@ export const FILE_EXT_TRACKER_MODULES = [
|
|||
'mmcmp',
|
||||
];
|
||||
|
||||
export const FILE_TYPE_FLASH_CONTENT = [
|
||||
'application/x-shockwave-flash',
|
||||
'application/vnd.adobe.flash.movie',
|
||||
];
|
||||
|
||||
export const FILE_EXT_FLASH_CONTENT = [
|
||||
'swf',
|
||||
];
|
||||
|
||||
/*
|
||||
https://github.com/sindresorhus/file-type/blob/main/supported.js
|
||||
https://github.com/sindresorhus/file-type/blob/main/core.js
|
||||
|
|
1
packages/frontend/@types/global.d.ts
vendored
1
packages/frontend/@types/global.d.ts
vendored
|
@ -14,6 +14,7 @@ declare const _PERF_PREFIX_: string;
|
|||
declare const _DATA_TRANSFER_DRIVE_FILE_: string;
|
||||
declare const _DATA_TRANSFER_DRIVE_FOLDER_: string;
|
||||
declare const _DATA_TRANSFER_DECK_COLUMN_: string;
|
||||
declare const _RUFFLE_VERSION_: string;
|
||||
|
||||
// for dev-mode
|
||||
declare const _LANGS_FULL_: string[][];
|
||||
|
|
|
@ -36,6 +36,7 @@ export default [
|
|||
_DATA_TRANSFER_DRIVE_FILE_: false,
|
||||
_DATA_TRANSFER_DRIVE_FOLDER_: false,
|
||||
_DATA_TRANSFER_DECK_COLUMN_: false,
|
||||
_RUFFLE_VERSION_: false,
|
||||
},
|
||||
parser,
|
||||
parserOptions: {
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "5.0.7",
|
||||
"@rollup/pluginutils": "5.1.3",
|
||||
"@transfem-org/sfm-js": "0.24.5",
|
||||
"@ruffle-rs/ruffle": "0.1.0-nightly.2024.10.15",
|
||||
"@syuilo/aiscript": "0.19.0",
|
||||
"@transfem-org/sfm-js": "0.24.5",
|
||||
"@twemoji/parser": "15.1.1",
|
||||
"@vitejs/plugin-vue": "5.2.0",
|
||||
"@vue/compiler-sfc": "3.5.12",
|
||||
|
|
|
@ -21,7 +21,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template v-for="media in mediaList.filter(media => previewable(media))">
|
||||
<XVideo v-if="media.type.startsWith('video')" :key="`video:${media.id}`" :class="$style.media" :video="media"/>
|
||||
<XImage v-else-if="media.type.startsWith('image')" :key="`image:${media.id}`" :class="$style.media" class="image" :data-id="media.id" :image="media" :raw="raw"/>
|
||||
<XModPlayer v-else-if="isModule(media)" :key="media.id" :module="media"/>
|
||||
<XModPlayer v-else-if="isModule(media)" :key="`module:${media.id}`" :class="$style.media" :module="media"/>
|
||||
<XFlashPlayer v-else-if="isFlash(media)" :key="`flash:${media.id}`" :class="$style.media" :flashFile="media"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,8 +39,9 @@ import XBanner from '@/components/MkMediaBanner.vue';
|
|||
import XImage from '@/components/MkMediaImage.vue';
|
||||
import XVideo from '@/components/MkMediaVideo.vue';
|
||||
import XModPlayer from '@/components/SkModPlayer.vue';
|
||||
import XFlashPlayer from '@/components/SkFlashPlayer.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { FILE_TYPE_BROWSERSAFE, FILE_EXT_TRACKER_MODULES, FILE_TYPE_TRACKER_MODULES } from '@@/js/const.js';
|
||||
import { FILE_TYPE_BROWSERSAFE, FILE_EXT_TRACKER_MODULES, FILE_TYPE_TRACKER_MODULES, FILE_TYPE_FLASH_CONTENT, FILE_EXT_FLASH_CONTENT } from '@@/js/const.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { focusParent } from '@/scripts/focus.js';
|
||||
|
||||
|
@ -99,6 +101,12 @@ const isModule = (file: Misskey.entities.DriveFile): boolean => {
|
|||
});
|
||||
};
|
||||
|
||||
const isFlash = (file: Misskey.entities.DriveFile): boolean => {
|
||||
return FILE_TYPE_FLASH_CONTENT.includes(file.type) || FILE_EXT_FLASH_CONTENT.some((ext) => {
|
||||
return (file.name.toLowerCase().endsWith('.' + ext) || file.name.toLowerCase().endsWith('.' + ext + '.unknown'));
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
calcAspectRatio();
|
||||
|
||||
|
@ -224,6 +232,7 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
|
|||
if (file.type === 'image/svg+xml') return true; // svgのwebpublic/thumbnailはpngなのでtrue
|
||||
// FILE_TYPE_BROWSERSAFEに適合しないものはブラウザで表示するのに不適切
|
||||
if (isModule(file)) return true;
|
||||
if (isFlash(file)) return true;
|
||||
return (file.type.startsWith('video') || file.type.startsWith('image')) && FILE_TYPE_BROWSERSAFE.includes(file.type);
|
||||
};
|
||||
|
||||
|
|
493
packages/frontend/src/components/SkFlashPlayer.vue
Normal file
493
packages/frontend/src/components/SkFlashPlayer.vue
Normal file
|
@ -0,0 +1,493 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: CenTdemeern1 and other Sharkey contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div :class="$style.flash_player_container">
|
||||
<canvas :class="$style.ratio" height="300" width="300"></canvas>
|
||||
|
||||
<div v-if="hide" :class="$style.flash_player_disabled" @click="toggleVisible()">
|
||||
<div>
|
||||
<b><i class="ph-eye ph-bold ph-lg"></i> {{ i18n.ts.sensitive }}</b>
|
||||
<span>{{ i18n.ts.clickToShow }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else :class="$style.flash_player_enabled">
|
||||
<div :class="$style.flash_display">
|
||||
<div v-if="playerHide" :class="$style.player_hide" @click="dismissWarning()">
|
||||
<b><i class="ph-eye ph-bold ph-lg"></i> {{ i18n.ts._flash.contentHidden }}</b>
|
||||
<span>{{ i18n.ts._flash.poweredByRuffle }}</span>
|
||||
<span>{{ i18n.ts._flash.arbitraryCodeExecutionWarning }}</span>
|
||||
<span>{{ i18n.ts.clickToShow }}</span>
|
||||
</div>
|
||||
<div v-if="ruffleError" :class="$style.player_hide">
|
||||
<b><i class="ph-warning ph-bold ph-lg"></i> {{ i18n.ts._flash.failedToLoad }}</b>
|
||||
<code>{{ ruffleError }}</code>
|
||||
</div>
|
||||
<div v-else-if="loadingStatus" :class="$style.player_hide">
|
||||
<b>{{ i18n.ts._flash.isLoading }}<MkEllipsis/></b>
|
||||
<MkLoading/>
|
||||
<p>{{ loadingStatus }}</p>
|
||||
</div>
|
||||
<div ref="ruffleContainer" :class="$style.container"></div>
|
||||
</div>
|
||||
<div :class="$style.controls">
|
||||
<button :key="playPauseButtonKey" @click="playPause()">
|
||||
<i v-if="player?.isPlaying" class="ph-pause ph-bold ph-lg"></i>
|
||||
<i v-else class="ph-play ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<button :disabled="playerHide" @click="stop()">
|
||||
<i class="ph-stop ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<input v-if="player && !playerHide" v-model="player.volume" type="range" min="0" max="1" step="0.1"/>
|
||||
<input v-else type="range" min="0" max="1" value="1" disabled/>
|
||||
<a :title="i18n.ts.download" :href="flashFile.url" :download="flashFile.name" target="_blank">
|
||||
<i class="ph-download ph-bold ph-lg"></i>
|
||||
</a>
|
||||
<button :class="$style.fullscreen" :disabled="playerHide" @click="fullscreen()">
|
||||
<i class="ph-arrows-out ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="comment" :class="$style.alt" :title="comment">ALT</div>
|
||||
<i :class="$style.hide" class="ph-eye-slash ph-bold ph-lg" @click="toggleVisible()"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onDeactivated } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkEllipsis from '@/components/global/MkEllipsis.vue';
|
||||
import MkLoading from '@/components/global/MkLoading.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { PublicAPI, PublicAPILike } from '@/types/ruffle/setup'; // This gives us the types for window.RufflePlayer, etc via side effects
|
||||
import { PlayerElement } from '@/types/ruffle/player';
|
||||
|
||||
const props = defineProps<{
|
||||
flashFile: Misskey.entities.DriveFile
|
||||
}>();
|
||||
|
||||
const isSensitive = props.flashFile.isSensitive;
|
||||
const url = props.flashFile.url;
|
||||
const comment = props.flashFile.comment ?? '';
|
||||
let hide = ref((defaultStore.state.nsfw === 'force') || isSensitive && (defaultStore.state.nsfw !== 'ignore'));
|
||||
let playerHide = ref(true);
|
||||
let ruffleContainer = ref<HTMLDivElement>();
|
||||
let playPauseButtonKey = ref<number>(0);
|
||||
let loadingStatus = ref<string | undefined>(undefined);
|
||||
let player = ref<PlayerElement | undefined>(undefined);
|
||||
let ruffleError = ref<string | undefined>(undefined);
|
||||
|
||||
async function dismissWarning() {
|
||||
playerHide.value = false;
|
||||
try {
|
||||
await loadRuffle();
|
||||
createPlayer();
|
||||
await loadContent();
|
||||
} catch (error) {
|
||||
handleError(error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleError(error: unknown) {
|
||||
if (error instanceof Error) ruffleError.value = error.stack;
|
||||
else ruffleError.value = `${error}`; // Fallback for if something is horribly wrong
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws if esm.sh shits itself
|
||||
*/
|
||||
async function loadRuffle() {
|
||||
if (window.RufflePlayer !== undefined) return;
|
||||
loadingStatus.value = i18n.ts._flash.loadingRufflePlayer;
|
||||
await import('@ruffle-rs/ruffle'); // Assumption: this will throw if esm.sh has a hiccup or something. If not, the next undefined check will catch it.
|
||||
window.RufflePlayer = window.RufflePlayer as PublicAPILike | PublicAPI | undefined; // Assert unknown type due to side effects
|
||||
if (window.RufflePlayer === undefined) throw Error('esm.sh has shit itself, but not in an expected way (has esm.sh permanently shut down? how close is the heat death of the universe?)');
|
||||
|
||||
window.RufflePlayer.config = {
|
||||
// Options affecting the whole page
|
||||
'publicPath': `https://raw.esm.sh/@ruffle-rs/ruffle@${_RUFFLE_VERSION_}/`,
|
||||
'polyfills': false,
|
||||
|
||||
// Options affecting files only
|
||||
'allowScriptAccess': false,
|
||||
'autoplay': true,
|
||||
'unmuteOverlay': 'visible',
|
||||
'backgroundColor': null,
|
||||
'wmode': 'window',
|
||||
'letterbox': 'on',
|
||||
'warnOnUnsupportedContent': true,
|
||||
'contextMenu': 'off', // Prevent two overlapping context menus. Most of the stuff in this context menu is available in the controls below the player.
|
||||
'showSwfDownload': false, // Handled by custom download button
|
||||
'upgradeToHttps': window.location.protocol === 'https:',
|
||||
'maxExecutionDuration': 15,
|
||||
'logLevel': 'error',
|
||||
'base': null,
|
||||
'menu': true,
|
||||
'salign': '',
|
||||
'forceAlign': false,
|
||||
'scale': 'showAll',
|
||||
'forceScale': false,
|
||||
'frameRate': null,
|
||||
'quality': 'high',
|
||||
'splashScreen': false,
|
||||
'preferredRenderer': null,
|
||||
'openUrlMode': 'deny',
|
||||
'allowNetworking': 'none',
|
||||
'favorFlash': false,
|
||||
'socketProxy': [],
|
||||
'fontSources': [],
|
||||
'defaultFonts': {},
|
||||
'credentialAllowList': [],
|
||||
'playerRuntime': 'flashPlayer',
|
||||
'allowFullscreen': false, // Handled by custom fullscreen button
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws If `ruffle.newest()` fails (impossible)
|
||||
*/
|
||||
function createPlayer() {
|
||||
if (player.value !== undefined) return;
|
||||
const ruffle = (() => {
|
||||
const ruffleAPI = (window.RufflePlayer as PublicAPI).newest();
|
||||
if (ruffleAPI === null) {
|
||||
// This error exists because non-null assertions are forbidden, apparently.
|
||||
throw Error('Ruffle could not get the latest Ruffle source. Since we\'re loading from esm.sh this is genuinely impossible and you must\'ve done something incredibly cursed.');
|
||||
}
|
||||
return ruffleAPI;
|
||||
})();
|
||||
player.value = ruffle.createPlayer();
|
||||
player.value.style.width = '100%';
|
||||
player.value.style.height = '100%';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws If `player.value` is uninitialized.
|
||||
*/
|
||||
async function loadContent() {
|
||||
if (player.value === undefined) throw Error('Player is uninitialized.');
|
||||
ruffleContainer.value?.appendChild(player.value);
|
||||
loadingStatus.value = i18n.ts._flash.loadingFlashFile;
|
||||
try {
|
||||
await player.value.load(url);
|
||||
loadingStatus.value = undefined;
|
||||
} catch (error) {
|
||||
try {
|
||||
await fetch('https://raw.esm.sh/', {
|
||||
mode: 'cors',
|
||||
});
|
||||
handleError(error); // Unexpected error
|
||||
} catch (_) {
|
||||
// Must be CSP because esm.sh should be online if `loadRuffle()` didn't fail
|
||||
handleError(i18n.ts._flash.cspError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function playPause() {
|
||||
if (playerHide.value) {
|
||||
dismissWarning();
|
||||
return;
|
||||
}
|
||||
if (player.value === undefined) return; // Not done loading or something
|
||||
if (player.value.isPlaying) {
|
||||
player.value.pause();
|
||||
} else {
|
||||
player.value.play();
|
||||
}
|
||||
playPauseButtonKey.value += 1; // HACK: Used to re-render play/pause button
|
||||
}
|
||||
|
||||
function fullscreen() {
|
||||
if (player.value === undefined) return; // Can't fullscreen an element that doesn't exist.
|
||||
if (player.value.isFullscreen) {
|
||||
player.value.exitFullscreen();
|
||||
} else {
|
||||
player.value.enterFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (player.value === undefined) return; // FIXME: This doesn't stop the loading process. (That said, should this even be implemented?)
|
||||
try {
|
||||
ruffleContainer.value?.removeChild(player.value);
|
||||
} catch {
|
||||
// This is fine
|
||||
}
|
||||
playerHide.value = true;
|
||||
}
|
||||
|
||||
function toggleVisible() {
|
||||
hide.value = !hide.value;
|
||||
playerHide.value = true;
|
||||
}
|
||||
|
||||
onDeactivated(() => {
|
||||
stop();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
||||
.flash_player_container {
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.ratio {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hide {
|
||||
border-radius: var(--radius-sm) !important;
|
||||
background-color: black !important;
|
||||
color: var(--accentLighten) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.flash_player_enabled {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
> i {
|
||||
display: block;
|
||||
position: absolute;
|
||||
border-radius: var(--radius-sm);
|
||||
background-color: var(--fg);
|
||||
color: var(--accentLighten);
|
||||
font-size: 14px;
|
||||
opacity: .5;
|
||||
padding: 3px 6px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
> .alt {
|
||||
display: block;
|
||||
position: absolute;
|
||||
border-radius: var(--radius-sm);
|
||||
background-color: black;
|
||||
color: var(--accentLighten);
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
opacity: .5;
|
||||
padding: 2px 5px;
|
||||
cursor: help;
|
||||
user-select: none;
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
> .flash_display {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 10;
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
background-color: black;
|
||||
text-align: center;
|
||||
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.player_hide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgba(64, 64, 64, 0.3);
|
||||
backdrop-filter: var(--modalBgFilter);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
> .container {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
> .controls {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background-color: var(--bg);
|
||||
z-index: 5;
|
||||
|
||||
> * {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
> button, a {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--fg);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
filter: grayscale(100%);
|
||||
background-color: transparent;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
> .fullscreen {
|
||||
margin-left: auto;
|
||||
|
||||
&:disabled {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
> input[type=range] {
|
||||
height: 21px;
|
||||
-webkit-appearance: none;
|
||||
width: 90px;
|
||||
padding: 0;
|
||||
margin: 4px 8px;
|
||||
overflow-x: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
&:disabled {
|
||||
filter: grayscale(100%);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
&::-ms-fill-lower, &::-ms-fill-upper {
|
||||
background: var(--bg);
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
animate: 0.2s;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--fg);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 14px;
|
||||
border-radius: 0;
|
||||
background: var(--accentLighten);
|
||||
-webkit-appearance: none;
|
||||
box-shadow: calc(-100vw - 14px) 0 0 100vw var(--accent);
|
||||
clip-path: polygon(1px 0, 100% 0, 100% 100%, 1px 100%, 1px calc(50% + 10.5px), -100vw calc(50% + 10.5px), -100vw calc(50% - 10.5px), 0 calc(50% - 10.5px));
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
animate: 0.2s;
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--fg);
|
||||
}
|
||||
|
||||
&::-moz-range-progress {
|
||||
height: 100%;
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
border: none;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
width: 14px;
|
||||
background: var(--accentLighten);
|
||||
}
|
||||
|
||||
&::-ms-track {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
animate: 0.2s;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
&::-ms-fill-lower {
|
||||
background: var(--accent);
|
||||
border: 1px solid var(--fg);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&::-ms-fill-upper {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--fg);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&::-ms-thumb {
|
||||
margin-top: 1px;
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 14px;
|
||||
border-radius: 0;
|
||||
background: var(--accentLighten);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flash_player_disabled {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
> div {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
|
||||
> b {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -4,44 +4,44 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div v-if="hide" class="mod-player-disabled" @click="toggleVisible()">
|
||||
<div v-if="hide" :class="$style.mod_player_disabled" @click="toggleVisible()">
|
||||
<div>
|
||||
<b><i class="ph-eye ph-bold ph-lg"></i> {{ i18n.ts.sensitive }}</b>
|
||||
<span>{{ i18n.ts.clickToShow }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="mod-player-enabled">
|
||||
<div class="pattern-display" @click="togglePattern()" @scroll="scrollHandler" @scrollend="scrollEndHandle">
|
||||
<div v-if="patternHide" class="pattern-hide">
|
||||
<div v-else :class="$style.mod_player_enabled">
|
||||
<div :class="$style.pattern_display" @click="togglePattern()" @scroll="scrollHandler" @scrollend="scrollEndHandle">
|
||||
<div v-if="patternHide" :class="$style.pattern_hide">
|
||||
<b><i class="ph-eye ph-bold ph-lg"></i> Pattern Hidden</b>
|
||||
<span>{{ i18n.ts.clickToShow }}</span>
|
||||
</div>
|
||||
<span class="patternShadowTop"></span>
|
||||
<span class="patternShadowBottom"></span>
|
||||
<canvas ref="displayCanvas" class="pattern-canvas"></canvas>
|
||||
<span :class="$style.patternShadowTop"></span>
|
||||
<span :class="$style.patternShadowBottom"></span>
|
||||
<canvas ref="displayCanvas" :class="$style.pattern_canvas"></canvas>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<input v-if="patternScrollSliderShow" ref="patternScrollSlider" v-model="patternScrollSliderPos" class="pattern-slider" type="range" min="0" max="100" step="0.01" style=""/>
|
||||
<button class="play" @click="playPause()">
|
||||
<div :class="$style.controls">
|
||||
<input v-if="patternScrollSliderShow" ref="patternScrollSlider" v-model="patternScrollSliderPos" :class="$style.pattern_slider" type="range" min="0" max="100" step="0.01" style=""/>
|
||||
<button :class="$style.play" @click="playPause()">
|
||||
<i v-if="playing" class="ph-pause ph-bold ph-lg"></i>
|
||||
<i v-else class="ph-play ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<button class="stop" @click="stop()">
|
||||
<button :class="$style.stop" @click="stop()">
|
||||
<i class="ph-stop ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<input ref="progress" v-model="position" class="progress" type="range" min="0" max="1" step="0.1" @mousedown="initSeek()" @mouseup="performSeek()"/>
|
||||
<input ref="progress" v-model="position" :class="$style.progress" type="range" min="0" max="1" step="0.1" @mousedown="initSeek()" @mouseup="performSeek()"/>
|
||||
<input v-model="player.context.gain.value" type="range" min="0" max="1" step="0.1"/>
|
||||
<a class="download" :title="i18n.ts.download" :href="module.url" target="_blank">
|
||||
<a :class="$style.download" :title="i18n.ts.download" :href="module.url" :download="module.name" target="_blank">
|
||||
<i class="ph-download ph-bold ph-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
<i class="hide ph-eye-slash ph-bold ph-lg" @click="toggleVisible()"></i>
|
||||
<i :class="$style.hide" class="ph-eye-slash ph-bold ph-lg" @click="toggleVisible()"></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick, computed, watch, onDeactivated, onMounted } from 'vue';
|
||||
import { ref, nextTick, watch, onDeactivated, onMounted } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
@ -70,9 +70,9 @@ const props = defineProps<{
|
|||
module: Misskey.entities.DriveFile
|
||||
}>();
|
||||
|
||||
const isSensitive = computed(() => { return props.module.isSensitive; });
|
||||
const url = computed(() => { return props.module.url; });
|
||||
let hide = ref((defaultStore.state.nsfw === 'force') ? true : isSensitive.value && (defaultStore.state.nsfw !== 'ignore'));
|
||||
const isSensitive = props.module.isSensitive;
|
||||
const url = props.module.url;
|
||||
let hide = ref((defaultStore.state.nsfw === 'force') ? true : isSensitive && (defaultStore.state.nsfw !== 'ignore'));
|
||||
let patternHide = ref(false);
|
||||
let playing = ref(false);
|
||||
let displayCanvas = ref<HTMLCanvasElement>();
|
||||
|
@ -111,7 +111,7 @@ function bakeNumberRow() {
|
|||
}
|
||||
|
||||
onMounted(() => {
|
||||
player.value.load(url.value).then((result) => {
|
||||
player.value.load(url).then((result) => {
|
||||
buffer = result;
|
||||
try {
|
||||
player.value.play(buffer);
|
||||
|
@ -437,7 +437,7 @@ onDeactivated(() => {
|
|||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss" module>
|
||||
|
||||
.hide {
|
||||
border-radius: var(--MI-radius-sm) !important;
|
||||
|
@ -446,7 +446,7 @@ onDeactivated(() => {
|
|||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.mod-player-enabled {
|
||||
.mod_player_enabled {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
@ -469,7 +469,7 @@ onDeactivated(() => {
|
|||
z-index: 4;
|
||||
}
|
||||
|
||||
> .pattern-display {
|
||||
> .pattern_display {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
|
@ -484,7 +484,7 @@ onDeactivated(() => {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.pattern-canvas {
|
||||
.pattern_canvas {
|
||||
position: relative;
|
||||
background-color: black;
|
||||
image-rendering: pixelated;
|
||||
|
@ -513,7 +513,7 @@ onDeactivated(() => {
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
.pattern-hide {
|
||||
.pattern_hide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
@ -563,7 +563,7 @@ onDeactivated(() => {
|
|||
margin: 4px 8px;
|
||||
overflow-x: hidden;
|
||||
|
||||
&.pattern-slider {
|
||||
&.pattern_slider {
|
||||
position: absolute;
|
||||
width: calc( 100% - 8px * 2 );
|
||||
top: calc( 100% - 21px * 3 );
|
||||
|
@ -677,7 +677,7 @@ onDeactivated(() => {
|
|||
}
|
||||
}
|
||||
|
||||
.mod-player-disabled {
|
||||
.mod_player_disabled {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
|
||||
worker-src 'self' blob:;
|
||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh https://cdn.jsdelivr.net;
|
||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh https://cdn.jsdelivr.net https://raw.esm.sh;
|
||||
style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000 activitypub.software secure.gravatar.com avatars.githubusercontent.com;
|
||||
media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
||||
connect-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000 https://newassets.hcaptcha.com https://api.listenbrainz.org https://api.friendlycaptcha.com;
|
||||
connect-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000 https://newassets.hcaptcha.com https://api.listenbrainz.org https://api.friendlycaptcha.com https://raw.esm.sh;
|
||||
frame-src *;"
|
||||
/>
|
||||
<meta property="og:site_name" content="[DEV BUILD] Misskey" />
|
||||
|
|
|
@ -42,7 +42,7 @@ const KEY_ALIASES = {
|
|||
|
||||
const MODIFIER_KEYS = ['ctrl', 'alt', 'shift'];
|
||||
|
||||
const IGNORE_ELEMENTS = ['input', 'textarea'];
|
||||
const IGNORE_ELEMENTS = ['input', 'textarea', 'ruffle-player'];
|
||||
//#endregion
|
||||
|
||||
//#region store
|
||||
|
|
2
packages/frontend/src/types/ruffle/config/default.d.ts
vendored
Normal file
2
packages/frontend/src/types/ruffle/config/default.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import type { BaseLoadOptions } from './load-options.d.ts';
|
||||
export declare const DEFAULT_CONFIG: Required<BaseLoadOptions>;
|
10
packages/frontend/src/types/ruffle/config/index.d.ts
vendored
Normal file
10
packages/frontend/src/types/ruffle/config/index.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* The Config module contains all the types that Ruffle uses for movie configs.
|
||||
*
|
||||
* The main interface of interest here is {@link BaseLoadOptions}, which you can apply to `window.RufflePlayer.config`
|
||||
* to set the default configuration of all players.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
export type * from './default.d.ts';
|
||||
export type * from './load-options.d.ts';
|
620
packages/frontend/src/types/ruffle/config/load-options.d.ts
vendored
Normal file
620
packages/frontend/src/types/ruffle/config/load-options.d.ts
vendored
Normal file
|
@ -0,0 +1,620 @@
|
|||
/**
|
||||
* Represents the various types of auto-play behaviours that are supported.
|
||||
*/
|
||||
export declare enum AutoPlay {
|
||||
/**
|
||||
* The player should automatically play the movie as soon as it is loaded.
|
||||
*
|
||||
* If the browser does not support automatic audio, the movie will begin
|
||||
* muted.
|
||||
*/
|
||||
On = "on",
|
||||
/**
|
||||
* The player should not attempt to automatically play the movie.
|
||||
*
|
||||
* This will leave it to the user or API to actually play when appropriate.
|
||||
*/
|
||||
Off = "off",
|
||||
/**
|
||||
* The player should automatically play the movie as soon as it is deemed
|
||||
* "appropriate" to do so.
|
||||
*
|
||||
* The exact behaviour depends on the browser, but commonly requires some
|
||||
* form of user interaction on the page in order to allow auto playing videos
|
||||
* with sound.
|
||||
*/
|
||||
Auto = "auto"
|
||||
}
|
||||
/**
|
||||
* Controls whether the content is letterboxed or pillarboxed when the
|
||||
* player's aspect ratio does not match the movie's aspect ratio.
|
||||
*
|
||||
* When letterboxed, black bars will be rendered around the exterior
|
||||
* margins of the content.
|
||||
*/
|
||||
export declare enum Letterbox {
|
||||
/**
|
||||
* The content will never be letterboxed.
|
||||
*/
|
||||
Off = "off",
|
||||
/**
|
||||
* The content will only be letterboxed if the content is running fullscreen.
|
||||
*/
|
||||
Fullscreen = "fullscreen",
|
||||
/**
|
||||
* The content will always be letterboxed.
|
||||
*/
|
||||
On = "on"
|
||||
}
|
||||
/**
|
||||
* When the player is muted, this controls whether or not Ruffle will show a
|
||||
* "click to unmute" overlay on top of the movie.
|
||||
*/
|
||||
export declare enum UnmuteOverlay {
|
||||
/**
|
||||
* Show an overlay explaining that the movie is muted.
|
||||
*/
|
||||
Visible = "visible",
|
||||
/**
|
||||
* Don't show an overlay and pretend that everything is fine.
|
||||
*/
|
||||
Hidden = "hidden"
|
||||
}
|
||||
/**
|
||||
* Console logging level.
|
||||
*/
|
||||
export declare enum LogLevel {
|
||||
Error = "error",
|
||||
Warn = "warn",
|
||||
Info = "info",
|
||||
Debug = "debug",
|
||||
Trace = "trace"
|
||||
}
|
||||
/**
|
||||
* The window mode of a Ruffle player.
|
||||
*/
|
||||
export declare enum WindowMode {
|
||||
/**
|
||||
* The Flash content is rendered in its own window and layering is done with the browser's
|
||||
* default behavior.
|
||||
*
|
||||
* In Ruffle, this mode functions like `WindowMode::Opaque` and will layer the Flash content
|
||||
* together with other HTML elements.
|
||||
*/
|
||||
Window = "window",
|
||||
/**
|
||||
* The Flash content is layered together with other HTML elements, and the stage color is
|
||||
* opaque. Content can render above or below Ruffle based on CSS rendering order.
|
||||
*/
|
||||
Opaque = "opaque",
|
||||
/**
|
||||
* The Flash content is layered together with other HTML elements, and the SWF stage color is
|
||||
* transparent. Content beneath Ruffle will be visible through transparent areas.
|
||||
*/
|
||||
Transparent = "transparent",
|
||||
/**
|
||||
* Request compositing with hardware acceleration when possible.
|
||||
* This mode has no effect in Ruffle and will function like `WindowMode.Opaque`.
|
||||
*/
|
||||
Direct = "direct",
|
||||
/**
|
||||
* Request a direct rendering path, bypassing browser compositing when possible.
|
||||
* This mode has no effect in Ruffle and will function like `WindowMode::Opaque`.
|
||||
*/
|
||||
Gpu = "gpu"
|
||||
}
|
||||
/**
|
||||
* The render backend of a Ruffle player.
|
||||
*
|
||||
* The available backends may change in future releases.
|
||||
*/
|
||||
export declare enum RenderBackend {
|
||||
/**
|
||||
* An [in-development API](https://caniuse.com/webgpu) that will be preferred if available in the future.
|
||||
* Should behave the same as wgpu-webgl, except with lower overhead and thus better performance.
|
||||
*/
|
||||
WebGpu = "webgpu",
|
||||
/**
|
||||
* The most featureful and currently preferred backend.
|
||||
* Rendering is done the same way as in the desktop app, then translated to WebGL on-the-fly.
|
||||
*/
|
||||
WgpuWebgl = "wgpu-webgl",
|
||||
/**
|
||||
* A vanilla WebGL backend. Was the default backend until the start of 2023,
|
||||
* but is now used as a fallback for devices that do not support WebGL 2.
|
||||
* Supports fewer features and has a faster initialization time;
|
||||
* may be useful for content that does not need advanced features like bitmap drawing or blend modes.
|
||||
*/
|
||||
Webgl = "webgl",
|
||||
/**
|
||||
* The slowest and most basic backend, used as a fallback when all else fails.
|
||||
* However, this is currently the only backend that accurately scales hairline strokes.
|
||||
* If you notice excessively thick strokes in specific content,
|
||||
* you may want to use the canvas renderer for that content until the issue is resolved.
|
||||
*/
|
||||
Canvas = "canvas"
|
||||
}
|
||||
/**
|
||||
* Represents the various context menu options that are supported.
|
||||
*/
|
||||
export declare enum ContextMenu {
|
||||
/**
|
||||
* The context menu should appear when right-clicking or long-pressing
|
||||
* the Ruffle instance.
|
||||
*/
|
||||
On = "on",
|
||||
/**
|
||||
* The context menu should only appear when right-clicking
|
||||
* the Ruffle instance.
|
||||
*/
|
||||
RightClickOnly = "rightClickOnly",
|
||||
/**
|
||||
* The context menu should not appear when right-clicking or long-pressing
|
||||
* the Ruffle instance.
|
||||
*/
|
||||
Off = "off"
|
||||
}
|
||||
/**
|
||||
* Represents the player runtime to emulate.
|
||||
*/
|
||||
export declare enum PlayerRuntime {
|
||||
/**
|
||||
* Emulate Adobe AIR.
|
||||
*/
|
||||
AIR = "air",
|
||||
/**
|
||||
* Emulate Adobe Flash Player.
|
||||
*/
|
||||
FlashPlayer = "flashPlayer"
|
||||
}
|
||||
/**
|
||||
* Non-negative duration in seconds.
|
||||
*/
|
||||
export type SecsDuration = number;
|
||||
/**
|
||||
* Deprecated duration type, use SecsDuration instead.
|
||||
* Based on https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.new .
|
||||
*/
|
||||
export interface ObsoleteDuration {
|
||||
secs: number;
|
||||
nanos: number;
|
||||
}
|
||||
/**
|
||||
* Any new duration-based setting should use 'number' or 'SecsDuration' for its type,
|
||||
* instead of this type.
|
||||
*/
|
||||
export type Duration = SecsDuration | ObsoleteDuration;
|
||||
/**
|
||||
* The handling mode of links opening a new website.
|
||||
*/
|
||||
export declare enum OpenURLMode {
|
||||
/**
|
||||
* Allow all links to open a new website.
|
||||
*/
|
||||
Allow = "allow",
|
||||
/**
|
||||
* A confirmation dialog opens with every link trying to open a new website.
|
||||
*/
|
||||
Confirm = "confirm",
|
||||
/**
|
||||
* Deny all links to open a new website.
|
||||
*/
|
||||
Deny = "deny"
|
||||
}
|
||||
/**
|
||||
* The networking API access mode of the Ruffle player.
|
||||
*/
|
||||
export declare enum NetworkingAccessMode {
|
||||
/**
|
||||
* All networking APIs are permitted in the SWF file.
|
||||
*/
|
||||
All = "all",
|
||||
/**
|
||||
* The SWF file may not call browser navigation or browser interaction APIs.
|
||||
*
|
||||
* The APIs navigateToURL(), fscommand() and ExternalInterface.call() are
|
||||
* prevented in this mode.
|
||||
*/
|
||||
Internal = "internal",
|
||||
/**
|
||||
* The SWF file may not call browser navigation or browser interaction APIs
|
||||
* and it cannot use any SWF-to-SWF communication APIs.
|
||||
*
|
||||
* Additionally to the ones in internal mode, the APIs sendToURL(),
|
||||
* FileReference.download(), FileReference.upload(), Loader.load(),
|
||||
* LocalConnection.connect(), LocalConnection.send(), NetConnection.connect(),
|
||||
* NetStream.play(), Security.loadPolicyFile(), SharedObject.getLocal(),
|
||||
* SharedObject.getRemote(), Socket.connect(), Sound.load(), URLLoader.load(),
|
||||
* URLStream.load() and XMLSocket.connect() are prevented in this mode.
|
||||
*
|
||||
* This mode is not implemented yet.
|
||||
*/
|
||||
None = "none"
|
||||
}
|
||||
/**
|
||||
* Represents a host, port and proxyUrl. Used when a SWF file tries to use a Socket.
|
||||
*/
|
||||
export interface SocketProxy {
|
||||
/**
|
||||
* Host used by the SWF.
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
* Port used by the SWF.
|
||||
*/
|
||||
port: number;
|
||||
/**
|
||||
* The proxy URL to use when SWF file tries to connect to the specified host and port.
|
||||
*/
|
||||
proxyUrl: string;
|
||||
}
|
||||
/**
|
||||
* Defines the names of the fonts to use for each "default" Flash device font.
|
||||
*
|
||||
* The name of each font provided will be used, in priority order.
|
||||
*
|
||||
* For example, defining `sans: ["Helvetica", "Arial"]` would use Helvetica if present, before trying Arial.
|
||||
*/
|
||||
export interface DefaultFonts {
|
||||
/**
|
||||
* `_sans`, a Sans-Serif font (similar to Helvetica or Arial)
|
||||
*/
|
||||
sans?: Array<string>;
|
||||
/**
|
||||
* `_serif`, a Serif font (similar to Times Roman)
|
||||
*/
|
||||
serif?: Array<string>;
|
||||
/**
|
||||
* `_typewriter`, a Monospace font (similar to Courier)
|
||||
*/
|
||||
typewriter?: Array<string>;
|
||||
/**
|
||||
* `_ゴシック`, a Japanese Gothic font
|
||||
*/
|
||||
japaneseGothic?: Array<string>;
|
||||
/**
|
||||
* `_等幅`, a Japanese Gothic Mono font
|
||||
*/
|
||||
japaneseGothicMono?: Array<string>;
|
||||
/**
|
||||
* `_明朝`, a Japanese Mincho font
|
||||
*/
|
||||
japaneseMincho?: Array<string>;
|
||||
}
|
||||
/**
|
||||
* Any options used for loading a movie.
|
||||
*/
|
||||
export interface BaseLoadOptions {
|
||||
/**
|
||||
* If set to true, the movie is allowed to interact with the page through
|
||||
* JavaScript, using a flash concept called `ExternalInterface`.
|
||||
*
|
||||
* This should only be enabled for movies you trust.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
allowScriptAccess?: boolean;
|
||||
/**
|
||||
* Also known as "flashvars" - these are values that may be passed to
|
||||
* and loaded by the movie.
|
||||
*
|
||||
* If a URL if specified when loading the movie, some parameters will
|
||||
* be extracted by the query portion of that URL and then overwritten
|
||||
* by any explicitly set here.
|
||||
*
|
||||
* @default {}
|
||||
*/
|
||||
parameters?: URLSearchParams | string | Record<string, string> | null;
|
||||
/**
|
||||
* Controls the auto-play behaviour of Ruffle.
|
||||
*
|
||||
* @default AutoPlay.Auto
|
||||
*/
|
||||
autoplay?: AutoPlay;
|
||||
/**
|
||||
* Controls the background color of the player.
|
||||
* Must be an HTML color (e.g. "#FFFFFF"). CSS colors are not allowed.
|
||||
* `null` uses the background color of the SWF file.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
backgroundColor?: string | null;
|
||||
/**
|
||||
* Controls letterbox behavior when the Flash container size does not
|
||||
* match the movie size.
|
||||
*
|
||||
* @default Letterbox.Fullscreen
|
||||
*/
|
||||
letterbox?: Letterbox;
|
||||
/**
|
||||
* Controls the visibility of the unmute overlay when the player
|
||||
* is started muted.
|
||||
*
|
||||
* @default UnmuteOverlay.Visible
|
||||
*/
|
||||
unmuteOverlay?: UnmuteOverlay;
|
||||
/**
|
||||
* Whether or not to auto-upgrade all embedded URLs to https.
|
||||
*
|
||||
* Flash content that embeds http urls will be blocked from
|
||||
* accessing those urls by the browser when Ruffle is loaded
|
||||
* in a https context. Set to `true` to automatically change
|
||||
* `http://` to `https://` for all embedded URLs when Ruffle is
|
||||
* loaded in an https context.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
upgradeToHttps?: boolean;
|
||||
/**
|
||||
* Enable (true) or disable (false) Ruffle's built in compatibility rules.
|
||||
*
|
||||
* These are rules that may make some content work by deliberately changing
|
||||
* behaviour, for example by rewriting requests or spoofing SWF urls if they
|
||||
* rely on websites that no longer exist.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
compatibilityRules?: boolean;
|
||||
/**
|
||||
* Favor using the real Adobe Flash Player over Ruffle if the browser supports it.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
favorFlash?: boolean;
|
||||
/**
|
||||
* This is no longer used and does not affect anything.
|
||||
* It is only kept for backwards compatibility.
|
||||
*
|
||||
* Previously:
|
||||
* "Whether or not to display an overlay with a warning when
|
||||
* loading a movie with unsupported content."
|
||||
*
|
||||
* @default true
|
||||
* @deprecated
|
||||
*/
|
||||
warnOnUnsupportedContent?: boolean;
|
||||
/**
|
||||
* Console logging level.
|
||||
*
|
||||
* @default LogLevel.Error
|
||||
*/
|
||||
logLevel?: LogLevel;
|
||||
/**
|
||||
* If set to true, the context menu has an option to download
|
||||
* the SWF.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
showSwfDownload?: boolean;
|
||||
/**
|
||||
* Whether or not to show a context menu when right-clicking
|
||||
* a Ruffle instance.
|
||||
*
|
||||
* @default ContextMenu.On
|
||||
*/
|
||||
contextMenu?: ContextMenu | boolean;
|
||||
/**
|
||||
* Whether or not to show a splash screen before the SWF has loaded with Ruffle (backwards-compatibility).
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
preloader?: boolean;
|
||||
/**
|
||||
* Whether or not to show a splash screen before the SWF has loaded with Ruffle.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
splashScreen?: boolean;
|
||||
/**
|
||||
* Maximum amount of time a script can take before scripting
|
||||
* is disabled.
|
||||
*
|
||||
* @default 15
|
||||
*/
|
||||
maxExecutionDuration?: Duration;
|
||||
/**
|
||||
* Specifies the base directory or URL used to resolve all relative path statements in the SWF file.
|
||||
* null means the current directory.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
base?: string | null;
|
||||
/**
|
||||
* If set to true, the built-in context menu items are visible
|
||||
*
|
||||
* This is equivalent to Stage.showMenu.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
menu?: boolean;
|
||||
/**
|
||||
* This is equivalent to Stage.align.
|
||||
*
|
||||
* @default ""
|
||||
*/
|
||||
salign?: string;
|
||||
/**
|
||||
* If set to true, movies are prevented from changing the stage alignment.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
forceAlign?: boolean;
|
||||
/**
|
||||
* This is equivalent to Stage.quality.
|
||||
*
|
||||
* @default "high"
|
||||
*/
|
||||
quality?: string;
|
||||
/**
|
||||
* This is equivalent to Stage.scaleMode.
|
||||
*
|
||||
* @default "showAll"
|
||||
*/
|
||||
scale?: string;
|
||||
/**
|
||||
* If set to true, movies are prevented from changing the stage scale mode.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
forceScale?: boolean;
|
||||
/**
|
||||
* If set to true, the Stage's displayState can be changed
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
allowFullscreen?: boolean;
|
||||
/**
|
||||
* Sets and locks the player's frame rate, overriding the movie's frame rate.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
frameRate?: number | null;
|
||||
/**
|
||||
* The window mode of the Ruffle player.
|
||||
*
|
||||
* This setting controls how the Ruffle container is layered and rendered with other content on the page.
|
||||
*
|
||||
* @default WindowMode.Window
|
||||
*/
|
||||
wmode?: WindowMode;
|
||||
/**
|
||||
* The emulated version of the player.
|
||||
*
|
||||
* This controls the version that is reported to the movie.
|
||||
* null means latest version.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
playerVersion?: number | null;
|
||||
/**
|
||||
* The preferred render backend of the Ruffle player.
|
||||
*
|
||||
* This option should only be used for testing;
|
||||
* the available backends may change in future releases.
|
||||
* By default, Ruffle chooses the most featureful backend supported by the user's system,
|
||||
* falling back to more basic backends if necessary.
|
||||
* The available values in order of default preference are:
|
||||
* "webgpu", "wgpu-webgl", "webgl", "canvas".
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
preferredRenderer?: RenderBackend | null;
|
||||
/**
|
||||
* The URL at which Ruffle can load its extra files (i.e. `.wasm`).
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
publicPath?: string | null;
|
||||
/**
|
||||
* Whether or not to enable polyfills on the page.
|
||||
*
|
||||
* Polyfills will look for "legacy" flash content like `<object>`
|
||||
* and `<embed>` elements, and replace them with compatible
|
||||
* Ruffle elements.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
polyfills?: boolean;
|
||||
/**
|
||||
* The handling mode of links opening a new website.
|
||||
*
|
||||
* @default OpenURLMode.Allow
|
||||
*/
|
||||
openUrlMode?: OpenURLMode;
|
||||
/**
|
||||
* Which flash networking APIs may be accessed.
|
||||
*
|
||||
* @default NetworkingAccessMode.All
|
||||
*/
|
||||
allowNetworking?: NetworkingAccessMode;
|
||||
/**
|
||||
* A function to call for opening content in a new tab.
|
||||
*
|
||||
* This is only used if the content cannot be loaded due to CORS,
|
||||
* and the Extension version of Ruffle will override this to provide a local player.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
openInNewTab?: ((swf: URL) => void) | null;
|
||||
/**
|
||||
* An array of SocketProxy objects.
|
||||
*
|
||||
* When a SWF tries to establish a Socket connection, Ruffle will search for
|
||||
* a matching SocketProxy object in this array and use it to establish a WebSocket connection,
|
||||
* through which all communication is tunneled through.
|
||||
*
|
||||
* When none are found, Ruffle will fail the connection gracefully.
|
||||
* When multiple matching SocketProxy objects exist, the first one is used.
|
||||
*
|
||||
* @default []
|
||||
*/
|
||||
socketProxy?: Array<SocketProxy>;
|
||||
/**
|
||||
* An array of font URLs to eagerly load and provide to Ruffle.
|
||||
*
|
||||
* These will be fetched by the browser as part of the loading of Flash content, which may slow down load times.
|
||||
*
|
||||
* Currently only SWFs are supported, and each font embedded within that SWF will be used as device font by Flash content.
|
||||
*
|
||||
* If any URL fails to load (either it's an invalid file, or a network error occurs), Ruffle will log an error but continue without it.
|
||||
*
|
||||
* @default []
|
||||
*/
|
||||
fontSources?: Array<string>;
|
||||
/**
|
||||
* The font names to use for each "default" Flash device font.
|
||||
*
|
||||
* @default {}
|
||||
*/
|
||||
defaultFonts?: DefaultFonts;
|
||||
/**
|
||||
* An array of origins that credentials may be sent to.
|
||||
* Credentials are cookies, authorization headers, or TLS client certificates.
|
||||
*
|
||||
* Entries should include the protocol and host, for example `https://example.org` or `http://subdomain.example.org`.
|
||||
*
|
||||
* Cookies will always be sent to the same origin as the page the content was loaded on.
|
||||
* If you configure this to send cookies to an origin but that origin does not configure CORS to allow it,
|
||||
* then requests will start failing due to CORS.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials.
|
||||
*
|
||||
* This directly corresponds to https://developer.mozilla.org/en-US/docs/Web/API/fetch#credentials
|
||||
* Every request will be `same-origin` unless specified here, in which case it will be `include`.
|
||||
*
|
||||
* @default []
|
||||
*/
|
||||
credentialAllowList?: Array<string>;
|
||||
/**
|
||||
* The player runtime to emulate
|
||||
*
|
||||
* This allows you to emulate Adobe AIR or Adobe Flash Player.
|
||||
*/
|
||||
playerRuntime?: PlayerRuntime;
|
||||
}
|
||||
/**
|
||||
* Options to load a movie by URL.
|
||||
*/
|
||||
export interface URLLoadOptions extends BaseLoadOptions {
|
||||
/**
|
||||
* The URL to load a movie from.
|
||||
*
|
||||
* If there is a query portion of this URL, then default {@link parameters}
|
||||
* will be extracted from that.
|
||||
*/
|
||||
url: string;
|
||||
}
|
||||
/**
|
||||
* Options to load a movie by a data stream.
|
||||
*/
|
||||
export interface DataLoadOptions extends BaseLoadOptions {
|
||||
/**
|
||||
* The data to load a movie from.
|
||||
*/
|
||||
data: ArrayLike<number> | ArrayBufferLike;
|
||||
/**
|
||||
* The filename of the SWF movie to provide to ActionScript.
|
||||
*
|
||||
* @default "movie.swf"
|
||||
*/
|
||||
swfFileName?: string;
|
||||
}
|
17
packages/frontend/src/types/ruffle/player/flash.d.ts
vendored
Normal file
17
packages/frontend/src/types/ruffle/player/flash.d.ts
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* These are properties and methods that Flash added to its `<embed>/<object>` tags.
|
||||
* These don't seem to be documented in full anywhere, and Ruffle adds them as we encounter some.
|
||||
* You are discouraged from using these, and they exist only to support legacy websites from decades ago.
|
||||
*
|
||||
* Extra methods or properties may appear at any time, due to `ExternalInterface.addCallback()`.
|
||||
* It may even overwrite existing methods or properties.
|
||||
*/
|
||||
export interface FlashAPI {
|
||||
/**
|
||||
* Returns the movies loaded process, in a percent from 0 to 100.
|
||||
* Ruffle may just return 0 or 100.
|
||||
*
|
||||
* @returns a value from 0 to 100, inclusive.
|
||||
*/
|
||||
PercentLoaded(): number;
|
||||
}
|
9
packages/frontend/src/types/ruffle/player/index.d.ts
vendored
Normal file
9
packages/frontend/src/types/ruffle/player/index.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* The Player module contains the actual {@link PlayerElement} and the various interfaces that exist to interact with the player.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
export type * from './flash.d.ts';
|
||||
export type * from './player-element.d.ts';
|
||||
export type * from './movie-metadata.d.ts';
|
||||
export type * from './legacy.d.ts';
|
163
packages/frontend/src/types/ruffle/player/legacy.d.ts
vendored
Normal file
163
packages/frontend/src/types/ruffle/player/legacy.d.ts
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
import type { DataLoadOptions, URLLoadOptions } from '../config/index.d.ts';
|
||||
import type { MovieMetadata } from './movie-metadata.d.ts';
|
||||
/**
|
||||
* Describes the loading state of an SWF movie.
|
||||
*/
|
||||
export enum ReadyState {
|
||||
/**
|
||||
* No movie is loaded, or no information is yet available about the movie.
|
||||
*/
|
||||
HaveNothing = 0,
|
||||
/**
|
||||
* The movie is still loading, but it has started playback, and metadata is available.
|
||||
*/
|
||||
Loading = 1,
|
||||
/**
|
||||
* The movie has completely loaded.
|
||||
*/
|
||||
Loaded = 2
|
||||
}
|
||||
/**
|
||||
* Legacy interface to the Ruffle API.
|
||||
*
|
||||
* These methods are deprecated and only exist for backwards compatibility.
|
||||
* Due to the nature of Flash, they may be replaced at any time via ActionScript's `ExternalInterface` class.
|
||||
*/
|
||||
export interface LegacyRuffleAPI {
|
||||
/**
|
||||
* A movie can communicate with the hosting page using fscommand
|
||||
* as long as script access is allowed.
|
||||
*
|
||||
* @param command A string passed to the host application for any use.
|
||||
* @param args A string passed to the host application for any use.
|
||||
* @returns True if the command was handled.
|
||||
*/
|
||||
onFSCommand: ((command: string, args: string) => boolean) | null;
|
||||
/**
|
||||
* Any configuration that should apply to this specific player.
|
||||
* This will be defaulted with any global configuration.
|
||||
*/
|
||||
config: URLLoadOptions | DataLoadOptions | object;
|
||||
/**
|
||||
* The effective config loaded with the last call to `load()`.
|
||||
* If no such call has been made, this will be `null`.
|
||||
*/
|
||||
readonly loadedConfig: URLLoadOptions | DataLoadOptions | null;
|
||||
/**
|
||||
* Indicates the readiness of the playing movie.
|
||||
*
|
||||
* @returns The `ReadyState` of the player.
|
||||
*/
|
||||
get readyState(): ReadyState;
|
||||
/**
|
||||
* The metadata of the playing movie (such as movie width and height).
|
||||
* These are inherent properties stored in the SWF file and are not affected by runtime changes.
|
||||
* For example, `metadata.width` is the width of the SWF file, and not the width of the Ruffle player.
|
||||
*
|
||||
* @returns The metadata of the movie, or `null` if the movie metadata has not yet loaded.
|
||||
*/
|
||||
get metadata(): MovieMetadata | null;
|
||||
/**
|
||||
* Reloads the player, as if you called {@link load} with the same config as the last time it was called.
|
||||
*
|
||||
* If this player has never been loaded, this method will return an error.
|
||||
*/
|
||||
reload(): Promise<void>;
|
||||
/**
|
||||
* Loads a specified movie into this player.
|
||||
*
|
||||
* This will replace any existing movie that may be playing.
|
||||
*
|
||||
* @param options One of the following:
|
||||
* - A URL, passed as a string, which will load a URL with default options.
|
||||
* - A {@link URLLoadOptions} object, to load a URL with options.
|
||||
* - A {@link DataLoadOptions} object, to load data with options.
|
||||
* The options, if provided, must only contain values provided for this specific movie.
|
||||
* They must not contain any default values, since those would overwrite other configuration
|
||||
* settings with a lower priority (e.g. the general RufflePlayer config).
|
||||
*
|
||||
* The options will be defaulted by the {@link config} field, which itself
|
||||
* is defaulted by a global `window.RufflePlayer.config`.
|
||||
*/
|
||||
load(options: string | URLLoadOptions | DataLoadOptions): Promise<void>;
|
||||
/**
|
||||
* Plays or resumes the movie.
|
||||
*/
|
||||
play(): void;
|
||||
/**
|
||||
* Whether this player is currently playing.
|
||||
*
|
||||
* @returns True if this player is playing, false if it's paused or hasn't started yet.
|
||||
*/
|
||||
get isPlaying(): boolean;
|
||||
/**
|
||||
* Returns the master volume of the player.
|
||||
*
|
||||
* The volume is linear and not adapted for logarithmic hearing.
|
||||
*
|
||||
* @returns The volume. 1.0 is 100% volume.
|
||||
*/
|
||||
get volume(): number;
|
||||
/**
|
||||
* Sets the master volume of the player.
|
||||
*
|
||||
* The volume should be linear and not adapted for logarithmic hearing.
|
||||
*
|
||||
* @param value The volume. 1.0 is 100% volume.
|
||||
*/
|
||||
set volume(value: number);
|
||||
/**
|
||||
* Checks if this player is allowed to be fullscreen by the browser.
|
||||
*
|
||||
* @returns True if you may call {@link enterFullscreen}.
|
||||
*/
|
||||
get fullscreenEnabled(): boolean;
|
||||
/**
|
||||
* Checks if this player is currently fullscreen inside the browser.
|
||||
*
|
||||
* @returns True if it is fullscreen.
|
||||
*/
|
||||
get isFullscreen(): boolean;
|
||||
/**
|
||||
* Exported function that requests the browser to change the fullscreen state if
|
||||
* it is allowed.
|
||||
*
|
||||
* @param isFull Whether to set to fullscreen or return to normal.
|
||||
*/
|
||||
setFullscreen(isFull: boolean): void;
|
||||
/**
|
||||
* Requests the browser to make this player fullscreen.
|
||||
*
|
||||
* This is not guaranteed to succeed, please check {@link fullscreenEnabled} first.
|
||||
*/
|
||||
enterFullscreen(): void;
|
||||
/**
|
||||
* Requests the browser to no longer make this player fullscreen.
|
||||
*/
|
||||
exitFullscreen(): void;
|
||||
/**
|
||||
* Pauses this player.
|
||||
*
|
||||
* No more frames, scripts or sounds will be executed.
|
||||
* This movie will be considered inactive and will not wake up until resumed.
|
||||
*/
|
||||
pause(): void;
|
||||
/**
|
||||
* Sets a trace observer on this flash player.
|
||||
*
|
||||
* The observer will be called, as a function, for each message that the playing movie will "trace" (output).
|
||||
*
|
||||
* @param observer The observer that will be called for each trace.
|
||||
*/
|
||||
set traceObserver(observer: ((message: string) => void) | null);
|
||||
/**
|
||||
* Fetches the loaded SWF and downloads it.
|
||||
*/
|
||||
downloadSwf(): Promise<void>;
|
||||
/**
|
||||
* Show a dismissible message in front of the player.
|
||||
*
|
||||
* @param message The message shown to the user.
|
||||
*/
|
||||
displayMessage(message: string): void;
|
||||
}
|
38
packages/frontend/src/types/ruffle/player/movie-metadata.d.ts
vendored
Normal file
38
packages/frontend/src/types/ruffle/player/movie-metadata.d.ts
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Metadata about a loaded SWF file.
|
||||
*/
|
||||
export interface MovieMetadata {
|
||||
/**
|
||||
* The width of the movie in pixels.
|
||||
*/
|
||||
readonly width: number;
|
||||
/**
|
||||
* The height of the movie in pixels.
|
||||
*/
|
||||
readonly height: number;
|
||||
/**
|
||||
* The frame rate of the movie in frames per second.
|
||||
*/
|
||||
readonly frameRate: number;
|
||||
/**
|
||||
* The number of frames on the root timeline of the movie.
|
||||
*/
|
||||
readonly numFrames: number;
|
||||
/**
|
||||
* The SWF version of the movie.
|
||||
*/
|
||||
readonly swfVersion: number;
|
||||
/**
|
||||
* The background color of the movie as a hex string, such as "#FFFFFF".
|
||||
* May be `null` if the background color is unavailable.
|
||||
*/
|
||||
readonly backgroundColor: string | null;
|
||||
/**
|
||||
* Whether this movie is an ActionScript 3.0 movie.
|
||||
*/
|
||||
readonly isActionScript3: boolean;
|
||||
/**
|
||||
* Uncompressed length in bytes.
|
||||
*/
|
||||
readonly uncompressedLength: number;
|
||||
}
|
12
packages/frontend/src/types/ruffle/player/player-element.d.ts
vendored
Normal file
12
packages/frontend/src/types/ruffle/player/player-element.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
import type { LegacyRuffleAPI } from './legacy.d.ts';
|
||||
import type { FlashAPI } from './flash.d.ts';
|
||||
/**
|
||||
* A Ruffle player's HTML element.
|
||||
*
|
||||
* This is either created through `window.RufflePlayer.latest().createPlayer()`, or polyfilled from a `<embed>`/`<object>` tag.
|
||||
*
|
||||
* In addition to usual HTML attributes, this player contains methods and properties that belong to both
|
||||
* the **Flash JS API** and **legacy Ruffle API**s.
|
||||
*/
|
||||
export interface PlayerElement extends HTMLElement, LegacyRuffleAPI, FlashAPI {
|
||||
}
|
19
packages/frontend/src/types/ruffle/setup/index.d.ts
vendored
Normal file
19
packages/frontend/src/types/ruffle/setup/index.d.ts
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* The Setup module contains the interfaces and methods needed to install Ruffle onto a page,
|
||||
* and create a {@link PlayerElement} with the latest version of Ruffle available.
|
||||
*
|
||||
* This is primarily relevant to users of `ruffle-core` as a npm module, as the "selfhosted" version of Ruffle preinstalls itself,
|
||||
* and without type checking the interfaces here are of limited use.
|
||||
*
|
||||
* For users of `ruffle-core` as a npm module, you are encouraged to call {@link installRuffle} once during page load to
|
||||
* make the `ruffle-core` library register itself as a version of Ruffle on the page.
|
||||
*
|
||||
* Multiple sources of Ruffle may exist - for example, the Ruffle browser extension also installs itself on page load.
|
||||
* For this reason, you are required to call `window.RufflePlayer.latest()` (for example) to grab the latest {@link SourceAPI},
|
||||
* from which you can create a {@link PlayerElement} via {@link SourceAPI.createPlayer}.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
export type * from './public-api.d.ts';
|
||||
export type * from './source-api.d.ts';
|
||||
export type * from './install.d.ts';
|
28
packages/frontend/src/types/ruffle/setup/install.d.ts
vendored
Normal file
28
packages/frontend/src/types/ruffle/setup/install.d.ts
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Options to use with this specific installation of Ruffle.
|
||||
*
|
||||
* This is mostly to provide a way to configure environmental settings, like using
|
||||
* `onFirstLoad` to potentially configure webpack prior to loading wasm files.
|
||||
*/
|
||||
export interface InstallationOptions {
|
||||
/**
|
||||
* A callback to be run before the very first time Ruffle is loaded.
|
||||
* This may be used to configure a bundler prior to asset loading.
|
||||
*/
|
||||
onFirstLoad?: () => void;
|
||||
}
|
||||
/**
|
||||
* Install this version of Ruffle into the current page.
|
||||
*
|
||||
* Multiple (or zero) versions of Ruffle may be installed at the same time,
|
||||
* and you should use `window.RufflePlayer.newest()` or similar to access the appropriate
|
||||
* installation at time of use.
|
||||
*
|
||||
* @param sourceName The name of this particular
|
||||
* Ruffle source. Common convention is "local" for websites that bundle their own Ruffle,
|
||||
* "extension" for browser extensions, and something else for other use cases.
|
||||
* Names are unique, and last-installed will replace earlier installations with the same name,
|
||||
* regardless of what those installations are or which version they represent.
|
||||
* @param options Any options used to configure this specific installation of Ruffle.
|
||||
*/
|
||||
export declare function installRuffle(sourceName: string, options?: InstallationOptions): void;
|
133
packages/frontend/src/types/ruffle/setup/public-api.d.ts
vendored
Normal file
133
packages/frontend/src/types/ruffle/setup/public-api.d.ts
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
import type { SourceAPI } from './source-api.d.ts';
|
||||
import type { DataLoadOptions, URLLoadOptions } from '../config/index.d.ts';
|
||||
declare global {
|
||||
interface Window {
|
||||
/**
|
||||
* The public API for generating a ruffle player.
|
||||
* This may be a config holder, which will be converted to a
|
||||
* {@link PublicAPI} via {@link installRuffle}, or an actual
|
||||
* {@link PublicAPI} instance itself.
|
||||
*/
|
||||
RufflePlayer?: PublicAPILike | PublicAPI;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Represents a potential installation of a Ruffle public API.
|
||||
*
|
||||
* Unlike {@link PublicAPI}, this may come from any source, past or future.
|
||||
* It needs to be forwards compatible and convertible into a modern day {@link PublicAPI}.
|
||||
*/
|
||||
export interface PublicAPILike {
|
||||
config?: DataLoadOptions | URLLoadOptions | object;
|
||||
sources?: Record<string, SourceAPI>;
|
||||
invoked?: boolean;
|
||||
newestName?: string | null;
|
||||
superseded?(): void;
|
||||
}
|
||||
/**
|
||||
* Represents the Ruffle public API.
|
||||
*
|
||||
* The public API exists primarily to allow multiple installations of Ruffle on a
|
||||
* page (e.g. an extension install and a local one) to cooperate. In an ideal
|
||||
* situation, all Ruffle sources on the page install themselves into a single
|
||||
* public API, and then the public API picks the newest version by default.
|
||||
*
|
||||
* This API *is* versioned, in case we need to upgrade it. However, it must be
|
||||
* backwards- and forwards-compatible with all known sources.
|
||||
*/
|
||||
export declare class PublicAPI implements PublicAPILike {
|
||||
/**
|
||||
* The configuration object used when Ruffle is instantiated.
|
||||
*/
|
||||
config: DataLoadOptions | URLLoadOptions | object;
|
||||
sources: Record<string, SourceAPI>;
|
||||
invoked: boolean;
|
||||
newestName: string | null;
|
||||
/**
|
||||
* Construct the Ruffle public API.
|
||||
*
|
||||
* Do not use this function to negotiate a public API. Instead, use
|
||||
* `public_api` to register your Ruffle source with an existing public API
|
||||
* if it exists.
|
||||
*
|
||||
* Constructing a Public API will also trigger it to initialize Ruffle once
|
||||
* the page loads, if the API has not already been superseded.
|
||||
*
|
||||
* @param prev What used to be in the public API slot.
|
||||
*
|
||||
* This is used to upgrade from a prior version of the public API, or from
|
||||
* a user-defined configuration object placed in the public API slot.
|
||||
*/
|
||||
constructor(prev?: PublicAPILike | null);
|
||||
/**
|
||||
* The version of the public API.
|
||||
*
|
||||
* This is *not* the version of Ruffle itself.
|
||||
*
|
||||
* This allows a page with an old version of the Public API to be upgraded
|
||||
* to a new version of the API. The public API is intended to be changed
|
||||
* very infrequently, if at all, but this provides an escape mechanism for
|
||||
* newer Ruffle sources to upgrade older installations.
|
||||
*
|
||||
* @returns The version of this public API.
|
||||
*/
|
||||
get version(): string;
|
||||
/**
|
||||
* Determine the name of the newest registered source in the Public API.
|
||||
*
|
||||
* @returns The name of the source, or `null` if no source
|
||||
* has yet to be registered.
|
||||
*/
|
||||
newestSourceName(): string | null;
|
||||
/**
|
||||
* Negotiate and start Ruffle.
|
||||
*
|
||||
* This function reads the config parameter to determine which polyfills
|
||||
* should be enabled. If the configuration parameter is missing, then we
|
||||
* use a built-in set of defaults sufficient to fool sites with static
|
||||
* content and weak plugin detection.
|
||||
*/
|
||||
init(): void;
|
||||
/**
|
||||
* Look up the newest Ruffle source and return it's API.
|
||||
*
|
||||
* @returns An instance of the Source API.
|
||||
*/
|
||||
newest(): SourceAPI | null;
|
||||
/**
|
||||
* Look up a specific Ruffle version (or any version satisfying a given set
|
||||
* of requirements) and return it's API.
|
||||
*
|
||||
* @param requirementString A set of semantic version requirement
|
||||
* strings that the player version must satisfy.
|
||||
* @returns An instance of the Source API, if one or more
|
||||
* sources satisfied the requirement.
|
||||
*/
|
||||
satisfying(requirementString: string): SourceAPI | null;
|
||||
/**
|
||||
* Look up the newest Ruffle version compatible with the `local` source, if
|
||||
* it's installed. Otherwise, use the latest version.
|
||||
*
|
||||
* @returns An instance of the Source API
|
||||
*/
|
||||
localCompatible(): SourceAPI | null;
|
||||
/**
|
||||
* Look up the newest Ruffle version with the exact same version as the
|
||||
* `local` source, if it's installed. Otherwise, use the latest version.
|
||||
*
|
||||
* @returns An instance of the Source API
|
||||
*/
|
||||
local(): SourceAPI | null;
|
||||
/**
|
||||
* Indicates that this version of the public API has been superseded by a
|
||||
* newer version.
|
||||
*
|
||||
* This should only be called by a newer version of the Public API.
|
||||
* Identical versions of the Public API should not supersede older versions
|
||||
* of that same API.
|
||||
*
|
||||
* Unfortunately, we can't disable polyfills after-the-fact, so this
|
||||
* only lets you disable the init event...
|
||||
*/
|
||||
superseded(): void;
|
||||
}
|
34
packages/frontend/src/types/ruffle/setup/source-api.d.ts
vendored
Normal file
34
packages/frontend/src/types/ruffle/setup/source-api.d.ts
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
import type { PlayerElement } from '../player/index.d.ts';
|
||||
/**
|
||||
* Represents this particular version of Ruffle.
|
||||
*
|
||||
* Multiple APIs can be instantiated from different sources; e.g. an "extension"
|
||||
* version, versus a "local" version. This expresses to the Public API
|
||||
* negotiator (see {@link PublicAPI}) what this particular version of Ruffle is and
|
||||
* how to control it.
|
||||
*/
|
||||
export interface SourceAPI {
|
||||
/**
|
||||
* The version of this particular API, as a string in a semver compatible format.
|
||||
*/
|
||||
version: string;
|
||||
/**
|
||||
* Start up the polyfills.
|
||||
*
|
||||
* Do not run polyfills for more than one Ruffle source at a time.
|
||||
*/
|
||||
polyfill(): void;
|
||||
/**
|
||||
* Polyfill the plugin detection.
|
||||
*
|
||||
* This needs to run before any plugin detection script does.
|
||||
*/
|
||||
pluginPolyfill(): void;
|
||||
/**
|
||||
* Create a Ruffle player element using this particular version of Ruffle.
|
||||
*
|
||||
* @returns The player element. This is a DOM element that may be inserted
|
||||
* into the current page as you wish.
|
||||
*/
|
||||
createPlayer(): PlayerElement;
|
||||
}
|
|
@ -28,6 +28,17 @@ const externalPackages = [
|
|||
: id;
|
||||
},
|
||||
},
|
||||
// sharkey: Used for SkFlashPlayer, has large wasm files so it's loaded via Ruffle's preferred CDN
|
||||
{
|
||||
name: 'ruffle',
|
||||
match: /^@ruffle-rs\/ruffle\/?(?<file>.*)$/,
|
||||
path(id: string, pattern: RegExp): string {
|
||||
const match = pattern.exec(id)?.groups;
|
||||
return match
|
||||
? `https://esm.sh/@ruffle-rs/ruffle@${packageInfo.dependencies['@ruffle-rs/ruffle']}/${match['file']}?raw`
|
||||
: id;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const hash = (str: string, seed = 0): number => {
|
||||
|
@ -128,6 +139,7 @@ export function getConfig(): UserConfig {
|
|||
_DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'),
|
||||
__VUE_OPTIONS_API__: true,
|
||||
__VUE_PROD_DEVTOOLS__: false,
|
||||
_RUFFLE_VERSION_: JSON.stringify(packageInfo.dependencies['@ruffle-rs/ruffle'])
|
||||
},
|
||||
|
||||
build: {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -736,6 +736,9 @@ importers:
|
|||
'@rollup/pluginutils':
|
||||
specifier: 5.1.3
|
||||
version: 5.1.3(rollup@4.26.0)
|
||||
'@ruffle-rs/ruffle':
|
||||
specifier: 0.1.0-nightly.2024.10.15
|
||||
version: 0.1.0-nightly.2024.10.15
|
||||
'@syuilo/aiscript':
|
||||
specifier: 0.19.0
|
||||
version: 0.19.0
|
||||
|
@ -3556,6 +3559,9 @@ packages:
|
|||
'@rtsao/scc@1.1.0':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
'@ruffle-rs/ruffle@0.1.0-nightly.2024.10.15':
|
||||
resolution: {integrity: sha512-NBR7BIbpOLznwc7XxrCQde1UIWMjsIBsKVkr4zziqMULM+ibOc02VekQuOchHkRTLdTIZ/se2lM4IC7dNBN7vQ==}
|
||||
|
||||
'@rushstack/node-core-library@5.9.0':
|
||||
resolution: {integrity: sha512-MMsshEWkTbXqxqFxD4gcIUWQOCeBChlGczdZbHfqmNZQFLHB3yWxDFSMHFUdu2/OB9NUk7Awn5qRL+rws4HQNg==}
|
||||
peerDependencies:
|
||||
|
@ -13783,6 +13789,8 @@ snapshots:
|
|||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@ruffle-rs/ruffle@0.1.0-nightly.2024.10.15': {}
|
||||
|
||||
'@rushstack/node-core-library@5.9.0(@types/node@22.9.0)':
|
||||
dependencies:
|
||||
ajv: 8.13.0
|
||||
|
@ -19361,7 +19369,7 @@ snapshots:
|
|||
whatwg-encoding: 3.1.1
|
||||
whatwg-mimetype: 4.0.0
|
||||
whatwg-url: 14.0.0
|
||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
|
||||
xml-name-validator: 5.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
|
|
|
@ -156,6 +156,16 @@ allowClickingNotifications: "Allow clicking on pop-up notifications"
|
|||
pinnedOnly: "Pinned"
|
||||
blockingYou: "Blocking you"
|
||||
warnExternalUrl: "Show warning when opening external URLs"
|
||||
flash: "Flash"
|
||||
_flash:
|
||||
contentHidden: "Flash Content Hidden"
|
||||
poweredByRuffle: "Powered by Ruffle."
|
||||
arbitraryCodeExecutionWarning: "Always be wary of arbitrary code execution!"
|
||||
failedToLoad: "Flash Content Failed To Load:"
|
||||
isLoading: "Flash Content Is Loading"
|
||||
loadingRufflePlayer: "Loading Ruffle player"
|
||||
loadingFlashFile: "Loading Flash file"
|
||||
cspError: "raw.esm.sh could not be accessed, meaning this instance's Content Security Policy is likely out of date. Please contact your instance administrators."
|
||||
_delivery:
|
||||
stop: "Suspend delivery"
|
||||
resume: "Resume delivery"
|
||||
|
|
|
@ -142,6 +142,15 @@ sensitiveMediaRevealConfirm: "センシティブなメディアです。表示
|
|||
severAllFollowRelations: "以下の関係をすべて断ち切る"
|
||||
severAllFollowRelationsConfirm: "すべての人間関係を壊す?これは不可逆です!これは{instanceName}の{followingCount}フォローと{followersCount}フォロワーの関係を壊す!"
|
||||
severAllFollowRelationsQueued: "キューに入れられた{host}とのすべてのフォロー関係を切断する。"
|
||||
_flash:
|
||||
contentHidden: "Flashコンテンツ非表示"
|
||||
poweredByRuffle: "Powered by Ruffle." # Doesn't need a translation, apparently.
|
||||
arbitraryCodeExecutionWarning: "任意コード実行にご注意!"
|
||||
failedToLoad: "Flashコンテンツ読込に失敗"
|
||||
isLoading: "Flashコンテンツ読込中"
|
||||
loadingRufflePlayer: "Ruffleプレイヤー読込中"
|
||||
loadingFlashFile: "Flashファイル読込中"
|
||||
cspError: "raw.esm.shにアクセスできませんでした。このサーバーのコンテンツセキュリティポリシー(CSP) が廃止されている可能性があり、サーバー管理者に連絡してください。"
|
||||
_delivery:
|
||||
stop: "配信停止"
|
||||
resume: "配信再開"
|
||||
|
|
Loading…
Reference in a new issue