show video tag path

This commit is contained in:
Thibault Duplessis 2015-03-23 02:34:45 +01:00
parent 62b2b2b524
commit b2405aaafe
7 changed files with 48 additions and 19 deletions

View file

@ -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)

View file

@ -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>
} }

View file

@ -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])
}
}
} }
} }

View file

@ -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}")
} }
} }

View file

@ -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;
} }

View file

@ -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;