diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index 03d88495..ad8d1d1c 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Dauer", "likes": "Likes", - "date-uploaded": "Hochladedatum" + "date-uploaded": "Hochladedatum", + "added-date": "Hinzugefügt am" } }, "playlists": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index fb33467b..e117f972 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Duration", "likes": "Likes", - "date-uploaded": "Date Uploaded" + "date-uploaded": "Date Uploaded", + "added-date": "Added Date" } }, "playlists": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 18d87f1f..7b29a743 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Duración", "likes": "Me gusta", - "date-uploaded": "Fecha de subida" + "date-uploaded": "Fecha de subida", + "added-date": "Fecha de adición" } }, "playlists": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index 81070c9d..83f35979 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Durée", "likes": "J'aime", - "date-uploaded": "Date de publication" + "date-uploaded": "Date de publication", + "added-date": "Date d'ajout" } }, "playlists": { diff --git a/assets/jsons/translations/it.json b/assets/jsons/translations/it.json index c7e542b4..8ed85b3b 100644 --- a/assets/jsons/translations/it.json +++ b/assets/jsons/translations/it.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Durata", "likes": "Mi piace", - "date-uploaded": "Data di caricamento" + "date-uploaded": "Data di caricamento", + "added-date": "Data di aggiunta" } }, "playlists": { diff --git a/assets/jsons/translations/ja.json b/assets/jsons/translations/ja.json index d2d05150..dadca05a 100644 --- a/assets/jsons/translations/ja.json +++ b/assets/jsons/translations/ja.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "持続時間", "likes": "いいね", - "date-uploaded": "アップロード日" + "date-uploaded": "アップロード日", + "added-date": "追加日" } }, "playlists": { diff --git a/assets/jsons/translations/ko.json b/assets/jsons/translations/ko.json index 24dc70e5..568c42fc 100644 --- a/assets/jsons/translations/ko.json +++ b/assets/jsons/translations/ko.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "지속 시간", "likes": "좋아요", - "date-uploaded": "업로드 날짜" + "date-uploaded": "업로드 날짜", + "added-date": "추가 날짜" } }, "playlists": { diff --git a/assets/jsons/translations/pt-br.json b/assets/jsons/translations/pt-br.json index 76921b70..ba13d33b 100644 --- a/assets/jsons/translations/pt-br.json +++ b/assets/jsons/translations/pt-br.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Duração", "likes": "Gostei", - "date-uploaded": "Data de envio" + "date-uploaded": "Data de envio", + "added-date": "Data de adição" } }, "playlists": { diff --git a/assets/jsons/translations/ru.json b/assets/jsons/translations/ru.json index ce71eeda..25f2ce95 100644 --- a/assets/jsons/translations/ru.json +++ b/assets/jsons/translations/ru.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Длительность", "likes": "Лайки", - "date-uploaded": "Дата загрузки" + "date-uploaded": "Дата загрузки", + "added-date": "Дата добавления" } }, "playlists": { diff --git a/assets/jsons/translations/tl.json b/assets/jsons/translations/tl.json index 748bcd43..0c3731a9 100644 --- a/assets/jsons/translations/tl.json +++ b/assets/jsons/translations/tl.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Haba", "likes": "Likes", - "date-uploaded": "Petsa ng Pagka-upload" + "date-uploaded": "Petsa ng Pagka-upload", + "added-date": "Petsa ng Pagdaragdag" } }, "playlists": { diff --git a/assets/jsons/translations/uk.json b/assets/jsons/translations/uk.json index 903d9824..967eeead 100644 --- a/assets/jsons/translations/uk.json +++ b/assets/jsons/translations/uk.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "Довжина", "likes": "Лайки", - "date-uploaded": "Дата завантаження" + "date-uploaded": "Дата завантаження", + "added-date": "Дата додавання" } }, "playlists": { diff --git a/assets/jsons/translations/zh-tw.json b/assets/jsons/translations/zh-tw.json index 84985291..66f2246d 100644 --- a/assets/jsons/translations/zh-tw.json +++ b/assets/jsons/translations/zh-tw.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "持續時間", "likes": "喜歡", - "date-uploaded": "上傳日期" + "date-uploaded": "上傳日期", + "added-date": "新增日期" } }, "playlists": { diff --git a/assets/jsons/translations/zh.json b/assets/jsons/translations/zh.json index 5f171a95..2ab8d74e 100644 --- a/assets/jsons/translations/zh.json +++ b/assets/jsons/translations/zh.json @@ -111,7 +111,8 @@ "bpm": "BPM", "duration": "持续时间", "likes": "喜欢", - "date-uploaded": "上传日期" + "date-uploaded": "上传日期", + "added-date": "添加日期" } }, "playlists": { diff --git a/src/main/services/additional-content/maps/local-maps-manager.service.ts b/src/main/services/additional-content/maps/local-maps-manager.service.ts index 4a4f31e9..c786aeb6 100644 --- a/src/main/services/additional-content/maps/local-maps-manager.service.ts +++ b/src/main/services/additional-content/maps/local-maps-manager.service.ts @@ -1,13 +1,13 @@ import path from "path"; import { BSVersion } from "shared/bs-version.interface"; import { BsvMapDetail } from "shared/models/maps"; -import { BsmLocalMap, BsmLocalMapsProgress, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface"; +import { BsmLocalMap, BsmLocalMapMetadata, BsmLocalMapsProgress, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface"; import { BSLocalVersionService } from "../../bs-local-version.service"; import { InstallationLocationService } from "../../installation-location.service"; import { UtilsService } from "../../utils.service"; import crypto, { BinaryLike } from "crypto"; import { lstatSync } from "fs"; -import { copy, createReadStream, ensureDir, pathExists, pathExistsSync, realpath } from "fs-extra"; +import { copy, createReadStream, ensureDir, existsSync, pathExists, pathExistsSync, readJson, realpath, writeJson } from "fs-extra"; import { RequestService } from "../../request.service"; import sanitize from "sanitize-filename"; import { DeepLinkService } from "../../deep-link.service"; @@ -31,6 +31,7 @@ import { CustomError } from "shared/models/exceptions/custom-error.class"; import { tryit } from "shared/helpers/error.helpers"; import { BsmZipExtractor } from "main/models/bsm-zip-extractor.class"; import { escapeRegExp } from "../../../../shared/helpers/string.helpers"; +import dateFormat from "dateformat"; export class LocalMapsManagerService { private static instance: LocalMapsManagerService; @@ -46,6 +47,7 @@ export class LocalMapsManagerService { public static readonly CUSTOM_LEVELS_FOLDER = "CustomLevels"; public static readonly RELATIVE_MAPS_FOLDER = path.join(LocalMapsManagerService.LEVELS_ROOT_FOLDER, LocalMapsManagerService.CUSTOM_LEVELS_FOLDER); public static readonly SHARED_MAPS_FOLDER = "SharedMaps"; + public static readonly METADATA_FILE = "metadata.json"; private readonly DEEP_LINKS = { BeatSaver: "beatsaver", @@ -138,16 +140,21 @@ export class LocalMapsManagerService { public async loadMapInfoFromPath(mapPath: string): Promise { - const getUrlsAndReturn = (mapInfo: MapInfo, hash: string, mapPath: string): BsmLocalMap => { + const getUrlsAndReturn = (mapInfo: MapInfo, hash: string, mapPath: string, metadata: BsmLocalMapMetadata): BsmLocalMap => { const coverUrl = pathToFileURL(path.join(mapPath, mapInfo.coverImageFilename)).href; const songUrl = pathToFileURL(path.join(mapPath, mapInfo.songFilename)).href; - return { mapInfo, coverUrl, songUrl, hash, path: mapPath, songDetails: this.songDetailsCache.getSongDetails(hash) }; + return { + mapInfo, coverUrl, songUrl, hash, path: mapPath, + songDetails: this.songDetailsCache.getSongDetails(hash), + metadata, + }; }; const cachedMapInfos = this.songCache.getMapInfoFromDirname(path.basename(mapPath)); if (cachedMapInfos) { - return getUrlsAndReturn(cachedMapInfos.mapInfo, cachedMapInfos.hash, mapPath); + const metadata = await this.getMetadata(mapPath); + return getUrlsAndReturn(cachedMapInfos.mapInfo, cachedMapInfos.hash, mapPath, metadata); } const files = await getFilesInFolder(mapPath); @@ -166,8 +173,9 @@ export class LocalMapsManagerService { } const hash = await this.computeMapHash(mapPath, rawInfoString); + const metadata = await this.getMetadata(mapPath); - return getUrlsAndReturn(mapInfo, hash, mapPath); + return getUrlsAndReturn(mapInfo, hash, mapPath, metadata); } private async downloadMapZip(zipUrl: string): Promise { @@ -462,6 +470,21 @@ export class LocalMapsManagerService { return localMap; } + private async getMetadata(mapPath: string): Promise { + const metadataPath = path.join(mapPath, LocalMapsManagerService.METADATA_FILE); + if (existsSync(metadataPath)) { + return await readJson(metadataPath) as BsmLocalMapMetadata; + } + + // Create the metadata then return it to the user + const metadata: BsmLocalMapMetadata = { + addedDate: dateFormat(new Date(), "yyyy-mm-dd'T'HH:MM:ss.l"), + }; + + await writeJson(metadataPath, metadata); + return metadata; + } + public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string): Promise> { const archive = new Archive(outPath); diff --git a/src/shared/models/maps/bsm-local-map.interface.ts b/src/shared/models/maps/bsm-local-map.interface.ts index c597b1a6..aac63a32 100644 --- a/src/shared/models/maps/bsm-local-map.interface.ts +++ b/src/shared/models/maps/bsm-local-map.interface.ts @@ -8,6 +8,12 @@ export interface BsmLocalMap { mapInfo: MapInfo; songDetails?: SongDetails; path: string; + metadata?: BsmLocalMapMetadata; +} + +export interface BsmLocalMapMetadata { + // Date of download or import + addedDate: string; } export interface BsmLocalMapsProgress { diff --git a/src/shared/models/maps/sorter.ts b/src/shared/models/maps/sorter.ts index a5cbe6de..d79b6193 100644 --- a/src/shared/models/maps/sorter.ts +++ b/src/shared/models/maps/sorter.ts @@ -35,6 +35,13 @@ export const mapSorter = new Sorter({ return !map2.songDetails ? Comparison.GREATER : map1.songDetails.uploadedAt - map2.songDetails.uploadedAt; }, + "added-date": (map1, map2) => { + if (!map1.metadata) { + return map2.metadata ? Comparison.LESSER : Comparison.EQUAL; + } + + return !map2.metadata ? Comparison.GREATER : map1.metadata.addedDate.localeCompare(map2.metadata.addedDate); + } }, tiebreak: sortName, defaultKey: "name"