diff --git a/README.md b/README.md
index b3ae04f1e..1d2dbe7a8 100644
--- a/README.md
+++ b/README.md
@@ -75,16 +75,14 @@ Inspired by [Jellyfin](https://jellyfin.org/), allows you to manage all your gam
Docker should be installed and set up before running the [image](https://hub.docker.com/r/zurdi15/romm/tags).
-1. Generate an API key for [IGDB](https://www.igdb.com/), and set the `IGDB_CLIENT_ID` and `IGDB_CLIENT_SECRET` variables. _This is required to run a library scan._ Instructions on generating the ID and Secret are [here](https://api-docs.igdb.com/#about). Note that IDGB requires a Twitch account with 2FA enabled to generate the ID and Secret.
+1. Generate an API key for [IGDB](https://www.igdb.com/), and set the `IGDB_CLIENT_ID` and `IGDB_CLIENT_SECRET` variables. _This is required to run a library scan._ Instructions on generating the ID and Secret are [here](https://api-docs.igdb.com/#about). Note that IGDB requires a Twitch account with 2FA enabled to generate the ID and Secret.
2. Verify that your library folder structure matches one of the options listed in the [following section](#folder-structure).
-3. Create a docker-compose file. See the following example [docker-compose.yml](https://github.com/zurdi15/romm/blob/master/examples/docker-compose.example.yml) file for reference. Customize for your setup and include the `IGDB_CLIENT_ID` and `IGDB_CLIENT_SECRET` vareiables where indicated in the environment section of the file.
+3. Create a docker-compose file. See the following example [docker-compose.yml](https://github.com/zurdi15/romm/blob/master/examples/docker-compose.example.yml) file for reference. Customize for your setup and include the `IGDB_CLIENT_ID` and `IGDB_CLIENT_SECRET` variables where indicated in the environment section of the file.
4. Launch the container:
```bash
docker-compose up -d
```
-
- If configured correctly, Romm will automatically run an initial scan on your library.
# Configuration
@@ -143,7 +141,7 @@ If you want to enable the user management system, a redis container and some env
- `ROMM_AUTH_ENABLED` and `ENABLE_EXPERIMENTAL_REDIS` must be set as `true`
- `ROMM_AUTH_SECRET_KEY` must be generated with `openssl rand -hex 32`
- `ROMM_AUTH_USERNAME` and `ROMM_AUTH_PASSWORD` can be set as wanted, being both `admin` by default.
- - `REDIS_HOST` and `REDIS_PORT` must point to your redis instance
+ - `REDIS_HOST` and `REDIS_PORT` must point to your redis instance. Aditionally, if your redis is secured you can set `REDIS_PASSWORD`
⚙️ Configuration file
diff --git a/backend/config/__init__.py b/backend/config/__init__.py
index a26453fd0..f01dd7b0e 100644
--- a/backend/config/__init__.py
+++ b/backend/config/__init__.py
@@ -43,6 +43,7 @@ ENABLE_EXPERIMENTAL_REDIS: Final = (
)
REDIS_HOST: Final = os.environ.get("REDIS_HOST", "localhost")
REDIS_PORT: Final = os.environ.get("REDIS_PORT", "6379")
+REDIS_PASSWORD: Final = os.environ.get("REDIS_PASSWORD")
# IGDB
IGDB_CLIENT_ID: Final = os.environ.get(
diff --git a/backend/utils/cache.py b/backend/utils/cache.py
index cfd900df9..60c80519d 100644
--- a/backend/utils/cache.py
+++ b/backend/utils/cache.py
@@ -1,6 +1,16 @@
from redis import Redis
-from config import REDIS_HOST, REDIS_PORT, ENABLE_EXPERIMENTAL_REDIS
+from config import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, ENABLE_EXPERIMENTAL_REDIS
+
+redis_client = Redis(
+ host=REDIS_HOST, port=int(REDIS_PORT), password=REDIS_PASSWORD, db=0
+)
+redis_url = (
+ f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}"
+ if REDIS_PASSWORD
+ else f"redis://{REDIS_HOST}:{REDIS_PORT}"
+)
+
class FallbackCache:
def __init__(self) -> None:
@@ -30,7 +40,11 @@ class FallbackCache:
# A seperate client that auto-decodes responses is needed
_cache_client = Redis(
- host=REDIS_HOST, port=int(REDIS_PORT), db=0, decode_responses=True
+ host=REDIS_HOST,
+ port=int(REDIS_PORT),
+ password=REDIS_PASSWORD,
+ db=0,
+ decode_responses=True,
)
_fallback_cache = FallbackCache()
cache = _cache_client if ENABLE_EXPERIMENTAL_REDIS else _fallback_cache
diff --git a/docker-compose.yml b/docker-compose.yml
index fadac7b25..203d11d58 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -15,6 +15,16 @@ services:
redis:
image: redis:alpine
container_name: redis
+ command:
+ # - /bin/sh
+ # - -c
+ # # - Double dollars, so that the variable is not expanded by Docker Compose
+ # # - Surround by quotes, so that the shell does not split the password
+ # # - The ${variable:?message} syntax causes shell to exit with a non-zero
+ # # code and print a message, when the variable is not set or empty
+ # - redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"
restart: unless-stopped
ports:
- ${REDIS_PORT}:6379
+ env_file:
+ - .env
diff --git a/env.template b/env.template
index d9f6cbe82..fadefe4c5 100644
--- a/env.template
+++ b/env.template
@@ -24,6 +24,7 @@ ENABLE_EXPERIMENTAL_REDIS=true
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
ENABLE_EXPERIMENTAL_REDIS=true
+#REDIS_PASSWORD=admin_redis
# Authentication (optional)
ROMM_AUTH_ENABLED=true
diff --git a/examples/docker-compose.example.yml b/examples/docker-compose.example.yml
index e8d6f9c9a..dbc1a5376 100644
--- a/examples/docker-compose.example.yml
+++ b/examples/docker-compose.example.yml
@@ -27,6 +27,7 @@ services:
- ENABLE_EXPERIMENTAL_REDIS=true # default: false
- REDIS_HOST=redis # default: localhost
- REDIS_PORT=6379 # default: 6379
+ - REDIS_PASSWORD= # [Optional] Support for secured redis
volumes:
- "/path/to/library:/romm/library"
- "/path/to/resources:/romm/resources" # [Optional] Path where roms metadata (covers) are stored
@@ -40,9 +41,9 @@ services:
restart: "unless-stopped"
# [Optional] Only required if using MariaDB as the database
- mariadb:
+ romm_db:
image: mariadb:latest
- container_name: mariadb
+ container_name: romm_db
environment:
- MYSQL_ROOT_PASSWORD=
- MYSQL_DATABASE=romm
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 1147bf500..58419b97e 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "romm",
- "version": "2.0.0",
+ "version": "2.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
diff --git a/frontend/package.json b/frontend/package.json
index 3536ecb36..cdbbd2101 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "romm",
- "version": "2.0.0",
+ "version": "2.0.1",
"private": true,
"scripts": {
"dev": "vite --host",
diff --git a/frontend/src/components/Drawer/Base.vue b/frontend/src/components/Drawer/Base.vue
index 9105f1702..84a30a170 100644
--- a/frontend/src/components/Drawer/Base.vue
+++ b/frontend/src/components/Drawer/Base.vue
@@ -50,7 +50,7 @@ emitter.on("toggleDrawerRail", () => {
value.reduce((count, p) => count + p.n_roms, 0),
+ filledPlatforms: ({ value }) => value.filter((p) => p.n_roms > 0),
},
actions: {
set(platforms) {
diff --git a/frontend/src/stores/roms.js b/frontend/src/stores/roms.js
index 48df6d1b5..64e1b84eb 100644
--- a/frontend/src/stores/roms.js
+++ b/frontend/src/stores/roms.js
@@ -3,6 +3,7 @@ import { defineStore } from "pinia";
export default defineStore("roms", {
state: () => ({
+ _platform: "",
_all: [],
_filteredIDs: [],
_searchIDs: [],
@@ -14,6 +15,7 @@ export default defineStore("roms", {
}),
getters: {
+ platform: (state) => state._platform,
allRoms: (state) => state._all,
filteredRoms: (state) =>
state._all.filter((rom) => state._filteredIDs.includes(rom.id)),
@@ -33,6 +35,9 @@ export default defineStore("roms", {
"id"
);
},
+ setPlatform(platform) {
+ this._platform = platform;
+ },
// All roms
set(roms) {
this._all = roms;
diff --git a/frontend/src/views/Dashboard/Platforms.vue b/frontend/src/views/Dashboard/Platforms.vue
index af6b4b349..d71faef44 100644
--- a/frontend/src/views/Dashboard/Platforms.vue
+++ b/frontend/src/views/Dashboard/Platforms.vue
@@ -17,7 +17,7 @@ const platforms = storePlatforms();
mdi-controller{{ platforms.value.length }} Platforms
+ >{{ platforms.filledPlatforms.length }} Platforms
mdi-disc{{ platforms.totalGames }} Games
diff --git a/frontend/src/views/Gallery/Base.vue b/frontend/src/views/Gallery/Base.vue
index 53427ec1a..197f52acd 100644
--- a/frontend/src/views/Gallery/Base.vue
+++ b/frontend/src/views/Gallery/Base.vue
@@ -68,10 +68,11 @@ async function fetchRoms(platform) {
const allRomsSet = [...allRoms.value, ...response.data.items];
romsStore.set(allRomsSet);
romsStore.setFiltered(allRomsSet);
+ romsStore.setPlatform(platform);
if (isFiltered) {
searchCursor.value = response.data.next_page;
-
+
const serchedRomsSet = [...searchRoms.value, ...response.data.items];
romsStore.setSearch(serchedRomsSet);
romsStore.setFiltered(serchedRomsSet);
@@ -143,7 +144,23 @@ function selectRom({ event, index, selected }) {
}
}
+function resetGallery() {
+ cursor.value = "";
+ searchCursor.value = "";
+ romsStore.reset();
+ scrolledToTop.value = true;
+}
+
onMounted(() => {
+ const platform = route.params.platform;
+
+ // If platform is different, reset store and fetch roms
+ if (platform != romsStore.platform) {
+ resetGallery();
+ fetchRoms(route.params.platform);
+ }
+
+ // If platform is the same but there are no roms, fetch them
if (filteredRoms.value.length == 0) {
fetchRoms(route.params.platform);
}
@@ -154,14 +171,12 @@ onBeforeUnmount(() => {
});
onBeforeRouteLeave((to, from, next) => {
- // Only reset selection if platform is the same
+ // Reset only the selection if platform is the same
if (to.fullPath.includes(from.path)) {
romsStore.resetSelection();
- // Otherwise reset store
+ // Otherwise reset the entire store
} else {
- cursor.value = "";
- searchCursor.value = "";
- romsStore.reset();
+ resetGallery();
}
next();
@@ -169,11 +184,8 @@ onBeforeRouteLeave((to, from, next) => {
onBeforeRouteUpdate((to, _) => {
// Reset store if switching to another platform
- cursor.value = "";
- searchCursor.value = "";
- romsStore.reset();
+ resetGallery();
fetchRoms(to.params.platform);
- scrolledToTop.value = true;
});
diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue
index f594be00a..2c19c9f56 100644
--- a/frontend/src/views/Login.vue
+++ b/frontend/src/views/Login.vue
@@ -11,8 +11,10 @@ const router = useRouter();
const username = ref();
const password = ref();
const visiblePassword = ref(false);
+const logging = ref(false);
function login() {
+ logging.value = true;
api
.post(
"/login",
@@ -36,6 +38,9 @@ function login() {
icon: "mdi-close-circle",
color: "red",
});
+ })
+ .finally(() => {
+ logging.value = false;
});
}
@@ -88,10 +93,20 @@ onBeforeMount(async () => {
Login
+ :loading="logging"
+ >Login
+
+
+
+
diff --git a/pyproject.toml b/pyproject.toml
index c89f73312..72e89eafa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "RomM"
-version = "2.0.0"
+version = "2.0.1"
description = "RomM (Rom Manager) is a web based retro roms manager integrated with IGDB."
authors = ["zurdi "]
readme = "README.md"
diff --git a/unraid_template/romm.xml b/unraid_template/romm.xml
index 9370f8070..bebb175d0 100644
--- a/unraid_template/romm.xml
+++ b/unraid_template/romm.xml
@@ -44,6 +44,7 @@
+