use board image creation in the og headers - through CDN
parent
e54e41946c
commit
3958d1ddc2
|
@ -13,3 +13,6 @@
|
||||||
[submodule "submodules/pdfexporter"]
|
[submodule "submodules/pdfexporter"]
|
||||||
path = submodules/pdfexporter
|
path = submodules/pdfexporter
|
||||||
url = https://github.com/clarkerubber/lichessPDFExporter
|
url = https://github.com/clarkerubber/lichessPDFExporter
|
||||||
|
[submodule "submodules/boardcreator"]
|
||||||
|
path = submodules/boardcreator
|
||||||
|
url = https://github.com/clarkerubber/board-creator
|
||||||
|
|
|
@ -31,7 +31,7 @@ private[app] final class Router(
|
||||||
case User(username) => sender ! R.User.show(username).url
|
case User(username) => sender ! R.User.show(username).url
|
||||||
case Player(fullId) => sender ! R.Round.player(fullId).url
|
case Player(fullId) => sender ! R.Round.player(fullId).url
|
||||||
case Watcher(gameId, color) => sender ! R.Round.watcher(gameId, color).url
|
case Watcher(gameId, color) => sender ! R.Round.watcher(gameId, color).url
|
||||||
case Pgn(gameId) => sender ! R.Analyse.pgn(gameId).url
|
case Pgn(gameId) => sender ! R.Export.pgn(gameId).url
|
||||||
case Tourney(tourId) => sender ! R.Tournament.show(tourId).url
|
case Tourney(tourId) => sender ! R.Tournament.show(tourId).url
|
||||||
case Puzzle(id) => sender ! R.Puzzle.show(id).url
|
case Puzzle(id) => sender ! R.Puzzle.show(id).url
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import akka.pattern.ask
|
||||||
import play.api.http.ContentTypes
|
import play.api.http.ContentTypes
|
||||||
import play.api.mvc._
|
import play.api.mvc._
|
||||||
import play.twirl.api.Html
|
import play.twirl.api.Html
|
||||||
import play.api.libs.iteratee.{ Iteratee, Enumerator }
|
|
||||||
|
|
||||||
import lila.analyse.{ Analysis, TimeChart, AdvantageChart }
|
import lila.analyse.{ Analysis, TimeChart, AdvantageChart }
|
||||||
import lila.api.Context
|
import lila.api.Context
|
||||||
|
@ -77,29 +76,6 @@ object Analyse extends LilaController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def pgn(id: String) = Open { implicit ctx =>
|
|
||||||
OptionFuResult(GameRepo game id) { game =>
|
|
||||||
(game.pgnImport.ifTrue(~get("as") == "imported") match {
|
|
||||||
case Some(i) => fuccess(i.pgn)
|
|
||||||
case None => for {
|
|
||||||
pgn ← Env.game.pgnDump(game)
|
|
||||||
analysis ← (~get("as") != "raw") ?? (env.analyser getDone game.id)
|
|
||||||
} yield Env.analyse.annotator(pgn, analysis, gameOpening(game), game.winnerColor, game.status, game.clock).toString
|
|
||||||
}) map { content =>
|
|
||||||
Ok(content).withHeaders(
|
|
||||||
CONTENT_TYPE -> ContentTypes.TEXT,
|
|
||||||
CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.game.pgnDump filename game)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def pdf(id: String) = Open { implicit ctx =>
|
|
||||||
OptionResult(GameRepo game id) { game =>
|
|
||||||
Ok.chunked(Enumerator.outputStream(Env.game.pdfExport(game.id))).withHeaders(
|
|
||||||
CONTENT_TYPE -> ContentTypes.withCharset("application/pdf"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def gameOpening(game: GameModel) =
|
private def gameOpening(game: GameModel) =
|
||||||
if (game.fromPosition || game.variant.exotic) none
|
if (game.fromPosition || game.variant.exotic) none
|
||||||
else chess.OpeningExplorer openingOf game.pgnMoves
|
else chess.OpeningExplorer openingOf game.pgnMoves
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import play.api.mvc.Action
|
||||||
|
|
||||||
|
import lila.app._
|
||||||
|
import lila.game.{ Game => GameModel, GameRepo }
|
||||||
|
import play.api.http.ContentTypes
|
||||||
|
import play.api.libs.iteratee.{ Iteratee, Enumerator }
|
||||||
|
import views._
|
||||||
|
|
||||||
|
object Export extends LilaController {
|
||||||
|
|
||||||
|
private def env = Env.game
|
||||||
|
|
||||||
|
def pgn(id: String) = Open { implicit ctx =>
|
||||||
|
OptionFuResult(GameRepo game id) { game =>
|
||||||
|
(game.pgnImport.ifTrue(~get("as") == "imported") match {
|
||||||
|
case Some(i) => fuccess(i.pgn)
|
||||||
|
case None => for {
|
||||||
|
pgn ← Env.game.pgnDump(game)
|
||||||
|
analysis ← (~get("as") != "raw") ?? (Env.analyse.analyser getDone game.id)
|
||||||
|
} yield Env.analyse.annotator(pgn, analysis, gameOpening(game), game.winnerColor, game.status, game.clock).toString
|
||||||
|
}) map { content =>
|
||||||
|
Ok(content).withHeaders(
|
||||||
|
CONTENT_TYPE -> ContentTypes.TEXT,
|
||||||
|
CONTENT_DISPOSITION -> ("attachment; filename=" + (Env.game.pgnDump filename game)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def pdf(id: String) = Open { implicit ctx =>
|
||||||
|
OptionResult(GameRepo game id) { game =>
|
||||||
|
Ok.chunked(Enumerator.outputStream(env.pdfExport(game.id))).withHeaders(
|
||||||
|
CONTENT_TYPE -> "application/pdf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def png(id: String) = Open { implicit ctx =>
|
||||||
|
OptionResult(GameRepo game id) { game =>
|
||||||
|
Ok.chunked(Enumerator.outputStream(env.pngExport(game))).withHeaders(
|
||||||
|
CONTENT_TYPE -> "image/png")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def gameOpening(game: GameModel) =
|
||||||
|
if (game.fromPosition || game.variant.exotic) none
|
||||||
|
else chess.OpeningExplorer openingOf game.pgnMoves
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel
|
||||||
|
|
||||||
def netBaseUrl: String
|
def netBaseUrl: String
|
||||||
def staticUrl(path: String): String
|
def staticUrl(path: String): String
|
||||||
|
def cdnUrl(path: String): String
|
||||||
|
|
||||||
def mandatorySecondsToMove = lila.game.Env.current.MandatorySecondsToMove
|
def mandatorySecondsToMove = lila.game.Env.current.MandatorySecondsToMove
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel
|
||||||
val variant = pov.game.variant.exotic ?? s" ${pov.game.variant.name}"
|
val variant = pov.game.variant.exotic ?? s" ${pov.game.variant.name}"
|
||||||
Map(
|
Map(
|
||||||
'type -> "website",
|
'type -> "website",
|
||||||
'image -> staticUrl("images/large_tile.png"),
|
'image -> cdnUrl(routes.Export.png(pov.game.id).url),
|
||||||
'title -> s"$speed$variant Chess - ${playerText(pov.game.whitePlayer)} vs ${playerText(pov.game.blackPlayer)}",
|
'title -> s"$speed$variant Chess - ${playerText(pov.game.whitePlayer)} vs ${playerText(pov.game.blackPlayer)}",
|
||||||
'site_name -> "lichess.org",
|
'site_name -> "lichess.org",
|
||||||
'url -> s"$netBaseUrl${routes.Round.watcher(pov.game.id, pov.color.name).url}",
|
'url -> s"$netBaseUrl${routes.Round.watcher(pov.game.id, pov.color.name).url}",
|
||||||
|
|
|
@ -138,14 +138,14 @@ openGraph = povOpenGraph(pov)) {
|
||||||
<div class="panel fen_pgn">
|
<div class="panel fen_pgn">
|
||||||
<p><strong>FEN</strong><input type="input" readonly="true" spellcheck="false" class="copyable fen" /></p>
|
<p><strong>FEN</strong><input type="input" readonly="true" spellcheck="false" class="copyable fen" /></p>
|
||||||
<p><strong>PGN</strong>
|
<p><strong>PGN</strong>
|
||||||
<a data-icon="x" href="@routes.Analyse.pgn(game.id)"> Download annotated</a>
|
<a data-icon="x" href="@routes.Export.pgn(game.id)"> Download annotated</a>
|
||||||
@if(analysis.isDefined) {
|
@if(analysis.isDefined) {
|
||||||
/
|
/
|
||||||
<a data-icon="x" href="@routes.Analyse.pgn(game.id)?as=raw"> Download raw</a>
|
<a data-icon="x" href="@routes.Export.pgn(game.id)?as=raw"> Download raw</a>
|
||||||
}
|
}
|
||||||
@if(game.isPgnImport) {
|
@if(game.isPgnImport) {
|
||||||
/
|
/
|
||||||
<a data-icon="x" href="@routes.Analyse.pgn(game.id)?as=imported"> Download imported</a>
|
<a data-icon="x" href="@routes.Export.pgn(game.id)?as=imported"> Download imported</a>
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
<div class="pgn">@Html(nl2br(escape(pgn)))</div>
|
<div class="pgn">@Html(nl2br(escape(pgn)))</div>
|
||||||
|
@ -173,7 +173,7 @@ openGraph = povOpenGraph(pov)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<a data-panel="fen_pgn">FEN & PGN</a>
|
<a data-panel="fen_pgn">FEN & PGN</a>
|
||||||
<a target="_blank" href="@cdnUrl(routes.Analyse.pdf(game.id).url)">Print</a>
|
<a target="_blank" href="@cdnUrl(routes.Export.pdf(game.id).url)">Print</a>
|
||||||
</div>
|
</div>
|
||||||
@analysis.filter(_.old && ctx.isAuth).map { a =>
|
@analysis.filter(_.old && ctx.isAuth).map { a =>
|
||||||
<form class="better_analysis" action="@routes.Analyse.betterAnalysis(gameId, color.name)" method="post">
|
<form class="better_analysis" action="@routes.Analyse.betterAnalysis(gameId, color.name)" method="post">
|
||||||
|
|
|
@ -74,7 +74,8 @@ fi
|
||||||
|
|
||||||
lilalog "Rsync scripts, binaries and assets"
|
lilalog "Rsync scripts, binaries and assets"
|
||||||
stage="target/universal/stage"
|
stage="target/universal/stage"
|
||||||
rsync_command="rsync $RSYNC_OPTIONS bin $stage/bin $stage/lib public $REMOTE:$REMOTE_DIR"
|
include="bin $stage/bin $stage/lib public submodules"
|
||||||
|
rsync_command="rsync $RSYNC_OPTIONS $include $REMOTE:$REMOTE_DIR"
|
||||||
echo "$rsync_command"
|
echo "$rsync_command"
|
||||||
$rsync_command
|
$rsync_command
|
||||||
echo "rsync complete"
|
echo "rsync complete"
|
||||||
|
|
|
@ -136,9 +136,10 @@ POST /team/:id/kick controllers.Team.kick(id: String)
|
||||||
POST /$gameId<\w{8}>/request-analysis controllers.Analyse.requestAnalysis(gameId: String)
|
POST /$gameId<\w{8}>/request-analysis controllers.Analyse.requestAnalysis(gameId: String)
|
||||||
POST /$gameId<\w{8}>/better-analysis/$color<white|black> controllers.Analyse.betterAnalysis(gameId: String, color: String)
|
POST /$gameId<\w{8}>/better-analysis/$color<white|black> controllers.Analyse.betterAnalysis(gameId: String, color: String)
|
||||||
POST /$gameId<\w{8}>/post-analysis controllers.Analyse.postAnalysis(gameId: String)
|
POST /$gameId<\w{8}>/post-analysis controllers.Analyse.postAnalysis(gameId: String)
|
||||||
GET /$gameId<\w{8}>/pgn controllers.Analyse.pgn(gameId: String)
|
|
||||||
|
|
||||||
GET /game/pdf/$gameId<\w{8}> controllers.Analyse.pdf(gameId: String)
|
GET /game/pgn/$gameId<\w{8}> controllers.Export.pgn(gameId: String)
|
||||||
|
GET /game/pdf/$gameId<\w{8}> controllers.Export.pdf(gameId: String)
|
||||||
|
GET /game/png/$gameId<\w{8}> controllers.Export.png(gameId: String)
|
||||||
|
|
||||||
# Pref
|
# Pref
|
||||||
POST /pref/:name controllers.Pref.set(name: String)
|
POST /pref/:name controllers.Pref.set(name: String)
|
||||||
|
|
|
@ -29,6 +29,7 @@ final class Env(
|
||||||
val UciMemoTtl = config duration "uci_memo.ttl"
|
val UciMemoTtl = config duration "uci_memo.ttl"
|
||||||
val netBaseUrl = config getString "net.base_url"
|
val netBaseUrl = config getString "net.base_url"
|
||||||
val PdfExecPath = config getString "pdf.exec_path"
|
val PdfExecPath = config getString "pdf.exec_path"
|
||||||
|
val PngExecPath = config getString "png.exec_path"
|
||||||
}
|
}
|
||||||
import settings._
|
import settings._
|
||||||
|
|
||||||
|
@ -38,6 +39,8 @@ final class Env(
|
||||||
|
|
||||||
lazy val pdfExport = PdfExport(PdfExecPath) _
|
lazy val pdfExport = PdfExport(PdfExecPath) _
|
||||||
|
|
||||||
|
lazy val pngExport = PngExport(PngExecPath) _
|
||||||
|
|
||||||
lazy val cached = new Cached(ttl = CachedNbTtl)
|
lazy val cached = new Cached(ttl = CachedNbTtl)
|
||||||
|
|
||||||
lazy val paginator = new PaginatorBuilder(
|
lazy val paginator = new PaginatorBuilder(
|
||||||
|
|
|
@ -63,7 +63,7 @@ case class Game(
|
||||||
|
|
||||||
def opponent(c: Color): Player = player(!c)
|
def opponent(c: Color): Player = player(!c)
|
||||||
|
|
||||||
private lazy val firstColor = (whitePlayer before blackPlayer).fold(White, Black)
|
lazy val firstColor = (whitePlayer before blackPlayer).fold(White, Black)
|
||||||
def firstPlayer = player(firstColor)
|
def firstPlayer = player(firstColor)
|
||||||
def secondPlayer = player(!firstColor)
|
def secondPlayer = player(!firstColor)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package lila.game
|
||||||
|
|
||||||
|
import chess.format.Forsyth
|
||||||
|
import java.io.{ File, OutputStream }
|
||||||
|
import scala.sys.process._
|
||||||
|
|
||||||
|
object PngExport {
|
||||||
|
|
||||||
|
private val logger = ProcessLogger(_ => (), _ => ())
|
||||||
|
|
||||||
|
def apply(execPath: String)(game: Game)(out: OutputStream) {
|
||||||
|
val fen = (Forsyth >> game.toChess).split(' ').head
|
||||||
|
val color = game.firstColor.letter.toString
|
||||||
|
val lastMove = ~game.castleLastMoveTime.lastMoveString
|
||||||
|
val exec = Process(Seq("php", "board-creator.php", fen, color, lastMove), new File(execPath))
|
||||||
|
exec #> out ! logger
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit a177efd0b4a023e09d8ce8f122c2b904ac312113
|
Loading…
Reference in New Issue