Merge pull request #214 from MarNicGit/DynamicCategories

Dynamic categories
This commit is contained in:
Bui 2020-05-09 17:24:23 +01:00 committed by GitHub
commit f346e05312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 218 deletions

10
app.py
View File

@ -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/<int:id>')
@ -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)

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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 = {}

View File

@ -38,25 +38,22 @@
"oni": 3,
"ura": 4
}
this.categories = {
"ボーカロイド曲": "ボーカロイド™曲",
"ボーカロイド": "ボーカロイド™曲",
"vocaloid music": "ボーカロイド™曲",
"vocaloid": "ボーカロイド™曲",
"バラエティー": "バラエティ",
"どうよう": "バラエティ",
"童謡・民謡": "バラエティ",
"children": "バラエティ",
"children/folk": "バラエティ",
"children-folk": "バラエティ",
"クラッシック": "クラシック",
"classic": "クラシック"
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
})
}
for(var i in allStrings){
for(var ja in allStrings[i].categories){
this.categories[allStrings[i].categories[ja].toLowerCase()] = ja
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)){
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]
}
}
}

View File

@ -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
@ -105,6 +105,28 @@ class Loader{
}), 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)
assets.songs = assets.songsDefault
@ -128,6 +150,20 @@ class Loader{
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()
@ -265,10 +301,7 @@ class Loader{
pageEvents.send("ready", readyEvent)
})
}, this.errorMsg.bind(this))
})
}
addPromise(promise, url){
this.promises.push(promise)

View File

@ -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){
@ -2307,6 +2291,15 @@ class SongSelect{
}
}
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

View File

@ -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",

View File

@ -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,
@ -342,14 +310,9 @@
})
ctx.fill()
if(selectedSong.category in strings.categories){
var categoryName = strings.categories[selectedSong.category]
}else{
var categoryName = selectedSong.category
}
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)