Merge branch 'master' into pools
* master: fix positioning of high rated graph seeks translate coordinate trainer, use icons for color buttons zh "中文" translation #9053. Author: squares-64. I just added everything that was missing, except where the percentages were because I didn't know what to do... puzzle: add missing chess.js extern - fixes underpromotion puzzle: somehow this fixes the production build fix flickering of board editor pieces upgrade chess module to support more PGN formats fix blinking pieces (was a redirect due to bad asset domain) give 15 seconds on deploy no captcha for blind dudes accessibility: buttons rather than <a> without href fix anon blind mode unify game API and analysis API use Game.analysed denormalization in search indexer denormalize presence of game analysis, expose filter in API improve game textual representation add game by id API entry point de "Deutsch" translation #9052. Author: schachfl. removed "elo-rage" sk "slovenčina" translation #9050. Author: MoKy. upgrade chess module to support ++ PGN mate notation
This commit is contained in:
commit
07f3c8c165
109
README.md
109
README.md
|
@ -130,7 +130,9 @@ name | type | default | description
|
|||
--- | --- | --- | ---
|
||||
**username** | string | - | filter games by user
|
||||
**rated** | 1 or 0 | - | filter rated or casual games
|
||||
**analysed** | 1 or 0 | - | filter only analysed (or not analysed) games
|
||||
**nb** | int | 10 | maximum number of games to return
|
||||
**with_analysis** | 1 or 0 | 0 | include deep analysis data in the result
|
||||
**token** | string | - | security token (unlocks secret game data)
|
||||
|
||||
```
|
||||
|
@ -143,7 +145,7 @@ name | type | default | description
|
|||
{
|
||||
"id": "x2kpaixn",
|
||||
"rated": false,
|
||||
"status": "mate",
|
||||
"status": "mate", // (1)
|
||||
"clock":{ // all clock values are expressed in seconds
|
||||
"limit": 300,
|
||||
"increment": 8,
|
||||
|
@ -165,36 +167,7 @@ name | type | default | description
|
|||
},
|
||||
"black": ... // other player
|
||||
}
|
||||
},
|
||||
{
|
||||
... // other game
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
(1) All game statuses: https://github.com/ornicar/scalachess/blob/master/src/main/scala/Status.scala#L16-L25
|
||||
|
||||
### `GET /api/analysis` fetch many analysis
|
||||
|
||||
This API requires a secret token to work.
|
||||
Analysis are returned by descendant chronological order.
|
||||
All parameters are optional.
|
||||
|
||||
name | type | default | description
|
||||
--- | --- | --- | ---
|
||||
**token** | string | - | security token
|
||||
**nb** | int | 10 | maximum number of analysis to return
|
||||
|
||||
```
|
||||
> curl http://en.lichess.org/api/analysis?nb=10
|
||||
```
|
||||
|
||||
```javascript
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"analysis": [
|
||||
"analysis": [ // only if the with_analysis flag is set
|
||||
{
|
||||
"eval": -26, // board evaluation in centipawns
|
||||
"move": "e4",
|
||||
|
@ -214,15 +187,81 @@ name | type | default | description
|
|||
},
|
||||
// ... more moves
|
||||
],
|
||||
"game": {
|
||||
// similar to the game API format, see above
|
||||
},
|
||||
"uci": "e2e4 e7e5 d2d4 e5d4 g1f3 g8f6" // UCI compatible game moves
|
||||
},
|
||||
{
|
||||
... // other game
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
(1) All game statuses: https://github.com/ornicar/scalachess/blob/master/src/main/scala/Status.scala#L16-L25
|
||||
|
||||
### `GET /api/game/{id}` fetch one game by ID
|
||||
|
||||
A single game is returned.
|
||||
All parameters are optional.
|
||||
|
||||
name | type | default | description
|
||||
--- | --- | --- | ---
|
||||
**with_analysis** | 1 or 0 | 0 | include deep analysis data in the result
|
||||
**token** | string | - | security token (unlocks secret game data)
|
||||
|
||||
```
|
||||
> curl http://en.lichess.org/api/game/x2kpaixn
|
||||
```
|
||||
|
||||
```javascript
|
||||
{
|
||||
"id": "x2kpaixn",
|
||||
"rated": false,
|
||||
"status": "mate", // (1)
|
||||
"clock":{ // all clock values are expressed in seconds
|
||||
"limit": 300,
|
||||
"increment": 8,
|
||||
"totalTime": 540 // evaluation of the game duration = limit + 30 * increment
|
||||
},
|
||||
"timestamp": 1389100907239,
|
||||
"turns": 44,
|
||||
"url": "http://lichess.org/x2kpaixn",
|
||||
"winner": "black",
|
||||
"players": {
|
||||
"white": {
|
||||
"userId": "thibault"
|
||||
"rating": 1642,
|
||||
"analysis": {
|
||||
"blunder": 1,
|
||||
"inaccuracy": 0,
|
||||
"mistake": 2
|
||||
}
|
||||
},
|
||||
"black": ... // other player
|
||||
},
|
||||
"analysis": [ // only if the with_analysis flag is set
|
||||
{
|
||||
"eval": -26, // board evaluation in centipawns
|
||||
"move": "e4",
|
||||
"ply": 1
|
||||
},
|
||||
{
|
||||
"eval": -8,
|
||||
"move": "b5",
|
||||
"ply": 2
|
||||
},
|
||||
{
|
||||
"comment": "(-0.08 → -0.66) Inaccuracy. The best move was c4.",
|
||||
"eval": -66,
|
||||
"move": "Nfe3",
|
||||
"ply": 3,
|
||||
"variation": "c4 bxc4 Nfe3 c5 Qf1 f6 Rxc4 Bb7 b4 Ba6"
|
||||
},
|
||||
// ... more moves
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
(1) All game statuses: https://github.com/ornicar/scalachess/blob/master/src/main/scala/Status.scala#L16-L25
|
||||
|
||||
### `GET /api/puzzle/<id>` fetch one puzzle
|
||||
|
||||
```
|
||||
|
|
|
@ -9,7 +9,6 @@ object Api extends LilaController {
|
|||
|
||||
private val userApi = Env.api.userApi
|
||||
private val gameApi = Env.api.gameApi
|
||||
private val analysisApi = Env.api.analysisApi
|
||||
private val puzzleApi = Env.api.puzzleApi
|
||||
|
||||
def user(username: String) = ApiResult { req =>
|
||||
|
@ -21,7 +20,7 @@ object Api extends LilaController {
|
|||
def users = ApiResult { req =>
|
||||
userApi.list(
|
||||
team = get("team", req),
|
||||
engine = get("engine", req) map ("1"==),
|
||||
engine = getBoolOpt("engine", req),
|
||||
token = get("token", req),
|
||||
nb = getInt("nb", req)
|
||||
) map (_.some)
|
||||
|
@ -30,17 +29,19 @@ object Api extends LilaController {
|
|||
def games = ApiResult { req =>
|
||||
gameApi.list(
|
||||
username = get("username", req),
|
||||
rated = get("rated", req) map ("1"==),
|
||||
rated = getBoolOpt("rated", req),
|
||||
analysed = getBoolOpt("analysed", req),
|
||||
withAnalysis = getBool("with_analysis", req),
|
||||
token = get("token", req),
|
||||
nb = getInt("nb", req)
|
||||
) map (_.some)
|
||||
}
|
||||
|
||||
def analysis = ApiResult { req =>
|
||||
analysisApi.list(
|
||||
nb = getInt("nb", req),
|
||||
token = get("token", req)
|
||||
) map (_.some)
|
||||
def game(id: String) = ApiResult { req =>
|
||||
gameApi.one(
|
||||
id = id take lila.game.Game.gameIdSize,
|
||||
withAnalysis = getBool("with_analysis", req),
|
||||
token = get("token", req))
|
||||
}
|
||||
|
||||
def puzzle(id: String) = ApiResult { req =>
|
||||
|
|
|
@ -64,7 +64,7 @@ object Auth extends LilaController {
|
|||
BadRequest(html.auth.signup(err, captcha))
|
||||
},
|
||||
data => Firewall {
|
||||
UserRepo.create(data.username, data.password) flatMap { userOption =>
|
||||
UserRepo.create(data.username, data.password, ctx.blindMode) flatMap { userOption =>
|
||||
val user = userOption err "No user could be created for %s".format(data.username)
|
||||
HistoryRepo.create(user) >> gotoSignupSucceeded(user.username)
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ private[controllers] trait LilaController
|
|||
}
|
||||
|
||||
private def pageDataBuilder(ctx: lila.user.UserContext): Fu[PageData] =
|
||||
ctx.me.fold(fuccess(PageData.default)) { me =>
|
||||
ctx.me.fold(fuccess(PageData anon blindMode(ctx.req))) { me =>
|
||||
val isPage = HTTPRequest.isSynchronousHttp(ctx.req)
|
||||
(Env.pref.api getPref me) zip {
|
||||
isPage ?? {
|
||||
|
@ -203,11 +203,13 @@ private[controllers] trait LilaController
|
|||
}
|
||||
} map {
|
||||
case (pref, ((friends, teamNbRequests), messageIds)) =>
|
||||
val blindMode = ctx.req.cookies.get(Env.api.accessibilityBlindCookieName).map(_.value) == "1".some
|
||||
PageData(friends, teamNbRequests, messageIds.size, pref, blindMode)
|
||||
PageData(friends, teamNbRequests, messageIds.size, pref, blindMode(ctx.req))
|
||||
}
|
||||
}
|
||||
|
||||
private def blindMode(req: RequestHeader) =
|
||||
req.cookies.get(Env.api.accessibilityBlindCookieName).map(_.value) == "1".some
|
||||
|
||||
private def restoreUser(req: RequestHeader): Fu[Option[UserModel]] =
|
||||
Env.security.api restoreUser req addEffect {
|
||||
_ ifTrue (HTTPRequest isSynchronousHttp req) foreach { user =>
|
||||
|
|
|
@ -23,4 +23,7 @@ trait RequestGetter {
|
|||
|
||||
protected def getBool(name: String, req: RequestHeader) =
|
||||
getInt(name, req) exists (1==)
|
||||
|
||||
protected def getBoolOpt(name: String, req: RequestHeader) =
|
||||
getInt(name, req) map (1==)
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ trait AssetHelper {
|
|||
|
||||
def isProd: Boolean
|
||||
|
||||
private val domain = lila.api.Env.current.Net.AssetDomain
|
||||
val assetDomain = lila.api.Env.current.Net.AssetDomain
|
||||
|
||||
def staticUrl(path: String) = s"http://$domain${routes.Assets.at(path)}"
|
||||
val assetBaseUrl = s"http://$assetDomain"
|
||||
|
||||
def staticUrl(path: String) = s"$assetBaseUrl${routes.Assets.at(path)}"
|
||||
|
||||
def cssTag(name: String, staticDomain: Boolean = true) = cssAt("stylesheets/" + name, staticDomain)
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
@(move: Field, gameId: Field, captcha: lila.common.Captcha)(implicit ctx: Context)
|
||||
|
||||
<input type="hidden" name="@gameId.name" id="@gameId.id" value="@captcha.gameId" />
|
||||
@if(ctx.blindMode) {
|
||||
<input type="hidden" name="@move.name" id="@move.id" value="@captcha.solutions.head" />
|
||||
} else {
|
||||
<div class="checkmateCaptcha clearfix" data-check-url="@routes.Main.captchaCheck(captcha.gameId)">
|
||||
<div class="checkmateFen">
|
||||
<div
|
||||
|
@ -23,3 +27,4 @@
|
|||
<input type="hidden" name="@move.name" id="@move.id" value="" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@ openGraph: Map[Symbol, String] = Map.empty)(body: Html)(implicit ctx: Context)
|
|||
<div id="site_description">@trans.freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents()</div>
|
||||
<div id="top" class="clearfix">
|
||||
@if(!zen) {
|
||||
<a data-hint="@trans.toggleSound()" id="sound_state" class="available hint--bottom-left">
|
||||
<button data-hint="@trans.toggleSound()" id="sound_state" class="a available hint--bottom-left">
|
||||
<span class="is2 on" data-icon="n"></span>
|
||||
<span class="is2 off" data-icon="o"></span>
|
||||
</a>
|
||||
</button>
|
||||
}
|
||||
@if(!zen) {
|
||||
@siteMenu.all(ctx.me).map { elem =>
|
||||
|
|
|
@ -16,7 +16,7 @@ title = trans.boardEditor.str(),
|
|||
menu = game.sideMenu(listMenu, "edit").some,
|
||||
moreJs = moreJs,
|
||||
moreCss = moreCss) {
|
||||
<div id="board_editor" class="content_box">
|
||||
<div id="board_editor" class="content_box" data-asset-url="@assetBaseUrl">
|
||||
<div id="chessboard_side">
|
||||
<div>
|
||||
<a class="button start">@trans.startPosition()</a>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
@(scoreOption: Option[lila.coordinate.Score])(implicit ctx: Context)
|
||||
|
||||
@import lila.pref.Pref.Color
|
||||
|
||||
@moreCss = {
|
||||
@cssTag("training.css")
|
||||
@cssTag("coordinate.css")
|
||||
|
@ -50,11 +52,11 @@ active = siteMenu.puzzle.some) {
|
|||
}
|
||||
</div>
|
||||
<form class="color buttons" action="@routes.Coordinate.color" method="POST">
|
||||
@lila.pref.Pref.Color.choices.map {
|
||||
@List(Color.BLACK -> trans.black(), Color.RANDOM -> trans.randomColor(), Color.WHITE -> trans.white()).map {
|
||||
case (id, name) => {
|
||||
<input type="radio" id="coord_color_@id" name="coord_color" value="@id"
|
||||
@(if(id == ctx.pref.coordColor) "checked" else "") />
|
||||
<label for="coord_color_@id">@name</label>
|
||||
<label for="coord_color_@id" data-hint="@name" class="color color_@id hint--bottom"></label>
|
||||
}
|
||||
}
|
||||
</form>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
data-color="@puzzle.color"
|
||||
data-move="@puzzle.initialMove"
|
||||
data-lines="@lila.puzzle.Line.toJsonString(puzzle.lines)"
|
||||
data-post-url="@routes.Puzzle.attempt(puzzle.id)">
|
||||
data-post-url="@routes.Puzzle.attempt(puzzle.id)"
|
||||
data-asset-url="@assetBaseUrl">
|
||||
|
||||
<div class="side">
|
||||
@trainingBox(puzzle, userInfos, true)
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
data-color="@puzzle.color"
|
||||
data-move="@puzzle.initialMove"
|
||||
data-lines="@lila.puzzle.Line.toJsonString(puzzle.lines)"
|
||||
data-new-url="@routes.Puzzle.newPuzzle">
|
||||
data-new-url="@routes.Puzzle.newPuzzle"
|
||||
data-asset-url="@assetBaseUrl">
|
||||
|
||||
<div class="side">
|
||||
@trainingBox(puzzle, userInfos, false)
|
||||
|
|
|
@ -14,23 +14,23 @@
|
|||
</div>
|
||||
<div class="lichess_control icons">
|
||||
@if(game.abortable) {
|
||||
<a class="abort button socket-link hint--bottom" data-msg="abort" data-hint="@trans.abortGame()">
|
||||
<button class="abort button socket-link hint--bottom" data-msg="abort" data-hint="@trans.abortGame()">
|
||||
<span data-icon="L"></span>
|
||||
</a>
|
||||
</button>
|
||||
} else {
|
||||
@if(takebackable && game.playerCanProposeTakeback(color)) {
|
||||
<a class="takeback button socket-link hint--bottom" data-msg="takeback-yes" data-hint="@trans.proposeATakeback()">
|
||||
<button class="takeback button socket-link hint--bottom" data-msg="takeback-yes" data-hint="@trans.proposeATakeback()">
|
||||
<span data-icon="i"></span>
|
||||
</a>
|
||||
</button>
|
||||
}
|
||||
@if(game.playerCanOfferDraw(color)) {
|
||||
<a class="draw button socket-link hint--bottom" data-msg="draw-yes" data-hint="@trans.offerDraw()">
|
||||
<button class="draw button socket-link hint--bottom" data-msg="draw-yes" data-hint="@trans.offerDraw()">
|
||||
<span data-icon="2"></span>
|
||||
</a>
|
||||
</button>
|
||||
}
|
||||
<a class="resign button socket-link hint--bottom" data-msg="resign" data-hint="@trans.resign()">
|
||||
<button class="resign button socket-link hint--bottom" data-msg="resign" data-hint="@trans.resign()">
|
||||
<span data-icon="b"></span>
|
||||
</a>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
@if(game.resignable && !game.hasAi) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<dt>Turn</dt>
|
||||
<dd>@pov.game.turns</dd>
|
||||
<dt>PGN</dt>
|
||||
<dd>@pov.game.pgnMoves.mkString(" ")</dd>
|
||||
<dd>@Html(pov.game.pgnMoves.mkString("<br />"))</dd>
|
||||
<dt>FEN</dt>
|
||||
<dd>@{chess.format.Forsyth.>>(pov.game.toChess)}</dd>
|
||||
<dt>Your color</dt>
|
||||
|
@ -25,8 +25,8 @@
|
|||
<label>
|
||||
Your move in UCI format (e.g. e2e4 or d7d8Q)
|
||||
<input name="move" class="move" type="text" value="" />
|
||||
<button type="submit">Send move</button>
|
||||
</label>
|
||||
<button type="submit">Send move</button>
|
||||
</form>
|
||||
}
|
||||
</dl>
|
||||
|
|
4
bin/mongodb/game-analysed.js
Normal file
4
bin/mongodb/game-analysed.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
var games = db.game5;
|
||||
db.analysis2.find({},{_id:true}).forEach(function(analysis) {
|
||||
games.update({_id: analysis._id},{$set:{an:true}});
|
||||
});
|
|
@ -5,7 +5,8 @@ var Chess = {
|
|||
load: function(fen) {},
|
||||
fen: function() {},
|
||||
turn: function() {},
|
||||
in_check: function() {}
|
||||
in_check: function() {},
|
||||
undo: function() {}
|
||||
};
|
||||
jQuery.prototype.sparkline = function(points, options) {};
|
||||
jQuery.displayBoardMarks = function(board, white) {};
|
||||
|
|
|
@ -22,13 +22,12 @@
|
|||
(jq/add-class ($ squares $puzzle) :last)
|
||||
(when $check (jq/add-class $check :check)))))
|
||||
|
||||
(defn make-chessboard [config]
|
||||
(let [static-domain (str "http://" (clojure.string/replace (.-domain js/document) #"^\w+" "static"))
|
||||
piece-set (jq/data ($ :body) :piece-set)]
|
||||
(defn make-chessboard [config asset-url]
|
||||
(let [piece-set (jq/data ($ :body) :piece-set)]
|
||||
(new js/ChessBoard "chessboard"
|
||||
(clj->js (merge {:sparePieces false
|
||||
:showNotation false
|
||||
:pieceTheme (str static-domain "/assets/piece/" piece-set "/{piece}.svg")}
|
||||
:pieceTheme (str asset-url "/assets/piece/" piece-set "/{piece}.svg")}
|
||||
config)))))
|
||||
|
||||
(defn board-marks! [$puzzle]
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
(defn on-drop! [orig, dest]
|
||||
(if (core/apply-move chess orig dest) (put! drop-chan (str orig dest)) "snapback"))
|
||||
|
||||
(defn make-chessboard [$puzzle fen]
|
||||
(defn make-chessboard [$puzzle asset-url fen]
|
||||
(core/make-chessboard {:orientation (jq/data $puzzle :color)
|
||||
:position fen
|
||||
:moveSpeed animation-delay
|
||||
:draggable true
|
||||
:dropOffBoard "snapback"
|
||||
:onDrop on-drop!}))
|
||||
:onDrop on-drop!}
|
||||
asset-url))
|
||||
|
||||
(defn show-turn! [$puzzle]
|
||||
(let [color (if (= (.turn chess) "w") "white" "black")
|
||||
|
@ -106,9 +107,10 @@
|
|||
|
||||
(defn run! []
|
||||
(let [$puzzle ($ :#puzzle)
|
||||
assets (jq/data $puzzle :asset-url)
|
||||
lines (js->clj (jq/data $puzzle :lines))
|
||||
initial-fen (jq/data $puzzle :fen)
|
||||
chessboard (make-chessboard $puzzle initial-fen)
|
||||
chessboard (make-chessboard $puzzle assets initial-fen)
|
||||
started-at (new js/Date)]
|
||||
(core/center-right! ($ :.right $puzzle))
|
||||
(core/board-marks! $puzzle)
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
(def continue-chan (async/chan))
|
||||
(def animation-delay 200)
|
||||
|
||||
(defn make-chessboard [$puzzle]
|
||||
(defn make-chessboard [$puzzle asset-url]
|
||||
(core/make-chessboard {:orientation (jq/data $puzzle :color)
|
||||
:moveSpeed animation-delay
|
||||
:draggable false}))
|
||||
:draggable false}
|
||||
asset-url))
|
||||
|
||||
(defn bind-vote! [$vote]
|
||||
(jq/on $vote :click ".enabled a:not(.active)"
|
||||
|
@ -72,6 +73,7 @@
|
|||
|
||||
(defn run! [progress]
|
||||
(let [$puzzle ($ :#puzzle)
|
||||
assets (jq/data $puzzle :asset-url)
|
||||
$browse ($ :#GameButtons $puzzle)
|
||||
$first ($ :.first $browse)
|
||||
$prev ($ :.prev $browse)
|
||||
|
@ -80,7 +82,7 @@
|
|||
lines (js->clj (jq/data $puzzle :lines))
|
||||
line (find-best-line-from-progress lines progress)
|
||||
history (vec (make-history (jq/data $puzzle :fen) (conj (seq line) (jq/data $puzzle :move))))
|
||||
chessboard (make-chessboard $puzzle)]
|
||||
chessboard (make-chessboard $puzzle assets)]
|
||||
(core/center-right! ($ :.right $puzzle))
|
||||
(core/board-marks! $puzzle)
|
||||
(core/buttons! $puzzle)
|
||||
|
|
|
@ -28,7 +28,7 @@ yourOpponentWantsToPlayANewGameWithYou=Dein Gegner möchte eine neue Partie mit
|
|||
joinTheGame=Der Partie beitreten
|
||||
whitePlays=Weiß am Zug
|
||||
blackPlays=Schwarz am Zug
|
||||
theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim=Dein Gegner hat die Partie verlassen. Du kannst den Sieg reklamieren oder auf deinen Gegner warten.
|
||||
theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim=Dein Gegner hat die Partie verlassen. Du kannst den Sieg reklamieren, dass Spiel remis erklären oder auf deinen Gegner warten.
|
||||
makeYourOpponentResign=Bringe deinen Gegner zur Aufgabe
|
||||
forceResignation=Sieg reklamieren
|
||||
forceDraw=Remis erzwingen
|
||||
|
@ -135,7 +135,7 @@ nbWins=%s Siege
|
|||
nbLosses=%s Niederlagen
|
||||
nbDraws=%s Remis
|
||||
exportGames=Spiele exportieren
|
||||
ratingRange=Elo-Bereich
|
||||
ratingRange=Rating-Bereich
|
||||
giveNbSeconds=%s Sekunden geben
|
||||
premoveEnabledClickAnywhereToCancel=Vorauszug aktiviert - Zum Abbrechen irgendwo klicken
|
||||
thisPlayerUsesChessComputerAssistance=Dieser Spieler verwendet einen Schachcomputer als Hilfe
|
||||
|
|
|
@ -50,7 +50,7 @@ theComputerAnalysisHasFailed=Počítačová analýza zlyhala
|
|||
viewTheComputerAnalysis=Zobraziť počítačovú analýzu
|
||||
requestAComputerAnalysis=Požiadať o počítačovú analýzu
|
||||
computerAnalysis=Počítačová anylýza
|
||||
blunders=Hrubyé chyby
|
||||
blunders=Hrubé chyby
|
||||
mistakes=Chyby
|
||||
inaccuracies=Nepresnosti
|
||||
moveTimes=Trvanie ťahu
|
||||
|
@ -65,7 +65,7 @@ viewAllNbGames=Zobraziť všetkých %s hier
|
|||
viewNbCheckmates=Zobraziť %s šach-maty
|
||||
nbBookmarks=%s Záložky
|
||||
nbPopularGames=%s Populárne hry
|
||||
nbAnalysedGames=%s Analyzovaných Hier
|
||||
nbAnalysedGames=%s Analyzovaných hier
|
||||
bookmarkedByNbPlayers=Záložku uložilo %s hráčov
|
||||
viewInFullSize=Zobraziť v plnej veľkosti
|
||||
logOut=Odhlásiť sa
|
||||
|
@ -73,7 +73,7 @@ signIn=Prihlásiť sa
|
|||
newToLichess=Nováčik na Lichess?
|
||||
youNeedAnAccountToDoThat=Pre túto požiadavku musíš byť prihlásený
|
||||
signUp=Zaregistrovať sa
|
||||
computersAreNotAllowedToPlay=I programmi scacchistici o l'ausilio di programmi scacchistici nono sono autorizzati,per cortesia evitate l'uso di programmi,databases,o i suggerimenti di altri giocatori durante una partita
|
||||
computersAreNotAllowedToPlay=Hráči využívajúci pomoc počítačov nie sú vítaní. Počas partie nepoužívajte šachové programy, databázy ani rady iných hráčov.
|
||||
games=Hry
|
||||
forum=Forum
|
||||
xPostedInForumY=%s príspevkov na fóre %s
|
||||
|
@ -124,7 +124,7 @@ inbox=Správy
|
|||
chatRoom=Chatovacia miestnosť
|
||||
spectatorRoom=Divácka miestnosť
|
||||
composeMessage=Napísať správu
|
||||
noNewMessages=Žiadne správy momentálne
|
||||
noNewMessages=Žiadne nové správy
|
||||
subject=Predmet
|
||||
recipient=Príjemca
|
||||
send=Poslať
|
||||
|
@ -156,7 +156,7 @@ tournamentPoints=Turnajové body
|
|||
viewTournament=Zobraz turnaj
|
||||
backToTournament=Návrat do turnaja
|
||||
xTournament=%s turnaj
|
||||
freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents=Šach online zadarmo. Hrajte šach teraz v novom rozhraní. Bez registrácie, reklám a zásuvných modulov. Hraj šach s počítačom, priateľmi alebo náhodnými protivníkmi.
|
||||
freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents=Šach online zadarmo. Hrajte šach teraz v novom rozhraní. Bez registrácie, reklám a zásuvných modulov. Hrajte šach s počítačom, priateľmi alebo náhodnými protivníkmi.
|
||||
teams=Tímy
|
||||
nbMembers=%s členovia
|
||||
allTeams=Všetky tímy
|
||||
|
@ -170,7 +170,7 @@ aConfirmationIsRequiredToJoin=Potvrdenie je potrebné na vstup
|
|||
joiningPolicy=Pravidlá vstupu
|
||||
teamLeader=Vecúci tímu
|
||||
teamBestPlayers=Najlepší hráči
|
||||
teamRecentMembers=Nový členovia tímu
|
||||
teamRecentMembers=Noví členovia tímu
|
||||
xJoinedTeamY=%s sa pripojil/la k tímu %s
|
||||
xCreatedTeamY=%s vytvoril/la tím %s
|
||||
averageElo=Priemerné Elo
|
||||
|
@ -181,15 +181,15 @@ reset=Reset
|
|||
apply=Použiť
|
||||
leaderboard=Rebríček
|
||||
pasteTheFenStringHere=Vlož sem hodnotu FEN
|
||||
pasteThePgnStringHere=Vlož sem PGN hodnotu
|
||||
pasteThePgnStringHere=Vlož sem PGN text
|
||||
fromPosition=Od pozície
|
||||
continueFromHere=Pokračuj odtiaľto
|
||||
importGame=Import hry
|
||||
nbImportedGames=%s importovaných hier
|
||||
thisIsAChessCaptcha=Šachová CAPTCHA
|
||||
clickOnTheBoardToMakeYourMove=Kliknite na šachovnicu a spravte ťah, aby ste dokázali, že ste človek.
|
||||
notACheckmate=Nie je šach mat
|
||||
colorPlaysCheckmateInOne=%s hrá; šach mat na jeden ťah
|
||||
notACheckmate=Nie je to mat
|
||||
colorPlaysCheckmateInOne=%s na ťahu; mat prvým ťahom
|
||||
retry=Znova
|
||||
reconnecting=Pripájanie
|
||||
onlineFriends=Online pritelia
|
||||
|
@ -221,14 +221,14 @@ required=Vyžaduje sa
|
|||
addToChrome=Pridať do Chrome
|
||||
openTournaments=Otvorené turnaje
|
||||
duration=Dĺžka
|
||||
winner=Výťaz
|
||||
winner=Víťaz
|
||||
standing=Pozícia
|
||||
createANewTournament=Vytvor nový turnaj
|
||||
join=Pripojiť
|
||||
withdraw=Odstúpiť
|
||||
points=Bodov
|
||||
wins=Výťazi
|
||||
losses=Porazený
|
||||
wins=Víťazi
|
||||
losses=Prehry
|
||||
winStreak=Séria výhier
|
||||
createdBy=Vytvorené
|
||||
waitingForNbPlayers=Čakanie na %s hráčov
|
||||
|
@ -250,7 +250,7 @@ biography=Životopis
|
|||
country=Krajina
|
||||
preferences=Nastavenia
|
||||
watchLichessTV=Sleduj Lichess TV
|
||||
previouslyOnLichessTV=Bolo na Liechess TV
|
||||
previouslyOnLichessTV=Bolo na Lichess TV
|
||||
todaysLeaders=Dnešní lídri
|
||||
onlinePlayers=Pripojený hráči
|
||||
progressToday=Dnešný pokrok
|
||||
|
@ -267,10 +267,10 @@ bestSlowPlayers=Najlepší hráči pomalých hier
|
|||
bewareTheGameIsRatedButHasNoClock=Pozor, hra je bodovaná, ale bez času!
|
||||
training=Tréning
|
||||
yourPuzzleRatingX=Hodnotenie z : %s
|
||||
findTheBestMoveForWhite=Trova la miglior mossa del bianco
|
||||
findTheBestMoveForBlack=Trova la miglior mossa del nero
|
||||
findTheBestMoveForWhite=Nájdite za bieleho najlepší ťah.
|
||||
findTheBestMoveForBlack=Nájdite za čierneho najlepší ťah.
|
||||
toTrackYourProgress=Sledovať svoj pokrok:
|
||||
trainingSignupExplanation=Lichess ponúka šachové rébusy, ktoré zlepšujú vašu šikovnosť pre ďalšie šachové partie .
|
||||
trainingSignupExplanation=Lichess ponúka šachové rébusy, ktoré zlepšujú vašu šikovnosť pre ďalšie šachové partie.
|
||||
recentlyPlayedPuzzles=Nedávno hrané rébusy
|
||||
puzzleId=Rébus %s
|
||||
puzzleOfTheDay=Rébus dňa
|
||||
|
@ -280,16 +280,16 @@ butYouCanDoBetter=Ale môžete to spraviť lepšie.
|
|||
bestMove=Najlepší ťah!
|
||||
keepGoing=Pokračujte...
|
||||
puzzleFailed=Nesprávne vyriešený rébus
|
||||
butYouCanKeepTrying=Napriek tomu môžte pokračovať.
|
||||
butYouCanKeepTrying=Napriek tomu môžete pokračovať.
|
||||
victory=Výhra!
|
||||
giveUp=Vzdať sa
|
||||
puzzleSolvedInXSeconds=Rébus vyriešený za %s sekúnd.
|
||||
wasThisPuzzleAnyGood=Bol rébus správny?
|
||||
wasThisPuzzleAnyGood=Bol tento rébus dobrý?
|
||||
pleaseVotePuzzle=Pomôžte zlepšiť lichess hlasovaním, kliknutím na šípku hore alebo dole:
|
||||
thankYou=Ďakujem!
|
||||
ratingX=Hodnotenie: %s
|
||||
playedXTimes=Hraný %s krát
|
||||
fromGameLink=Pre hru %s
|
||||
fromGameLink=Z hry %s
|
||||
startTraining=Začať tréning
|
||||
continueTraining=Pokračovanie v tréningu
|
||||
retryThisPuzzle=Opakovať tento rébus
|
||||
|
|
|
@ -73,6 +73,7 @@ signIn=登录
|
|||
newToLichess=新来的吗
|
||||
youNeedAnAccountToDoThat=你需要先登入帐号
|
||||
signUp=注册
|
||||
computersAreNotAllowedToPlay=电脑及电脑辅助队员不准玩。请不要从国际象棋引擎,数据库,或者从其他玩家边玩得到帮助
|
||||
games=棋
|
||||
forum=论坛
|
||||
xPostedInForumY=%s 张贴在论坛 %s
|
||||
|
@ -266,12 +267,27 @@ bestSlowPlayers=最佳慢棋棋手
|
|||
bewareTheGameIsRatedButHasNoClock=注意,这局是评分的但不计时
|
||||
training=训练
|
||||
yourPuzzleRatingX=您的难题评级:%s
|
||||
findTheBestMoveForWhite=找到白色的最好的移动
|
||||
findTheBestMoveForBlack=找到黑色的最好的移动
|
||||
toTrackYourProgress=跟踪你的进度:
|
||||
trainingSignupExplanation=Lichess将提供符合您的能力,从而为更好地训练难题。
|
||||
recentlyPlayedPuzzles=最近在玩拼图
|
||||
puzzleId=谜 %s
|
||||
puzzleOfTheDay=一天之谜
|
||||
clickToSolve=点击解决
|
||||
goodMove=好着
|
||||
butYouCanDoBetter=你可以做的更好
|
||||
bestMove=最理想的做法
|
||||
keepGoing=继续下去...
|
||||
puzzleFailed=失败之谜
|
||||
butYouCanKeepTrying=但是你可以不断尝试
|
||||
victory=胜利!
|
||||
giveUp=放弃
|
||||
wasThisPuzzleAnyGood=为这个难题有什么好处?
|
||||
pleaseVotePuzzle=通过投票帮助lichess提高,使用向上键或向下键:
|
||||
thankYou=谢谢!
|
||||
startTraining=开始训练
|
||||
continueTraining=继续训练
|
||||
retryThisPuzzle=重试这个难题
|
||||
thisPuzzleIsCorrect=这个难题是正确的,有趣的
|
||||
thisPuzzleIsWrong=这个难题是错误的或无聊
|
||||
|
|
|
@ -245,7 +245,7 @@ POST /report/:id/process controllers.Report.process(id: String)
|
|||
GET /api/user controllers.Api.users
|
||||
GET /api/user/:id controllers.Api.user(id: String)
|
||||
GET /api/game controllers.Api.games
|
||||
GET /api/analysis controllers.Api.analysis
|
||||
GET /api/game/:id controllers.Api.game(id: String)
|
||||
GET /api/puzzle/:id controllers.Api.puzzle(id: String)
|
||||
POST /api/puzzle controllers.Puzzle.importBatch
|
||||
|
||||
|
|
|
@ -31,11 +31,6 @@ final class Analyser(
|
|||
if (a.stalled) (AnalysisRepo remove a.id) inject none[Analysis] else fuccess(a.some)
|
||||
}
|
||||
|
||||
def hasDone(id: String): Fu[Boolean] = getDone(id) map (_.isDefined)
|
||||
|
||||
def hasMany(ids: Seq[String]): Fu[Set[String]] =
|
||||
$primitive[Analysis, String]($select byIds ids, "_id")(_.asOpt[String]) map (_.toSet)
|
||||
|
||||
def getOrGenerate(
|
||||
id: String,
|
||||
userId: String,
|
||||
|
@ -84,7 +79,7 @@ final class Analyser(
|
|||
game.userIds foreach { userId =>
|
||||
evaluator ! lila.hub.actorApi.evaluation.Refresh(userId)
|
||||
}
|
||||
} inject analysis
|
||||
} >>- GameRepo.setAnalysed(game.id) inject analysis
|
||||
}
|
||||
else fufail(s"[analysis] invalid $id")
|
||||
})
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package lila.api
|
||||
|
||||
import chess.format.pgn.Pgn
|
||||
import chess.format.UciDump
|
||||
import chess.Replay
|
||||
import play.api.libs.json._
|
||||
|
||||
import lila.analyse.{ Analysis, AnalysisRepo }
|
||||
import lila.common.PimpedJson._
|
||||
import lila.db.api._
|
||||
import lila.db.Implicits._
|
||||
import lila.game.{ Game, GameRepo, PgnDump }
|
||||
import lila.hub.actorApi.{ router => R }
|
||||
|
||||
private[api] final class AnalysisApi(
|
||||
apiToken: String,
|
||||
makeUrl: Any => Fu[String],
|
||||
nbAnalysis: () => Fu[Int],
|
||||
pgnDump: PgnDump) {
|
||||
|
||||
private def makeNb(nb: Option[Int]) = math.min(100, nb | 10)
|
||||
|
||||
private def makeSkip = nbAnalysis() map { nb => scala.util.Random.nextInt(nb) }
|
||||
|
||||
def list(nb: Option[Int], token: Option[String]): Fu[JsObject] =
|
||||
if (~token != apiToken) fuccess(Json.obj("oh" -> "bummer"))
|
||||
else makeSkip flatMap { skip =>
|
||||
AnalysisRepo.skipping(skip, makeNb(nb)) flatMap { as =>
|
||||
GameRepo games as.map(_.id) flatMap { games =>
|
||||
games.map { g =>
|
||||
as find (_.id == g.id) map { _ -> g }
|
||||
}.flatten.map {
|
||||
case (a, g) => GameRepo initialFen g.id flatMap { initialFen =>
|
||||
pgnDump(g) zip makeUrl(R.Watcher(g.id, g.firstPlayer.color.name)) map {
|
||||
case (pgn, url) => (g, a, url, pgn, initialFen)
|
||||
}
|
||||
}
|
||||
}.sequenceFu map { tuples =>
|
||||
Json.obj(
|
||||
"list" -> JsArray(tuples map {
|
||||
case (game, analysis, url, pgn, fen) => Json.obj(
|
||||
"game" -> (GameApi.gameToJson(game, url, analysis.some) ++ {
|
||||
fen ?? { f => Json.obj("initialFen" -> f) }
|
||||
}),
|
||||
"analysis" -> AnalysisApi.analysisToJson(analysis, pgn),
|
||||
"uci" -> uciMovesOf(game, fen).map(_.mkString(" "))
|
||||
).noNull
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def uciMovesOf(game: Game, initialFen: Option[String]): Option[List[String]] =
|
||||
Replay(game.pgnMoves mkString " ", initialFen, game.variant).toOption map UciDump.apply
|
||||
}
|
||||
|
||||
private[api] object AnalysisApi {
|
||||
|
||||
def analysisToJson(analysis: Analysis, pgn: Pgn) = JsArray(analysis.infoAdvices zip pgn.moves map {
|
||||
case ((info, adviceOption), move) => Json.obj(
|
||||
"ply" -> info.ply,
|
||||
"move" -> move.san,
|
||||
"eval" -> info.score.map(_.centipawns),
|
||||
"mate" -> info.mate,
|
||||
"variation" -> info.variation.isEmpty.fold(JsNull, info.variation mkString " "),
|
||||
"comment" -> adviceOption.map(_.makeComment(true, true))
|
||||
).noNull
|
||||
})
|
||||
}
|
|
@ -14,7 +14,10 @@ case class PageData(
|
|||
blindMode: Boolean)
|
||||
|
||||
object PageData {
|
||||
|
||||
val default = PageData(Nil, 0, 0, Pref.default, false)
|
||||
|
||||
def anon(blindMode: Boolean) = default.copy(blindMode = blindMode)
|
||||
}
|
||||
|
||||
sealed trait Context extends lila.user.UserContextWrapper {
|
||||
|
|
|
@ -44,12 +44,6 @@ final class Env(
|
|||
val gameApi = new GameApi(
|
||||
makeUrl = apiUrl,
|
||||
apiToken = apiToken,
|
||||
isOnline = userEnv.isOnline)
|
||||
|
||||
val analysisApi = new AnalysisApi(
|
||||
apiToken = apiToken,
|
||||
makeUrl = apiUrl,
|
||||
nbAnalysis = () => analyseEnv.cached.nbAnalysis,
|
||||
pgnDump = pgnDump)
|
||||
|
||||
val puzzleApi = new PuzzleApi(
|
||||
|
|
|
@ -2,58 +2,70 @@ package lila.api
|
|||
|
||||
import play.api.libs.json._
|
||||
|
||||
import chess.format.pgn.Pgn
|
||||
import lila.analyse.{ AnalysisRepo, Analysis }
|
||||
import lila.common.PimpedJson._
|
||||
import lila.db.api._
|
||||
import lila.db.Implicits._
|
||||
import lila.game.Game
|
||||
import lila.game.Game.{ BSONFields => G }
|
||||
import lila.game.tube.gameTube
|
||||
import lila.game.{ Game, PgnDump }
|
||||
import lila.hub.actorApi.{ router => R }
|
||||
import makeTimeout.short
|
||||
|
||||
private[api] final class GameApi(
|
||||
makeUrl: Any => Fu[String],
|
||||
apiToken: String,
|
||||
isOnline: String => Boolean) {
|
||||
pgnDump: PgnDump) {
|
||||
|
||||
private def makeNb(nb: Option[Int]) = math.min(100, nb | 10)
|
||||
|
||||
def list(
|
||||
username: Option[String],
|
||||
rated: Option[Boolean],
|
||||
analysed: Option[Boolean],
|
||||
withAnalysis: Boolean,
|
||||
token: Option[String],
|
||||
nb: Option[Int]): Fu[JsObject] = $find($query(Json.obj(
|
||||
G.status -> $gte(chess.Status.Mate.id),
|
||||
G.playerUids -> username,
|
||||
G.rated -> rated.map(_.fold(JsBoolean(true), $exists(false)))
|
||||
).noNull) sort lila.game.Query.sortCreated, makeNb(nb)) flatMap { games =>
|
||||
G.rated -> rated.map(_.fold(JsBoolean(true), $exists(false))),
|
||||
G.analysed -> analysed.map(_.fold(JsBoolean(true), $exists(false)))
|
||||
).noNull) sort lila.game.Query.sortCreated, makeNb(nb)) flatMap
|
||||
gamesJson(withAnalysis, token) map { games =>
|
||||
Json.obj("list" -> games)
|
||||
}
|
||||
|
||||
def one(
|
||||
id: String,
|
||||
withAnalysis: Boolean,
|
||||
token: Option[String]): Fu[Option[JsObject]] =
|
||||
$find byId id map (_.toList) flatMap gamesJson(withAnalysis, token) map (_.headOption)
|
||||
|
||||
private def gamesJson(withAnalysis: Boolean, token: Option[String])(games: List[Game]): Fu[List[JsObject]] =
|
||||
AnalysisRepo doneByIds games.map(_.id) flatMap { analysisOptions =>
|
||||
(games map { g => makeUrl(R.Watcher(g.id, g.firstPlayer.color.name)) }).sequenceFu map { urls =>
|
||||
val validToken = check(token)
|
||||
Json.obj(
|
||||
"list" -> JsArray(
|
||||
games zip urls zip analysisOptions map {
|
||||
case ((g, url), analysisOption) =>
|
||||
GameApi.gameToJson(g, url, analysisOption,
|
||||
withBlurs = validToken,
|
||||
withMoveTimes = validToken)
|
||||
}
|
||||
)
|
||||
)
|
||||
(games map { g => withAnalysis ?? (pgnDump(g) map (_.some)) }).sequenceFu flatMap { pgns =>
|
||||
(games map { g => makeUrl(R.Watcher(g.id, g.firstPlayer.color.name)) }).sequenceFu map { urls =>
|
||||
val validToken = check(token)
|
||||
games zip urls zip analysisOptions zip pgns map {
|
||||
case (((g, url), analysisOption), pgnOption) =>
|
||||
gameToJson(g, url, analysisOption, pgnOption,
|
||||
withAnalysis = withAnalysis,
|
||||
withBlurs = validToken,
|
||||
withMoveTimes = validToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def check(token: Option[String]) = token ?? (apiToken==)
|
||||
}
|
||||
|
||||
private[api] object GameApi {
|
||||
|
||||
def gameToJson(
|
||||
private def gameToJson(
|
||||
g: Game,
|
||||
url: String,
|
||||
analysisOption: Option[Analysis],
|
||||
pgnOption: Option[Pgn],
|
||||
withAnalysis: Boolean,
|
||||
withBlurs: Boolean = false,
|
||||
withMoveTimes: Boolean = false) = Json.obj(
|
||||
"id" -> g.id,
|
||||
|
@ -84,6 +96,18 @@ private[api] object GameApi {
|
|||
)
|
||||
).noNull
|
||||
}),
|
||||
"analysis" -> analysisOption.ifTrue(withAnalysis).|@|(pgnOption).apply {
|
||||
case (analysis, pgn) => JsArray(analysis.infoAdvices zip pgn.moves map {
|
||||
case ((info, adviceOption), move) => Json.obj(
|
||||
"ply" -> info.ply,
|
||||
"move" -> move.san,
|
||||
"eval" -> info.score.map(_.centipawns),
|
||||
"mate" -> info.mate,
|
||||
"variation" -> info.variation.isEmpty.fold(JsNull, info.variation mkString " "),
|
||||
"comment" -> adviceOption.map(_.makeComment(true, true))
|
||||
).noNull
|
||||
})
|
||||
},
|
||||
"winner" -> g.winnerColor.map(_.name),
|
||||
"url" -> url
|
||||
).noNull
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 87a28a41a6a9087a3af7af597cf9fedbe24c81ce
|
||||
Subproject commit 7b015665cd7d97c61c38800e10202a33d1d0beb0
|
|
@ -423,6 +423,7 @@ object Game {
|
|||
val castleLastMoveTime = "cl"
|
||||
val moveTimes = "mt"
|
||||
val rated = "ra"
|
||||
val analysed = "an"
|
||||
val variant = "v"
|
||||
val next = "ne"
|
||||
val bookmarks = "bm"
|
||||
|
|
|
@ -109,6 +109,18 @@ trait GameRepo {
|
|||
|
||||
def onTv(nb: Int): Fu[List[Game]] = $find($query(Json.obj(F.tvAt -> $exists(true))) sort $sort.desc(F.tvAt), nb)
|
||||
|
||||
def setAnalysed(id: ID) {
|
||||
$update.fieldUnchecked(id, F.analysed, true)
|
||||
}
|
||||
|
||||
private def selectAnalysed = Json.obj(F.analysed -> true)
|
||||
|
||||
def isAnalysed(id: ID): Fu[Boolean] =
|
||||
$count.exists($select(id) ++ selectAnalysed)
|
||||
|
||||
def filterAnalysed(ids: Seq[String]): Fu[Set[String]] =
|
||||
$primitive(($select byIds ids) ++ selectAnalysed, "_id")(_.asOpt[String]) map (_.toSet)
|
||||
|
||||
def incBookmarks(id: ID, value: Int) =
|
||||
$update($select(id), $incBson("bm" -> value))
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ import lila.game.tube.gameTube
|
|||
final class Env(
|
||||
config: Config,
|
||||
system: ActorSystem,
|
||||
client: ElasticClient,
|
||||
analyser: lila.analyse.Analyser) {
|
||||
client: ElasticClient) {
|
||||
|
||||
private val IndexName = config getString "index"
|
||||
private val TypeName = config getString "type"
|
||||
|
@ -21,8 +20,7 @@ final class Env(
|
|||
private val indexer: ActorRef = system.actorOf(Props(new Indexer(
|
||||
client = client,
|
||||
indexName = IndexName,
|
||||
typeName = TypeName,
|
||||
analyser = analyser
|
||||
typeName = TypeName
|
||||
)), name = IndexerName)
|
||||
|
||||
lazy val paginator = new lila.search.PaginatorBuilder(
|
||||
|
@ -49,6 +47,5 @@ object Env {
|
|||
lazy val current = "[boot] gameSearch" describes new Env(
|
||||
config = lila.common.PlayApp loadConfig "gameSearch",
|
||||
system = lila.common.PlayApp.system,
|
||||
client = lila.search.Env.current.client,
|
||||
analyser = lila.analyse.Env.current.analyser)
|
||||
client = lila.search.Env.current.client)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.sksamuel.elastic4s.ElasticClient
|
|||
import com.sksamuel.elastic4s.ElasticDsl._
|
||||
import com.sksamuel.elastic4s.mapping.FieldType._
|
||||
|
||||
import lila.game.GameRepo
|
||||
import lila.game.actorApi.{ InsertGame, FinishGame }
|
||||
import lila.search.actorApi._
|
||||
import lila.search.ElasticSearch
|
||||
|
@ -13,8 +14,7 @@ import lila.search.ElasticSearch
|
|||
private[gameSearch] final class Indexer(
|
||||
client: ElasticClient,
|
||||
indexName: String,
|
||||
typeName: String,
|
||||
analyser: lila.analyse.Analyser) extends Actor {
|
||||
typeName: String) extends Actor {
|
||||
|
||||
context.system.lilaBus.subscribe(self, 'finishGame)
|
||||
|
||||
|
@ -28,7 +28,7 @@ private[gameSearch] final class Indexer(
|
|||
case FinishGame(game, _, _) => self ! InsertGame(game)
|
||||
|
||||
case InsertGame(game) => if (storable(game)) {
|
||||
analyser hasDone game.id foreach { analysed =>
|
||||
GameRepo isAnalysed game.id foreach { analysed =>
|
||||
client execute store(game, analysed)
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ private[gameSearch] final class Indexer(
|
|||
$enumerate.bulk[Option[lila.game.Game]]($query.all, batchSize) { gameOptions =>
|
||||
val games = gameOptions.flatten filter storable
|
||||
val nbGames = games.size
|
||||
(analyser hasMany games.map(_.id).toSeq flatMap { analysedIds =>
|
||||
(GameRepo filterAnalysed games.map(_.id).toSeq flatMap { analysedIds =>
|
||||
client bulk {
|
||||
games.map { g => store(g, analysedIds(g.id)) }: _*
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ case class Modlog(
|
|||
case a => a
|
||||
}
|
||||
|
||||
override def toString = s"$mod $showAction $user"
|
||||
override def toString = s"$mod $showAction ${~user}"
|
||||
}
|
||||
|
||||
object Modlog {
|
||||
|
|
|
@ -128,14 +128,14 @@ private[round] final class Round(
|
|||
case Deploy(RemindDeployPost, _) => handle { game =>
|
||||
game.clock.filter(_ => game.playable) ?? { clock =>
|
||||
import chess.Color
|
||||
val freeSeconds = 12
|
||||
val freeSeconds = 15
|
||||
val newClock = clock.giveTime(Color.White, freeSeconds).giveTime(Color.Black, freeSeconds)
|
||||
val progress = (game withClock newClock) + Event.Clock(newClock)
|
||||
messenger.system(game, (_.untranslated("Deploy in progress")))
|
||||
messenger.system(game, (_.untranslated("Sorry for the inconvenience!")))
|
||||
Color.all.foreach { c =>
|
||||
messenger.system(game, (_.untranslated(s"$c + $freeSeconds seconds")))
|
||||
}
|
||||
messenger.system(game, (_.untranslated("Sorry for the inconvenience!")))
|
||||
GameRepo save progress inject progress.events
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,10 +180,10 @@ trait UserRepo {
|
|||
_ ?? (data => data.enabled && data.compare(password))
|
||||
}
|
||||
|
||||
def create(username: String, password: String): Fu[Option[User]] =
|
||||
def create(username: String, password: String, blind: Boolean): Fu[Option[User]] =
|
||||
!nameExists(username) flatMap {
|
||||
_ ?? {
|
||||
$insert.bson(newUser(username, password)) >> named(normalize(username))
|
||||
$insert.bson(newUser(username, password, blind)) >> named(normalize(username))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ trait UserRepo {
|
|||
def filterByEngine(userIds: List[String]): Fu[List[String]] =
|
||||
$primitive(Json.obj("_id" -> $in(userIds)) ++ engineSelect(true), F.username)(_.asOpt[String])
|
||||
|
||||
private def newUser(username: String, password: String) = {
|
||||
private def newUser(username: String, password: String, blind: Boolean) = {
|
||||
|
||||
val salt = ornicar.scalalib.Random nextStringUppercase 32
|
||||
val perfs = Perfs.default
|
||||
|
@ -295,7 +295,9 @@ trait UserRepo {
|
|||
F.count -> Count.default,
|
||||
F.enabled -> true,
|
||||
F.createdAt -> DateTime.now,
|
||||
F.seenAt -> DateTime.now)
|
||||
F.seenAt -> DateTime.now) ++ {
|
||||
if (blind) BSONDocument("blind" -> true) else BSONDocument()
|
||||
}
|
||||
}
|
||||
|
||||
def artificialSetPassword(id: String, password: String) =
|
||||
|
|
|
@ -118,7 +118,7 @@ object ApplicationBuild extends Build {
|
|||
play.api, RM, PRM)
|
||||
)
|
||||
|
||||
lazy val gameSearch = project("gameSearch", Seq(common, hub, chess, search, game, analyse)).settings(
|
||||
lazy val gameSearch = project("gameSearch", Seq(common, hub, chess, search, game)).settings(
|
||||
libraryDependencies ++= provided(
|
||||
play.api, RM, PRM, elastic4s)
|
||||
)
|
||||
|
|
|
@ -506,7 +506,7 @@ var storage = {
|
|||
});
|
||||
}
|
||||
|
||||
$('#lichess').on('click', 'a.socket-link:not(.disabled)', function() {
|
||||
$('#lichess').on('click', '.socket-link:not(.disabled)', function() {
|
||||
lichess.socket.send($(this).data('msg'), $(this).data('data'));
|
||||
});
|
||||
|
||||
|
@ -2517,7 +2517,7 @@ var storage = {
|
|||
return $plot.data('hook', hook).powerTip({
|
||||
fadeInTime: 0,
|
||||
fadeOutTime: 0,
|
||||
placement: 'ne',
|
||||
placement: hook.rating > 2200 ? 'se' : 'ne',
|
||||
mouseOnToPopup: true,
|
||||
closeDelay: 200,
|
||||
intentPollInterval: 50,
|
||||
|
|
|
@ -11,6 +11,7 @@ $(function() {
|
|||
bq: 'q'
|
||||
};
|
||||
$wrap.find('.castling input').on('change', onChange);
|
||||
var assetUrl = $wrap.data('asset-url');
|
||||
|
||||
function getRich() {
|
||||
return toRich(board.fen());
|
||||
|
@ -38,7 +39,7 @@ $(function() {
|
|||
});
|
||||
}
|
||||
|
||||
var pieceTheme = 'http://' + document.domain.replace(/^\w+/, 'static') + '/assets/piece/' + $('body').data('piece-set') + '/{piece}.svg';
|
||||
var pieceTheme = assetUrl + '/assets/piece/' + $('body').data('piece-set') + '/{piece}.svg';
|
||||
board = new ChessBoard('chessboard', {
|
||||
position: toBase($('#chessboard').data('fen')) || 'start',
|
||||
draggable: true,
|
||||
|
|
|
@ -513,7 +513,7 @@ div.lichess_table div.username.connected span.status:before {
|
|||
div.lichess_table div.username a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
div.lichess_table a.button.strong {
|
||||
div.lichess_table .button.strong {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
font-weight: bold;
|
||||
|
@ -622,23 +622,26 @@ div.lichess_control div.rematch_alert .button {
|
|||
div.lichess_control div.rematch_wait {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
div.lichess_control.icons a.button {
|
||||
div.lichess_control.icons .button {
|
||||
font-size: 16px;
|
||||
height: 22px;
|
||||
height: 34px;
|
||||
padding: 0 10px;
|
||||
margin: 0 3px;
|
||||
}
|
||||
div.lichess_control.icons a.takeback span:before {
|
||||
vertical-align: -7px;
|
||||
}
|
||||
div.lichess_control.icons a.draw span:before {
|
||||
div.lichess_control.icons .takeback span:before {
|
||||
display: inline-block;
|
||||
transform: rotate(-90deg);
|
||||
transform: translateY(1px);
|
||||
}
|
||||
div.lichess_control.icons .draw span:before {
|
||||
display: inline-block;
|
||||
transform: translateY(-1px) rotate(-90deg);
|
||||
-webkit-transform: rotate(-90deg);
|
||||
vertical-align: -4px;
|
||||
}
|
||||
div.lichess_control.icons a.resign span:before {
|
||||
vertical-align: -6px;
|
||||
div.lichess_control.icons .resign span:before {
|
||||
display: inline-block;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
div.lichess_control.buttons a.button {
|
||||
div.lichess_control.buttons .button {
|
||||
display: block;
|
||||
margin-bottom: 0.7em;
|
||||
text-align: center;
|
||||
|
|
|
@ -513,6 +513,10 @@ a.revert-underline {
|
|||
a.revert-underline:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
button.a {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -841,7 +845,7 @@ body.tight div.side_menu a {
|
|||
#reconnecting,
|
||||
a.goto_nav,
|
||||
#top a.toggle,
|
||||
a#sound_state {
|
||||
#sound_state {
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
height: 24px;
|
||||
|
@ -877,7 +881,7 @@ body.offline #nb_connected_players {
|
|||
}
|
||||
#top a.goto_nav:hover,
|
||||
#top a.toggle:hover,
|
||||
a#sound_state:hover {
|
||||
#sound_state:hover {
|
||||
color: #303030;
|
||||
border-color: #808080;
|
||||
}
|
||||
|
@ -1723,7 +1727,7 @@ div.game_config div.color_submits button.random span {
|
|||
}
|
||||
#hooks_wrap table.list thead th {
|
||||
cursor: pointer;
|
||||
padding: 13px 12px;
|
||||
padding: 12.5px 12px;
|
||||
font-weight: lighter;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
form.color .color span {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-size: 30px 30px;
|
||||
background-repeat: no-repeat;
|
||||
padding: 0;
|
||||
margin: 10px 15px;
|
||||
}
|
||||
form.color .color_1 span {
|
||||
background-image: url(../piece/cburnett/wK.svg);
|
||||
}
|
||||
form.color .color_2 span {
|
||||
background-image: url(../piece/cburnett/wbK.svg);
|
||||
}
|
||||
form.color .color_3 span {
|
||||
background-image: url(../piece/cburnett/bK.svg);
|
||||
}
|
||||
#trainer .lichess_board {
|
||||
display: none;
|
||||
border: 1px solid #c0c0c0;
|
||||
|
|
|
@ -140,7 +140,7 @@ body.dark #top a.toggle:hover,
|
|||
body.dark #top .dropdown,
|
||||
body.dark #top a.goto_nav.current,
|
||||
body.dark #top a.goto_nav:hover,
|
||||
body.dark a#sound_state:hover {
|
||||
body.dark #sound_state:hover {
|
||||
color: #c0c0c0;
|
||||
}
|
||||
body.dark #site_title,
|
||||
|
|
Loading…
Reference in a new issue