Updated to Bootstrap 5.3, added more playlist logic, cleanup

This commit is contained in:
itdominator 2023-02-06 17:49:53 -06:00
parent 20800fc750
commit ae0486f020
27 changed files with 251 additions and 489 deletions

Binary file not shown.

Before

(image error) Size: 1.4 MiB

After

(image error) Size: 1.3 MiB

Binary file not shown.

Before

(image error) Size: 1.1 MiB

After

(image error) Size: 1.3 MiB

Binary file not shown.

Before

(image error) Size: 1.0 MiB

After

(image error) Size: 1.0 MiB

Binary file not shown.

Before

(image error) Size: 541 KiB

After

(image error) Size: 370 KiB

Binary file not shown.

Before

(image error) Size: 363 KiB

After

(image error) Size: 299 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -20,16 +20,11 @@
}
#master-container {
height: 80vh;
height: 85vh;
overflow-x: hidden;
overflow-y: auto;
}
#video-controls {
background-color: rgba(0, 0, 0, 0.64);
}
/* CLASSES */
.scroller {
@ -47,6 +42,9 @@
supported by Chrome, Edge, Opera and Firefox */
}
.selectedActiveMedia {
background-color: rgba(25, 65, 0, 0.64);
}
.page-alert-zone-container {
position: sticky;

View File

@ -47,7 +47,8 @@ input[type=range][orient=vertical] {
.modal-header {
.modal-header,
.modal-footer {
background-color: rgba(0, 0, 0, 0.64);
}
@ -56,11 +57,6 @@ input[type=range][orient=vertical] {
border-color: rgba(249, 148, 6, 0.74);
}
.sticky-top,
.card {
background-color: rgba(50, 56, 62, 0.84);
}
.card-body {
min-height: 326px;
font-size: x-large;
@ -74,10 +70,6 @@ input[type=range][orient=vertical] {
object-fit: contain;
}
.list-group-item {
color: rgba(255, 255, 255, 1) !important;
}
.label-as-badge {
border-radius: 1em;
cursor: pointer;

View File

@ -1,5 +1,7 @@
const goHomeAjax = async (hash) => {
const data = "empty=NULL";
clearPlaylistMode();
clearSelectedActiveMedia();
doAjax("api/file-manager-action/reset-path/None", data, "reset-path");
}
@ -10,6 +12,8 @@ const deleteItemAjax = async (hash) => {
const listFilesAjax = async (hash) => {
const data = "empty=NULL";
clearPlaylistMode();
clearSelectedActiveMedia();
doAjax("api/list-files/" + hash, data, "list-files");
}
@ -20,6 +24,8 @@ const getFavesAjax = async () => {
const loadFavoriteLink = async (id) => {
const data = "empty=NULL";
clearPlaylistMode();
clearSelectedActiveMedia();
doAjax("api/load-favorite/" + id, data, "load-favorite");
}
@ -111,6 +117,19 @@ const doAjaxUpload = (actionPath, data, fname, action) => {
}
const fetchData = async (url) => {
let response = await fetch(url);
return await response.json();
return await fetch(url).then((response) => {
if(response.status == 200) {
return response.json();
} else if (response.status == 504) {
msg = "[Warning] Status Code: 504 Timeout\n[Message] --> Please wait for conversion to complete then try again.";
return {'message': { 'type': "warning", 'text': msg} }
} else {
msg = "[Error] Status Code: " + response.status + "\n[Message] --> Network response was not ok...";
return {'message': { 'type': "error", 'text': msg} }
}
}).catch(function(error) {
let subStr1 = 'There has been a problem with your fetch operation: ' + error.message;
msg = "[Error] Status Code: 000\n[Message] -->" + subStr1;
return {'message': { 'type': "error", 'text': msg} }
});
}

View File

@ -0,0 +1,60 @@
/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2022 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
*/
(() => {
'use strict'
const storedTheme = localStorage.getItem('theme')
const getPreferredTheme = () => {
if (storedTheme) {
return storedTheme
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
const setTheme = function (theme) {
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}
setTheme(getPreferredTheme())
const showActiveTheme = theme => {
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
})
btnToActive.classList.add('active')
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (storedTheme !== 'light' || storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())
document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
localStorage.setItem('theme', theme)
setTheme(theme)
showActiveTheme(theme)
})
})
})
})()

View File

@ -21,7 +21,6 @@ document.body.onload = (eve) => {
}, 400);
}
const loadFavePath = (e) => {
const target = e.target;
const faveId = target.getAttribute("faveid");
@ -42,7 +41,7 @@ const openFile = (eve) => {
if (ftype === "dir") {
listFilesAjax(hash);
} else if (ftype === "video") {
showFile(title, hash, extension, "video");
showFile(title, hash, extension, "video", target);
} else {
showFile(title, hash, extension, "file");
}
@ -84,3 +83,7 @@ $( "#scroll-files-to-top-btn" ).bind( "click", async function(eve) {
$( "#playlist-mode-btn").bind( "click", async function(eve) {
togglePlaylistMode(eve.target);
});
$( "#close-file-modal-btn").bind( "click", async function(eve) {
closeFile();
});

File diff suppressed because one or more lines are too long

19
src/core/static/js/libs/dash.all.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -65,10 +65,11 @@ const closeFile = () => {
trailerPlayer.src = "#";
trailerPlayer.style.display = "none";
clearSelectedActiveMedia();
clearModalFades();
}
const showFile = async (title, hash, extension, type) => {
const showFile = async (title, hash, extension, type, target=null) => {
document.getElementById("image-viewer").style.display = "none";
document.getElementById("text-viewer").style.display = "none";
document.getElementById("pdf-viewer").style.display = "none";
@ -80,6 +81,7 @@ const showFile = async (title, hash, extension, type) => {
if (type === "video") {
setupVideo(hash, extension);
setSelectedActiveMedia(target);
}
if (type === "file") {
setupFile(hash, extension);
@ -106,7 +108,7 @@ const setupVideo = async (hash, extension) => {
video.src = "#"
video_path = "api/file-manager-action/files/" + hash;
clearSelectedActiveMedia();
try {
if ((/\.(avi|mkv|wmv|flv|f4v|mov|m4v|mpg|mpeg|mp4|webm|mp3|flac|ogg)$/i).test(extension)) {
if ((/\.(avi|mkv|wmv|flv|f4v)$/i).test(extension)) {
@ -114,7 +116,7 @@ const setupVideo = async (hash, extension) => {
if ( data.hasOwnProperty('path') ) {
video_path = data.path;
} else {
displayMessage(data.message.text, data.message.type, 3);
displayMessage(data.message.text, data.message.type);
return;
}
} else if ((/\.(flv|mov|m4v|mpg|mpeg)$/i).test(extension)) {
@ -293,6 +295,33 @@ const clearModalFades = (elm) => {
}
}
const clearPlaylistMode = () => {
const playListState = document.getElementById("playlist-mode-btn");
if (playListState.checked) { playListState.click(); }
}
const setSelectedActiveMedia = (elm) => {
clearSelectedActiveMedia();
let card = elm;
while (card.parentElement) {
if (!card.classList.contains("card")) {
card = card.parentElement;
continue;
}
break
}
card.classList.add("selectedActiveMedia");
}
const clearSelectedActiveMedia = () => {
try {
const elm = document.getElementsByClassName('selectedActiveMedia')[0];
elm.classList.remove("selectedActiveMedia");
} catch (e) {}
}
// Cache Buster
const clearCache = () => {
const rep = /.*\?.*/;

View File

@ -79,22 +79,35 @@ const toggleFullscreen = (video) => {
const toggleVolumeControl = () => {
const volume = document.getElementById("volume-slider");
if (volume.style.display === "none") {
volume.style.display = "";
} else {
volume.style.display = "none";
volume.style.display = (volume.style.display === "none") ? "" : "none";
}
const togglePlaylistMode = (elm) => {
playListMode = elm.checked;
}
const previousMedia = () => {
const current_title = document.getElementById('selectedFile').innerText;
for (let i = videoPlaylist.length - 1; i >= 0; i--) {
if (videoPlaylist[i].title === current_title) {
const index = (i === 0) ? videoPlaylist.length - 1 : i-=1;
clearModalFades();
videoPlaylist[index].click();
break
}
}
}
const togglePlaylistMode = (elm) => {
const classType = "btn-info";
const hasClass = elm.classList.contains(classType);
if (playListMode) {
elm.classList.remove(classType);
playListMode = false;
} else {
elm.classList.add(classType);
playListMode = true;
const nextMedia = () => {
const current_title = document.getElementById('selectedFile').innerText;
for (let i = 0; i < videoPlaylist.length; i++) {
if (videoPlaylist[i].title === current_title) {
const index = (i === videoPlaylist.length) ? 0 : i+=1;
clearModalFades();
videoPlaylist[index].click();
break
}
}
}
@ -196,6 +209,10 @@ $( "#video" ).bind( "timeupdate", async function(eve) {
videoDuration.innerText = getTimeFormatted(video.currentTime);
});
$( "#video").bind( "stalled", async function(eve) {
console.log("Stalled load...");
});
$( "#seek-slider").bind( "change", async function(eve) {
const slider = eve.target;
let video = document.getElementById("video");
@ -221,14 +238,16 @@ $( "#video" ).bind( "ended", async function(eve) {
videoDuration.innerText = getTimeFormatted(video.currentTime);
video.play();
} else {
const current_title = document.getElementById('selectedFile').innerText;
for (let i = 0; i < videoPlaylist.length; i++) {
if (videoPlaylist[i].title === current_title) {
const index = (i === videoPlaylist.length) ? 0 : i+=1;
clearModalFades();
videoPlaylist[index].click();
break
}
}
nextMedia();
}
});
$( "#previousVideoInPlaylist").bind( "click", async function(eve) {
previousMedia();
});
$( "#nextVideoInPlaylist").bind( "click", async function(eve) {
nextMedia();
});

View File

@ -1,91 +0,0 @@
/*START OF HOMEPAGE BUTTON SETTINGS*/
.homeSection {
float: left;
width: 40%;
height: 14em;
position: relative;
text-align: center;
font-size: 100%;
border-style: solid;
border-width: .2em;
color: rgba(0, 232, 255, .69); /*#00E8FF*/
background: rgba(19, 21, 21, .6);
}
/*END OF HOMEPAGE BUTTON SETTINGS*/
.header {
margin-left: auto;
margin-right: auto;
width: 99%;
}
.section, .lnksNdirs, .header {
display: block;
float: left;
text-align: center;
font-size: 100%;
padding-top: 1em;
margin: 1em;
background: rgba(19, 21, 21, .7);
color: rgba(0, 232, 255, .69); /*#00E8FF*/
/* border-style: solid;
border-width: .2em;
*/
}
.backbutton {
top: 3.55em;
clear: both;
z-index: 2;
position: fixed;
float: left;
width: 5%;
height: 50px;
opacity: .8;
}
iframe {
position: fixed;
bottom: 2em;
left: 25%;
width: 50%;
height: 360px;
background: rgba(0,0,0,.5);
transition: 0s;
transition-delay:2s;
}
iframe:hover {
left: 2%;
width: 99%;
height: 700px;
transition-delay:2s;
}
.lnkStyl {
clear: right;
float: left;
border-style: solid;
}
.imgsStyl {
margin-left: 50%;
opacity: 0.699999988079071044921875;
width: 32.333%;
height: 20em;
}
.imgsStyl:hover {
opacity: 1;
}
#bg {
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index: -1;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: -1;
}

View File

@ -1,89 +0,0 @@
body {
width: 600%;
}
/*START OF HOMEPAGE BUTTON SETTINGS*/
.homeSection {
float: left;
width: 40%;
height: 14em;
position: relative;
text-align: center;
font-size: 100%;
border-style: solid;
border-width: .2em;
color: rgba(0, 232, 255, .69); /*#00E8FF*/
background: rgba(19, 21, 21, .6);
}
/*END OF HOMEPAGE BUTTON SETTINGS*/
.header {
margin-left: auto;
margin-right: auto;
width: 99%;
}
.section, .lnksNdirs, .header {
display: block;
clear: right;
float: left;
text-align: center;
font-size: 100%;
padding-top: 1em;
margin: 1em;
background: rgba(19, 21, 21, .7);
color: rgba(0, 232, 255, .69); /*#00E8FF*/
/* border-style: solid;
border-width: .2em;
*/
}
.backbutton {
top: 3.55em;
clear: both;
z-index: 2;
position: fixed;
float: left;
width: 5%;
height: 50px;
opacity: .8;
}
iframe {
position: fixed;
bottom: 2em;
left: 25%;
width: 50%;
height: 360px;
background: rgba(0,0,0,.5)
transition: 0s;
transition-delay:2s;
}
.lnkStyl {
clear: right;
float: left;
border-style: solid;
}
.imgsStyl {
margin-left: 50%;
opacity: 0.699999988079071044921875;
width: 32.333%;
height: 20em;
}
.imgsStyl:hover {
opacity: 1;
}
#bg {
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index: -1;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: -1;
}

View File

@ -1,89 +0,0 @@
/*START OF HOMEPAGE BUTTON SETTINGS*/
.homeSection {
float: left;
width: 40%;
height: 14em;
position: relative;
text-align: center;
font-size: 100%;
border-style: solid;
border-width: .2em;
color: rgba(0, 232, 255, .69); /*#00E8FF*/
background: rgba(19, 21, 21, .6);
}
/*END OF HOMEPAGE BUTTON SETTINGS*/
.header {
margin-left: auto;
margin-right: auto;
width: 99%;
}
.section, .lnksNdirs, .header {
position: relative;
text-align: center;
font-size: 100%;
padding-top: 1em;
margin-top: 1em;
background: rgba(19, 21, 21, .7);
color: rgba(0, 232, 255, .69); /*#00E8FF*/
/* border-style: solid;
border-width: .2em;
*/
}
.backbutton {
top: 3.55em;
clear: both;
z-index: 2;
position: fixed;
float: left;
width: 5%;
height: 50px;
opacity: .8;
}
iframe {
clear: both;
z-index: 1;
position: fixed;
bottom: 5%;
width: 40%;
height: 500px;
background: rgba(0,0,0,.5)
transition: 0s;
transition-delay:2s;
}
iframe:hover {
width: 99%;
transition-delay:2s;
}
.lnkStyl {
clear: right;
float: left;
border-style: solid;
}
.imgsStyl {
margin-left: 50%;
opacity: 0.699999988079071044921875;
width: 32.333%;
height: 20em;
}
.imgsStyl:hover {
opacity: 1;
}
#bg {
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index: -1;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: -1;
}

View File

@ -1,110 +0,0 @@
/*START OF HOMEPAGE BUTTON SETTINGS*/
.homeSection {
float: left;
width: 40%;
height: 14em;
position: relative;
text-align: center;
font-size: 100%;
border-style: solid;
border-width: .2em;
color: rgba(0, 232, 255, .69); /*#00E8FF*/
background: rgba(19, 21, 21, .6);
}
/*END OF HOMEPAGE BUTTON SETTINGS*/
.lnkStyl {
clear: right;
float: left;
border-style: solid;
}
.imgsStyl {
clear: both;
float: left;
opacity: 0.699999988079071044921875;
width: 20%;
height: 15em;
}
.imgsStyl:hover {
opacity: 1;
}
.header {
margin-left: auto;
margin-right: auto;
width: 100%;
float: left;
}
.lnksNdirs {
width: 20%;
float:left;
}
/* used to format sections of pgs*/
.section, .lnksNdirs, .header {
clear: both;
position: relative;
text-align: center;
padding-top: 1em;
margin-top: 1em;
font-size: 100%;
background: rgba(19, 21, 21, .6);
background: rgba(19, 21, 21, .7);
color: rgba(0, 232, 255, .69); /*#00E8FF*/
/* border-style: solid;
border-width: .2em;
*/
}
.backbutton {
top: 3em;
clear: both;
z-index: 2;
position: fixed;
float: left;
width: 5%;
height: 55px;
opacity: .8;
}
.ifrmbutton2 {
top: 3em;
float: right;
right: .5em;
z-index:2;
position: fixed;
width: 5%;
height: 30px;
opacity: .6;
}
iframe {
margin-left: 2%;
z-index: 2;
position: fixed;
top: 8em;
right: 0.534em;
bottom: 2%;
width: 75%;
height: 525px;
background: rgba(0,0,0,.5)
transition: 0s;
transition-delay:2s;
}
iframe:hover {
height: 775px;
transition-delay:2s;
}
#bg {
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index: -1;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: -1;
}

View File

@ -8,7 +8,7 @@
<div id="navbarTogglerFooter" class="row collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item mr-2">
<li class="nav-item mx-3">
<span id="tggl-faves-btn" class="btn btn-info btn-sm" title="Add/Delete from favorites..." >&#9734;</span>
</li>
<li class="nav-item mx-auto">

View File

@ -35,9 +35,15 @@
</i>
</li>
<li class="nav-item">
<i id="playlist-mode-btn" class="nav-link" aria-label="Playlist Mode" title="Playlist Mode..." >
<div class="ml-2 mt-2 form-check">
<input class="form-check-input" type="checkbox" value="" id="playlist-mode-btn">
<label class="form-check-label" for="playlist-mode-btn">
Playlist Mode
</i>
</label>
</div>
<!-- <i id="playlist-mode-btn" class="nav-link" aria-label="Playlist Mode" title="Playlist Mode..." >
Playlist Mode
</i> -->
</li>
</ul>
</div>
@ -93,6 +99,32 @@
</div>
</li>
{% endif %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-bs-toggle="dropdown">
Theme
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme" style="--bs-dropdown-min-width: 8rem;">
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light">
<i title="Register A User..." class="bi bi-brightness-high"></i>
&nbsp;&nbsp;&nbsp;&nbsp;Light
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="dark">
<i title="Register A User..." class="bi bi-brightness-low"></i>
&nbsp;&nbsp;&nbsp;&nbsp;Dark
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto">
<i title="Register A User..." class="bi bi-brightness-high"></i>
&nbsp;&nbsp;&nbsp;&nbsp;Auto&nbsp;&nbsp;&nbsp;&nbsp;
<i title="Register A User..." class="bi bi-brightness-low"></i>
</button>
</li>
</ul>
</li>
</ul>
</div>
</div>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<html lang="en" dir="ltr" data-bs-theme="dark">
{% block header %}
<head>
{% block header_meta %}
@ -21,7 +21,6 @@
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap5/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap5/bootstrap-dark.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-icons/bootstrap-icons.css')}}">
<!-- Site CSS -->
@ -113,14 +112,18 @@
<script src="{{ url_for('static', filename='js/libs/bootstrap5/bootstrap.bundle.min.js')}}"></script>
<!-- For React -->
<script src="{{ url_for('static', filename='js/libs/babel.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/libs/react/react.production.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/libs/react/react-dom.production.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/libs/babel.min.js')}}"></script>
<!-- DASH JS -->
<script src="{{ url_for('static', filename='js/libs/dash.all.min.js')}}" type="text/javascript"></script>
<!-- Application Imports -->
{% block body_scripts_additional %}
{% endblock body_scripts_additional%}
<script src="{{ url_for('static', filename='js/color-mode-toggler.js')}}"></script>
<script src="{{ url_for('static', filename='js/context-menu.js')}}"></script>
{% endblock %}
</body>

View File

@ -5,9 +5,7 @@
<div class="modal-content">
<div class="modal-header">
<h3>Favorites:</h3>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">

View File

@ -4,8 +4,11 @@
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h3>File Viewer:</h3> <span id="selectedFile"></span>
<button onclick="closeFile()" type="button" data-bs-dismiss="modal" class="btn btn-danger btn-sm">Close</button>
<h3>File Viewer:</h3>
<button id="previousVideoInPlaylist" class="btn btn-dark btn-sm">Previous</button>
<span id="selectedFile"></span>
<button id="nextVideoInPlaylist" class="btn btn-dark btn-sm">Next</button>
<button id="close-file-modal-btn" class="btn btn-danger btn-sm" type="button" data-bs-dismiss="modal">Close</button>
</div>
<div class="modal-body text-center justify-content-center">

View File

@ -5,9 +5,7 @@
<div class="modal-content">
<div class="modal-header">
<h3>Settings:</h3>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">

View File

@ -25,26 +25,6 @@
{% block body_scripts_additional %}
<!-- GBA JS Emulator -->
<script src="{{ url_for('static', filename='js/gbajs/js/util.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/core.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/arm.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/thumb.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/mmu.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/io.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/audio.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/video.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/video/proxy.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/video/software.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/irq.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/keypad.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/sio.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/savedata.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/gpio.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/js/gba.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/xhr.js')}}"></script>
<script src="{{ url_for('static', filename='js/gbajs/gbajs.js')}}"></script>
<!-- App JS -->
<script type="text/jsx" src="{{ url_for('static', filename='js/react-ui-logic.js')}}"></script>
<script src="{{ url_for('static', filename='js/ui-logic.js')}}"></script>