From 21e6b2f304307206881cd4eba474ecf143093e32 Mon Sep 17 00:00:00 2001 From: ibratabian17 Date: Mon, 1 Jul 2024 16:32:59 +0800 Subject: [PATCH] use SaveData for data saving --- core/carousel/carousel.js | 12 +++- core/helper.js | 58 ++++++++++++----- core/route/account.js | 121 +++++++++++++++++----------------- core/route/leaderboard.js | 133 +++++++++++++++++++++----------------- settings.json | 2 +- 5 files changed, 189 insertions(+), 137 deletions(-) diff --git a/core/carousel/carousel.js b/core/carousel/carousel.js index 91f32f9..3c5e3b9 100644 --- a/core/carousel/carousel.js +++ b/core/carousel/carousel.js @@ -2,9 +2,17 @@ console.log(`[CAROUSEL] Initializing....`); const { CloneObject, readDatabaseJson } = require('../helper'); const fs = require('fs'); +const path = require('path'); const cClass = require("./classList.json"); const songdb = require("../../database/Platforms/openparty-all/songdbs.json"); -const mostPlayed = require(`${__dirname}/../../database/carousel/mostplayed.json`); +const helper = require('../helper') +var mostPlayed = {} + +if (fs.existsSync(path.join(helper.getSavefilePath(), 'carousel/mostplayed.json'))) { + mostPlayed = require(path.join(helper.getSavefilePath(), 'carousel/mostplayed.json')); +} else if (fs.existsSync(`${__dirname}/../../database/carousel/mostplayed.json`)) { + mostPlayed = require(`${__dirname}/../../database/carousel/mostplayed.json`) +} var carousel = {}; //avoid list cached const WEEKLY_PLAYLIST_PREFIX = 'DFRecommendedFU'; @@ -13,7 +21,7 @@ function updateMostPlayed(maps) { const currentWeek = getWeekNumber(); mostPlayed[currentWeek] = mostPlayed[currentWeek] || {}; mostPlayed[currentWeek][maps] = (mostPlayed[currentWeek][maps] || 0) + 1; - fs.writeFileSync(`${__dirname}/../../database/carousel/mostplayed.json`, JSON.stringify(mostPlayed, null, 2)); + fs.writeFileSync(path.join(helper.getSavefilePath(), 'carousel/mostplayed.json'), JSON.stringify(mostPlayed, null, 2)); } function addCategories(categories) { diff --git a/core/helper.js b/core/helper.js index f10fbe1..b429ce1 100644 --- a/core/helper.js +++ b/core/helper.js @@ -1,13 +1,16 @@ //JDPARTY CLONE OBJECT const fs = require('fs'); const axios = require('axios'); +const os = require('os'); +const path = require('path'); +const settings = require('../settings.json'); const downloader = { }; function CloneObject(ObjectC) { - return JSON.parse(JSON.stringify(ObjectC)) + return JSON.parse(JSON.stringify(ObjectC)) } function readDatabaseJson(path) { - return JSON.parse(fs.readFileSync(`${__dirname}/../database/${path}`, 'utf8')); + return JSON.parse(fs.readFileSync(`${__dirname}/../database/${path}`, 'utf8')); } downloader.getJson = async (url, options) => { @@ -16,21 +19,44 @@ downloader.getJson = async (url, options) => { } function extractSkuIdInfo(url) { - // Split the URL by '/' - const parts = url.split('/'); - // Get the last part of the URL - const lastPart = parts[parts.length - 1]; - // Remove the file extension (.json) - const filename = lastPart.split('.')[0]; - const filenameParts = filename.split('-'); - let version = filenameParts[0]; - version = version.slice(2); - const platform = filenameParts[1]; - const type = filenameParts.slice(2).join('-') - return { version, platform, type }; + // Split the URL by '/' + const parts = url.split('/'); + // Get the last part of the URL + const lastPart = parts[parts.length - 1]; + // Remove the file extension (.json) + const filename = lastPart.split('.')[0]; + const filenameParts = filename.split('-'); + let version = filenameParts[0]; + version = version.slice(2); + const platform = filenameParts[1]; + const type = filenameParts.slice(2).join('-') + return { version, platform, type }; +} + +function getSavefilePath() { + var isWin = process.platform === "win32"; + var path = "" + if (isWin) { + path = settings.server.SaveData.windows.replace('{Home}', os.homedir()) + } else { + path = settings.server.SaveData.linux.replace('{Home}', os.homedir()) } - + return path +} + + +//Check Savedata Dir before starting +if (!fs.existsSync(getSavefilePath())) { + console.log(`[HELPER] ${getSavefilePath()} Doesn't Exist!`) + fs.mkdirSync(getSavefilePath()); + fs.mkdirSync(path.join(getSavefilePath(), 'account/profiles'), { recursive: true }); + fs.mkdirSync(path.join(getSavefilePath(), 'carousel/pages'), { recursive: true }); + fs.mkdirSync(path.join(getSavefilePath(), 'Platforms/openparty-all'), { recursive: true }); + fs.mkdirSync(path.join(getSavefilePath(), 'leaderboard/dotw'), { recursive: true }); + fs.mkdirSync(path.join(getSavefilePath(), 'server-log'), { recursive: true }); +} + module.exports = { - CloneObject, readDatabaseJson, downloader, extractSkuIdInfo + CloneObject, readDatabaseJson, downloader, extractSkuIdInfo, getSavefilePath } \ No newline at end of file diff --git a/core/route/account.js b/core/route/account.js index dcffb67..8002e3f 100644 --- a/core/route/account.js +++ b/core/route/account.js @@ -2,6 +2,9 @@ //shit implementation, i need to fix it asap const fs = require("fs"); const axios = require("axios"); +const path = require('path') +const { getSavefilePath } = require('../helper'); + const hidepass = btoa('SkROZXh0Q2F1dGlvblBsZWFzZURvTm90U3RlYWxVc2VyRGF0YS4xMg=='); @@ -29,70 +32,70 @@ exports.initroute = (app) => { const ubiwsurl = "https://public-ubiservices.ubi.com"; const prodwsurl = "https://prod.just-dance.com"; -// Endpoint to get profiles based on profileIds -app.get("/profile/v2/profiles", (req, res) => { - const ticket = req.header("Authorization"); // Extract Authorization header - const profilesid = req.query.profileIds.split(','); // Split profileIds into an array - const dataFilePath = 'database/account/profiles/user.json'; // Path to user data file - const encryptedData = fs.readFileSync(dataFilePath, 'utf8'); // Read encrypted user data - let decryptedData; - try { - decryptedData = JSON.parse(encryptedData); // Parse decrypted user data - } catch (err) { - decryptedData = {}; // Set empty object if data cannot be parsed - } - - // Map over profileIds to retrieve corresponding user profiles or create default profiles - const responseProfiles = profilesid.map(profileId => { - const userProfile = decryptedData[profileId]; // Get user profile based on profileId - if (userProfile) { - return { ...userProfile, ip: req.ip }; // Add IP to userProfile but not in the response - } else { - const defaultProfile = { ip: req.ip }; // Create a default profile with IP address - decryptedData[profileId] = defaultProfile; // Add default profile to decrypted data - return {}; // Return an empty object (don't include defaultProfile in response) + // Endpoint to get profiles based on profileIds + app.get("/profile/v2/profiles", (req, res) => { + const ticket = req.header("Authorization") || ''; // Extract Authorization header + const profilesid = req.query.profileIds.split(','); // Split profileIds into an array + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); // Path to user data file + let decryptedData; + try { + const encryptedData = fs.readFileSync(dataFilePath, 'utf8'); // Read encrypted user data + decryptedData = JSON.parse(encryptedData); // Parse decrypted user data + } catch (err) { + decryptedData = {}; // Set empty object if data cannot be parsed } - }); - const encryptedUserProfiles = JSON.stringify(decryptedData); // Stringify decrypted data - fs.writeFileSync(dataFilePath, encryptedUserProfiles); // Write updated data to file - res.send(responseProfiles); // Send response containing user profiles -}); + // Map over profileIds to retrieve corresponding user profiles or create default profiles + const responseProfiles = profilesid.map(profileId => { + const userProfile = decryptedData[profileId]; // Get user profile based on profileId + if (userProfile) { + return { ...userProfile, ip: req.ip, ticket: ticket }; // Add IP to userProfile but not in the response + } else { + const defaultProfile = { ip: req.ip, ticket: ticket }; // Create a default profile with IP address + decryptedData[profileId] = defaultProfile; // Add default profile to decrypted data + return {}; // Return an empty object (don't include defaultProfile in response) + } + }); -// Endpoint to update or create a user profile -app.post("/profile/v2/profiles", (req, res) => { - const ticket = req.header("Authorization"); // Extract Authorization header - const content = req.body; // Extract content from request body - const dataFilePath = 'database/account/profiles/user.json'; // Path to user data file - const encryptedData = fs.readFileSync(dataFilePath, 'utf8'); // Read encrypted user data - let decryptedData; - try { - decryptedData = JSON.parse(encryptedData); // Parse decrypted user data - } catch (err) { - decryptedData = {}; // Set empty object if data cannot be parsed - } - - // Find a matching profile based on name or IP address (only one profile) - // Check whether this user is a cracked game user - if (content.name === "ALI123") { - return res.status(400).send({ - error: "Cracked user is not allowed to use profiles" - }); // Send 400 status with error message - } - const matchedProfileId = Object.keys(decryptedData).find(profileId => { - const userProfile = decryptedData[profileId]; // Get user profile based on profileId - return userProfile.name === content.name || userProfile.ip === req.ip; // Check for name or IP match - }); - - if (matchedProfileId) { - decryptedData[matchedProfileId] = content; // Update existing profile with posted content const encryptedUserProfiles = JSON.stringify(decryptedData); // Stringify decrypted data fs.writeFileSync(dataFilePath, encryptedUserProfiles); // Write updated data to file - res.send(encryptedUserProfiles); // Send updated encrypted data as response - } else { - res.status(404).send("Profile not found."); // Send 404 status if profile not found - } -}); + res.send(responseProfiles); // Send response containing user profiles + }); + + // Endpoint to update or create a user profile + app.post("/profile/v2/profiles", (req, res) => { + const ticket = req.header("Authorization"); // Extract Authorization header + const content = req.body; // Extract content from request body + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); // Path to user data file + let decryptedData; + try { + const encryptedData = fs.readFileSync(dataFilePath, 'utf8'); // Read encrypted user data + decryptedData = JSON.parse(encryptedData); // Parse decrypted user data + } catch (err) { + decryptedData = {}; // Set empty object if data cannot be parsed + } + + // Find a matching profile based on name or IP address (only one profile) + // Check whether this user is a cracked game user + if (content.name === "ALI123") { + return res.status(400).send({ + error: "Cracked user is not allowed to use profiles" + }); // Send 400 status with error message + } + const matchedProfileId = Object.keys(decryptedData).find(profileId => { + const userProfile = decryptedData[profileId]; // Get user profile based on profileId + return userProfile.name === content.name || userProfile.ticket === ticket || userProfile.ip === req.ip; // Check for name or IP match + }); + + if (matchedProfileId) { + decryptedData[matchedProfileId] = content; // Update existing profile with posted content + const encryptedUserProfiles = JSON.stringify(decryptedData); // Stringify decrypted data + fs.writeFileSync(dataFilePath, encryptedUserProfiles); // Write updated data to file + res.send(encryptedUserProfiles); // Send updated encrypted data as response + } else { + res.status(404).send("Profile not found."); // Send 404 status if profile not found + } + }); app.delete("/profile/v2/favorites/maps/:MapName", async (req, res) => { try { diff --git a/core/route/leaderboard.js b/core/route/leaderboard.js index c5ce7e9..b76db34 100644 --- a/core/route/leaderboard.js +++ b/core/route/leaderboard.js @@ -2,12 +2,14 @@ console.log(`[LEADERBOARD] Initializing....`); const fs = require("fs"); const axios = require("axios"); +const path = require("path"); const core = { main: require('../var').main, - CloneObject: require('../helper').CloneObject, + CloneObject: require('../helper').CloneObject, getSavefilePath: require('../helper').getSavefilePath, generateCarousel: require('../carousel/carousel').generateCarousel, generateSweatCarousel: require('../carousel/carousel').generateSweatCarousel, generateCoopCarousel: require('../carousel/carousel').generateCoopCarousel, updateMostPlayed: require('../carousel/carousel').updateMostPlayed } var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; +const DOTW_PATH = path.join(core.getSavefilePath(), 'leaderboard/dotw/'); function generateToolNickname() { const prefixes = ["Wordkeeper", "Special", "Krakenbite", "DinosaurFan", "Definehub", "Termtracker", "Lexiconet", "Vocabvault", "Lingolink", "Glossarygenius", "Thesaurustech", "Synonymster", "Definitionary", "Jargonjot", "Idiomizer", "Phraseforge", "Meaningmaker", "Languageledger", "Etymologyengine", "Grammarguard", "Syntaxsense", "Semanticsearch", "Orthographix", "Phraseology", "Vernacularvault", "Dictionet", "Slangscroll", "Lingualist", "Grammargrid", "Lingoledge", "Termtoolbox", "Wordware", "Lexigizmo", "Synosearch", "Thesaurustech", "Phrasefinder", "Vocabvortex", "Meaningmatrix", "Languageledger", "Etymologist", "Grammargate", "Syntaxsphere", "Semanticsearch", "Orthographix", "Phraseplay", "Vernacularvault", "Dictionator", "Slangstack", "Lingolink", "Grammarguide", "Lingopedia", "Termtracker", "Wordwizard", "Lexilist", "Synomate", "Thesaurustool", "Definitizer", "Jargonjunction", "Idiomgenius", "Phrasemaker", "Meaningmate", "Duolingo", "Languagelink", "Etymoengine", "Grammarguru", "Syntaxsage", "Semanticsuite", "Orthography", "Phrasefinder", "Vocabverse", "Lexipedia", "Synoscribe", "Thesaurusware", "Definitionary", "Jargonscribe", "Idiomster", "Phrasetech", "Meaningmax", "Flop", "Slayguy", "Languagelex", "Etymoedge", "Grammargenie", "Syntaxsync", "Semanticsearch", "Orthography", "Phraseforge", "Vernacularex", "Dictionmaster", "Slangster", "Lingoware", "Grammargraph", "Lingomate", "Termmate", "Wordwork", "Lexixpert", "Synostar", "Thesaurusmax", "OculusVision", "FlowerPower", "RustySilver", "Underfire", "Shakeawake", "Truthhand", "Kittywake", "Definize", "Jargonize", "Idiomify", "Phrasemaster", "Meaningmark", "Lingualine", "Etymogenius", "Grammarguard", "Syntaxsmart", "Semanticsearch", "Orthography", "Phrasedex", "Vocabmax", "Lexilock", "Synomind", "Thesaurusmart", "Definify", "Jargonmatrix", "Idiomnet", "Phraseplay", "Meaningmate", "Lingolink", "Etymoexpert", "Grammargetter", "Syntaxsage", "Semanticsearch", "Orthography", "Phrasepad", "Vernacularvibe", "Dictiondom", "Slangster", "Lingolytics", "Grammargenie", "Lingotutor", "Termtracker", "Wordwarp", "Lexisync", "Synomind", "Thesaurusmate", "Definizer", "Jargonify", "Idiomster", "Phraselab", "Meaningmark", "Languageleaf", "Etymoedge", "Grammargrid", "Syntaxsync", "Semanticsuite", "Orthographix", "Phraseforge", "Vernacularvibe", "Dictiondom", "Slangster", "Lingolytics", "Grammargenie", "Lingotutor", "Termtracker", "Wordwarp", "Lexisync", "Synomind", "Thesaurusmate", "Definizer", "Jargonify", "Idiomster", "Phraselab", "Meaningmark", "Languageleaf", "Etymoedge", "Grammargrid", "Syntaxsync", "Semanticsuite", "Orthographix"]; @@ -25,6 +27,35 @@ function generateToolNickname() { } } +const getProfileData = (req) => { + return new Promise((resolve, reject) => { + const ticket = req.header("Authorization"); + const sku = req.header('X-SkuId'); + const prodwsurl = "https://prod.just-dance.com/"; + const xhr33 = new XMLHttpRequest(); + + xhr33.open(req.method, prodwsurl + req.url, true); + xhr33.setRequestHeader("X-SkuId", sku); + xhr33.setRequestHeader("Authorization", ticket); + xhr33.setRequestHeader("Content-Type", "application/json"); + + xhr33.onload = () => { + if (xhr33.status >= 200 && xhr33.status < 300) { + resolve(JSON.parse(xhr33.responseText)); + } else { + reject(new Error(`HTTP status ${xhr33.status}`)); + } + }; + + xhr33.onerror = () => reject(new Error('Network error')); + xhr33.send(JSON.stringify(req.body)); + }); +}; + +const getGameVersion = (req) => { + const sku = req.header('X-SkuId'); + return sku.substring(0, 6); +}; const initroute = (app) => { app.post("/leaderboard/v1/maps/:mapName/friends", async (req, res) => { @@ -231,73 +262,57 @@ const initroute = (app) => { } }); - app.post("/profile/v2/map-ended", (req, res) => { - var codename = req.body; - for (let i = 0; i < codename.length; i++) { - var song = codename[i]; - core.updateMostPlayed(song) - if (fs.existsSync("./../../database/leaderboard/dotw/" + song.mapName + ".json")) { - const readFile = fs.readFileSync( - "./../../database/leaderboard/dotw/" + song.mapName + ".json" - ); - var JSONParFile = JSON.parse(readFile); - if (JSONParFile.score > song.score) { - res.send(`1`); - } - } else { - var ticket = req.header("Authorization"); - var xhr33 = new XMLHttpRequest(); - var sku = req.header('X-SkuId'); - var gameVer = sku.substring(0, 6); - var prodwsurl = "https://prod.just-dance.com/" - xhr33.open(req.method, prodwsurl + req.url, true); - xhr33.setRequestHeader("X-SkuId", sku); - xhr33.setRequestHeader("Authorization", ticket); - xhr33.setRequestHeader("Content-Type", "application/json"); - xhr33.send(JSON.stringify(req.body), null, 2); - var getprofil1 = xhr33.responseText.toString(); - for (let i = 0; i < getprofil1.length; i++) { - var profiljson = getprofil1[i]; - } + app.post("/profile/v2/map-ended", async (req, res) => { + const codename = req.body; - console.log(profiljson) + try { + for (let song of codename) { + core.updateMostPlayed(song); - // Creates the local DOTW file - var profiljson1 = JSON.parse(profiljson); - console.log(profiljson1) - var jsontodancerweek = { - __class: "DancerOfTheWeek", - score: song.score, - profileId: profiljson1.profileId, - gameVersion: gameVer, - rank: profiljson1.rank, - name: profiljson1.name, - avatar: profiljson1.avatar, - country: profiljson1.country, - platformId: profiljson1.platformId, - //"platformId": "2535467426396224", - alias: profiljson1.alias, - aliasGender: profiljson1.aliasGender, - jdPoints: profiljson1.jdPoints, - portraitBorder: profiljson1.portraitBorder, - }; - fs.writeFile("./../../database/leaderboard/dotw/" + song.mapName + ".json", jsontodancerweek, function (err) { - if (err) { - console.log(err); - } else { - console.log("DOTW file for" + song.mapName + "created!"); + const dotwFilePath = path.join(DOTW_PATH, `${song.mapName}.json`); + if (fs.existsSync(dotwFilePath)) { + const readFile = fs.readFileSync(dotwFilePath, 'utf-8'); + const JSONParFile = JSON.parse(readFile); + if (JSONParFile.score > song.score) { + return res.send('1'); } + } else { + const profiljson1 = await getProfileData(req); + if (!profiljson1) { + return res.status(500).send('Error fetching profile data'); + } + + const jsontodancerweek = { + __class: "DancerOfTheWeek", + score: song.score, + profileId: profiljson1.profileId, + gameVersion: getGameVersion(req), + rank: profiljson1.rank, + name: profiljson1.name, + avatar: profiljson1.avatar, + country: profiljson1.country, + platformId: profiljson1.platformId, + alias: profiljson1.alias, + aliasGender: profiljson1.aliasGender, + jdPoints: profiljson1.jdPoints, + portraitBorder: profiljson1.portraitBorder, + }; + + fs.writeFileSync(dotwFilePath, JSON.stringify(jsontodancerweek, null, 2)); + console.log(`DOTW file for ${song.mapName} created!`); + res.send(profiljson1); } - ); - res.send(profiljson); } + } catch (error) { + console.error(error); + res.status(500).send('Internal Server Error'); } }); app.get("/leaderboard/v1/maps/:map/dancer-of-the-week", (req, res) => { - const checkFile = fs.existsSync("./../../database/leaderboard/dotw/" + req.params.map + ".json"); - if (checkFile) { - const readFile = fs.readFile("./../../database/leaderboard/dotw/" + req.params.map + ".json"); + const dotwFilePath = path.join(DOTW_PATH, `${req.params.map}.json`); + if (fs.existsSync(dotwFilePath)) { + const readFile = fs.readFileSync(dotwFilePath, 'utf-8'); res.send(readFile); } else { res.setHeader('Content-Type', 'application/json; charset=utf-8'); diff --git a/settings.json b/settings.json index dd6706c..c0538a6 100644 --- a/settings.json +++ b/settings.json @@ -1,7 +1,7 @@ { "server": { "SaveData": { - "windows": "{Home}/AppData/Roaming/openparty/", + "windows": "{Home}\\AppData\\Roaming\\openparty\\", "linux": "{Home}/.openparty/" }, "port": 80,