Merge pull request #69 from LoveEevee/songselect-add-sub-titles

SongSelect: Add sub-titles
This commit is contained in:
Bui 2018-11-10 21:09:53 +00:00 committed by GitHub
commit 76108d47d6
6 changed files with 106 additions and 24 deletions

View File

@ -10,7 +10,7 @@ Still in developement. Works best with Chrome.
Create a SQLite databse named `taiko.db` with the following schema:
CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `ura` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL )
CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `subtitle` TEXT, `subtitle_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `ura` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL )
CREATE TABLE "categories" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT NOT NULL )
When inserting song rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them.

10
app.py
View File

@ -161,22 +161,24 @@ def route_api_songs():
songs_out = []
for song in songs:
song_id = song[0]
song_type = song[10]
song_type = song[12]
preview = get_preview(song_id, song_type)
category_out = categories[song[9]] if song[9] in categories else def_category
category_out = categories[song[11]] if song[11] in categories else def_category
songs_out.append({
'id': song_id,
'title': song[1],
'title_en': song[2],
'subtitle': song[3],
'subtitle_en': song[4],
'stars': [
song[3], song[4], song[5], song[6], song[7]
song[5], song[6], song[7], song[8], song[9]
],
'preview': preview,
'category': category_out['title'],
'category_en': category_out['title_en'],
'type': song_type,
'offset': song[11]
'offset': song[13]
})
return jsonify(songs_out)

View File

@ -50,8 +50,9 @@
comma: /[,.]/,
ideographicComma: /[、。]/,
apostrophe: /[']/,
degree: /[゚°]/,
brackets: /[\(\))「」『』]/,
tilde: /[\-~]/,
tilde: /[\-~]/,
tall: /[bdfh-l-t0-9-9♪]/,
uppercase: /[A-Z-]/,
lowercase: /[a-z-z・]/,
@ -283,15 +284,20 @@
}else if(symbol === "ー"){
// Long-vowel mark
drawn.push({realText: symbol, svg: this.longVowelMark, x: -4, y: 5, h: 33, scale: [mul, mul]})
}else if(symbol === "∀"){
drawn.push({text: symbol, x: 0, y: 3, h: 39, rotate: true})
}else if(r.comma.test(symbol)){
// Comma, full stop
drawn.push({text: symbol, x: 16, y: -7, h: 0, scale: [1.2, 0.7]})
drawn.push({text: symbol, x: 13, y: -9, h: 13, scale: [1.2, 0.7]})
}else if(r.ideographicComma.test(symbol)){
// Ideographic comma, full stop
drawn.push({text: symbol, x: 16, y: -16, h: 18})
}else if(r.apostrophe.test(symbol)){
// Apostrophe
drawn.push({realText: symbol, text: ",", x: 20, y: -39, h: 0, scale: [1.2, 0.7]})
}else if(r.degree.test(symbol)){
// Degree
drawn.push({text: symbol, x: 16, y: 3, h: 18})
}else if(r.brackets.test(symbol)){
// Rotated brackets
drawn.push({text: symbol, x: 0, y: -5, h: 25, rotate: true})
@ -359,6 +365,10 @@
}
}
if(config.align === "bottom"){
drawn.reverse()
}
var drawnHeight = 0
for(let symbol of drawn){
if(config.letterSpacing){
@ -382,9 +392,17 @@
style.transform = ""
}
var scaling = 1
if(config.height && drawnHeight > config.height){
var scaling = config.height / drawnHeight
ctx.scale(1, scaling)
if(config.align === "bottom"){
scaling = Math.max(0.6, config.height / drawnHeight)
ctx.translate(40 * mul, 0)
ctx.scale(scaling, config.height / drawnHeight)
ctx.translate(-40 * mul, 0)
}else{
scaling = config.height / drawnHeight
ctx.scale(1, scaling)
}
if(config.selectable){
style.transform = "scale(1, " + scaling + ")"
style.top = (config.y + (config.height - drawnHeight) / 2 - 15 / 2 * scaling) * scale + "px"
@ -407,12 +425,19 @@
if(action === "stroke"){
ctx.strokeStyle = config.outline
ctx.lineWidth = config.outlineSize * mul
if(config.align === "bottom"){
ctx.lineWidth /= scaling
}
ctx.lineJoin = "round"
ctx.miterLimit = 1
}else if(action === "fill"){
ctx.fillStyle = config.fill
}
var offsetY = 0
if(config.align === "bottom"){
var offsetY = drawnHeight > config.height ? drawnHeight : config.height
}else{
var offsetY = 0
}
for(let symbol of drawn){
var saved = false
@ -421,7 +446,10 @@
currentX += 20 * mul
}
var currentY = offsetY + symbol.y * mul
offsetY += symbol.h * mul
if(config.align === "bottom"){
currentY -= symbol.h * mul
}
offsetY = offsetY + symbol.h * mul * (config.align === "bottom" ? -1 : 1)
if(action === "selectable"){
let div = document.createElement("div")
div.classList.add("stroke-sub")

View File

@ -85,7 +85,8 @@ pageEvents.add(versionDiv, ["click", "touchend"], () => {
resizeRoot()
setInterval(resizeRoot, 100)
pageEvents.keyAdd(debugObj, "all", "down", event => {
if(event.keyCode === 186 && event.ctrlKey && event.shiftKey && !event.altKey){
if((event.keyCode === 186 || event.keyCode === 59) && event.ctrlKey && event.shiftKey && !event.altKey){
// Semicolon
if(debugObj.state === "open"){
debugObj.debug.minimise()
}else if(debugObj.state === "minimised"){
@ -95,6 +96,7 @@ pageEvents.keyAdd(debugObj, "all", "down", event => {
}
}
if(event.keyCode === 82 && debugObj.debug && debugObj.controller){
// R
debugObj.controller.restartSong()
}
})

View File

@ -91,6 +91,7 @@ class SongSelect{
this.songs.push({
id: song.id,
title: song.title,
subtitle: song.subtitle,
skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default,
stars: song.stars,
category: song.category,
@ -218,6 +219,8 @@ class SongSelect{
this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_" + sort].src + "')"
this.previewId = 0
this.previewList = Array(5)
var skipStart = fromTutorial || p2.session
this.state = {
screen: fadeIn ? "titleFadeIn" : (skipStart ? "song" : "title"),
@ -708,7 +711,11 @@ class SongSelect{
this.canvas.style.height = (winH / this.pixelRatio) + "px"
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
this.songTitleCache.resize((this.songAsset.width - borders + 1) * this.songs.length, (this.songAsset.height - borders + 1) * 2, ratio + 0.5)
this.songTitleCache.resize(
(this.songAsset.width - borders + 1) * this.songs.length,
(this.songAsset.height - borders + 1) * 3,
ratio + 0.5
)
this.selectTextCache.resize((280 + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5)
@ -1285,30 +1292,55 @@ class SongSelect{
drawDifficulty(ctx, i, currentUra)
}
}
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
var textW = this.songAsset.width - borders
var textH = this.songAsset.height - borders
var textX = Math.max(w - 37 - textW / 2, w / 2 - textW / 2)
var textY = opened * 12 + (1 - opened) * 7
if(currentSong.subtitle){
this.songTitleCache.get({
ctx: ctx,
x: x + textX - textW,
y: y + textY,
w: textW,
h: textH,
id: currentSong.subtitle,
}, ctx => {
this.draw.verticalText({
ctx: ctx,
text: currentSong.subtitle,
x: textW / 2,
y: 7,
width: textW,
height: textH - 35,
fill: "#fff",
outline: "#000",
outlineSize: 14,
fontSize: 28,
fontFamily: this.font,
align: "bottom"
})
})
}
if(!songSel && currentSong.stars[4]){
var fade = ((ms - this.state.screenMS) % 1200) / 1200
var _x = x + 402 + 4 * 100 + fade * 25
var _y = y + 258
ctx.save()
ctx.globalAlpha = this.draw.easeInOut(1 - fade)
ctx.fillStyle = "#e0be28"
ctx.fillStyle = "rgba(0, 0, 0, " + 0.2 * this.draw.easeInOut(1 - fade) + ")"
ctx.beginPath()
ctx.moveTo(_x - 35, _y - 25)
ctx.lineTo(_x - 10, _y)
ctx.lineTo(_x - 35, _y + 25)
ctx.fill()
ctx.restore()
}
ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2
ctx.fillStyle = selectedSkin.background
ctx.fillRect(x, y, w, h)
ctx.globalAlpha = 1
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
var textW = this.songAsset.width - borders
var textH = this.songAsset.height - borders
var textX = Math.max(w - 37 - textW / 2, w / 2 - textW / 2)
var textY = opened * 12 + (1 - opened) * 7
this.songTitleCache.get({
ctx: ctx,
x: x + textX,
@ -1551,15 +1583,17 @@ class SongSelect{
var currentId = this.previewId
this.previewing = this.selectedSong
}
var songObj = assets.songs.find(song => song.id == id)
var songObj = this.previewList.find(song => song && song.id === id)
if(songObj.preview_sound){
if(songObj){
if(!loadOnly){
this.preview = songObj.preview_sound
this.preview.gain = snd.previewGain
this.previewLoaded(startLoad, songObj.preview_time)
}
}else{
songObj = {id: id}
var previewFilename = prvTime > 0.1 ? "/preview.mp3" : "/main.mp3"
var loadPreview = previewFilename => {
@ -1575,6 +1609,14 @@ class SongSelect{
songObj.preview_sound = sound
this.preview = sound
this.previewLoaded(startLoad, songObj.preview_time)
var oldPreview = this.previewList.shift()
if(oldPreview){
oldPreview.preview_sound.clean()
}
this.previewList.push(songObj)
}else{
sound.clean()
}
})
}
@ -1714,6 +1756,11 @@ class SongSelect{
}
this.redrawRunning = false
this.endPreview()
this.previewList.forEach(song => {
if(song){
song.preview_sound.clean()
}
})
pageEvents.keyRemove(this, "all")
pageEvents.remove(loader.screen, ["mousemove", "mouseleave", "mousedown", "touchstart"])
pageEvents.remove(p2, "message")

View File

@ -206,4 +206,7 @@ class Sound{
}
}
}
clean(){
delete this.buffer
}
}