diff --git a/app.py b/app.py index 4519357..3d75228 100644 --- a/app.py +++ b/app.py @@ -191,8 +191,9 @@ def route_admin(): @admin_required(level=50) def route_admin_songs(): songs = db.songs.find({}) + categories = db.categories.find({}) user = db.users.find_one({'username': session['username']}) - return render_template('admin_songs.html', songs=list(songs), admin=user) + return render_template('admin_songs.html', songs=list(songs), admin=user, categories=list(categories)) @app.route('/admin/songs/') @@ -373,7 +374,7 @@ def route_api_songs(): song['category'] = db.categories.find_one({'id': song['category_id']})['title'] else: song['category'] = None - del song['category_id'] + #del song['category_id'] if song['skin_id']: song['song_skin'] = db.song_skins.find_one({'id': song['skin_id']}, {'_id': False, 'id': False}) @@ -383,6 +384,11 @@ def route_api_songs(): return jsonify(songs) +@app.route('/api/categories') +@app.cache.cached(timeout=15) +def route_api_categories(): + categories = list(db.categories.find({},{'_id': False})) + return jsonify(categories) @app.route('/api/config') @app.cache.cached(timeout=15) diff --git a/public/assets/img/bg_genre_7.png b/public/assets/img/bg_genre_def.png similarity index 100% rename from public/assets/img/bg_genre_7.png rename to public/assets/img/bg_genre_def.png diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 919b5f3..dd9830c 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -75,14 +75,7 @@ var assets = { "don_anim_clear_b2.png", "fire_anim.png", "fireworks_anim.png", - "bg_genre_0.png", - "bg_genre_1.png", - "bg_genre_2.png", - "bg_genre_3.png", - "bg_genre_4.png", - "bg_genre_5.png", - "bg_genre_6.png", - "bg_genre_7.png", + "bg_genre_def.png", "bg_score_p1.png", "bg_score_p2.png", "bg_settings.png", @@ -157,7 +150,8 @@ var assets = { "songs": [], "sounds": {}, "image": {}, - "pages": {} + "pages": {}, + "categories": [] } var gameConfig = {} diff --git a/public/src/js/importsongs.js b/public/src/js/importsongs.js index 87d63df..1687e0b 100644 --- a/public/src/js/importsongs.js +++ b/public/src/js/importsongs.js @@ -38,25 +38,22 @@ "oni": 3, "ura": 4 } - this.categories = { - "ボーカロイド曲": "ボーカロイド™曲", - "ボーカロイド": "ボーカロイド™曲", - "vocaloid music": "ボーカロイド™曲", - "vocaloid": "ボーカロイド™曲", - "バラエティー": "バラエティ", - "どうよう": "バラエティ", - "童謡・民謡": "バラエティ", - "children": "バラエティ", - "children/folk": "バラエティ", - "children-folk": "バラエティ", - "クラッシック": "クラシック", - "classic": "クラシック" - } - for(var i in allStrings){ - for(var ja in allStrings[i].categories){ - this.categories[allStrings[i].categories[ja].toLowerCase()] = ja + + this.categoryAliases = {} + assets.categories.forEach(cat => { + this.categoryAliases[cat.title.toLowerCase()] = cat.id + if(cat.aliases){ + cat.aliases.forEach(alias => { + this.categoryAliases[alias.toLowerCase()] = cat.id + }) } - } + if(cat.title_lang){ + for(var i in cat.title_lang){ + this.categoryAliases[cat.title_lang[i].toLowerCase()] = cat.id + } + } + }) + this.assetSelectors = { "bg-pattern-1": ".pattern-bg", "bg_genre_0": "#song-select", @@ -137,7 +134,11 @@ var equalsPos = line.indexOf("=") if(equalsPos !== -1 && line.slice(0, equalsPos).trim() === "genrename"){ var value = line.slice(equalsPos + 1).trim() - category = this.categories[value] || data[i].trim().slice(equalsPos + 1).trim() + if(value.toLowerCase() in this.categoryAliases){ + category = value + }else{ + category = data[i].trim().slice(equalsPos + 1).trim() + } break } } @@ -147,12 +148,16 @@ var line = data[i].trim().toLowerCase() if(line.startsWith("#title:")){ var value = line.slice(7).trim() - if(value in this.categories){ - category = this.categories[value] + if(value.toLowerCase() in this.categoryAliases){ + category = value } }else if(line.startsWith("#genre:")){ var value = line.slice(7).trim() - category = this.categories[value] || data[i].trim().slice(7).trim() + if(value.toLowerCase() in this.categoryAliases){ + category = value + }else{ + category = data[i].trim().slice(7).trim() + } break } } @@ -176,7 +181,11 @@ var filesLoop = fileObj => { var tjaPath = fileObj.file.webkitRelativePath.toLowerCase().slice(0, fileObj.file.name.length * -1) if(tjaPath.startsWith(metaPath) && (!("categoryLevel" in fileObj) || fileObj.categoryLevel < level)){ - fileObj.category = category + if(category.toLowerCase() in this.categoryAliases){ + fileObj.category_id = this.categoryAliases[category.toLowerCase()] + }else{ + fileObj.category = category + } fileObj.categoryLevel = level } } @@ -196,6 +205,7 @@ var file = fileObj.file var index = fileObj.index var category = fileObj.category + var category_id = fileObj.category_id var reader = new FileReader() var promise = pageEvents.load(reader).then(event => { var data = event.target.result.replace(/\0/g, "").split("\n") @@ -215,7 +225,6 @@ var subtitleLang = {} var dir = file.webkitRelativePath.toLowerCase() dir = dir.slice(0, dir.lastIndexOf("/") + 1) - var hasCategory = false for(var diff in tja.metadata){ var meta = tja.metadata[diff] songObj.title = meta.title || file.name.slice(0, file.name.lastIndexOf(".")) @@ -234,7 +243,11 @@ songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music } if(meta.genre){ - songObj.category = this.categories[meta.genre.toLowerCase()] || meta.genre + if(meta.genre.toLowerCase() in this.categoryAliases){ + songObj.category_id = this.categoryAliases[meta.genre.toLowerCase()] + }else{ + songObj.category = meta.genre + } } if(meta.taikowebskin){ songObj.song_skin = this.getSkin(dir, meta.taikowebskin) @@ -298,8 +311,15 @@ if(subtitleLangAdded){ songObj.subtitle_lang = subtitleLang } - if(!songObj.category){ - songObj.category = category || this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))]) + if(!songObj.category_id && !songObj.category){ + if(!category && category_id === undefined){ + songObj.category_id = this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))]) + }else if(category){ + songObj.category = category + songObj.orginalCategory = category + }else{ + songObj.category_id = category_id + } } if(coursesAdded){ this.songs[index] = songObj @@ -320,6 +340,7 @@ var file = fileObj.file var index = fileObj.index var category = fileObj.category + var category_id = fileObj.category_id var reader = new FileReader() var promise = pageEvents.load(reader).then(event => { var data = event.target.result.replace(/\0/g, "").split("\n") @@ -360,7 +381,14 @@ songObj.title = filename } this.songs[index] = songObj - songObj.category = category || this.getCategory(file, [osu.metadata.TitleUnicode, osu.metadata.Title, file.name.slice(0, file.name.lastIndexOf("."))]) + if(!category && category_id === undefined){ + songObj.category_id = this.getCategory(file, [osu.metadata.TitleUnicode, osu.metadata.Title, file.name.slice(0, file.name.lastIndexOf("."))]) + }else if(category){ + songObj.category = category + songObj.orginalCategory = category + }else{ + songObj.category_id = category_id + } var hash = md5.base64(event.target.result).slice(0, -2) songObj.hash = hash scoreStorage.songTitles[songObj.title] = hash @@ -445,9 +473,9 @@ } } if(!hasTitle){ - for(var cat in this.categories){ + for(var cat in this.categoryAliases){ if(path[i].indexOf(cat) !== -1){ - return this.categories[cat] + return this.categoryAliases[cat] } } } diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 8bb00ef..fee5647 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -86,7 +86,7 @@ class Loader{ }), url) } - assets.img.forEach(name => { + assets.img.forEach(name=>{ var id = this.getFilename(name) var image = document.createElement("img") var url = gameConfig.assets_baseurl + "img/" + name @@ -104,6 +104,28 @@ class Loader{ assets.pages[id] = page }), url) }) + + this.addPromise(this.ajax("/api/categories").then(cats => { + assets.categories = JSON.parse(cats) + assets.categories.forEach(cat => { + if(cat.song_skin){ + cat.songSkin = cat.song_skin //rename the song_skin property and add category title to categories array + delete cat.song_skin + cat.songSkin.infoFill = cat.songSkin.info_fill + delete cat.songSkin.info_fill + } + }); + + assets.categories.push({ + title: "default", + songSkin: { + background: "#ececec", + border: ["#fbfbfb", "#8b8b8b"], + outline: "#656565", + infoFill: "#656565" + } + }) + }), "/api/categories") this.addPromise(this.ajax("/api/songs").then(songs => { assets.songsDefault = JSON.parse(songs) @@ -127,7 +149,21 @@ class Loader{ if(this.error){ return } - + + assets.categories //load category backgrounds to DOM + .filter(cat=>cat.songSkin && cat.songSkin.bg_img) + .forEach(cat=>{ + let name = cat.songSkin.bg_img + var id = this.getFilename(name) + var image = document.createElement("img") + var url = gameConfig.assets_baseurl + "img/" + name + this.addPromise(pageEvents.load(image), url) + image.id = name + image.src = url + this.assetsDiv.appendChild(image) + assets.image[id] = image + }) + snd.buffer = new SoundBuffer() snd.musicGain = snd.buffer.createGain() snd.sfxGain = snd.buffer.createGain() @@ -264,11 +300,8 @@ class Loader{ this.callback(songId) pageEvents.send("ready", readyEvent) }) - }, this.errorMsg.bind(this)) - - - }) - + }, this.errorMsg.bind(this)) + }) } addPromise(promise, url){ this.promises.push(promise) diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index b8836bc..43ca8d8 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -26,98 +26,84 @@ class SongSelect{ outline: "#ad7723" }, "random": { - sort: 7, + sort: 0, background: "#fa91ff", border: ["#ffdfff", "#b068b2"], outline: "#b221bb" }, "tutorial": { - sort: 7, + sort: 0, background: "#29e8aa", border: ["#86ffbd", "#009a8c"], outline: "#08a28c" }, "about": { - sort: 7, + sort: 0, background: "#a2d0e7", border: ["#c6dfff", "#4485d9"], outline: "#2390d9" }, "settings": { - sort: 7, + sort: 0, background: "#ce93fa", border: ["#dec4fd", "#a543ef"], outline: "#a741ef" }, "browse": { - sort: 7, + sort: 0, background: "#fab5d3", border: ["#ffe7ef", "#d36aa2"], outline: "#d36aa2" }, - "J-POP": { - sort: 0, - background: "#219fbb", - border: ["#7ec3d3", "#0b6773"], - outline: "#005058" - }, - "アニメ": { - sort: 1, - background: "#ff9700", - border: ["#ffdb8c", "#e75500"], - outline: "#9c4100" - }, - "ボーカロイド™曲": { - sort: 2, - background: "#def2ef", - border: ["#f7fbff", "#79919f"], - outline: "#5a6584" - }, - "バラエティ": { - sort: 3, - background: "#8fd321", - border: ["#f7fbff", "#587d0b"], - outline: "#374c00" - }, - "クラシック": { - sort: 4, - background: "#d1a016", - border: ["#e7cf6b", "#9a6b00"], - outline: "#734d00" - }, - "ゲームミュージック": { - sort: 5, - background: "#9c72c0", - border: ["#bda2ce", "#63407e"], - outline: "#4b1c74" - }, - "ナムコオリジナル": { - sort: 6, - background: "#ff5716", - border: ["#ffa66b", "#b53000"], - outline: "#9c2000" - }, "default": { - sort: 7, + sort: null, background: "#ececec", border: ["#fbfbfb", "#8b8b8b"], - outline: "#656565" + outline: "#656565", + infoFill: "#656565" } } + + var songSkinLength = Object.keys(this.songSkin).length + for(var i in assets.categories){ + var category = assets.categories[i] + if(!this.songSkin[category.title] && category.songSkin){ + if(category.songSkin.sort === null){ + category.songSkin.sort = songSkinLength + 1 + } + this.songSkin[category.title] = category.songSkin + } + } + this.songSkin["default"].sort = songSkinLength + 1 + this.font = strings.font this.songs = [] for(let song of assets.songs){ var title = this.getLocalTitle(song.title, song.title_lang) var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang) + var skin = null + var categoryName = "" + var originalCategory = "" + if(song.category_id !== null && song.category_id !== undefined){ + var category = assets.categories.find(cat => cat.id === song.category_id) + var categoryName = this.getLocalTitle(category.title, category.title_lang) + var originalCategory = category.title + var skin = this.songSkin[category.title] + }else if(song.category){ + var categoryName = song.category + var originalCategory = song.category + } this.songs.push({ id: song.id, title: title, originalTitle: song.title, subtitle: subtitle, - skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default, + skin: skin || this.songSkin.default, courses: song.courses, - category: song.category, + originalCategory: originalCategory, + category: categoryName, + category_id: song.category_id, preview: song.preview || 0, type: song.type, offset: song.offset, @@ -132,16 +118,16 @@ class SongSelect{ }) } this.songs.sort((a, b) => { - var catA = a.category in this.songSkin ? this.songSkin[a.category] : this.songSkin.default - var catB = b.category in this.songSkin ? this.songSkin[b.category] : this.songSkin.default - if(catA.sort === catB.sort){ - if(a.order === b.order){ - return a.id > b.id ? 1 : -1 - }else{ - return a.order > b.order ? 1 : -1 - } - }else{ + var catA = a.originalCategory in this.songSkin ? this.songSkin[a.originalCategory] : this.songSkin.default + var catB = b.originalCategory in this.songSkin ? this.songSkin[b.originalCategory] : this.songSkin.default + if(catA.sort !== catB.sort){ return catA.sort > catB.sort ? 1 : -1 + }else if(a.originalCategory !== b.originalCategory){ + return a.originalCategory > b.originalCategory ? 1 : -1 + }else if(a.order !== b.order){ + return a.order > b.order ? 1 : -1 + }else{ + return a.id > b.id ? 1 : -1 } }) this.songs.push({ @@ -290,9 +276,8 @@ class SongSelect{ } this.songSelect = document.getElementById("song-select") - var cat = this.songs[this.selectedSong].category - var sort = cat in this.songSkin ? this.songSkin[cat].sort : 7 - this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_" + sort].src + "')" + var cat = this.songs[this.selectedSong].originalCategory + this.drawBackground(cat) this.previewId = 0 this.previewList = Array(5) @@ -799,6 +784,7 @@ class SongSelect{ "folder": selectedSong.id, "difficulty": diff, "category": selectedSong.category, + "category_id":selectedSong.category_id, "type": selectedSong.type, "offset": selectedSong.offset, "songSkin": selectedSong.songSkin, @@ -953,13 +939,11 @@ class SongSelect{ this.nameplateCache.resize(274, 134, ratio + 0.2) - var categories = 0 var lastCategory this.songs.forEach(song => { var cat = (song.category || "") + song.skin.outline if(lastCategory !== cat){ lastCategory = cat - categories++ } }) this.categoryCache.resize(280, this.songAsset.marginTop + 1 , ratio + 0.5) @@ -1075,8 +1059,8 @@ class SongSelect{ ]) }) - var category = this.songs[this.selectedSong].category var selectedSong = this.songs[this.selectedSong] + var category = selectedSong.category this.draw.category({ ctx: ctx, x: winW / 2 - 280 / 2 - 30, @@ -1101,8 +1085,9 @@ class SongSelect{ id: category + selectedSong.skin.outline }, ctx => { if(category){ - if(category in strings.categories){ - var categoryName = strings.categories[category] + let cat = assets.categories.find(cat=>cat.title === category) + if(cat){ + var categoryName = this.getLocalTitle(cat.title, cat.title_lang) }else{ var categoryName = category } @@ -1199,9 +1184,8 @@ class SongSelect{ } if(this.songs[this.selectedSong].action !== "back"){ - var cat = this.songs[this.selectedSong].category - var sort = cat in this.songSkin ? this.songSkin[cat].sort : 7 - this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_" + sort].src + "')" + var cat = this.songs[this.selectedSong].originalCategory + this.drawBackground(cat) } } if(this.state.moveMS && ms < this.state.moveMS + changeSpeed){ @@ -2306,6 +2290,15 @@ class SongSelect{ scoreStorage.eventLoop() } } + + drawBackground(cat){ + if(this.songSkin[cat] && this.songSkin[cat].bg_img){ + let filename = this.songSkin[cat].bg_img.slice(0, this.songSkin[cat].bg_img.lastIndexOf(".")) + this.songSelect.style.backgroundImage = "url('" + assets.image[filename].src + "')" + }else{ + this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_def"].src + "')" + } + } drawClosedSong(config){ var ctx = config.ctx diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 9d99ff2..cca613e 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -46,54 +46,6 @@ var translations = { titleCopyright: { en: "Taiko no Tatsujin ©&™ 2011 BANDAI NAMCO Entertainment Inc." }, - categories: { - "J-POP": { - ja: "J-POP", - en: "Pop", - cn: "流行音乐", - tw: "流行音樂", - ko: "POP" - }, - "アニメ": { - ja: "アニメ", - en: "Anime", - cn: "卡通动画音乐", - tw: "卡通動畫音樂", - ko: "애니메이션" - }, - "ボーカロイド™曲": { - ja: "ボーカロイド™曲", - en: "VOCALOID™ Music" - }, - "バラエティ": { - ja: "バラエティ", - en: "Variety", - cn: "综合音乐", - tw: "綜合音樂", - ko: "버라이어티" - }, - "クラシック": { - ja: "クラシック", - en: "Classical", - cn: "古典音乐", - tw: "古典音樂", - ko: "클래식" - }, - "ゲームミュージック": { - ja: "ゲームミュージック", - en: "Game Music", - cn: "游戏音乐", - tw: "遊戲音樂", - ko: "게임" - }, - "ナムコオリジナル": { - ja: "ナムコオリジナル", - en: "NAMCO Original", - cn: "NAMCO原创音乐", - tw: "NAMCO原創音樂", - ko: "남코 오리지널" - } - }, selectSong: { ja: "曲をえらぶ", en: "Select Song", diff --git a/public/src/js/view.js b/public/src/js/view.js index 21ab405..5c5711f 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -23,40 +23,6 @@ this.darkDonBg = false this.pauseOptions = strings.pauseOptions - this.categories = { - "J-POP": { - sort: 0, - infoFill: "#004d68" - }, - "アニメ": { - sort: 1, - infoFill: "#9c4002" - }, - "ボーカロイド™曲": { - sort: 2, - infoFill: "#546184" - }, - "バラエティ": { - sort: 3, - infoFill: "#3c6800" - }, - "クラシック": { - sort: 4, - infoFill: "#865800" - }, - "ゲームミュージック": { - sort: 5, - infoFill: "#4f2886" - }, - "ナムコオリジナル": { - sort: 6, - infoFill: "#961e00" - }, - "default": { - sort: 7, - infoFill: "#656565" - } - } this.difficulty = { "easy": 0, "normal": 1, @@ -329,10 +295,12 @@ var _h = 22 var _x = 628 - _w var _y = 88 - _h - if(selectedSong.category in this.categories){ - ctx.fillStyle = this.categories[selectedSong.category].infoFill + + let category = assets.categories.find(cat=>cat.id == selectedSong.category_id) + if(category != null && category.songSkin != null && category.songSkin.infoFill != null){ + ctx.fillStyle = category.songSkin.infoFill }else{ - ctx.fillStyle = this.categories.default.infoFill + ctx.fillStyle = assets.categories.find(cat=>cat.title == 'default').songSkin.infoFill } this.draw.roundedRect({ ctx: ctx, @@ -340,16 +308,11 @@ w: _w, h: _h, radius: 11 }) - ctx.fill() - - if(selectedSong.category in strings.categories){ - var categoryName = strings.categories[selectedSong.category] - }else{ - var categoryName = selectedSong.category - } + ctx.fill() + this.draw.layeredText({ ctx: ctx, - text: categoryName, + text: selectedSong.category, fontSize: 15, fontFamily: this.font, align: "center", @@ -1425,12 +1388,6 @@ var songLayers = [document.getElementById("layer1"), document.getElementById("layer2")] var prefix = "" - if(selectedSong.category in this.categories){ - var catId = this.categories[selectedSong.category].sort - }else{ - var catId = this.categories.default.sort - } - if(!selectedSong.songSkin.song){ var id = selectedSong.songBg this.songBg.classList.add("songbg-" + id)