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"] [submodule "public/vendor/bar-rating"]
path = public/vendor/bar-rating path = public/vendor/bar-rating
url = https://github.com/antennaio/jquery-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 => def pgn(id: String) = Open { implicit ctx =>
OnlyHumans { OnlyHumans {
lila.mon.export.pgn.game() lila.mon.export.pgn.game()
OptionFuResult(GameRepo game id) { OptionFuResult(GameRepo game id) { game =>
case game if game.playable => NotFound("Can't export PGN of game in progress").fuccess gameToPgn(
case game => (game.pgnImport.ifTrue(get("as") contains "imported") match { game,
case Some(i) => fuccess(i.pgn) asImported = get("as") contains "imported",
case None => for { asRaw = get("as").contains("raw")) map { content =>
initialFen <- GameRepo initialFen game Ok(content).withHeaders(
pgn = Env.api.pgnDump(game, initialFen) CONTENT_TYPE -> ContentTypes.TEXT,
analysis !get("as").contains("raw") ?? (Env.analyse.analyser get game.id) CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.api.pgnDump filename game)))
} yield Env.analyse.annotator(pgn, analysis, game.opening, game.winnerColor, game.status, game.clock).toString } recover {
}) map { content => case err => NotFound(err.getMessage)
Ok(content).withHeaders( }
CONTENT_TYPE -> ContentTypes.TEXT,
CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.api.pgnDump filename game)))
}
} }
} }
} }
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( private val PdfRateLimitGlobal = new lila.memo.RateLimit(
credits = 20, credits = 20,
duration = 1 minute, 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 => def puzzlePng(id: Int) = Open { implicit ctx =>
OnlyHumansAndFacebook { OnlyHumansAndFacebook {
PngRateLimitGlobal("-", msg = HTTPRequest lastRemoteAddress ctx.req) { PngRateLimitGlobal("-", msg = HTTPRequest lastRemoteAddress ctx.req) {

View File

@ -64,17 +64,19 @@ atom = atom.some) {
<div class="panel fen_pgn"> <div class="panel fen_pgn">
<p><strong>FEN</strong><input type="input" readonly="true" spellcheck="false" class="copyable autoselect fen" /></p> <p><strong>FEN</strong><input type="input" readonly="true" spellcheck="false" class="copyable autoselect fen" /></p>
<p><strong>PGN</strong> <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) { @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) { @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> </p>
<div class="pgn">@Html(nl2br(escapeHtml(pgn)))</div> <div class="pgn">@Html(nl2br(escapeHtml(pgn)))</div>
</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/$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/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/export/png/$gameId<\w{8}>.png controllers.Export.png(gameId: String)
GET /game/visualizer/$gameId<\w{8}> controllers.Export.visualizer(gameId: String)
# Fishnet # Fishnet
POST /fishnet/acquire controllers.Fishnet.acquire POST /fishnet/acquire controllers.Fishnet.acquire

View File

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

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