From 184779f92cb6e187b1e7c0d1e8b8f9097b571f7e Mon Sep 17 00:00:00 2001 From: Alper Alkan Date: Fri, 18 Oct 2024 14:50:58 +0200 Subject: [PATCH] improve migration --- CHANGELOG.md | 53 +-- .../postgres/1728421385000-v13-final.ts | 352 ++++++++++++------ .../sqlite/1728421385000-v13-final.ts | 293 +++++++++++---- src/modules/games/files.service.ts | 1 - 4 files changed, 476 insertions(+), 223 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2a0fb..af9bf9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,39 +2,44 @@ ## 13.0.0 -Recommended Gamevault App Version: `v1.12.0.4` +Recommended Gamevault App Version: `v1.12.0.5` ### Breaking Changes & Migration -**Lots** of things have changed this version. Ive almost rewritten the entire codebase to be honest. - -Read the Migration Instructions below **BEFORE UPDATING**! (Migration Instructions are marked **fat**) - -- Huge Database and Codebase overhaul! - - **I've tried my best to migrate your existing data. But nobody's perfect. Make sure to back your data up thoroughly, before migrating and contact us if you encounter any migration errors.** -- Some configurations / environment variables changed. - - **Check if your used env vars are [being used correctly](https://gamevau.lt/docs/server-docs/configuration).** -- [#140](https://github.com/Phalcode/gamevault-backend/issues/140) Introduced a new Plugin Framework that universally supports any metadata provider plugin and implemented a built-in IGDB Metadata Provider Plugin as the new default metadata provider. - - **You will need this, as there is no RAWG Integration anymore. Learn how to set it up [here](https://gamevaul.lt/docs/server-docs/metadata-enrichment/provider-igdb)** - - **IDBG Metadata by default is more important than RAWG metadata, as the data quality is much better. If you want your existing data to be the primarily used metadata set the `METADATA_IGDB_PRIORITY` environment variable to a value lower than `-10` before running the update.** - - **Old Experimental Plugins are no longer supported. Remove them if you used them (Spoiler: You probably didn't).** -- Added support for more media-types than just images. Meaning that you can now upload audio and video files. - - **From now on you need to mount your `/images` volume as `/media`.** +**A lot** has changed in this version. Honestly, I’ve almost rewritten the entire codebase. + +Please read the migration instructions below **BEFORE UPDATING**! (Migration instructions are marked **in bold**) + +- Major database and codebase overhaul! + - **I’ve done my best to migrate your existing data, but nobody’s perfect. Be sure to back up your data thoroughly before migrating, and contact us if you encounter any migration errors.** +- Some configurations and environment variables have changed. + - **Ensure your environment variables are [configured correctly](https://gamevau.lt/docs/server-docs/configuration).** +- [#140](https://github.com/Phalcode/gamevault-backend/issues/140): Introduced a new plugin framework that universally supports any metadata provider plugin and implemented a built-in IGDB Metadata Provider Plugin as the new default. + - **This is necessary, as RAWG integration has been removed. Learn how to set up the IGDB plugin [here](https://gamevaul.lt/docs/server-docs/metadata-enrichment/provider-igdb).** + - **IGDB metadata is now prioritized over RAWG, as its data quality is superior. If you want your existing data to remain the primary source, set the `METADATA_IGDB_PRIORITY` environment variable to a value lower than `-10` before running the update.** + - **We recommend first migrating the server to v13, then setting up IGDB and restarting, to minimize downtime.** + - **Old experimental plugins are no longer supported. Remove them if you were using any (Spoiler: You probably weren’t).** +- Added support for more media types beyond just images. You can now upload audio and video files as well. + - **You now need to mount your `/images` volume as `/media`.** - Implemented parental control features. [#304](https://github.com/Phalcode/gamevault-backend/issues/304) - - **Learn how it works and how to set it up [here](https://gamevau.lt/docs/server-docs/parental-control)** + - **Learn how it works and how to set it up [here](https://gamevau.lt/docs/server-docs/parental-control).** - Various API changes. - - **Check the API Docs for any changes if you're using the Rest API.** + - **Check the API documentation for any updates if you're using the REST API.** + +**For existing servers:** The migration process may take up to 30 minutes or even longer for larger servers. During this time, clients will not be able to use the server. The container may appear as UNHEALTHY after 5 minutes during a long migration, but don’t worry—let it run as long as logs are active. Be sure to disable any auto-heal processes for GameVault to avoid interruptions. + +**After the migration:** The existing data might not be visible at first glance because we need to "merge" it. This could also take a while. Check the logs for inactivity before contacting us about this. ### Changes -- Removed RAWG Integration and all configuration for it. +- Removed RAWG integration and all configurations for it. - Removed Google Images Boxart Scraper. (Let's be honest, it was shit anyway.) -- Optimized Game Indexer. It now usually only reads games that have changed instead of reading all files all the time. -- Optimized Startup Time. -- Implemented Editing of Games -- Implemented a `news.md` (a.k.a. Message of the Day) file and a `GET /config/news` API you can use to communicate news to your users. -> **Learn how to set it up [here](https://gamevau.lt/docs/server-docs/server-news)** -- Implemented Notes field in Games -- Implemented Default Launch Parameters, Default Launch Executable & Default Installer File fields in Games +- Optimized the Game Indexer. It now usually only reads games that have changed instead of reading all files all the time. +- Optimized startup time. +- [#161](https://github.com/Phalcode/gamevault-backend/issues/161) Implemented editing of games. +- [#423](https://github.com/Phalcode/gamevault-app/issues/423) Implemented a `news.md` (a.k.a. Message of the Day) file and a `GET /config/news` API you can use to communicate news to your users. -> **Learn how to set it up [here](https://gamevau.lt/docs/server-docs/server-news).** +- Implemented a notes field in games. +- Implemented default launch parameters, default launch executable, and default installer file fields in games. ## 12.2.0 diff --git a/src/modules/database/migrations/postgres/1728421385000-v13-final.ts b/src/modules/database/migrations/postgres/1728421385000-v13-final.ts index 93f571c..6d70c59 100644 --- a/src/modules/database/migrations/postgres/1728421385000-v13-final.ts +++ b/src/modules/database/migrations/postgres/1728421385000-v13-final.ts @@ -2,8 +2,8 @@ import { Logger, NotImplementedException } from "@nestjs/common"; import { randomBytes } from "crypto"; import { existsSync } from "fs"; import { toLower } from "lodash"; +import { setTimeout } from "timers/promises"; import { In, MigrationInterface, QueryRunner } from "typeorm"; -import { logMedia } from "../../../../logging"; import { GamevaultGame } from "../../../games/gamevault-game.entity"; import { Media } from "../../../media/media.entity"; import { DeveloperMetadata } from "../../../metadata/developers/developer.metadata.entity"; @@ -29,12 +29,96 @@ export class V13Final1728421385000 implements MigrationInterface { if (await this.checkMigrationRun(queryRunner)) { return; } + + const totalSteps = 6; + let currentStep = 1; + + console.warn( + `IMPORTANT INFORMATIONS: + - Be sure to back up your data thoroughly before migrating, and contact us if you encounter any migration errors. + - The migration process may take up to 30 minutes or even longer for larger servers. During this time, clients will not be able to use the server. + - If it takes too long, you can set SERVER_LOG_LEVEL=debug in the environment variables to track the track progress. However, note that enabling verbose logs may slow down the migration. + - The container might appear as UNHEALTHY during the migration. This is expected behavior, and no action is needed. Let it complete the process. + - Make sure to disable any Docker auto-heal features for GameVault, as they might terminate the container during the migration. + - Restarting the server will restart the migration.`, + ); + + console.warn( + "Waiting 15 seconds for you to read this, before starting migration...", + ); + await setTimeout(15_000); + + console.warn(" Alright, let's go."); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⢻⡿⠿⣿⣿⣿⣿⡿⠿⣿⡇⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⢀⣴⣦⡈⠻⣦⣤⣿⣿⣧⣤⣶⠏⢀⣦⣄⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⢀⣴⣿⣿⣿⣷⣤⣈⠙⠛⠛⠛⢉⣠⣴⣿⣿⣿⣷⣄⠀⠀⠀"); + console.warn("⠀⠀⢠⣿⣿⣿⣿⠟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢻⣿⣿⣿⣆⠀⠀"); + console.warn("⠀⢀⣿⣿⣿⣿⠃⣰⣿⣿⡿⠛⠋⠉⠛⠻⣿⣿⣷⡀⠹⣿⣿⣿⡆⠀"); + console.warn("⠀⣸⣿⣿⣿⠃⣰⣿⣿⠋⣠⣾⡇⢸⣷⣦⠈⣿⣿⣿⡄⢹⣿⣿⣿⠀"); + console.warn("⠀⣿⣿⣿⠋⠀⠉⠉⠉⠀⣿⣿⡇⢸⣿⣿⡇⠉⠉⠉⠁⠀⢻⣿⣿⡆"); + console.warn("⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇"); + console.warn("⠀⠙⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠃⠘⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠁"); + console.warn("⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀ "); + console.warn("⠀⠀⠀⠀⠀⠀⠈⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠃⠀⠀⠀⠀⠀⠀ "); + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Renaming tables - Running...`, + ); await this.part1_rename_tables(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Renaming tables - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Generating new schema - Running...`, + ); await this.part2_generate_new_schema(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Generating new schema - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating data - Running...`, + ); await this.part3_migrate_data(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating data - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Deleting old tables - Running...`, + ); await this.part4_delete_old_tables(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Deleting old tables - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Synchronizing changes - Running...`, + ); await this.part5_sync(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Synchronizing changes - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Sorting title - Running...`, + ); await this.part6_sorting_title(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Sorting title - Completed`, + ); + + this.logger.log("info", "Migration completed successfully."); } private async checkMigrationRun(queryRunner: QueryRunner): Promise { @@ -44,9 +128,6 @@ export class V13Final1728421385000 implements MigrationInterface { if (migrations.length > 0) { this.logger.warn("V13 MIGRATIONS ALREADY RUN SKIPPING..."); - for (const migration of migrations) { - this.logger.warn(JSON.stringify(migration)); - } return true; } @@ -56,7 +137,7 @@ export class V13Final1728421385000 implements MigrationInterface { private async part1_rename_tables(queryRunner: QueryRunner) { if (existsSync("/images")) { throw new Error( - "Your media volume mount point is still pointing to /images. This is deprecated since v13.0.0. From now on, mount your images to /media instead.", + "Oof... Your media volume mount point is still pointing to /images. This is deprecated since v13.0.0. From now on, mount your images to /media instead of /images. Did you even bother to read the migration instructions? 🥲", ); } @@ -168,7 +249,7 @@ export class V13Final1728421385000 implements MigrationInterface { } private async part2_generate_new_schema(queryRunner: QueryRunner) { - this.logger.log("Creating ENUM type: progress_state_enum"); + this.logger.debug("Creating ENUM type: progress_state_enum"); await queryRunner.query(` DO $$ BEGIN @@ -185,7 +266,7 @@ export class V13Final1728421385000 implements MigrationInterface { END $$; `); - this.logger.log("Creating ENUM type: gamevault_game_type_enum"); + this.logger.debug("Creating ENUM type: gamevault_game_type_enum"); await queryRunner.query(` DO $$ BEGIN @@ -200,7 +281,7 @@ export class V13Final1728421385000 implements MigrationInterface { END $$; `); - this.logger.log("Creating ENUM type: gamevault_user_role_enum"); + this.logger.debug("Creating ENUM type: gamevault_user_role_enum"); await queryRunner.query(` DO $$ BEGIN @@ -210,7 +291,7 @@ export class V13Final1728421385000 implements MigrationInterface { END $$; `); - this.logger.log("Creating table: media"); + this.logger.debug("Creating table: media"); await queryRunner.query(` CREATE TABLE "media" ( "id" SERIAL NOT NULL, @@ -227,7 +308,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: developer_metadata"); + this.logger.debug("Creating table: developer_metadata"); await queryRunner.query(` CREATE TABLE "developer_metadata" ( "id" SERIAL NOT NULL, @@ -242,7 +323,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: genre_metadata"); + this.logger.debug("Creating table: genre_metadata"); await queryRunner.query(` CREATE TABLE "genre_metadata" ( "id" SERIAL NOT NULL, @@ -257,7 +338,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: publisher_metadata"); + this.logger.debug("Creating table: publisher_metadata"); await queryRunner.query(` CREATE TABLE "publisher_metadata" ( "id" SERIAL NOT NULL, @@ -272,7 +353,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: tag_metadata"); + this.logger.debug("Creating table: tag_metadata"); await queryRunner.query(` CREATE TABLE "tag_metadata" ( "id" SERIAL NOT NULL, @@ -287,7 +368,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: game_metadata"); + this.logger.debug("Creating table: game_metadata"); await queryRunner.query(` CREATE TABLE "game_metadata" ( "id" SERIAL NOT NULL, @@ -320,7 +401,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: progress"); + this.logger.debug("Creating table: progress"); await queryRunner.query(` CREATE TABLE "progress" ( "id" SERIAL NOT NULL, @@ -337,7 +418,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: gamevault_game"); + this.logger.debug("Creating table: gamevault_game"); await queryRunner.query(` CREATE TABLE "gamevault_game" ( "id" SERIAL NOT NULL, @@ -363,7 +444,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating table: gamevault_user"); + this.logger.debug("Creating table: gamevault_user"); await queryRunner.query(` CREATE TABLE "gamevault_user" ( "id" SERIAL NOT NULL, @@ -390,7 +471,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log( + this.logger.debug( "Creating join table: game_metadata_gamevault_games_gamevault_game", ); await queryRunner.query(` @@ -401,7 +482,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log( + this.logger.debug( "Creating join table: game_metadata_publishers_publisher_metadata", ); await queryRunner.query(` @@ -412,7 +493,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log( + this.logger.debug( "Creating join table: game_metadata_developers_developer_metadata", ); await queryRunner.query(` @@ -423,7 +504,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating join table: game_metadata_tags_tag_metadata"); + this.logger.debug("Creating join table: game_metadata_tags_tag_metadata"); await queryRunner.query(` CREATE TABLE "game_metadata_tags_tag_metadata" ( "game_metadata_id" integer NOT NULL, @@ -432,7 +513,9 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating join table: game_metadata_genres_genre_metadata"); + this.logger.debug( + "Creating join table: game_metadata_genres_genre_metadata", + ); await queryRunner.query(` CREATE TABLE "game_metadata_genres_genre_metadata" ( "game_metadata_id" integer NOT NULL, @@ -441,7 +524,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log( + this.logger.debug( "Creating join table: gamevault_game_provider_metadata_game_metadata", ); await queryRunner.query(` @@ -452,7 +535,7 @@ export class V13Final1728421385000 implements MigrationInterface { ) `); - this.logger.log("Creating join table: bookmark"); + this.logger.debug("Creating join table: bookmark"); await queryRunner.query(` CREATE TABLE "bookmark" ( "gamevault_user_id" integer NOT NULL, @@ -714,17 +797,106 @@ export class V13Final1728421385000 implements MigrationInterface { } private async part3_migrate_data(queryRunner: QueryRunner) { + const totalSteps = 10; + let currentStep = 1; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Disabling auto-increment IDs - Sub-Step 1 - Running...`, + ); await this.toggleAutoIncrementId(queryRunner, false); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Disabling auto-increment IDs - Sub-Step 1 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating images - Sub-Step 2 - Running...`, + ); await this.migrateImages(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating images - Sub-Step 2 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating tags - Sub-Step 3 - Running...`, + ); await this.migrateTags(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating tags - Sub-Step 3 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating genres - Sub-Step 4 - Running...`, + ); await this.migrateGenres(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating genres - Sub-Step 4 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating developers - Sub-Step 5 - Running...`, + ); await this.migrateDevelopers(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating developers - Sub-Step 5 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating publishers - Sub-Step 6 - Running...`, + ); await this.migratePublishers(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating publishers - Sub-Step 6 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating games - Sub-Step 7 - Running...`, + ); await this.migrateGames(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating games - Sub-Step 7 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating users - Sub-Step 8 - Running...`, + ); await this.migrateUsers(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating users - Sub-Step 8 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating bookmarks - Sub-Step 9 - Running...`, + ); await this.migrateBookmarks(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating bookmarks - Sub-Step 9 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating progresses - Sub-Step 10 - Running...`, + ); await this.migrateProgresses(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating progresses - Sub-Step 10 - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Enabling auto-increment IDs - Sub-Step 11 - Running...`, + ); await this.toggleAutoIncrementId(queryRunner, true); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Enabling auto-increment IDs - Sub-Step 11 - Completed`, + ); } private async part4_delete_old_tables(queryRunner: QueryRunner) { @@ -826,19 +998,16 @@ export class V13Final1728421385000 implements MigrationInterface { } private async migrateImages(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Images..." }); - const images = await queryRunner.manager.find(ImageV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${images.length} images in the V12 database.`, }); for (const image of images) { - this.logger.log({ - message: `Migrating image.`, - image: logMedia(image as Media), + this.logger.debug({ + message: `Migrating image ID ${image.id}, Source: ${image.source}`, }); await queryRunner.query( @@ -858,23 +1027,17 @@ export class V13Final1728421385000 implements MigrationInterface { image.uploader?.id, ], ); - - this.logger.log({ message: `Image migrated successfully` }); } - - this.logger.log({ message: "Image migration completed." }); } private async migrateTags(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Tags..." }); - const tags = await queryRunner.manager.find(TagV12, { withDeleted: true }); - this.logger.log({ + this.logger.debug({ message: `Found ${tags.length} tags in the V12 database.`, }); for (const tag of tags) { - this.logger.log({ + this.logger.debug({ message: `Migrating tag ID ${tag.id}, Name: ${tag.name}`, }); @@ -884,7 +1047,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: tag.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Tag ID ${tag.id} already exists. Skipping.`, }); continue; @@ -906,25 +1069,19 @@ export class V13Final1728421385000 implements MigrationInterface { tag.name, ], ); - - this.logger.log({ message: `Tag migrated successfully` }); } - - this.logger.log({ message: "Tag migration completed." }); } private async migrateGenres(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Genres..." }); - const genres = await queryRunner.manager.find(GenreV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${genres.length} genres in the V12 database.`, }); for (const genre of genres) { - this.logger.log({ + this.logger.debug({ message: `Migrating genre ID ${genre.id}, Name: ${genre.name}`, }); @@ -934,7 +1091,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: genre.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Genre ID ${genre.id} already exists. Skipping.`, }); continue; @@ -956,25 +1113,19 @@ export class V13Final1728421385000 implements MigrationInterface { genre.name, ], ); - - this.logger.log({ message: `Genre migrated successfully` }); } - - this.logger.log({ message: "Genre migration completed." }); } private async migrateDevelopers(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Developers..." }); - const developers = await queryRunner.manager.find(DeveloperV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${developers.length} developers in the V12 database.`, }); for (const developer of developers) { - this.logger.log({ + this.logger.debug({ message: `Migrating developer ID ${developer.id}, Name: ${developer.name}`, }); @@ -984,7 +1135,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: developer.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Developer ID ${developer.id} already exists. Skipping.`, }); continue; @@ -1006,27 +1157,19 @@ export class V13Final1728421385000 implements MigrationInterface { developer.name, ], ); - - this.logger.log({ - message: `Developer migrated successfully`, - }); } - - this.logger.log({ message: "Developer migration completed." }); } private async migratePublishers(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Publishers..." }); - const publishers = await queryRunner.manager.find(PublisherV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${publishers.length} publishers in the V12 database.`, }); for (const publisher of publishers) { - this.logger.log({ + this.logger.debug({ message: `Migrating publisher ID ${publisher.id}, Name: ${publisher.name}`, }); @@ -1036,7 +1179,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: publisher.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Publisher ID ${publisher.id} already exists. Skipping.`, }); continue; @@ -1058,18 +1201,10 @@ export class V13Final1728421385000 implements MigrationInterface { publisher.name, ], ); - - this.logger.log({ - message: `Publisher migrated successfully`, - }); } - - this.logger.log({ message: "Publisher migration completed." }); } private async migrateGames(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Games..." }); - const games = await queryRunner.manager.find(GameV12, { relations: [ "box_image", @@ -1082,12 +1217,12 @@ export class V13Final1728421385000 implements MigrationInterface { withDeleted: true, relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${games.length} games in the V12 database.`, }); for (const game of games) { - this.logger.log({ + this.logger.debug({ message: `Migrating game ID ${game.id}, Title: ${game.title}`, }); @@ -1133,7 +1268,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (cover) - this.logger.log({ message: `Linked cover image, ID: ${cover?.id}` }); + this.logger.debug({ message: `Linked cover image, ID: ${cover?.id}` }); const background = game.background_image ? await queryRunner.manager.findOne(Media, { @@ -1142,7 +1277,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (background) - this.logger.log({ + this.logger.debug({ message: `Linked background image, ID: ${background?.id}`, }); @@ -1156,13 +1291,13 @@ export class V13Final1728421385000 implements MigrationInterface { }); migratedGame.user_metadata = userMetadata; await queryRunner.manager.save(GamevaultGame, migratedGame); - this.logger.log({ + this.logger.debug({ message: `User metadata saved successfully. Metadata ID: ${userMetadata.id}, Title: ${userMetadata.title}`, }); continue; } - this.logger.log({ + this.logger.debug({ message: `No rawg_id or custom images found. Skipping metadata for game ID: ${game.id}.`, }); continue; @@ -1174,7 +1309,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.tags.map((t) => t.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${tags.length} tags for game ID: ${game.id}`, }); @@ -1184,7 +1319,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.genres.map((g) => g.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${genres.length} genres for game ID: ${game.id}`, }); @@ -1194,7 +1329,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.developers.map((d) => d.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${developers.length} developers for game ID: ${game.id}`, }); @@ -1204,7 +1339,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.publishers.map((p) => p.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${publishers.length} publishers for game ID: ${game.id}`, }); @@ -1217,7 +1352,7 @@ export class V13Final1728421385000 implements MigrationInterface { ); if (existingMetadata) { - this.logger.log({ + this.logger.debug({ message: `Rawg Metadata already exists for game ID ${game.id}. Linking...`, }); migratedGame.provider_metadata = [existingMetadata]; @@ -1240,24 +1375,23 @@ export class V13Final1728421385000 implements MigrationInterface { publishers, }); migratedGame.provider_metadata = [gameMetadata]; - this.logger.log({ + this.logger.debug({ message: `New Game metadata saved successfully. Metadata ID: ${gameMetadata.id}, Title: ${gameMetadata.title}`, }); } - const savedGame = await queryRunner.manager.save( + const newGame = await queryRunner.manager.save( GamevaultGame, migratedGame, ); - this.logger.log({ message: "Migrated Game Successfully.", savedGame }); + this.logger.debug({ + message: "Migrated Game Successfully.", + savedGame: newGame, + }); } - - this.logger.log({ message: "Game migration completed." }); } private async migrateUsers(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Users..." }); - const users = await queryRunner.manager.find(GamevaultUserV12, { withDeleted: true, select: [ @@ -1280,12 +1414,12 @@ export class V13Final1728421385000 implements MigrationInterface { relations: ["profile_picture", "background_image"], relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${users.length} users in the V12 database.`, }); for (const user of users) { - this.logger.log({ + this.logger.debug({ message: `Migrating user ID ${user.id}, Username: ${user.username}`, }); @@ -1296,7 +1430,9 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (avatar) - this.logger.log({ message: `Linked avatar image, ID: ${avatar?.id}` }); + this.logger.debug({ + message: `Linked avatar image, ID: ${avatar?.id}`, + }); const background = user.background_image ? await queryRunner.manager.findOne(Media, { @@ -1305,7 +1441,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (background) - this.logger.log({ + this.logger.debug({ message: `Linked background image, ID: ${background?.id}`, }); @@ -1332,41 +1468,31 @@ export class V13Final1728421385000 implements MigrationInterface { user.id, ], ); - - this.logger.log({ - message: `User migrated successfully.`, - }); } - - this.logger.log({ message: "User migration completed." }); } private async migrateBookmarks(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Bookmarks..." }); await queryRunner.query( ` INSERT INTO "bookmark" ("gamevault_user_id", "gamevault_game_id") SELECT "v12_gamevault_user_id", "v12_game_id" FROM "v12_bookmark" `, ); - this.logger.log({ message: "Bookmark migration completed." }); } private async migrateProgresses(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Progresses..." }); - const progresses = await queryRunner.manager.find(ProgressV12, { withDeleted: true, loadEagerRelations: true, relations: ["user", "game"], relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${progresses.length} progresses in the V12 database.`, }); for (const progress of progresses) { - this.logger.log({ + this.logger.debug({ message: `Migrating progress ID ${progress.id}, User: ${progress.user?.id}, Game: ${progress.game?.id}`, }); @@ -1388,13 +1514,7 @@ export class V13Final1728421385000 implements MigrationInterface { progress.game?.id, ], ); - - this.logger.log({ - message: `Progress migrated successfully.`, - }); } - - this.logger.log({ message: "Progress migration completed." }); } private createSortTitle(title: string): string { diff --git a/src/modules/database/migrations/sqlite/1728421385000-v13-final.ts b/src/modules/database/migrations/sqlite/1728421385000-v13-final.ts index 08cafe2..461548c 100644 --- a/src/modules/database/migrations/sqlite/1728421385000-v13-final.ts +++ b/src/modules/database/migrations/sqlite/1728421385000-v13-final.ts @@ -2,6 +2,7 @@ import { Logger, NotImplementedException } from "@nestjs/common"; import { randomBytes } from "crypto"; import { existsSync } from "fs"; import { toLower } from "lodash"; +import { setTimeout } from "timers/promises"; import { In, MigrationInterface, QueryRunner } from "typeorm"; import { GamevaultGame } from "../../../games/gamevault-game.entity"; import { Media } from "../../../media/media.entity"; @@ -31,13 +32,107 @@ export class V13Final1728421385000 implements MigrationInterface { if (await this.checkMigrationRun(queryRunner)) { return; } + + const totalSteps = 7; + let currentStep = 1; + + console.warn( + `IMPORTANT INFORMATIONS: + - Be sure to back up your data thoroughly before migrating, and contact us if you encounter any migration errors. + - The migration process may take up to 30 minutes or even longer for larger servers. During this time, clients will not be able to use the server. + - If it takes too long, you can set SERVER_LOG_LEVEL=debug in the environment variables to track the track progress. However, note that enabling verbose logs may slow down the migration. + - The container might appear as UNHEALTHY during the migration. This is expected behavior, and no action is needed. Let it complete the process. + - Make sure to disable any Docker auto-heal features for GameVault, as they might terminate the container during the migration. + - Restarting the server will restart the migration.`, + ); + + console.warn( + "Waiting 15 seconds for you to read this, before starting migration...", + ); + await setTimeout(15_000); + + console.warn(" Alright, let's go."); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⠀⠀⠀⢻⡿⠿⣿⣿⣿⣿⡿⠿⣿⡇⠀⠀⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⠀⠀⢀⣴⣦⡈⠻⣦⣤⣿⣿⣧⣤⣶⠏⢀⣦⣄⠀⠀⠀⠀⠀"); + console.warn("⠀⠀⠀⢀⣴⣿⣿⣿⣷⣤⣈⠙⠛⠛⠛⢉⣠⣴⣿⣿⣿⣷⣄⠀⠀⠀"); + console.warn("⠀⠀⢠⣿⣿⣿⣿⠟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢻⣿⣿⣿⣆⠀⠀"); + console.warn("⠀⢀⣿⣿⣿⣿⠃⣰⣿⣿⡿⠛⠋⠉⠛⠻⣿⣿⣷⡀⠹⣿⣿⣿⡆⠀"); + console.warn("⠀⣸⣿⣿⣿⠃⣰⣿⣿⠋⣠⣾⡇⢸⣷⣦⠈⣿⣿⣿⡄⢹⣿⣿⣿⠀"); + console.warn("⠀⣿⣿⣿⠋⠀⠉⠉⠉⠀⣿⣿⡇⢸⣿⣿⡇⠉⠉⠉⠁⠀⢻⣿⣿⡆"); + console.warn("⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇"); + console.warn("⠀⠙⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠃⠘⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠁"); + console.warn("⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀ "); + console.warn("⠀⠀⠀⠀⠀⠀⠈⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠃⠀⠀⠀⠀⠀⠀ "); + + this.logger.log("info", "Starting migration..."); + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Synchronizing - Running...`, + ); await this.part0_sync(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Synchronizing - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Renaming tables - Running...`, + ); await this.part1_rename_tables(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Renaming tables - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Generating new schema - Running...`, + ); await this.part2_generate_new_schema(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Generating new schema - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating data - Running...`, + ); await this.part3_migrate_data(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Migrating data - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Enabling auto-increment - Running...`, + ); await this.part4_enable_auto_increment(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Enabling auto-increment - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Deleting old tables - Running...`, + ); await this.part5_delete_old_tables(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Deleting old tables - Completed`, + ); + currentStep++; + + this.logger.log( + `Step ${currentStep}/${totalSteps}: Sorting title - Running...`, + ); await this.part6_sorting_title(queryRunner); + this.logger.log( + `Step ${currentStep}/${totalSteps}: Sorting title - Completed`, + ); + + this.logger.log("info", "Migration completed successfully."); } private async checkMigrationRun(queryRunner: QueryRunner): Promise { @@ -632,7 +727,7 @@ export class V13Final1728421385000 implements MigrationInterface { private async part1_rename_tables(queryRunner: QueryRunner) { if (existsSync("/images")) { throw new Error( - "Your media volume mount point is still pointing to /images. This is deprecated since v13.0.0. From now on, mount your images to /media instead.", + "Oof... Your media volume mount point is still pointing to /images. This is deprecated since v13.0.0. From now on, mount your images to /media instead of /images. Did you even bother to read the migration instructions? 🥲", ); } @@ -3079,16 +3174,83 @@ export class V13Final1728421385000 implements MigrationInterface { CREATE INDEX "IDX_3c8d93fdd9e34a97f5a5903129" ON "bookmark" ("gamevault_game_id") `); } + private async part3_migrate_data(queryRunner: QueryRunner) { + const totalSteps = 8; + let currentStep = 1; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating images - Running...`, + ); await this.migrateImages(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating images - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating tags - Running...`, + ); await this.migrateTags(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating tags - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating genres - Running...`, + ); await this.migrateGenres(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating genres - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating developers - Running...`, + ); await this.migrateDevelopers(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating developers - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating publishers - Running...`, + ); await this.migratePublishers(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating publishers - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating games - Running...`, + ); await this.migrateGames(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating games - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating users and bookmarks - Running...`, + ); await this.migrateUsersAndBookmarks(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating users and bookmarks - Completed`, + ); + currentStep++; + + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating progresses - Running...`, + ); await this.migrateProgresses(queryRunner); + this.logger.log( + `Sub-Step ${currentStep}/${totalSteps}: Migrating progresses - Completed`, + ); } + private async part4_enable_auto_increment(queryRunner: QueryRunner) { await queryRunner.query(` DROP INDEX "IDX_907a95c00ab6d81140c1a1b4a3" @@ -4268,17 +4430,15 @@ export class V13Final1728421385000 implements MigrationInterface { } private async migrateImages(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Images..." }); - const images = await queryRunner.manager.find(ImageV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${images.length} images in the V12 database.`, }); for (const image of images) { - this.logger.log({ + this.logger.debug({ message: `Migrating image ID ${image.id}, Source: ${image.source}`, }); @@ -4294,22 +4454,18 @@ export class V13Final1728421385000 implements MigrationInterface { entity_version: image.entity_version, }); - this.logger.log({ message: `Image migrated successfully`, newImage }); + this.logger.debug({ message: "Migrated Image Successfully.", newImage }); } - - this.logger.log({ message: "Image migration completed." }); } private async migrateTags(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Tags..." }); - const tags = await queryRunner.manager.find(TagV12, { withDeleted: true }); - this.logger.log({ + this.logger.debug({ message: `Found ${tags.length} tags in the V12 database.`, }); for (const tag of tags) { - this.logger.log({ + this.logger.debug({ message: `Migrating tag ID ${tag.id}, Name: ${tag.name}`, }); @@ -4319,7 +4475,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: tag.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Tag ID ${tag.id} already exists. Skipping.`, }); continue; @@ -4336,24 +4492,20 @@ export class V13Final1728421385000 implements MigrationInterface { entity_version: tag.entity_version, }); - this.logger.log({ message: `Tag migrated successfully`, newTag }); + this.logger.debug({ message: "Migrated Tag Successfully.", newTag }); } - - this.logger.log({ message: "Tag migration completed." }); } private async migrateGenres(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Genres..." }); - const genres = await queryRunner.manager.find(GenreV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${genres.length} genres in the V12 database.`, }); for (const genre of genres) { - this.logger.log({ + this.logger.debug({ message: `Migrating genre ID ${genre.id}, Name: ${genre.name}`, }); @@ -4363,7 +4515,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: genre.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Genre ID ${genre.id} already exists. Skipping.`, }); continue; @@ -4380,24 +4532,20 @@ export class V13Final1728421385000 implements MigrationInterface { entity_version: genre.entity_version, }); - this.logger.log({ message: `Genre migrated successfully`, newGenre }); + this.logger.debug({ message: "Migrated Genre Successfully.", newGenre }); } - - this.logger.log({ message: "Genre migration completed." }); } private async migrateDevelopers(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Developers..." }); - const developers = await queryRunner.manager.find(DeveloperV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${developers.length} developers in the V12 database.`, }); for (const developer of developers) { - this.logger.log({ + this.logger.debug({ message: `Migrating developer ID ${developer.id}, Name: ${developer.name}`, }); @@ -4407,7 +4555,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: developer.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Developer ID ${developer.id} already exists. Skipping.`, }); continue; @@ -4424,27 +4572,23 @@ export class V13Final1728421385000 implements MigrationInterface { entity_version: developer.entity_version, }); - this.logger.log({ - message: `Developer migrated successfully`, + this.logger.debug({ + message: "Migrated Developer Successfully.", newDeveloper, }); } - - this.logger.log({ message: "Developer migration completed." }); } private async migratePublishers(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Publishers..." }); - const publishers = await queryRunner.manager.find(PublisherV12, { withDeleted: true, }); - this.logger.log({ + this.logger.debug({ message: `Found ${publishers.length} publishers in the V12 database.`, }); for (const publisher of publishers) { - this.logger.log({ + this.logger.debug({ message: `Migrating publisher ID ${publisher.id}, Name: ${publisher.name}`, }); @@ -4454,7 +4598,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: publisher.rawg_id.toString(), }) ) { - this.logger.log({ + this.logger.debug({ message: `Publisher ID ${publisher.id} already exists. Skipping.`, }); continue; @@ -4470,19 +4614,14 @@ export class V13Final1728421385000 implements MigrationInterface { deleted_at: publisher.deleted_at, entity_version: publisher.entity_version, }); - - this.logger.log({ - message: `Publisher migrated successfully`, + this.logger.debug({ + message: "Migrated Publisher Successfully.", newPublisher, }); } - - this.logger.log({ message: "Publisher migration completed." }); } private async migrateGames(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Games..." }); - const games = await queryRunner.manager.find(GameV12, { relations: [ "box_image", @@ -4495,12 +4634,12 @@ export class V13Final1728421385000 implements MigrationInterface { withDeleted: true, relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${games.length} games in the V12 database.`, }); for (const game of games) { - this.logger.log({ + this.logger.debug({ message: `Migrating game ID ${game.id}, Title: ${game.title}`, }); @@ -4527,7 +4666,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (cover) - this.logger.log({ message: `Linked cover image, ID: ${cover?.id}` }); + this.logger.debug({ message: `Linked cover image, ID: ${cover?.id}` }); const background = game.background_image ? await queryRunner.manager.findOne(Media, { @@ -4536,7 +4675,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (background) - this.logger.log({ + this.logger.debug({ message: `Linked background image, ID: ${background?.id}`, }); @@ -4550,13 +4689,13 @@ export class V13Final1728421385000 implements MigrationInterface { }); migratedGame.user_metadata = userMetadata; await queryRunner.manager.save(GamevaultGame, migratedGame); - this.logger.log({ + this.logger.debug({ message: `User metadata saved successfully. Metadata ID: ${userMetadata.id}, Game ID: ${game.id}, Title: ${userMetadata.title}`, }); continue; } - this.logger.log({ + this.logger.debug({ message: `No rawg_id or custom images found. Skipping metadata for game ID: ${game.id}.`, }); continue; @@ -4568,7 +4707,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.tags.map((t) => t.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${tags.length} tags for game ID: ${game.id}`, }); @@ -4578,7 +4717,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.genres.map((g) => g.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${genres.length} genres for game ID: ${game.id}`, }); @@ -4588,7 +4727,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.developers.map((d) => d.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${developers.length} developers for game ID: ${game.id}`, }); @@ -4598,7 +4737,7 @@ export class V13Final1728421385000 implements MigrationInterface { provider_data_id: In(game.publishers.map((p) => p.rawg_id)), }) : []; - this.logger.log({ + this.logger.debug({ message: `Linked ${publishers.length} publishers for game ID: ${game.id}`, }); @@ -4611,7 +4750,7 @@ export class V13Final1728421385000 implements MigrationInterface { ); if (existingMetadata) { - this.logger.log({ + this.logger.debug({ message: `Rawg Metadata already exists for game ID ${game.id}. Linking...`, }); migratedGame.provider_metadata = [existingMetadata]; @@ -4634,7 +4773,7 @@ export class V13Final1728421385000 implements MigrationInterface { publishers, }); migratedGame.provider_metadata = [gameMetadata]; - this.logger.log({ + this.logger.debug({ message: `New Game metadata saved successfully. Metadata ID: ${gameMetadata.id}, Title: ${gameMetadata.title}`, }); } @@ -4643,17 +4782,13 @@ export class V13Final1728421385000 implements MigrationInterface { GamevaultGame, migratedGame, ); - this.logger.log({ message: "Migrated Game Successfully.", savedGame }); + this.logger.debug({ message: "Migrated Game Successfully.", savedGame }); } - - this.logger.log({ message: "Game migration completed." }); } private async migrateUsersAndBookmarks( queryRunner: QueryRunner, ): Promise { - this.logger.log({ message: "Migrating Users..." }); - const users = await queryRunner.manager.find(GamevaultUserV12, { withDeleted: true, select: [ @@ -4677,12 +4812,12 @@ export class V13Final1728421385000 implements MigrationInterface { relations: ["profile_picture", "background_image", "bookmarked_games"], relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${users.length} users in the V12 database.`, }); for (const user of users) { - this.logger.log({ + this.logger.debug({ message: `Migrating user ID ${user.id}, Username: ${user.username}`, }); @@ -4693,7 +4828,9 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (avatar) - this.logger.log({ message: `Linked avatar image, ID: ${avatar?.id}` }); + this.logger.debug({ + message: `Linked avatar image, ID: ${avatar?.id}`, + }); const background = user.background_image ? await queryRunner.manager.findOne(Media, { @@ -4702,7 +4839,7 @@ export class V13Final1728421385000 implements MigrationInterface { }) : undefined; if (background) - this.logger.log({ + this.logger.debug({ message: `Linked background image, ID: ${background?.id}`, }); @@ -4731,31 +4868,24 @@ export class V13Final1728421385000 implements MigrationInterface { deleted_at: user.deleted_at, entity_version: user.entity_version, }); - this.logger.log({ - message: `User migrated successfully.`, - username: newUser.username, - userId: newUser.id, - }); - } - this.logger.log({ message: "User migration completed." }); + this.logger.debug({ message: "Migrated User Successfully.", newUser }); + } } private async migrateProgresses(queryRunner: QueryRunner): Promise { - this.logger.log({ message: "Migrating Progresses..." }); - const progresses = await queryRunner.manager.find(ProgressV12, { withDeleted: true, loadEagerRelations: true, relations: ["user", "game"], relationLoadStrategy: "query", }); - this.logger.log({ + this.logger.debug({ message: `Found ${progresses.length} progresses in the V12 database.`, }); for (const progress of progresses) { - this.logger.log({ + this.logger.debug({ message: `Migrating progress ID ${progress.id}, User: ${progress.user?.id}, Game: ${progress.game?.id}`, }); @@ -4785,13 +4915,12 @@ export class V13Final1728421385000 implements MigrationInterface { deleted_at: progress.deleted_at, entity_version: progress.entity_version, }); - this.logger.log({ - message: `Progress migrated successfully.`, - progress: newProgress, + + this.logger.debug({ + message: "Migrated User Successfully.", + newProgress, }); } - - this.logger.log({ message: "Progress migration completed." }); } public async down(): Promise { diff --git a/src/modules/games/files.service.ts b/src/modules/games/files.service.ts index 0f8bef3..459b0ae 100644 --- a/src/modules/games/files.service.ts +++ b/src/modules/games/files.service.ts @@ -107,7 +107,6 @@ export class FilesService implements OnApplicationBootstrap { public async index(files?: File[]): Promise { this.logger.log({ message: "Indexing game(s).", - files, jobs: this.indexJobs.size, }); this.indexJobs.clear();