export study chapter as gif (closes #6180)

pull/6464/head
Niklas Fiekas 2020-04-24 21:58:17 +02:00
parent b56401de36
commit 9a7170f6b2
6 changed files with 80 additions and 6 deletions

View File

@ -406,7 +406,7 @@ final class Study(
lila.mon.export.pgn.study.increment()
env.study.pgnDump(study) map { pgns =>
Ok(pgns.mkString("\n\n\n")).withHeaders(
CONTENT_DISPOSITION -> ("attachment; filename=" + (env.study.pgnDump filename study))
CONTENT_DISPOSITION -> s"attachment; filename=${env.study.pgnDump filename study}.pgn"
) as pgnContentType
}
}
@ -422,8 +422,7 @@ final class Study(
lila.mon.export.pgn.studyChapter.increment()
Ok(env.study.pgnDump.ofChapter(study, chapter).toString)
.withHeaders(
CONTENT_DISPOSITION -> ("attachment; filename=" + (env.study.pgnDump
.filename(study, chapter)))
CONTENT_DISPOSITION -> s"attachment; filename=${env.study.pgnDump.filename(study, chapter)}.pgn"
)
.as(pgnContentType)
.fuccess
@ -432,6 +431,23 @@ final class Study(
}
}
def chapterGif(id: String, chapterId: String) = Open { implicit ctx =>
env.study.api.byIdWithChapter(id, chapterId) flatMap {
_.fold(notFound) {
case WithChapter(study, chapter) =>
CanViewResult(study) {
env.study.gifExport.ofChapter(chapter) map { stream =>
Ok.chunked(stream)
.withHeaders(
noProxyBufferHeader,
CONTENT_DISPOSITION -> s"attachment; filename=${env.study.pgnDump.filename(study, chapter)}.gif"
) as "image/gif"
}
}
}
}
}
def multiBoard(id: String, page: Int) = Open { implicit ctx =>
OptionFuResult(env.study.api byId id) { study =>
CanViewResult(study) {

View File

@ -119,6 +119,7 @@ POST /study controllers.Study.create
POST /study/as controllers.Study.createAs
GET /study/$id<\w{8}>.pgn controllers.Study.pgn(id: String)
GET /study/$id<\w{8}>/$chapterId<\w{8}>.pgn controllers.Study.chapterPgn(id: String, chapterId: String)
GET /study/$id<\w{8}>/$chapterId<\w{8}>.gif controllers.Study.chapterGif(id: String, chapterId: String)
POST /study/$id<\w{8}>/delete controllers.Study.delete(id: String)
GET /study/$id<\w{8}>/clone controllers.Study.cloneStudy(id: String)
POST /study/$id<\w{8}>/cloneAplly controllers.Study.cloneApply(id: String)

View File

@ -1,6 +1,7 @@
package lila.study
import com.softwaremill.macwire._
import play.api.Configuration
import play.api.libs.ws.WSClient
import lila.common.config._
@ -9,6 +10,7 @@ import lila.user.User
@Module
final class Env(
appConfig: Configuration,
ws: WSClient,
lightUserApi: lila.user.LightUserApi,
gamePgnDump: lila.game.PgnDump,
@ -78,6 +80,8 @@ final class Env(
lazy val pgnDump = wire[PgnDump]
lazy val gifExport = new GifExport(ws, appConfig.get[String]("game.gifUrl"))
def cli = new lila.common.Cli {
def process = {
case "study" :: "rank" :: "reset" :: Nil =>

View File

@ -0,0 +1,47 @@
package lila.study
import akka.stream.scaladsl._
import akka.util.ByteString
import play.api.libs.json._
import play.api.libs.ws.WSClient
import org.joda.time.format.DateTimeFormat
final class GifExport(
ws: WSClient,
url: String
)(implicit ec: scala.concurrent.ExecutionContext) {
def ofChapter(chapter: Chapter): Fu[Source[ByteString, _]] =
ws.url(s"$url/game.gif")
.withMethod("POST")
.addHttpHeaders("Content-Type" -> "application/json")
.withBody(
Json.obj(
"delay" -> 80,
"orientation" -> chapter.setup.orientation.name,
"white" -> List(
chapter.tags(_.WhiteTitle),
chapter.tags(_.White),
chapter.tags(_.WhiteElo).map(elo => s"($elo)")
).flatten.mkString(" "),
"black" -> List(
chapter.tags(_.BlackTitle),
chapter.tags(_.Black),
chapter.tags(_.BlackElo).map(elo => s"($elo)")
).flatten.mkString(" "),
"frames" -> (chapter.root :: chapter.root.mainline).map { node =>
Json
.obj(
"fen" -> node.fen.value
)
.add("check", node.check option true)
.add("lastMove", node.moveOption.map(_.uci.uci))
}
)
)
.stream() flatMap {
case res if res.status != 200 =>
logger.warn(s"GifExport study ${chapter.studyId}/${chapter._id} ${res.status}")
fufail(res.statusText)
case res => fuccess(res.bodyAsSource)
}
}

View File

@ -36,7 +36,7 @@ final class PgnDump(
def filename(study: Study): String = {
val date = dateFormat.print(study.createdAt)
fileR.replaceAllIn(
s"lichess_study_${slugify(study.name.value)}_by_${ownerName(study)}_${date}.pgn",
s"lichess_study_${slugify(study.name.value)}_by_${ownerName(study)}_${date}",
""
)
}
@ -44,7 +44,7 @@ final class PgnDump(
def filename(study: Study, chapter: Chapter): String = {
val date = dateFormat.print(chapter.createdAt)
fileR.replaceAllIn(
s"lichess_study_${slugify(study.name.value)}_${slugify(chapter.name.value)}_by_${ownerName(study)}_${date}.pgn",
s"lichess_study_${slugify(study.name.value)}_${slugify(chapter.name.value)}_by_${ownerName(study)}_${date}",
""
)
}

View File

@ -70,7 +70,13 @@ export function view(ctrl): VNode {
'data-icon': 'x',
href: `/study/${studyId}/${chapter.id}.pgn`
}
}, ctrl.trans.noarg('chapterPgn'))
}, ctrl.trans.noarg('chapterPgn')),
h('a.button.text', {
attrs: {
'data-icon': 'x',
href: `/study/${studyId}/${chapter.id}.gif`
}
}, 'GIF')
]),
h('form.form3', [
h('div.form-group', [