show video tag path
This commit is contained in:
parent
62b2b2b524
commit
b2405aaafe
|
@ -16,7 +16,7 @@ object Video extends LilaController {
|
||||||
|
|
||||||
private def WithUserControl[A](f: UserControl => Fu[A])(implicit ctx: Context): Fu[A] = {
|
private def WithUserControl[A](f: UserControl => Fu[A])(implicit ctx: Context): Fu[A] = {
|
||||||
val reqTags = get("tags") ?? (_.split(',').toList.map(_.trim.toLowerCase))
|
val reqTags = get("tags") ?? (_.split(',').toList.map(_.trim.toLowerCase))
|
||||||
env.api.tag.popularAnd(25, reqTags) map { tags =>
|
env.api.tag.pathsAnd(25, reqTags) map { tags =>
|
||||||
UserControl(
|
UserControl(
|
||||||
filter = Filter(reqTags),
|
filter = Filter(reqTags),
|
||||||
tags = tags)
|
tags = tags)
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
<div id="video_side">
|
<div id="video_side">
|
||||||
<div class="tag_list">
|
<div class="tag_list">
|
||||||
@control.tags.map { t =>
|
@control.tags.map { t =>
|
||||||
<a class="@if(control.filter.tags contains t.tag) {checked}"
|
@defining(control.filter.tags contains t.tag) { checked =>
|
||||||
|
<a class="@if(checked) {checked} @if(checked || t.nb > 0) {full} else {empty}"
|
||||||
href="@routes.Video.index?@control.filter.toggle(t.tag).queryString">
|
href="@routes.Video.index?@control.filter.toggle(t.tag).queryString">
|
||||||
<em>@t.nb</em>
|
@if(t.nb > 0) {<em>@t.nb</em>}
|
||||||
@t.tag.capitalize
|
@t.tag.capitalize
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,21 +133,27 @@ private[video] final class VideoApi(
|
||||||
|
|
||||||
object tag {
|
object tag {
|
||||||
|
|
||||||
private val cache: Cache[List[TagNb]] = LruCache(timeToLive = 1.day)
|
private val nbCache: Cache[List[TagNb]] = LruCache(timeToLive = 1.day)
|
||||||
|
|
||||||
def clearCache = fuccess(cache.clear)
|
def clearCache = fuccess {
|
||||||
|
nbCache.clear
|
||||||
def popularAnd(max: Int, forced: List[Tag]): Fu[List[TagNb]] = popular map { all =>
|
|
||||||
val tags = all take max
|
|
||||||
val missing = forced filterNot { t =>
|
|
||||||
tags exists (_.tag == t)
|
|
||||||
}
|
|
||||||
tags.take(max - missing.size) ::: missing.flatMap { t =>
|
|
||||||
all find (_.tag == t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def popular: Fu[List[TagNb]] = cache(true) {
|
def pathsAnd(max: Int, forced: List[Tag]): Fu[List[TagNb]] =
|
||||||
|
popular zip paths(forced) map {
|
||||||
|
case (all, paths) =>
|
||||||
|
val tags = all take max map { t =>
|
||||||
|
paths find (_._id == t._id) getOrElse TagNb(t._id, 0)
|
||||||
|
}
|
||||||
|
val missing = forced filterNot { t =>
|
||||||
|
tags exists (_.tag == t)
|
||||||
|
}
|
||||||
|
tags.take(max - missing.size) ::: missing.flatMap { t =>
|
||||||
|
all find (_.tag == t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def popular: Fu[List[TagNb]] = nbCache("") {
|
||||||
import reactivemongo.core.commands._
|
import reactivemongo.core.commands._
|
||||||
val command = Aggregate(videoColl.name, Seq(
|
val command = Aggregate(videoColl.name, Seq(
|
||||||
Project("tags" -> BSONBoolean(true)),
|
Project("tags" -> BSONBoolean(true)),
|
||||||
|
@ -159,5 +165,22 @@ private[video] final class VideoApi(
|
||||||
_.toList.flatMap(_.asOpt[TagNb])
|
_.toList.flatMap(_.asOpt[TagNb])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def paths(tags: List[Tag]): Fu[List[TagNb]] =
|
||||||
|
if (tags.isEmpty) popular
|
||||||
|
else nbCache(tags.sorted.mkString(",")) {
|
||||||
|
import reactivemongo.core.commands._
|
||||||
|
val command = Aggregate(videoColl.name, Seq(
|
||||||
|
Match(BSONDocument("tags" -> BSONDocument("$all" -> tags))),
|
||||||
|
Project("tags" -> BSONBoolean(true)),
|
||||||
|
Unwind("tags"),
|
||||||
|
// Match(BSONDocument("tags" -> BSONDocument("$nin" -> tags))),
|
||||||
|
GroupField("tags")("nb" -> SumValue(1)),
|
||||||
|
Sort(Seq(Descending("nb")))
|
||||||
|
))
|
||||||
|
videoColl.db.command(command) map {
|
||||||
|
_.toList.flatMap(_.asOpt[TagNb])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ private[video] final class Youtube(
|
||||||
case JsSuccess(entries, _) => fuccess(entries.toList)
|
case JsSuccess(entries, _) => fuccess(entries.toList)
|
||||||
}
|
}
|
||||||
case res =>
|
case res =>
|
||||||
println(res.body)
|
println(s"key: $apiKey")
|
||||||
fufail(s"[video youtube] fetch ${res.status}")
|
fufail(s"[video youtube] fetch ${res.status}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ body.dark div.chat_menu > a.active {
|
||||||
body.dark .crosstable td {
|
body.dark .crosstable td {
|
||||||
border-color: #1a1a1a;
|
border-color: #1a1a1a;
|
||||||
}
|
}
|
||||||
body.dark #video_side .tag_list a:hover {
|
body.dark #video_side .tag_list a.full:hover {
|
||||||
background: #222;
|
background: #222;
|
||||||
border-color: #444;
|
border-color: #444;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,20 +129,24 @@
|
||||||
border-left: 2px solid transparent;
|
border-left: 2px solid transparent;
|
||||||
transition: 0.13s;
|
transition: 0.13s;
|
||||||
}
|
}
|
||||||
#video_side .tag_list a:hover {
|
#video_side .tag_list a.full:hover {
|
||||||
background: #f8f8f8;
|
background: #f8f8f8;
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
}
|
}
|
||||||
#video_side .tag_list em {
|
#video_side .tag_list em {
|
||||||
float: right;
|
float: right;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
opacity: 0.5;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
#video_side .tag_list a.checked {
|
#video_side .tag_list a.checked {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-color: #d85000!important;
|
border-color: #d85000!important;
|
||||||
}
|
}
|
||||||
|
#video_side .tag_list a.empty {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
#video .not_found {
|
#video .not_found {
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
|
|
Loading…
Reference in a new issue