mirror of
https://github.com/rommapp/romm.git
synced 2026-02-18 00:27:41 +01:00
Refactor socket connections
This commit is contained in:
@@ -35,9 +35,8 @@ async def updateRom(req: Request, p_slug: str, id: int) -> dict:
|
||||
try:
|
||||
fs.rename_rom(platform.fs_slug, db_rom.file_name, updated_rom['file_name'])
|
||||
except RomAlreadyExistsException as e:
|
||||
error: str = f"{e}"
|
||||
log.error(error)
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=error)
|
||||
log.error(str(e))
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
||||
updated_rom['file_name_no_tags'] = get_file_name_with_no_tags(updated_rom['file_name'])
|
||||
updated_rom.update(fs.get_cover(True, p_slug, updated_rom['file_name'], updated_rom['url_cover']))
|
||||
updated_rom.update(fs.get_screenshots(p_slug, updated_rom['file_name'], updated_rom['url_screenshots']))
|
||||
@@ -58,7 +57,7 @@ def delete_rom(p_slug: str, id: int, filesystem: bool=False) -> dict:
|
||||
platform: Platform = dbh.get_platform(p_slug)
|
||||
fs.remove_rom(platform.fs_slug, rom.file_name)
|
||||
except RomNotFoundError as e:
|
||||
error: str = f"{e}. Couldn't delete from filesystem."
|
||||
error = f"Couldn't delete from filesystem: {str(e)}"
|
||||
log.error(error)
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error)
|
||||
return {'msg': f'{rom.file_name} deleted successfully!'}
|
||||
|
||||
@@ -9,7 +9,7 @@ from models.platform import Platform
|
||||
from models.rom import Rom
|
||||
|
||||
|
||||
async def scan(sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
async def scan(_sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
"""Scan platforms and roms and write them in database."""
|
||||
|
||||
log.info(emoji.emojize(":magnifying_glass_tilted_right: Scanning "))
|
||||
@@ -18,7 +18,7 @@ async def scan(sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
try: # Scanning platforms
|
||||
fs_platforms: list[str] = fs.get_platforms()
|
||||
except PlatformsNotFoundException as e:
|
||||
log.error(e); await sm.emit('done_ko', e.message); return
|
||||
log.error(e); await sm.emit('scan:done_ko', e.message); return
|
||||
|
||||
platforms: list[str] = json.loads(platforms) if len(json.loads(platforms)) > 0 else fs_platforms
|
||||
log.info(f"Platforms to be scanned: {', '.join(platforms)}")
|
||||
@@ -28,7 +28,7 @@ async def scan(sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
scanned_platform: Platform = fastapi.scan_platform(platform)
|
||||
except RomsNotFoundException as e:
|
||||
log.error(e); continue
|
||||
await sm.emit('scanning_platform', [scanned_platform.name, scanned_platform.slug]); await sm.emit('') # Workaround to emit in real-time
|
||||
await sm.emit('scan:scanning_platform', [scanned_platform.name, scanned_platform.slug]); await sm.emit('') # Workaround to emit in real-time
|
||||
if platform != str(scanned_platform): log.info(f"Identified as {COLORS['blue']}{scanned_platform}{COLORS['reset']}")
|
||||
dbh.add_platform(scanned_platform)
|
||||
|
||||
@@ -37,7 +37,7 @@ async def scan(sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
for rom in fs_roms:
|
||||
rom_id: int = dbh.rom_exists(scanned_platform.slug, rom['file_name'])
|
||||
if rom_id and not complete_rescan: continue
|
||||
await sm.emit('scanning_rom', rom['file_name']); await sm.emit('') # Workaround to emit in real-time
|
||||
await sm.emit('scan:scanning_rom', rom['file_name']); await sm.emit('') # Workaround to emit in real-time
|
||||
log.info(f"Scanning {COLORS['orange']}{rom['file_name']}{COLORS['reset']}")
|
||||
if rom['multi']: [log.info(f"\t - {COLORS['orange_i']}{file}{COLORS['reset']}") for file in rom['files']]
|
||||
scanned_rom: Rom = fastapi.scan_rom(scanned_platform, rom)
|
||||
@@ -45,4 +45,4 @@ async def scan(sid: str, platforms: str, complete_rescan: bool=True, sm=None):
|
||||
dbh.add_rom(scanned_rom)
|
||||
dbh.purge_roms(scanned_platform.slug, [rom['file_name'] for rom in fs_roms])
|
||||
dbh.purge_platforms(fs_platforms)
|
||||
await sm.emit('done')
|
||||
await sm.emit('scan:done')
|
||||
|
||||
@@ -27,9 +27,8 @@ class DBHandler:
|
||||
|
||||
@staticmethod
|
||||
def raise_error(e: Exception) -> None:
|
||||
error: str = f"{e}"
|
||||
log.critical(error)
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=error)
|
||||
log.critical(str(e))
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
||||
|
||||
|
||||
# ========= Platforms =========
|
||||
|
||||
@@ -21,8 +21,12 @@ app.include_router(rom.router)
|
||||
sm = SocketManager()
|
||||
sm.mount_to("/ws", app)
|
||||
|
||||
async def scan_handler(*args): await scan.scan(*args, sm)
|
||||
sm.on('scan', handler=scan_handler)
|
||||
|
||||
async def scan_handler(*args):
|
||||
await scan.scan(*args, sm)
|
||||
|
||||
|
||||
sm.on("scan", handler=scan_handler)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
@@ -31,6 +35,6 @@ def startup() -> None:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("main:app", host=DEV_HOST, port=DEV_PORT, reload=True)
|
||||
# uvicorn.run("main:app", host=DEV_HOST, port=DEV_PORT, reload=False, workers=2)
|
||||
|
||||
@@ -1,26 +1,85 @@
|
||||
import re
|
||||
|
||||
|
||||
LANGUAGES = [
|
||||
"Ar",
|
||||
"Da",
|
||||
"De",
|
||||
"En",
|
||||
"En-US",
|
||||
"Es",
|
||||
"Fi",
|
||||
"Fr",
|
||||
"It",
|
||||
"Ja",
|
||||
"Ko",
|
||||
"Nl",
|
||||
"Pl",
|
||||
"Pt",
|
||||
"Pt-BR",
|
||||
"Ru",
|
||||
"Sv",
|
||||
"Zh",
|
||||
"Zh-Hans",
|
||||
"Zh-Hant",
|
||||
"nolang",
|
||||
]
|
||||
|
||||
REGIONS = [
|
||||
("U", "USA"),
|
||||
("E", "Europe"),
|
||||
("J", "Japan"),
|
||||
("K", "Korea"),
|
||||
("T", "Taiwan"),
|
||||
("G", "Germany"),
|
||||
("B", "Brazil"),
|
||||
("A", "Australia"),
|
||||
("CH", "China"),
|
||||
("NL", "Netherlands"),
|
||||
("PD", "Public Domain"),
|
||||
("F", "France"),
|
||||
("S", "Spain"),
|
||||
("W", "World"),
|
||||
("C", "Canada"),
|
||||
("SW", "Sweden"),
|
||||
("FN", "Finland"),
|
||||
("UK", "England"),
|
||||
("GR", "Greece"),
|
||||
("UNK", "Unknown"),
|
||||
("HK", "Hong Kong"),
|
||||
("I", "Italy"),
|
||||
("H", "Holland"),
|
||||
("UNL", "Unlicensed"),
|
||||
("AS", "Asia"),
|
||||
("R", "Russia"),
|
||||
("NO", "Norway"),
|
||||
]
|
||||
|
||||
REGIONS_BY_SHORTCODE = {region[0].lower(): region[1] for region in REGIONS}
|
||||
REGIONS_NAME_KEYS = [region[1].lower() for region in REGIONS]
|
||||
|
||||
|
||||
def parse_tags(file_name: str) -> tuple:
|
||||
reg: str = ''
|
||||
rev: str = ''
|
||||
other_tags: list = []
|
||||
tags: list = re.findall('\(([^)]+)', file_name)
|
||||
reg = ""
|
||||
rev = ""
|
||||
other_tags = []
|
||||
tags = re.findall("\(([^)]+)", file_name)
|
||||
|
||||
for tag in tags:
|
||||
if tag.split('-')[0].lower() == 'reg':
|
||||
try: reg = tag.split('-', 1)[1]
|
||||
except IndexError: pass
|
||||
elif tag.split('-')[0].lower() == 'rev':
|
||||
try: rev = tag.split('-', 1)[1]
|
||||
except IndexError: pass
|
||||
if tag.lower() in REGIONS_BY_SHORTCODE.keys():
|
||||
reg = REGIONS_BY_SHORTCODE[tag.lower()]
|
||||
elif tag.lower() in REGIONS_NAME_KEYS:
|
||||
reg = tag
|
||||
elif "rev" in tag.lower():
|
||||
rev = tag.split(" ")[1]
|
||||
else:
|
||||
other_tags.append(tag)
|
||||
return reg, rev, other_tags
|
||||
|
||||
|
||||
def get_file_name_with_no_tags(file_name: str) -> str:
|
||||
return re.sub('[\(\[].*?[\)\]]', '', file_name.split('.')[0])
|
||||
return re.sub("[\(\[].*?[\)\]]", "", file_name.split(".")[0])
|
||||
|
||||
|
||||
def get_file_extension(rom: dict) -> str:
|
||||
return rom['file_name'].split('.')[-1] if not rom['multi'] else ''
|
||||
return rom["file_name"].split(".")[-1] if not rom["multi"] else ""
|
||||
|
||||
15
frontend/.eslintignore
Normal file
15
frontend/.eslintignore
Normal file
@@ -0,0 +1,15 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
10
frontend/.eslintrc.json
Normal file
10
frontend/.eslintrc.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"browser": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-recommended"
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"dev": "vite --host",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --fix --ignore-path .gitignore"
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "7.0.96",
|
||||
|
||||
@@ -7,7 +7,7 @@ const snackbarStatus = ref({})
|
||||
|
||||
// Event listeners bus
|
||||
const emitter = inject('emitter')
|
||||
emitter.on('snackbarScan', (snackbar) => {
|
||||
emitter.on('snackbarShow', (snackbar) => {
|
||||
snackbarShow.value = true
|
||||
snackbarStatus.value = snackbar
|
||||
})
|
||||
@@ -21,4 +21,4 @@ emitter.on('snackbarScan', (snackbar) => {
|
||||
<v-btn @click="snackbarShow=false" variant="text"><v-icon icon="mdi-close"/></v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@ const downloading = storeDownloading()
|
||||
|
||||
export async function downloadRom(rom, emitter, filesToDownload=[]) {
|
||||
downloading.add(rom.file_name)
|
||||
emitter.emit('snackbarScan', {'msg': `Downloading ${rom.file_name}...`, 'icon': 'mdi-download', 'color': 'green'})
|
||||
emitter.emit('snackbarShow', {'msg': `Downloading ${rom.file_name}...`, 'icon': 'mdi-download', 'color': 'green'})
|
||||
if(rom.multi){
|
||||
const zip = new JSZip()
|
||||
var zipFilename = `${rom.file_name}.zip`
|
||||
@@ -33,4 +33,4 @@ export async function downloadRom(rom, emitter, filesToDownload=[]) {
|
||||
downloading.remove(rom.file_name)
|
||||
}
|
||||
|
||||
export async function downloadSave(rom) { console.log(`Downloading ${rom.file_name} save file`) }
|
||||
export async function downloadSave(rom) { console.log(`Downloading ${rom.file_name} save file`) }
|
||||
|
||||
9
frontend/src/utils/socket.js
Normal file
9
frontend/src/utils/socket.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const socket = io({
|
||||
path: "/ws/socket.io/",
|
||||
transports: ["websocket", "polling"],
|
||||
autoConnect: false,
|
||||
});
|
||||
|
||||
export default socket;
|
||||
@@ -59,10 +59,10 @@ async function updateRom(updatedData={...updatedRom.value}) {
|
||||
.then((response) => {
|
||||
rom.value = response.data.data
|
||||
updatedRom.value = {...response.data.data}
|
||||
emitter.emit('snackbarScan', {'msg': response.data.msg, 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
emitter.emit('snackbarShow', {'msg': response.data.msg, 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
emitter.emit('refreshGallery')
|
||||
}).catch((error) => {
|
||||
emitter.emit('snackbarScan', {'msg': error.response.data.detail, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
emitter.emit('snackbarShow', {'msg': error.response.data.detail, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
})
|
||||
renameAsIGDB.value = false
|
||||
updating.value = false
|
||||
@@ -72,11 +72,11 @@ async function updateRom(updatedData={...updatedRom.value}) {
|
||||
async function deleteRom() {
|
||||
await deleteRomApi(rom.value.p_slug, deleteFromFs.value)
|
||||
.then((response) => {
|
||||
emitter.emit('snackbarScan', {'msg': response.data.msg, 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
emitter.emit('snackbarShow', {'msg': response.data.msg, 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
router.push(`/platform/${rom.value.p_slug}`)
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
emitter.emit('snackbarScan', {'msg': error.response.data.detail, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
emitter.emit('snackbarShow', {'msg': error.response.data.detail, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
if (error.response.status == 404) { router.push(`/platform/${rom.value.p_slug}`) }
|
||||
})
|
||||
dialogDeleteRom.value = false
|
||||
|
||||
@@ -1,142 +1,154 @@
|
||||
<script setup>
|
||||
import { ref, inject, onMounted } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRoute } from 'vue-router'
|
||||
import { io } from "socket.io-client";
|
||||
import { views } from '@/utils/utils.js'
|
||||
import { fetchRomsApi } from '@/services/api.js'
|
||||
import { storeFilter } from '@/stores/filter.js'
|
||||
import { storeGalleryView } from '@/stores/galleryView.js'
|
||||
import { normalizeString } from '@/utils/utils.js'
|
||||
import FilterBar from '@/components/GameGallery/FilterBar.vue'
|
||||
import GalleryViewBtn from '@/components/GameGallery/GalleryViewBtn.vue'
|
||||
import GameCard from '@/components/GameGallery/Card/Base.vue'
|
||||
import GameListHeader from '@/components/GameGallery/ListItem/Header.vue'
|
||||
import GameListItem from '@/components/GameGallery/ListItem/Item.vue'
|
||||
import { storeScanning } from '@/stores/scanning.js'
|
||||
|
||||
|
||||
import { useDisplay } from "vuetify"
|
||||
import { downloadRom, downloadSave } from '@/services/download.js'
|
||||
import { storeDownloading } from '@/stores/downloading.js'
|
||||
import BackgroundHeader from '@/components/GameDetails/BackgroundHeader.vue'
|
||||
const { xs, mdAndDown, lgAndUp } = useDisplay()
|
||||
import { ref, inject, onMounted } from "vue";
|
||||
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||
import { views } from "@/utils/utils.js";
|
||||
import { fetchRomsApi } from "@/services/api.js";
|
||||
import { storeFilter } from "@/stores/filter.js";
|
||||
import { storeGalleryView } from "@/stores/galleryView.js";
|
||||
import { normalizeString } from "@/utils/utils.js";
|
||||
import FilterBar from "@/components/GameGallery/FilterBar.vue";
|
||||
import GalleryViewBtn from "@/components/GameGallery/GalleryViewBtn.vue";
|
||||
import GameCard from "@/components/GameGallery/Card/Base.vue";
|
||||
import GameListHeader from "@/components/GameGallery/ListItem/Header.vue";
|
||||
import GameListItem from "@/components/GameGallery/ListItem/Item.vue";
|
||||
import { storeScanning } from "@/stores/scanning.js";
|
||||
import socket from "@/utils/socket";
|
||||
|
||||
import { useDisplay } from "vuetify";
|
||||
import { downloadRom, downloadSave } from "@/services/download.js";
|
||||
import { storeDownloading } from "@/stores/downloading.js";
|
||||
import BackgroundHeader from "@/components/GameDetails/BackgroundHeader.vue";
|
||||
const { xs, mdAndDown, lgAndUp } = useDisplay();
|
||||
|
||||
// Props
|
||||
const route = useRoute()
|
||||
const route = useRoute();
|
||||
// const sections = ['roms', 'firmwares']
|
||||
const currentSection = ref('roms')
|
||||
const roms = ref([])
|
||||
const gettingRoms = ref(false)
|
||||
const filter = storeFilter()
|
||||
const romsFiltered = ref([])
|
||||
const currentSection = ref("roms");
|
||||
const roms = ref([]);
|
||||
const gettingRoms = ref(false);
|
||||
const filter = storeFilter();
|
||||
const romsFiltered = ref([]);
|
||||
// const firmwares = ["firmware_base", "firmware_bios"]
|
||||
const galleryView = storeGalleryView()
|
||||
const scanning = storeScanning()
|
||||
const galleryView = storeGalleryView();
|
||||
const scanning = storeScanning();
|
||||
|
||||
// Event listeners bus
|
||||
const emitter = inject('emitter')
|
||||
emitter.on('filter', () => { filterRoms() })
|
||||
const emitter = inject("emitter");
|
||||
emitter.on("filter", () => {
|
||||
filterRoms();
|
||||
});
|
||||
|
||||
// Functions
|
||||
async function scan() {
|
||||
scanning.set(true);
|
||||
emitter.emit('snackbarScan', {'msg': `Scanning ${route.params.platform}...`, 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
const socket = io({ path: '/ws/socket.io/', transports: ['websocket', 'polling'] })
|
||||
socket.on("done", () => {
|
||||
scanning.set(false)
|
||||
emitter.emit('refreshGallery')
|
||||
emitter.emit('snackbarScan', {'msg': "Scan completed successfully!", 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
socket.close()
|
||||
})
|
||||
socket.on("done_ko", (msg) => {
|
||||
scanning.set(false)
|
||||
emitter.emit('snackbarScan', {'msg': `Scan couldn't be completed. Something went wrong: ${msg}`, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
socket.close()
|
||||
})
|
||||
socket.emit("scan", JSON.stringify([route.params.platform]), false)
|
||||
scanning.set(true);
|
||||
emitter.emit("snackbarShow", {
|
||||
msg: `Scanning ${route.params.platform}...`,
|
||||
icon: "mdi-loading mdi-spin",
|
||||
color: "yellow",
|
||||
});
|
||||
if (!socket.connected) socket.connect();
|
||||
socket.on("scan:done", () => {
|
||||
scanning.set(false);
|
||||
emitter.emit("refreshGallery");
|
||||
emitter.emit("snackbarShow", {
|
||||
msg: "Scan completed successfully!",
|
||||
icon: "mdi-check-bold",
|
||||
color: "green",
|
||||
});
|
||||
socket.disconnect();
|
||||
});
|
||||
socket.on("scan:done_ko", (msg) => {
|
||||
scanning.set(false);
|
||||
emitter.emit("snackbarShow", {
|
||||
msg: `Scan couldn't be completed. Something went wrong: ${msg}`,
|
||||
icon: "mdi-close-circle",
|
||||
color: "red",
|
||||
});
|
||||
socket.disconnect();
|
||||
});
|
||||
socket.emit("scan", JSON.stringify([route.params.platform]), false);
|
||||
}
|
||||
|
||||
function filterRoms() {
|
||||
romsFiltered.value = roms.value.filter(rom => {
|
||||
return normalizeString(rom.file_name).includes(filter.value)
|
||||
})
|
||||
romsFiltered.value = roms.value.filter((rom) => {
|
||||
return normalizeString(rom.file_name).includes(filter.value);
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchRoms(platform) {
|
||||
gettingRoms.value = true
|
||||
await fetchRomsApi(platform)
|
||||
.then((response) => {
|
||||
roms.value = response.data.data
|
||||
filterRoms()
|
||||
})
|
||||
.catch((error) => {console.log(error);console.log(`Couldn't fetch roms for ${platform}`)})
|
||||
gettingRoms.value = false
|
||||
gettingRoms.value = true;
|
||||
await fetchRomsApi(platform)
|
||||
.then((response) => {
|
||||
roms.value = response.data.data;
|
||||
filterRoms();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
console.log(`Couldn't fetch roms for ${platform}`);
|
||||
})
|
||||
.finally(() => {
|
||||
gettingRoms.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(async () => { fetchRoms(route.params.platform)})
|
||||
onBeforeRouteUpdate(async (to, _) => { fetchRoms(to.params.platform) })
|
||||
onMounted(async () => {
|
||||
fetchRoms(route.params.platform);
|
||||
});
|
||||
onBeforeRouteUpdate(async (to, _) => {
|
||||
fetchRoms(to.params.platform);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<v-app-bar id="gallery-app-bar" elevation="0" density="compact">
|
||||
<!-- <v-select item-title="name" :items="sections" v-model="currentSection" hide-details/> -->
|
||||
<filter-bar/>
|
||||
<gallery-view-btn/>
|
||||
<v-btn @click="scan" rounded="0" variant="text" class="mr-0" icon="mdi-magnify-scan"/>
|
||||
</v-app-bar>
|
||||
|
||||
<template v-if="gettingRoms">
|
||||
<v-row class="fill-height justify-center align-center" no-gutters>
|
||||
<v-progress-circular color="rommAccent1" :width="3" :size="70" indeterminate/>
|
||||
</v-row>
|
||||
<v-app-bar id="gallery-app-bar" elevation="0" density="compact">
|
||||
<!-- <v-select item-title="name" :items="sections" v-model="currentSection" hide-details/> -->
|
||||
<filter-bar />
|
||||
<gallery-view-btn />
|
||||
<v-btn @click="scan" rounded="0" variant="text" class="mr-0" icon="mdi-magnify-scan" />
|
||||
</v-app-bar>
|
||||
|
||||
<template v-if="gettingRoms">
|
||||
<v-row class="fill-height justify-center align-center" no-gutters>
|
||||
<v-progress-circular color="rommAccent1" :width="3" :size="70" indeterminate />
|
||||
</v-row>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="roms.length > 0">
|
||||
<v-row v-show="galleryView.value != 2" id="card-view" no-gutters>
|
||||
<v-col v-for="rom in romsFiltered" class="pa-1" :key="rom.file_name" :cols="views[galleryView.value]['size-cols']"
|
||||
:xs="views[galleryView.value]['size-xs']" :sm="views[galleryView.value]['size-sm']"
|
||||
:md="views[galleryView.value]['size-md']" :lg="views[galleryView.value]['size-lg']">
|
||||
<game-card :rom="rom" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-show="galleryView.value == 2" id="list-view" no-gutters>
|
||||
<v-col :cols="views[galleryView.value]['size-cols']" :xs="views[galleryView.value]['size-xs']"
|
||||
:sm="views[galleryView.value]['size-sm']" :md="views[galleryView.value]['size-md']"
|
||||
:lg="views[galleryView.value]['size-lg']">
|
||||
<v-table class="bg-secondary">
|
||||
<game-list-header />
|
||||
<v-divider class="border-opacity-100 mb-4 ml-2 mr-2" color="rommAccent1" :thickness="1" />
|
||||
<tbody>
|
||||
<game-list-item v-for="rom in romsFiltered" :key="rom.file_name" :rom="rom" />
|
||||
</tbody>
|
||||
</v-table>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<template v-if="roms.length>0">
|
||||
|
||||
<v-row v-show="galleryView.value != 2" id="card-view" no-gutters>
|
||||
<v-col v-for="rom in romsFiltered" class="pa-1" :key="rom.file_name"
|
||||
:cols="views[galleryView.value]['size-cols']"
|
||||
:xs="views[galleryView.value]['size-xs']"
|
||||
:sm="views[galleryView.value]['size-sm']"
|
||||
:md="views[galleryView.value]['size-md']"
|
||||
:lg="views[galleryView.value]['size-lg']">
|
||||
<game-card :rom="rom"/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-show="galleryView.value == 2" id="list-view" no-gutters>
|
||||
<v-col
|
||||
:cols="views[galleryView.value]['size-cols']"
|
||||
:xs="views[galleryView.value]['size-xs']"
|
||||
:sm="views[galleryView.value]['size-sm']"
|
||||
:md="views[galleryView.value]['size-md']"
|
||||
:lg="views[galleryView.value]['size-lg']">
|
||||
<v-table class="bg-secondary">
|
||||
<game-list-header/>
|
||||
<v-divider class="border-opacity-100 mb-4 ml-2 mr-2" color="rommAccent1" :thickness="1"/>
|
||||
<tbody>
|
||||
<game-list-item v-for="rom in romsFiltered" :key="rom.file_name" :rom="rom"/>
|
||||
</tbody>
|
||||
</v-table>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
|
||||
<v-row class="fill-height justify-center align-center" no-gutters>
|
||||
<div class="text-h6">Feels cold here... <v-icon>mdi-emoticon-sad</v-icon></div>
|
||||
</v-row>
|
||||
|
||||
</template>
|
||||
|
||||
<v-row class="fill-height justify-center align-center" no-gutters>
|
||||
<div class="text-h6">
|
||||
Feels cold here... <v-icon>mdi-emoticon-sad</v-icon>
|
||||
</div>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
#gallery-app-bar { z-index: 999 !important; }
|
||||
#gallery-app-bar {
|
||||
z-index: 999 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,95 +1,94 @@
|
||||
<script setup>
|
||||
import { ref, inject } from "vue"
|
||||
import { io } from "socket.io-client";
|
||||
import { storePlatforms } from '@/stores/platforms.js'
|
||||
import { storeScanning } from '@/stores/scanning.js'
|
||||
import { ref, inject } from "vue";
|
||||
import { storePlatforms } from "@/stores/platforms.js";
|
||||
import { storeScanning } from "@/stores/scanning.js";
|
||||
import socket from "@/utils/socket";
|
||||
|
||||
// Props
|
||||
const platforms = storePlatforms()
|
||||
const platformsToScan = ref([])
|
||||
const scanning = storeScanning()
|
||||
const scanningPlatform = ref("")
|
||||
const scannedPlatforms = ref([])
|
||||
const completeRescan = ref(false)
|
||||
|
||||
const platforms = storePlatforms();
|
||||
const platformsToScan = ref([]);
|
||||
const scanning = storeScanning();
|
||||
const scanningPlatform = ref("");
|
||||
const scannedPlatforms = ref([]);
|
||||
const completeRescan = ref(false);
|
||||
|
||||
// Event listeners bus
|
||||
const emitter = inject('emitter')
|
||||
const emitter = inject("emitter");
|
||||
|
||||
// Functions
|
||||
async function scan() {
|
||||
scanning.set(true);
|
||||
scannedPlatforms.value = []
|
||||
const socket = io({ path: '/ws/socket.io/', transports: ['websocket', 'polling'] })
|
||||
socket.on("scanning_platform", (platform) => { scannedPlatforms.value.push({'p_name': platform[0], 'p_slug': platform[1], 'r': []}); scanningPlatform.value = platform[1] })
|
||||
socket.on("scanning_rom", (r) => { scannedPlatforms.value.forEach(e => { if(e['p_slug'] == scanningPlatform.value){ e['r'].push(r) } }) })
|
||||
socket.on("done", () => {
|
||||
scanning.set(false)
|
||||
emitter.emit('refresPlatforms')
|
||||
emitter.emit('snackbarScan', {'msg': "Scan completed successfully!", 'icon': 'mdi-check-bold', 'color': 'green'})
|
||||
socket.close()
|
||||
})
|
||||
socket.on("done_ko", (msg) => {
|
||||
scanning.set(false)
|
||||
emitter.emit('snackbarScan', {'msg': `Scan couldn't be completed. Something went wrong: ${msg}`, 'icon': 'mdi-close-circle', 'color': 'red'})
|
||||
socket.close()
|
||||
})
|
||||
socket.emit("scan", JSON.stringify(platformsToScan.value.map(p => p.fs_slug)), completeRescan.value)
|
||||
scanning.set(true);
|
||||
scannedPlatforms.value = [];
|
||||
if (!socket.connected) socket.connect();
|
||||
socket.on("scan:scanning_platform", (platform) => {
|
||||
scannedPlatforms.value.push({
|
||||
p_name: platform[0],
|
||||
p_slug: platform[1],
|
||||
r: [],
|
||||
});
|
||||
scanningPlatform.value = platform[1];
|
||||
});
|
||||
socket.on("scan:scanning_rom", (r) => {
|
||||
scannedPlatforms.value.forEach((e) => {
|
||||
if (e["p_slug"] == scanningPlatform.value) {
|
||||
e["r"].push(r);
|
||||
}
|
||||
});
|
||||
});
|
||||
socket.on("scan:done", () => {
|
||||
scanning.set(false);
|
||||
emitter.emit("refresPlatforms");
|
||||
emitter.emit("snackbarShow", {
|
||||
msg: "Scan completed successfully!",
|
||||
icon: "mdi-check-bold",
|
||||
color: "green",
|
||||
});
|
||||
socket.disconnect();
|
||||
});
|
||||
socket.on("scan:done_ko", (msg) => {
|
||||
scanning.set(false);
|
||||
emitter.emit("snackbarShow", {
|
||||
msg: `Scan couldn't be completed. Something went wrong: ${msg}`,
|
||||
icon: "mdi-close-circle",
|
||||
color: "red",
|
||||
});
|
||||
socket.disconnect();
|
||||
});
|
||||
socket.emit(
|
||||
"scan",
|
||||
JSON.stringify(platformsToScan.value.map((p) => p.fs_slug)),
|
||||
completeRescan.value
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-select label="Platforms" item-title="name" v-model="platformsToScan" :items="platforms.value" variant="outlined"
|
||||
density="comfortable" multiple return-object clearable hide-details rounded="0" chips />
|
||||
</v-row>
|
||||
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-select
|
||||
label="Platforms"
|
||||
item-title="name"
|
||||
v-model="platformsToScan"
|
||||
:items="platforms.value"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
multiple
|
||||
return-object
|
||||
clearable
|
||||
hide-details
|
||||
rounded="0"
|
||||
chips/>
|
||||
</v-row>
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-checkbox v-model="completeRescan" label="Complete Rescan" prepend-icon="mdi-cached"
|
||||
hint="Rescan every rom, including already scanned roms" persistent-hint />
|
||||
</v-row>
|
||||
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-checkbox
|
||||
v-model="completeRescan"
|
||||
label="Complete Rescan"
|
||||
prepend-icon="mdi-cached"
|
||||
hint="Rescan every rom, including already scanned roms"
|
||||
persistent-hint/>
|
||||
</v-row>
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-btn @click="scan()" :disabled="scanning.value" prepend-icon="mdi-magnify-scan" rounded="0">
|
||||
<span v-if="!scanning.value">Scan</span>
|
||||
<v-progress-circular v-show="scanning.value" color="rommAccent1" class="ml-3 mr-2" :width="2" :size="20"
|
||||
indeterminate />
|
||||
</v-btn>
|
||||
</v-row>
|
||||
|
||||
<v-row class="pa-4" no-gutters>
|
||||
<v-btn
|
||||
@click="scan()"
|
||||
:disabled="scanning.value"
|
||||
prepend-icon="mdi-magnify-scan"
|
||||
rounded="0">
|
||||
<span v-if="!scanning.value">Scan</span>
|
||||
<v-progress-circular
|
||||
v-show="scanning.value"
|
||||
color="rommAccent1"
|
||||
class="ml-3 mr-2"
|
||||
:width="2"
|
||||
:size="20"
|
||||
indeterminate/>
|
||||
</v-btn>
|
||||
</v-row>
|
||||
<v-divider class="border-opacity-100 ma-4" color="rommAccent1" :thickness="1" />
|
||||
|
||||
<v-divider class="border-opacity-100 ma-4" color="rommAccent1" :thickness="1"/>
|
||||
|
||||
<v-row no-gutters class="align-center pa-4" v-for="d in scannedPlatforms">
|
||||
<v-col>
|
||||
<v-avatar :rounded="0" size="40"><v-img :src="`/assets/platforms/${d['p_slug']}.ico`"></v-img></v-avatar>
|
||||
<span class="text-body-2 ml-5"> {{ d['p_name'] }}</span>
|
||||
<v-list-item v-for="r in d['r']" class="text-body-2" disabled> - {{ r }}</v-list-item>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</template>
|
||||
<v-row no-gutters class="align-center pa-4" v-for="d in scannedPlatforms">
|
||||
<v-col>
|
||||
<v-avatar :rounded="0" size="40"><v-img :src="`/assets/platforms/${d['p_slug']}.ico`"></v-img></v-avatar>
|
||||
<span class="text-body-2 ml-5"> {{ d["p_name"] }}</span>
|
||||
<v-list-item v-for="r in d['r']" class="text-body-2" disabled>
|
||||
- {{ r }}</v-list-item>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user