add game visualizer

pub_chat_mod
Thibault Duplessis 2016-09-04 13:40:37 +02:00
parent 584aa856fe
commit afa988ce3c
6 changed files with 51 additions and 18 deletions

3
.gitmodules vendored
View File

@ -40,3 +40,6 @@
[submodule "public/vendor/bar-rating"]
path = public/vendor/bar-rating
url = https://github.com/antennaio/jquery-bar-rating
[submodule "public/visualizer"]
path = public/visualizer
url = https://github.com/ornicar/chess_game_visualizer

View File

@ -18,24 +18,33 @@ object Export extends LilaController {
def pgn(id: String) = Open { implicit ctx =>
OnlyHumans {
lila.mon.export.pgn.game()
OptionFuResult(GameRepo game id) {
case game if game.playable => NotFound("Can't export PGN of game in progress").fuccess
case game => (game.pgnImport.ifTrue(get("as") contains "imported") match {
case Some(i) => fuccess(i.pgn)
case None => for {
initialFen <- GameRepo initialFen game
pgn = Env.api.pgnDump(game, initialFen)
analysis !get("as").contains("raw") ?? (Env.analyse.analyser get game.id)
} yield Env.analyse.annotator(pgn, analysis, game.opening, game.winnerColor, game.status, game.clock).toString
}) map { content =>
Ok(content).withHeaders(
CONTENT_TYPE -> ContentTypes.TEXT,
CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.api.pgnDump filename game)))
}
OptionFuResult(GameRepo game id) { game =>
gameToPgn(
game,
asImported = get("as") contains "imported",
asRaw = get("as").contains("raw")) map { content =>
Ok(content).withHeaders(
CONTENT_TYPE -> ContentTypes.TEXT,
CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.api.pgnDump filename game)))
} recover {
case err => NotFound(err.getMessage)
}
}
}
}
private def gameToPgn(from: GameModel, asImported: Boolean, asRaw: Boolean): Fu[String] = from match {
case game if game.playable => fufail("Can't export PGN of game in progress")
case game => (game.pgnImport.ifTrue(asImported) match {
case Some(i) => fuccess(i.pgn)
case None => for {
initialFen <- GameRepo initialFen game
pgn = Env.api.pgnDump(game, initialFen)
analysis !asRaw ?? (Env.analyse.analyser get game.id)
} yield Env.analyse.annotator(pgn, analysis, game.opening, game.winnerColor, game.status, game.clock).toString
})
}
private val PdfRateLimitGlobal = new lila.memo.RateLimit(
credits = 20,
duration = 1 minute,
@ -74,6 +83,22 @@ object Export extends LilaController {
}
}
def visualizer(id: String) = Open { implicit ctx =>
OptionFuResult(GameRepo game id) { game =>
gameToPgn(game, asImported = true, asRaw = true) map { pgn =>
lila.mon.export.visualizer()
Redirect {
import lila.api.Env.current.Net._
val base = s"$Protocol$AssetDomain/assets"
val encoded = java.net.URLEncoder.encode(pgn.toString, "UTF-8")
s"$base/visualizer/index_lichess.html?pgn=$encoded"
}
} recoverWith {
case _: Exception => notFound
}
}
}
def puzzlePng(id: Int) = Open { implicit ctx =>
OnlyHumansAndFacebook {
PngRateLimitGlobal("-", msg = HTTPRequest lastRemoteAddress ctx.req) {

View File

@ -64,17 +64,19 @@ atom = atom.some) {
<div class="panel fen_pgn">
<p><strong>FEN</strong><input type="input" readonly="true" spellcheck="false" class="copyable autoselect fen" /></p>
<p><strong>PGN</strong>
<a data-icon="x" rel="nofollow" href="@routes.Export.pgn(game.id)"> @trans.downloadAnnotated()</a>
<a data-icon="x" class="text" rel="nofollow" href="@routes.Export.pgn(game.id)">@trans.downloadAnnotated()</a>
@if(analysis.isDefined) {
/
<a data-icon="x" rel="nofollow" href="@routes.Export.pgn(game.id)?as=raw"> @trans.downloadRaw()</a>
<a data-icon="x" class="text" rel="nofollow" href="@routes.Export.pgn(game.id)?as=raw">@trans.downloadRaw()</a>
}
@if(game.isPgnImport) {
/
<a data-icon="x" rel="nofollow" href="@routes.Export.pgn(game.id)?as=imported"> @trans.downloadImported()</a>
<a data-icon="x" class="text" rel="nofollow" href="@routes.Export.pgn(game.id)?as=imported">@trans.downloadImported()</a>
}
/
<a data-icon="x" target="_blank" rel="nofollow" href="@cdnUrl(routes.Export.pdf(game.id).url)"> @trans.printFriendlyPDF()</a>
<a data-icon="x" class="text" target="_blank" rel="nofollow" href="@cdnUrl(routes.Export.pdf(game.id).url)">@trans.printFriendlyPDF()</a>
/
<a data-icon="x" class="text" target="_blank" href="@routes.Export.visualizer(game.id)">Generate images</a>
</p>
<div class="pgn">@Html(nl2br(escapeHtml(pgn)))</div>
</div>

View File

@ -256,6 +256,7 @@ POST /$gameId<\w{8}>/request-analysis controllers.Analyse.requestAnalysi
GET /game/export/$gameId<\w{8}>.pgn controllers.Export.pgn(gameId: String)
GET /game/export/pdf/$gameId<\w{8}>.pdf controllers.Export.pdf(gameId: String)
GET /game/export/png/$gameId<\w{8}>.png controllers.Export.png(gameId: String)
GET /game/visualizer/$gameId<\w{8}> controllers.Export.visualizer(gameId: String)
# Fishnet
POST /fishnet/acquire controllers.Fishnet.acquire

View File

@ -379,6 +379,7 @@ object mon {
def puzzle = inc("export.png.puzzle")
}
def pdf = inc("export.pdf.game")
def visualizer = inc("export.visualizer.game")
}
def measure[A](path: RecPath)(op: => A) = {

@ -0,0 +1 @@
Subproject commit 64e15a1f0e95f6e79735e24f30dda9f9042f6053