Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ROMM-1107] Add env variable to disable in-browser emulation #1133

Merged
merged 3 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions backend/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

load_dotenv()


def str_to_bool(value: str) -> bool:
return value.lower() in ("true", "1")


# GUNICORN
DEV_PORT: Final = int(os.environ.get("VITE_BACKEND_DEV_PORT", "5000"))
DEV_HOST: Final = "127.0.0.1"
Expand Down Expand Up @@ -53,35 +58,41 @@
ROMM_AUTH_SECRET_KEY: Final = os.environ.get(
"ROMM_AUTH_SECRET_KEY", secrets.token_hex(32)
)
DISABLE_CSRF_PROTECTION = os.environ.get("DISABLE_CSRF_PROTECTION", "false") == "true"
DISABLE_DOWNLOAD_ENDPOINT_AUTH = (
os.environ.get("DISABLE_DOWNLOAD_ENDPOINT_AUTH", "false") == "true"
DISABLE_CSRF_PROTECTION = str_to_bool(
os.environ.get("DISABLE_CSRF_PROTECTION", "false")
)
DISABLE_DOWNLOAD_ENDPOINT_AUTH = str_to_bool(
os.environ.get("DISABLE_DOWNLOAD_ENDPOINT_AUTH", "false")
)

# SCANS
SCAN_TIMEOUT: Final = int(os.environ.get("SCAN_TIMEOUT", 60 * 60 * 4)) # 4 hours

# TASKS
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE: Final = (
os.environ.get("ENABLE_RESCAN_ON_FILESYSTEM_CHANGE", "false") == "true"
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE: Final = str_to_bool(
os.environ.get("ENABLE_RESCAN_ON_FILESYSTEM_CHANGE", "false")
)
RESCAN_ON_FILESYSTEM_CHANGE_DELAY: Final = int(
os.environ.get("RESCAN_ON_FILESYSTEM_CHANGE_DELAY", 5) # 5 minutes
)
ENABLE_SCHEDULED_RESCAN: Final = (
os.environ.get("ENABLE_SCHEDULED_RESCAN", "false") == "true"
ENABLE_SCHEDULED_RESCAN: Final = str_to_bool(
os.environ.get("ENABLE_SCHEDULED_RESCAN", "false")
)
SCHEDULED_RESCAN_CRON: Final = os.environ.get(
"SCHEDULED_RESCAN_CRON",
"0 3 * * *", # At 3:00 AM every day
)
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB: Final = (
os.environ.get("ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB", "false") == "true"
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB: Final = str_to_bool(
os.environ.get("ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB", "false")
)
SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON: Final = os.environ.get(
"SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON",
"0 4 * * *", # At 4:00 AM every day
)

# EMULATION
DISABLE_EMULATOR_JS = str_to_bool(os.environ.get("DISABLE_EMULATOR_JS", "false"))
DISABLE_RUFFLE_RS = str_to_bool(os.environ.get("DISABLE_RUFFLE_RS", "false"))

# TESTING
IS_PYTEST_RUN: Final = bool(os.environ.get("PYTEST_VERSION", False))
6 changes: 6 additions & 0 deletions backend/endpoints/heartbeat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from config import (
DISABLE_EMULATOR_JS,
DISABLE_RUFFLE_RS,
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE,
ENABLE_SCHEDULED_RESCAN,
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB,
Expand Down Expand Up @@ -55,4 +57,8 @@ def heartbeat() -> HeartbeatResponse:
"MESSAGE": "Updates the Nintendo Switch TitleDB file",
},
},
"EMULATION": {
"DISABLE_EMULATOR_JS": DISABLE_EMULATOR_JS,
"DISABLE_RUFFLE_RS": DISABLE_RUFFLE_RS,
},
}
6 changes: 6 additions & 0 deletions backend/endpoints/responses/heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class MetadataSourcesDict(TypedDict):
STEAMGRIDDB_ENABLED: bool


class EmulationDict(TypedDict):
DISABLE_EMULATOR_JS: bool
DISABLE_RUFFLE_RS: bool


class HeartbeatResponse(TypedDict):
VERSION: str
SHOW_SETUP_WIZARD: bool
Expand All @@ -30,3 +35,4 @@ class HeartbeatResponse(TypedDict):
ANY_SOURCE_ENABLED: bool
METADATA_SOURCES: MetadataSourcesDict
FS_PLATFORMS: list
EMULATION: EmulationDict
4 changes: 4 additions & 0 deletions env.template
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ ENABLE_SCHEDULED_RESCAN=true
SCHEDULED_RESCAN_CRON=0 3 * * *
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB=true
SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON=0 4 * * *

# In-browser emulation
DISABLE_EMULATOR_JS=false
DISABLE_RUFFLE_RS=false
2 changes: 2 additions & 0 deletions frontend/src/__generated__/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions frontend/src/__generated__/models/EmulationDict.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/src/__generated__/models/HeartbeatResponse.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/src/__generated__/models/TinfoilFeedSchema.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions frontend/src/__generated__/models/TinfoilFeedTitleDBSchema.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 16 additions & 5 deletions frontend/src/components/Details/ActionBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@ import AdminMenu from "@/components/common/Game/AdminMenu.vue";
import romApi from "@/services/api/rom";
import storeDownload from "@/stores/download";
import type { DetailedRom } from "@/stores/roms";
import storeHeartbeat from "@/stores/heartbeat";
import type { Events } from "@/types/emitter";
import { getDownloadLink, isEJSEmulationSupported, isRuffleEmulationSupported } from "@/utils";
import {
getDownloadLink,
isEJSEmulationSupported,
isRuffleEmulationSupported,
} from "@/utils";
import type { Emitter } from "mitt";
import { inject, ref } from "vue";
import { inject, ref, computed } from "vue";

// Props
const props = defineProps<{ rom: DetailedRom }>();
const downloadStore = storeDownload();
const heartbeatStore = storeHeartbeat();
const emitter = inject<Emitter<Events>>("emitter");
const playInfoIcon = ref("mdi-play");
const ejsEmulationSupported = isEJSEmulationSupported(props.rom.platform_slug);
const ruffleEmulationSupported = isRuffleEmulationSupported(props.rom.platform_slug);

const ejsEmulationSupported = computed(() =>
isEJSEmulationSupported(props.rom.platform_slug, heartbeatStore.value),
);
const ruffleEmulationSupported = computed(() =>
isRuffleEmulationSupported(props.rom.platform_slug, heartbeatStore.value),
);

// Functions
async function copyDownloadLink(rom: DetailedRom) {
Expand All @@ -26,7 +37,7 @@ async function copyDownloadLink(rom: DetailedRom) {
getDownloadLink({
rom,
files: downloadStore.filesToDownload,
})
}),
);
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(downloadLink);
Expand Down
34 changes: 24 additions & 10 deletions frontend/src/components/common/Game/Card/ActionBar.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
<script setup lang="ts">
import { computed } from "vue";
import AdminMenu from "@/components/common/Game/AdminMenu.vue";
import romApi from "@/services/api/rom";
import storeDownload from "@/stores/download";
import storeHeartbeat from "@/stores/heartbeat";
import type { SimpleRom } from "@/stores/roms";
import { isEJSEmulationSupported, isRuffleEmulationSupported } from "@/utils";

// Props
defineProps<{ rom: SimpleRom }>();
const props = defineProps<{ rom: SimpleRom }>();
const downloadStore = storeDownload();
const heartbeatStore = storeHeartbeat();

const ejsEmulationSupported = computed(() => {
return isEJSEmulationSupported(props.rom.platform_slug, heartbeatStore.value);
});

const ruffleEmulationSupported = computed(() => {
return isRuffleEmulationSupported(
props.rom.platform_slug,
heartbeatStore.value,
);
});
</script>

<template>
<v-row no-gutters>
<v-col>
<v-col class="d-flex">
<v-btn
class="action-bar-btn-small"
class="action-bar-btn-small flex-grow-1"
size="x-small"
:disabled="downloadStore.value.includes(rom.id)"
icon="mdi-download"
Expand All @@ -23,10 +37,10 @@ const downloadStore = storeDownload();
@click="romApi.downloadRom({ rom })"
/>
</v-col>
<v-col>
<v-col class="d-flex">
<v-btn
v-if="isEJSEmulationSupported(rom.platform_slug)"
class="action-bar-btn-small"
v-if="ejsEmulationSupported"
class="action-bar-btn-small flex-grow-1"
size="x-small"
@click="
$router.push({
Expand All @@ -39,8 +53,8 @@ const downloadStore = storeDownload();
variant="text"
/>
<v-btn
v-if="isRuffleEmulationSupported(rom.platform_slug)"
class="action-bar-btn-small"
v-if="ruffleEmulationSupported"
class="action-bar-btn-small flex-grow-1"
size="x-small"
@click="
$router.push({
Expand All @@ -56,7 +70,7 @@ const downloadStore = storeDownload();
<v-menu location="bottom">
<template #activator="{ props }">
<v-btn
class="action-bar-btn-small"
class="action-bar-btn-small flex-grow-1"
size="x-small"
v-bind="props"
icon="mdi-dots-vertical"
Expand All @@ -71,7 +85,7 @@ const downloadStore = storeDownload();

<style scoped>
.action-bar-btn-small {
max-width: 22px;
max-height: 30px;
width: unset;
}
</style>
22 changes: 18 additions & 4 deletions frontend/src/components/common/Game/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import RAvatar from "@/components/common/Game/RAvatar.vue";
import romApi from "@/services/api/rom";
import storeDownload from "@/stores/download";
import storeRoms, { type SimpleRom } from "@/stores/roms";
import storeHeartbeat from "@/stores/heartbeat";
import type { Events } from "@/types/emitter";
import {
formatBytes,
Expand All @@ -30,6 +31,7 @@ const router = useRouter();
const route = useRoute();
const downloadStore = storeDownload();
const romsStore = storeRoms();
const heartbeatStore = storeHeartbeat();
const page = ref(parseInt(window.location.hash.slice(1)) || 1);
const storedRomsPerPage = parseInt(localStorage.getItem("romsPerPage") ?? "");
const itemsPerPage = ref(isNaN(storedRomsPerPage) ? 25 : storedRomsPerPage);
Expand Down Expand Up @@ -82,14 +84,22 @@ function rowClick(_: Event, row: { item: SimpleRom }) {

function updateDataTablePages() {
pageCount.value = Math.ceil(
romsStore.filteredRoms.length / itemsPerPage.value
romsStore.filteredRoms.length / itemsPerPage.value,
);
}

function updateUrlHash() {
window.location.hash = String(page.value);
}

function checkIfEJSEmulationSupported(platformSlug: string) {
return isEJSEmulationSupported(platformSlug, heartbeatStore.value);
}

function checkIfRuffleEmulationSupported(platformSlug: string) {
return isRuffleEmulationSupported(platformSlug, heartbeatStore.value);
}

watch(itemsPerPage, async () => {
localStorage.setItem("romsPerPage", itemsPerPage.value.toString());
updateDataTablePages();
Expand Down Expand Up @@ -137,7 +147,11 @@ onMounted(() => {
>
<template #append>
<v-chip
v-if="item.sibling_roms && item.sibling_roms.length > 0 && showSiblings"
v-if="
item.sibling_roms &&
item.sibling_roms.length > 0 &&
showSiblings
"
class="translucent-dark ml-2"
size="x-small"
>
Expand Down Expand Up @@ -176,7 +190,7 @@ onMounted(() => {
<v-icon>mdi-download</v-icon>
</v-btn>
<v-btn
v-if="isEJSEmulationSupported(item.platform_slug)"
v-if="checkIfEJSEmulationSupported(item.platform_slug)"
size="small"
@click.stop="
$router.push({
Expand All @@ -188,7 +202,7 @@ onMounted(() => {
<v-icon>mdi-play</v-icon>
</v-btn>
<v-btn
v-if="isRuffleEmulationSupported(item.platform_slug)"
v-if="checkIfRuffleEmulationSupported(item.platform_slug)"
size="small"
@click.stop="
$router.push({
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/stores/heartbeat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { HeartbeatResponse } from "@/__generated__";
import { defineStore } from "pinia";
import { computed } from "vue";

export type Heartbeat = HeartbeatResponse;

export default defineStore("heartbeat", {
state: () => {
return { value: {} as HeartbeatResponse };
Expand Down
Loading
Loading