diff --git a/public/javascript/user.js b/public/javascript/user.js index c8eb5a9..7ec3d31 100644 --- a/public/javascript/user.js +++ b/public/javascript/user.js @@ -20,8 +20,6 @@ clearStorageBtn.addEventListener('click', () => { // Example usage removeCookies(); - - console.log('Local storage cleared.'); window.location = "/"; }); @@ -51,7 +49,6 @@ for (let i = 0; i < cookies.length; i++) { // Send the user to the sign in page if they aren't already signed in to the website. if (ext_id && luid) { - console.log(`ext_id: ${ext_id}, luid: ${luid}`); } else { console.log('User Data Not Detected! Please Sign In.'); @@ -73,7 +70,7 @@ function padNumber(num, size) { return s; } -async function getSongInformation(musicData, id) { +async function getReleventInformation(musicData, id) { const songMatch = musicData[id]; if (!songMatch) { return null; @@ -147,11 +144,11 @@ let scoreIncrement = 0; let errorIncrement = 0; let displayedScoreCount = 20; +/* welcome to hell */ async function userPlayLogFormatter(div, loadMoreButton) { const UserPlayLogData = await UserPlayLog(aime_card_id); - console.log(UserPlayLogData) let scoresWrapperDiv = document.getElementById("scoreWrapper"); - + document.getElementById('RawUserPlayLog').innerHTML = JSON.stringify(UserPlayLogData, null, 2); // If the scores wrapper div doesn't exist, create it. if (scoresWrapperDiv === null) { scoresWrapperDiv = document.createElement('div'); @@ -174,7 +171,10 @@ async function userPlayLogFormatter(div, loadMoreButton) { for (let i = UserPlayLogData.length - 1; i >= 0; i--) { const scoreDiv = document.createElement('div'); // Create a Div let score = JSON.parse(JSON.stringify(UserPlayLogData[i])); // get score data - let song = await getSongInformation(musicData, score.music_id) // get song data + let song = await getReleventInformation(musicData, score.music_id) // get song data + if (song === null) { + continue + } let diffucultyData = song.difficultys.Notes[score.level] // get difficulty information if (!song || !song.name) { // if a song can't be found, skip it and increment the error counter by 1. @@ -231,12 +231,15 @@ async function userPlayLogFormatter(div, loadMoreButton) { /* DX Score */ const scoreDXScoreDiv = document.createElement('div'); scoreDXScoreDiv.classList.add('DX-Score'); - scoreDXScoreDiv.innerHTML = `

DX Score: ${score.deluxscore} / ${diffucultyData.maxNotes * 3}

`; + scoreDXScoreDiv.innerHTML = `
DX Score: ${score.deluxscore}/${diffucultyData.maxNotes * 3}
`; scoreInfoGridDiv.append(scoreDXScoreDiv); scoreInfoDiv.append(scoreInfoGridDiv); scoreDiv.append(scoreInfoDiv); - - + /* Full Combo */ + /* Full Sync */ + /* Player Placement */ + /* Side note: Can't Do Any of this without the Image Assets / Information, So Moving on for now */ + /* setting stuff up */ scoreDiv.setAttribute("class", "score-grid"); scoreIncrement++ @@ -258,13 +261,54 @@ async function userPlayLogFormatter(div, loadMoreButton) { } } +/* User Area Status Renderer */ - - - - - - +async function userAreaStatusFormatter(div) { + const UserAreaData = await userAreaInfomation(aime_card_id); + document.getElementById('RawUserArea').innerHTML = JSON.stringify(UserAreaData, null, 2); + const mapMetadata = await mapsMetadata() + let areaWrapper = document.createElement('div'); // create the Wrapper Div + for (let i = UserAreaData.length - 1; i >= 0; i--) { + const area = UserAreaData[i]; // get the area + const mapInfo = await getReleventInformation(mapMetadata, area.map_id); // get the relevent Map Information + console.log(mapInfo) + const areaGrid = document.createElement('div'); // create the Grid for the area inforrmation to go + areaGrid.classList.add('areaGrid'); // add the appropriate class + /* Area Title */ + let areaTitle = document.createElement('div'); + areaTitle.classList.add('areaTitle'); + areaTitle.innerHTML = `

${mapInfo.name.str}

` + areaGrid.append(areaTitle) + /* Kilometers */ + let areaKilometers = document.createElement('div'); + areaKilometers.classList.add('areaKilometers'); + areaKilometers.innerHTML = `${area.distance} KM Traveled!`; + if (area.is_complete === 1) { // If the Area is complete, denote that in the areaKilometers. + areaKilometers.innerHTML = areaKilometers.innerHTML + ` Area Complete!`; + } else { // else check if unlock rewards exist, and then calculate the diffrence between the next reward and the current distance traveled. + if (mapInfo.mapInfomation.unlockRewards !== undefined) { + for (unlock of mapInfo.mapInfomation.unlockRewards) { + if (area.distance > unlock.Distance) { + continue + } else if (area.distance !== 0) { + let diffrence = unlock.Distance - area.distance + if (diffrence === 0) { + areaKilometers.innerHTML = areaKilometers.innerHTML + ` Task Track! Clear the song to continue!`; + } else { + areaKilometers.innerHTML = areaKilometers.innerHTML + ` ${diffrence} KM until Next Reward.`; + } + break + } + } + } + } + areaGrid.append(areaKilometers) + // Append to AreaGrid + areaWrapper.append(areaGrid); + } + // Place everything done here Inside the parent Div + div.appendChild(areaWrapper) +} //===================================================================== // Now Exiting: User Data ////////////// Now Entering: Nested Div Hell @@ -280,6 +324,8 @@ const showContent = (contentNumber) => { if (div === contentDiv) { if (contentNumber === 2) { // If the ContentNumber is set to the PlayLog, Go to the userPlayLogFormatter Function userPlayLogFormatter(div) + } else if (contentNumber === 6) { + userAreaStatusFormatter(div) } div.classList.remove('hidden'); } else { @@ -311,6 +357,25 @@ function UserPlayLog(aime_card_id) { .catch(error => console.error(error)); } +function userAreaInfomation(aime_card_id) { + const input = aime_card_id; + const url = "/api/getUserArea/"; + + // Return the fetch promise so that it can be handled within userPlayLogFormatter + return fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + input: aime_card_id + }) + }) + .then(response => response.json()) + .then(data => data.data) + .catch(error => console.error(error)); +} + async function musicMetadata() { const url = "/assets/metadata/musicMetadata.json"; @@ -335,5 +400,26 @@ async function musicMetadata() { } } +async function mapsMetadata() { + const url = "/assets/metadata/mapMetadata.json"; + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + + const mapping = {}; + data.forEach((song) => { + mapping[song.name.id] = song; + }); + + return mapping; + } catch (error) { + console.error(error); + } +} \ No newline at end of file diff --git a/public/stylesheets/user.css b/public/stylesheets/user.css index 21b4c97..b6a3ab2 100644 --- a/public/stylesheets/user.css +++ b/public/stylesheets/user.css @@ -147,27 +147,101 @@ h4.profile { #scoreWrapper { grid-area: 3 / 2 / 4 / 4; - width:auto; + width: auto; align-items: start; justify-items: start; + margin: auto; } +#areaWrapper { + grid-area: 3 / 2 / 4 / 4; + width: auto; + align-items: start; + justify-items: start; + margin: auto; +} + +/* Grid Hell */ + +.areaGrid { + display: grid; + + grid-template-rows: min-content min-content min-content; + grid-template-columns: max-content max-content min-content; + + grid-template-areas: + 'title title title' + 'kilometers kilometers kilometersReward' + '. . details'; + + gap: 0px; + height: 100%; + max-width: 75%; +} + +.areaTitle { + grid-area: title; +} + +.areaKilometers { + grid-area: kilometers; +} +/* Galexion make your fucking mind up are you going to use camelCase or dashe-instead-of-spaces */ .score-grid { display: grid; - grid-template-rows: min-content min-content 1fr; - grid-template-columns: 300px 300px 5em; + grid-template-rows: min-content min-content min-content; + grid-template-columns: 15em min-content min-content; grid-template-areas: - 'label0 label0 label0' - 'label1 label2 label3' - 'label1 label4 label4'; + 'label0 label0' + 'label1 label2' + 'label1 label3' + 'label1 label4'; gap: 0px; + height: 100%; + max-width: 75%; } +@media (min-width: 600px) { + .score-grid { + max-width: 80%; + width: 80%; + grid-template-rows: max-content min-content min-content; + grid-template-columns: 1fr 1fr 1fr; + grid-template-areas: + 'label0 label0 label0' + 'label1 label2 label3' + 'label1 label4 label4'; + margin: auto; + } + .score-jacket { + + background-color: #9EF6B5; + grid-area: label1; + display: block; + margin-left: auto; + margin-right: auto; + max-width: 100%; + width: 100%; + + } + + /* Please I really dont want to make a nested grid */ +.score-info-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(3, 1fr); + grid-gap: 10px; + grid-template-areas: + "DX-Score DX-Score DX-Score" + "full-combo full-sync multi-place" + ". . details"; +} +} .score-title { @@ -176,18 +250,6 @@ h4.profile { } -.score-jacket { - - background-color: #9EF6B5; - grid-area: label1; - display: block; - margin-left: auto; - margin-right: auto; - max-width: 100%; - width: 100%; - -} - .score-achivement { background-color: #ED69FD; @@ -211,8 +273,8 @@ h4.profile { /* Please I really dont want to make a nested grid */ .score-info-grid { display: grid; - grid-template-columns: repeat(3, 1fr); - grid-template-rows: repeat(3, 1fr); + grid-template-columns: repeat(3, min-content); + grid-template-rows: repeat(3, min-content); grid-gap: 10px; grid-template-areas: "DX-Score DX-Score DX-Score" @@ -222,4 +284,20 @@ h4.profile { .DX-Score { grid-area: DX-Score; +} + +.score-jacket { + + background-color: #9EF6B5; + grid-area: label1; + display: block; + margin-left: auto; + margin-right: auto; + max-width: 75%; + width: 75%; + +} + +h4.DX-Score { + font-size: 2em; } \ No newline at end of file diff --git a/readme.md b/readme.md index 296eab9..1fff88f 100644 --- a/readme.md +++ b/readme.md @@ -16,12 +16,19 @@ in the public folder, the assets should look like this ``` -- Public | - Assets -\_ | - icon (icons should go here) - | - more soon +\_ | - icon + | - jacket + | - metadata ``` Then, create the `/public/image/` folder. this will be where the images will be stored. +You'll also need the Game metadata, extracted using SegaParser (Not Released Yet), +to get the game metadata. this is ***Nessasary*** for the interface to function. + +Q. Why isn't SegaParser Released yet? +A. SegaParser is still being developed and I want to make sure that I can provide the code to actually make it possible to just run 1 or more js files, and extract all the metadata you need to run the interface. if your intrested in helping me out, reach out to me on discord, and I'll provide Segaparser to help you get your own instance running. + ## Aqua Create a `config.json` file and paste this in, with paths to your instance. @@ -40,10 +47,15 @@ ToDo: - Get User Playlog Data (Done) - Sort From Most Recent (Done) - Assign Song Names to Each Score (done) - - Re-Create the MaiMaiDXNet Playlog list (Partially Done) + - Re-Create the MaiMaiDXNet Playlog list (90% Done, can't continue without image assets that are only on the offical Server) - Create Detailed Look Into Score - Create Photos Tab - Create Area Tab + - Get User Area Data (Done) + - Get Metadata for Area (Done) + - Show if Area is complete (Done) + - Show Kilometers left until Next Reward (Done+, you can also see if you have a Task Track you need to complete) + - create what ever is in the details tab - Create Collection Tab - Create Ranking Tab - Create Options Tab diff --git a/routes/api.js b/routes/api.js index b0112b6..1ac2390 100644 --- a/routes/api.js +++ b/routes/api.js @@ -70,5 +70,25 @@ let db = new sqlite3.Database('A:\\db.sqlite'); }); }); + router.post('/getUserArea/', function (req,res,next) { + db.all('SELECT * FROM maimai2_user_map', (err, rows) => { + if (err) { + console.error(err); + // Return a Failed Message. + res.status(500).json({ error: err.message, status: "Failed" }); + } else { + // Make the Request easier to get to. + var request = req.body; + var mUser = new Array(); // Leave the Matched User's Areas undefined until the user is found. + for (map of rows) { // For Each Area in Rows + if (request.input == map.user_id) { // If the inputed User ID and Score's User ID Matches, + mUser.push(map) // add that Area into the array. + } + } + // Return a Response with all the Areas listed under that user. + res.status(200).json({ data: mUser, status: "Complete" }); + } + }); + }); module.exports = router; \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index 2eb63dc..2a718bc 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -11,6 +11,15 @@ +
+

+ Known Issues: +

+
+ - Site Is Not Complete
+ - Unfortunatly Some Song Jackets Cannot be found, which will lead certain lisenced and original songs to load without their jackets when checking your play log. +
+
\ No newline at end of file diff --git a/views/user.ejs b/views/user.ejs index d6335c9..7b0a248 100644 --- a/views/user.ejs +++ b/views/user.ejs @@ -42,6 +42,12 @@

Please Wait, Obtaining Scores...

+ @@ -54,6 +60,14 @@ Raw User Details
<%=JSON.stringify(userdata, null, 2)%>
+
+ Raw User Playlog +
{"No Data": "Load the `Play Log` Tab First to See the Raw Playlog Data"}
+
+
+ Raw User Area +
{"No Data": "Load the `Area` Tab First to See the Raw User Area Data"}
+