add %eval annotations to study PGN exports - closes #9533
parent
57b1e93e74
commit
ffb4edb9b0
|
@ -465,10 +465,11 @@ final class Study(
|
|||
_.fold(notFound) { case WithChapter(study, chapter) =>
|
||||
CanView(study, ctx.me) {
|
||||
lila.mon.export.pgn.studyChapter.increment()
|
||||
Ok(env.study.pgnDump.ofChapter(study, requestPgnFlags(ctx.req))(chapter).toString)
|
||||
.pipe(asAttachment(s"${env.study.pgnDump.filename(study, chapter)}.pgn"))
|
||||
.as(pgnContentType)
|
||||
.fuccess
|
||||
env.study.pgnDump.ofChapter(study, requestPgnFlags(ctx.req))(chapter) map { pgn =>
|
||||
Ok(pgn.toString)
|
||||
.pipe(asAttachment(s"${env.study.pgnDump.filename(study, chapter)}.pgn"))
|
||||
.as(pgnContentType)
|
||||
}
|
||||
}(privateUnauthorizedFu(study), privateForbiddenFu(study))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,32 @@ final class Annotator(netDomain: lila.common.config.NetDomain) {
|
|||
)
|
||||
}
|
||||
|
||||
def addEvals(p: Pgn, analysis: Analysis): Pgn =
|
||||
analysis.infos.foldLeft(p) { case (pgn, info) =>
|
||||
pgn.updateTurn(
|
||||
info.turn,
|
||||
turn =>
|
||||
turn.update(
|
||||
info.color,
|
||||
move => {
|
||||
val comment = info.cp
|
||||
.map(_.pawns.toString)
|
||||
.orElse(info.mate.map(m => s"#${m.value}"))
|
||||
move.copy(
|
||||
comments = comment.map(c => s"[%eval $c]").toList ::: move.comments
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def toPgnString(pgn: Pgn) = {
|
||||
// merge analysis & eval comments
|
||||
// 1. e4 { [%eval 0.17] } { [%clk 0:00:30] }
|
||||
// 1. e4 { [%eval 0.17] [%clk 0:00:30] }
|
||||
s"$pgn\n\n\n".replaceIf("] } { [", "] [")
|
||||
}
|
||||
|
||||
private def annotateStatus(winner: Option[Color], status: Status)(p: Pgn) =
|
||||
lila.game.StatusText(status, winner, chess.variant.Standard) match {
|
||||
case "" => p
|
||||
|
|
|
@ -28,6 +28,7 @@ final class GameApiV2(
|
|||
playerRepo: lila.tournament.PlayerRepo,
|
||||
swissApi: lila.swiss.SwissApi,
|
||||
analysisRepo: lila.analyse.AnalysisRepo,
|
||||
annotator: lila.analyse.Annotator,
|
||||
getLightUser: LightUser.Getter,
|
||||
realPlayerApi: RealPlayerApi,
|
||||
gameProxy: GameProxyRepo
|
||||
|
@ -57,7 +58,7 @@ final class GameApiV2(
|
|||
analysis,
|
||||
config.flags,
|
||||
realPlayers = realPlayers
|
||||
) dmap pgnDump.toPgnString
|
||||
) dmap annotator.toPgnString
|
||||
}
|
||||
} yield export
|
||||
}
|
||||
|
@ -274,7 +275,7 @@ final class GameApiV2(
|
|||
pgn <-
|
||||
withFlags.pgnInJson ?? pgnDump
|
||||
.apply(g, initialFen, analysisOption, withFlags, realPlayers = realPlayers)
|
||||
.dmap(pgnDump.toPgnString)
|
||||
.dmap(annotator.toPgnString)
|
||||
.dmap(some)
|
||||
} yield Json
|
||||
.obj(
|
||||
|
|
|
@ -34,32 +34,13 @@ final class PgnDump(
|
|||
}
|
||||
else fuccess(pgn)
|
||||
} map { pgn =>
|
||||
val evaled = analysis.ifTrue(flags.evals).fold(pgn)(addEvals(pgn, _))
|
||||
val evaled = analysis.ifTrue(flags.evals).fold(pgn)(annotator.addEvals(pgn, _))
|
||||
if (flags.literate) annotator(evaled, game, analysis)
|
||||
else evaled
|
||||
} map { pgn =>
|
||||
realPlayers.fold(pgn)(_.update(game, pgn))
|
||||
}
|
||||
|
||||
private def addEvals(p: Pgn, analysis: Analysis): Pgn =
|
||||
analysis.infos.foldLeft(p) { case (pgn, info) =>
|
||||
pgn.updateTurn(
|
||||
info.turn,
|
||||
turn =>
|
||||
turn.update(
|
||||
info.color,
|
||||
move => {
|
||||
val comment = info.cp
|
||||
.map(_.pawns.toString)
|
||||
.orElse(info.mate.map(m => s"#${m.value}"))
|
||||
move.copy(
|
||||
comments = comment.map(c => s"[%eval $c]").toList ::: move.comments
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def formatter(flags: WithFlags) =
|
||||
(
|
||||
game: Game,
|
||||
|
@ -67,12 +48,5 @@ final class PgnDump(
|
|||
analysis: Option[Analysis],
|
||||
teams: Option[GameTeams],
|
||||
realPlayers: Option[RealPlayers]
|
||||
) => apply(game, initialFen, analysis, flags, teams, realPlayers) dmap toPgnString
|
||||
|
||||
def toPgnString(pgn: Pgn) = {
|
||||
// merge analysis & eval comments
|
||||
// 1. e4 { [%eval 0.17] } { [%clk 0:00:30] }
|
||||
// 1. e4 { [%eval 0.17] [%clk 0:00:30] }
|
||||
s"$pgn\n\n\n".replaceIf("] } { [", "] [")
|
||||
}
|
||||
) => apply(game, initialFen, analysis, flags, teams, realPlayers) dmap annotator.toPgnString
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ final class Env(
|
|||
timeline: lila.hub.actors.Timeline,
|
||||
fishnet: lila.hub.actors.Fishnet,
|
||||
chatApi: lila.chat.ChatApi,
|
||||
analyser: lila.analyse.Analyser,
|
||||
annotator: lila.analyse.Annotator,
|
||||
mongo: lila.db.Env,
|
||||
net: lila.common.config.NetConfig,
|
||||
cacheApi: lila.memo.CacheApi
|
||||
|
|
|
@ -4,33 +4,37 @@ import akka.stream.scaladsl._
|
|||
import chess.format.pgn.{ Glyphs, Initial, Pgn, Tag, Tags }
|
||||
import chess.format.{ pgn => chessPgn }
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
import lila.common.String.slugify
|
||||
import lila.tree.Node.{ Shape, Shapes }
|
||||
|
||||
final class PgnDump(
|
||||
chapterRepo: ChapterRepo,
|
||||
analyser: lila.analyse.Analyser,
|
||||
annotator: lila.analyse.Annotator,
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
net: lila.common.config.NetConfig
|
||||
) {
|
||||
)(implicit ec: ExecutionContext) {
|
||||
|
||||
import PgnDump._
|
||||
|
||||
def apply(study: Study, flags: WithFlags): Source[String, _] =
|
||||
chapterRepo
|
||||
.orderedByStudySource(study.id)
|
||||
.map(ofChapter(study, flags))
|
||||
.map(_.toString)
|
||||
.intersperse("\n\n\n")
|
||||
.mapAsync(1)(ofChapter(study, flags))
|
||||
|
||||
def ofChapter(study: Study, flags: WithFlags)(chapter: Chapter) =
|
||||
Pgn(
|
||||
tags = makeTags(study, chapter),
|
||||
turns = toTurns(chapter.root)(flags).toList,
|
||||
initial = Initial(
|
||||
chapter.root.comments.list.map(_.text.value) ::: shapeComment(chapter.root.shapes).toList
|
||||
def ofChapter(study: Study, flags: WithFlags)(chapter: Chapter): Fu[String] =
|
||||
chapter.serverEval.exists(_.done) ?? analyser.byId(chapter.id.value) map { analysis =>
|
||||
val pgn = Pgn(
|
||||
tags = makeTags(study, chapter),
|
||||
turns = toTurns(chapter.root)(flags).toList,
|
||||
initial = Initial(
|
||||
chapter.root.comments.list.map(_.text.value) ::: shapeComment(chapter.root.shapes).toList
|
||||
)
|
||||
)
|
||||
)
|
||||
annotator toPgnString analysis.fold(pgn)(annotator.addEvals(pgn, _))
|
||||
}
|
||||
|
||||
private val fileR = """[\s,]""".r
|
||||
|
||||
|
|
Loading…
Reference in New Issue