您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Osu beatmap search with designated date
当前为
// ==UserScript== // @name Osu beatmap search // @namespace Osu // @version 0.1 // @description Osu beatmap search with designated date // @author Monorail // @match https://osu.ppy.sh/beatmapsets* // @grant none // ==/UserScript== (function() { 'use strict'; let parser = new DOMParser(); function componentInitialize(){ let a = new Date(); let TimeNow = { year: a.getFullYear(), month: a.getMonth(), day: a.getDate(), hour: a.getHours() }; // 設置開啟按鍵(左下方)、搜尋頁面、輸入框樣式,以及外層DOM結構 let ty = ` <style type="text/css"> .search-button { position: fixed; left: 150px; bottom: 20px; width: 75px; height: 75px; background: hsl(324, 68%, 45%); color: #fff; border-radius: 50%; display: flex; justify-content: center; align-items: center; cursor: pointer; z-index: 506; } .search-button-a { user-select: none; margin: 10px 10px; font-size: 2em; } .hidden { display: none; } .search-container { width: 100%; height: 75vh; position: fixed; top: 18vh; z-index: 505; } .search-main { margin: auto; width: 70%; height: 100%; background: hsl(0, 0%, 87%); box-shadow: 0px 0px 2px 1px #112233; } .inputArea { display: flex; align-items: center; } .inputArea input { max-width: 4em; } .goFind { background: hsl(210, 65%, 48%); color: #fff; border: none; border-radius: 1em; cursor: pointer; padding: 0.4em 0.8em; margin: 0.2em 0.2em; } .result-area { width: 96%; margin: auto; max-height: 67vh; overflow: auto; } </style> <div class="search-container hidden"> <div class="search-main"> <div class="inputArea"> <div class="input-start"> <input type="text" value=${TimeNow.year} class="input-start-year"> <input type="text" value=${TimeNow.month + 1} class="input-start-month"> <input type="text" value=${TimeNow.day} class="input-start-day"> </div> <button class="goFind">gogogogogo</button> </div> <div class="result-area"> </div> </div> </div> <div class="search-button"> <div class="search-button-a">S</div> </div> `; // insert DOM let DOM = parser.parseFromString(ty, "text/html"); let origBody = document.querySelectorAll("body")[0]; origBody.appendChild(DOM.querySelectorAll("style")[0]); DOM.querySelectorAll("body > div").forEach((divPart) => { origBody.appendChild(divPart); }); // set eventListenser of inserted button let btn = document.querySelectorAll(".search-button")[0]; let searchBox = document.querySelectorAll(".search-container")[0]; btn.addEventListener("click", (e) => { searchBox.classList.toggle("hidden"); }); return searchBox; } let searchBox = componentInitialize(); // search action & results layout let goFind = document.querySelectorAll(".goFind")[0]; function getUnixTime(date){ return new Date(date.year, date.month, date.day, 23).getTime(); } function fetchBeatmapData(unixTime){ return fetch(`https://osu.ppy.sh/beatmapsets/search?cursor%5Bapproved_date%5D=${unixTime}&cursor%5B_id%5D=`) .then(res => res.json()); } let resultArea = searchBox.querySelectorAll(".result-area")[0]; let cursor; function resultInitialize(){ resultArea.innerHTML = ` <style type="text/css"> .bm { display: flex; margin-bottom: 5px; } .bm-img > img:hover { box-shadow: 0 0 3px 1px #112233; cursor: pointer; } .bm-img-playing { box-shadow: 0 0 3px 2px #112233; } .bm-info { margin: 0 0 0.5em 1em; flex-grow: 1; } .bm a { text-decoration: none; } .bm-info-1, .bm-info-2 { margin-bottom: 0.5em; } .bm-info-2, .bm-info-3, .bm-info-4 { font-size: 0.8em; } .bm-info-float-right { float: right; } .bm-diff { margin-right: 4px; color: #fff; padding: 0 2px; border-radius: 4px; } .bm-mode-osu::before { content: "●"; } .bm-mode-taiko::before { content: "◎"; } .bm-mode-mania::before { content: "M"; } .bm-mode-fruits::before { content: "F"; } .bm-diff-easy { background: #8dad2c; } .bm-diff-normal { background: #43a0cf; } .bm-diff-hard { background: #d8af22; } .bm-diff-insane { background: #d52f6c; } .bm-diff-extra { background: #7e61d4; } .bm-diff-black { background: #2e2e2f; } </style>`; let inputTime = { year: searchBox.querySelectorAll(".input-start-year")[0].value, month: searchBox.querySelectorAll(".input-start-month")[0].value - 1, day: searchBox.querySelectorAll(".input-start-day")[0].value }; cursor = getUnixTime(inputTime); console.log(inputTime, cursor); } function arrange(bms){ let bmResult = []; bms.forEach((bm) => { let rankedDate = ""; if(bm.ranked_date != undefined){ let d = new Date(bm.ranked_date); rankedDate = `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}_${d.getHours()}時`; } function withVideo(){ if(bm.video === true) return "video included "; return ""; } function withSB(){ if(bm.storyboard === true) return "SB included"; return ""; } function generateDifficulty(diffs){ function inRange(a, b, c){ return a >= b && a <= c; } function diffColor(rate){ if(inRange(rate, -Infinity, 1.5)){ return "easy"; } // actually 2.25 by some observation else if(inRange(rate, 1.5, 2.4)){ return "normal"; } else if(inRange(rate, 2.4, 3.75)){ return "hard"; } // 6.7 ~ 6.85 else if(inRange(rate, 3.75, 5.25)){ return "insane"; } else if(inRange(rate, 5.25, 6.75)){ return "extra"; } else { return "black"; } } let str = ""; // 1. sort by difficulty rating diffs.sort((diff1, diff2) => { return diff1.difficulty_rating - diff2.difficulty_rating; }); // 2. sort by mode(osu, taiko, mania, fruits) let diffs_class = [[], [], [], []]; diffs.forEach((diff) => { diffs_class[diff.mode_int].push(diff); }) // 3. build string diffs_class.forEach((diff_class) => { diff_class.forEach((diff) => { str = str + `<span class="bm-mode-${diff.mode} bm-diff bm-diff-${diffColor(diff.difficulty_rating)}">${Math.round(diff.difficulty_rating * 10) / 10}</span>`; }); }); return str; } let bmt_v2 = ` <div class="bm"> <div class="bm-img js-audio--play" data-audio-url=${bm.preview_url}> <img src=${bm.covers.card}> </div> <div class="bm-info"> <div class="bm-info-3"> ${bm.source} </div> <div class="bm-info-1"> <a class="bm-title" href="/beatmapsets/${bm.id}" target="_blank">${bm.title}</a> <span class="bm-artist"> <- ${bm.artist}</span> </div> <div class="bm-info-2"> ${generateDifficulty(bm.beatmaps)} </div> <div class="bm-info-4"> <span class="bm-status">${bm.status}</span> <span class="bm-status">${rankedDate} </span> mapped by <a class="bm-creator" href="/users/${bm.user_id}" target="_blank">${bm.creator} </a> <a class="bm-download" data-turbolinks="false" href="/beatmapsets/${bm.id}/download">[dl]</a> <span>${withVideo()}${withSB()}</span><span class="bm-info-float-right">▶ ${bm.play_count}</span> </div> </div> </div> `; resultArea.appendChild( parser.parseFromString(bmt_v2, "text/html").querySelector(".bm") ); // let audio = document.querySelector("audio"); // audio.addEventListener("play", (e) => { // console.log(e.target.src); // }); // audio.addEventListener("pause", (e) => { // console.log(e.target.src); // }); }); } let limit = 300; let bmLoaded = 0; function appendLoadMoreButton(){ let loadSection = ` <div class="load-section"> <style> .load-section { display: flex; } .load-btn { background: hsl(210, 65%, 48%); color: #fff; border-radius: 1em; cursor: pointer; padding: 0.4em 0.8em; margin: 0.2em 0.2em; } </style> <div class="load-btn">load</div> </div> `; let loadSectionDOM = parser.parseFromString(loadSection, "text/html").querySelector(".load-section"); let loadBtnDOM = loadSectionDOM.querySelector(".load-btn"); loadBtnDOM.addEventListener("click", SLBM); resultArea.appendChild(loadSectionDOM); } function SLBM(e){ if(e.target.classList.contains("goFind")){ resultInitialize(); } if(e.target.classList.contains("load-btn")){ resultArea.querySelector(".load-section").remove(); } fetchBeatmapData(cursor) .then(data => { console.log(data.beatmapsets); console.log(data.cursor); arrange(data.beatmapsets); appendLoadMoreButton(); cursor = data.cursor.approved_date; }); } goFind.addEventListener("click", SLBM); })();