display viewed videos
This commit is contained in:
parent
a20c1ecadc
commit
e91060252e
|
@ -24,10 +24,10 @@ object Video extends LilaController {
|
|||
def index = Open { implicit ctx =>
|
||||
WithUserControl { control =>
|
||||
control.query match {
|
||||
case Some(query) => env.api.video.search(query, getInt("page") | 1) map { videos =>
|
||||
case Some(query) => env.api.video.search(ctx.me, query, getInt("page") | 1) map { videos =>
|
||||
Ok(html.video.search(videos, control))
|
||||
}
|
||||
case None => env.api.video.byTags(control.filter.tags, getInt("page") | 1) zip
|
||||
case None => env.api.video.byTags(ctx.me, control.filter.tags, getInt("page") | 1) zip
|
||||
env.api.video.count.apply map {
|
||||
case (videos, count) =>
|
||||
Ok(html.video.index(videos, count, control))
|
||||
|
@ -40,7 +40,7 @@ object Video extends LilaController {
|
|||
WithUserControl { control =>
|
||||
env.api.video.find(id) flatMap {
|
||||
case None => fuccess(NotFound(html.video.notFound(control)))
|
||||
case Some(video) => env.api.video.similar(video, 9) zip
|
||||
case Some(video) => env.api.video.similar(ctx.me, video, 9) zip
|
||||
ctx.userId.?? { userId =>
|
||||
env.api.view.add(View.make(videoId = video.id, userId = userId))
|
||||
} map {
|
||||
|
@ -53,7 +53,7 @@ object Video extends LilaController {
|
|||
|
||||
def author(author: String) = Open { implicit ctx =>
|
||||
WithUserControl { control =>
|
||||
env.api.video.byAuthor(author, getInt("page") | 1) map { videos =>
|
||||
env.api.video.byAuthor(ctx.me, author, getInt("page") | 1) map { videos =>
|
||||
Ok(html.video.author(author, videos, control))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(author: String, videos: Paginator[lila.video.Video], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
@(author: String, videos: Paginator[lila.video.VideoView], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
|
||||
@layout(
|
||||
title = s"$author • Free Chess Videos",
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
@(video: lila.video.Video, control: lila.video.UserControl)(implicit ctx: Context)
|
||||
@(vv: lila.video.VideoView, control: lila.video.UserControl)(implicit ctx: Context)
|
||||
|
||||
<a class="card paginated_element" href="@routes.Video.show(video.id)?@control.queryString">
|
||||
<span class="img" style="background-image: url(@video.thumbnail)"></span>
|
||||
<a class="card paginated_element" href="@routes.Video.show(vv.video.id)?@control.queryString">
|
||||
@if(ctx.isAuth) {
|
||||
<span class="view@if(vv.view){ yes}" data-icon="v"></span>
|
||||
}
|
||||
<span class="img" style="background-image: url(@vv.video.thumbnail)"></span>
|
||||
<span class="info">
|
||||
<span class="title">@video.title</span>
|
||||
<span class="title">@vv.video.title</span>
|
||||
</span>
|
||||
<span class="reveal">
|
||||
<span class="full-title">@video.title</span>
|
||||
<span class="author">@video.author</span>
|
||||
<span class="target">@video.targets.map(lila.video.Target.name).mkString(", ")</span>
|
||||
<span class="full-title">@vv.video.title</span>
|
||||
<span class="author">@vv.video.author</span>
|
||||
<span class="target">@vv.video.targets.map(lila.video.Target.name).mkString(", ")</span>
|
||||
<span class="tags">
|
||||
@video.tags.map { tag =>
|
||||
@vv.video.tags.map { tag =>
|
||||
<span data-icon="o">@tag.capitalize</span>
|
||||
}
|
||||
</span>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(videos: Paginator[lila.video.Video], count: Int, control: lila.video.UserControl)(implicit ctx: Context)
|
||||
@(videos: Paginator[lila.video.VideoView], count: Int, control: lila.video.UserControl)(implicit ctx: Context)
|
||||
|
||||
@layout(
|
||||
title = "Free Chess Videos",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(videos: Paginator[lila.video.Video], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
@(videos: Paginator[lila.video.VideoView], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
|
||||
@layout(
|
||||
title = s"${control.query.getOrElse("Search")} • Free Chess Videos",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(video: lila.video.Video, similar: List[lila.video.Video], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
@(video: lila.video.Video, similar: Seq[lila.video.VideoView], control: lila.video.UserControl)(implicit ctx: Context)
|
||||
|
||||
@layout(
|
||||
title = s"${video.title} • Free Chess Videos",
|
||||
|
@ -24,8 +24,8 @@ control = control) {
|
|||
}
|
||||
</div>
|
||||
<div class="similar list">
|
||||
@similar.map { video =>
|
||||
@card(video, control)
|
||||
@similar.map { vv =>
|
||||
@card(vv, control)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,6 +26,17 @@ private[video] final class VideoApi(
|
|||
private implicit val TagNbBSONHandler = Macros.handler[TagNb]
|
||||
import View.viewBSONHandler
|
||||
|
||||
private def videoViews(userOption: Option[User])(videos: Seq[Video]): Fu[Seq[VideoView]] = userOption match {
|
||||
case None => fuccess {
|
||||
videos map { VideoView(_, false) }
|
||||
}
|
||||
case Some(user) => view.seenVideoIds(user, videos) map { ids =>
|
||||
videos.map { v =>
|
||||
VideoView(v, ids contains v.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object video {
|
||||
|
||||
private val maxPerPage = 18
|
||||
|
@ -33,7 +44,7 @@ private[video] final class VideoApi(
|
|||
def find(id: Video.ID): Fu[Option[Video]] =
|
||||
videoColl.find(BSONDocument("_id" -> id)).one[Video]
|
||||
|
||||
def search(query: String, page: Int): Fu[Paginator[Video]] = {
|
||||
def search(user: Option[User], query: String, page: Int): Fu[Paginator[VideoView]] = {
|
||||
val q = query.split(' ').map { word => s""""$word"""" } mkString " "
|
||||
val textScore = BSONDocument("score" -> BSONDocument("$meta" -> "textScore"))
|
||||
Paginator(
|
||||
|
@ -44,7 +55,7 @@ private[video] final class VideoApi(
|
|||
),
|
||||
projection = textScore,
|
||||
sort = textScore
|
||||
),
|
||||
) mapFutureList videoViews(user),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage)
|
||||
}
|
||||
|
@ -75,18 +86,18 @@ private[video] final class VideoApi(
|
|||
doc flatMap (_.getAs[String]("_id"))
|
||||
}
|
||||
|
||||
def popular(page: Int): Fu[Paginator[Video]] = Paginator(
|
||||
def popular(user: Option[User], page: Int): Fu[Paginator[VideoView]] = Paginator(
|
||||
adapter = new BSONAdapter[Video](
|
||||
collection = videoColl,
|
||||
selector = BSONDocument(),
|
||||
projection = BSONDocument(),
|
||||
sort = BSONDocument("metadata.likes" -> -1)
|
||||
),
|
||||
) mapFutureList videoViews(user),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage)
|
||||
|
||||
def byTags(tags: List[Tag], page: Int): Fu[Paginator[Video]] =
|
||||
if (tags.isEmpty) popular(page)
|
||||
def byTags(user: Option[User], tags: List[Tag], page: Int): Fu[Paginator[VideoView]] =
|
||||
if (tags.isEmpty) popular(user, page)
|
||||
else Paginator(
|
||||
adapter = new BSONAdapter[Video](
|
||||
collection = videoColl,
|
||||
|
@ -95,11 +106,11 @@ private[video] final class VideoApi(
|
|||
),
|
||||
projection = BSONDocument(),
|
||||
sort = BSONDocument("metadata.likes" -> -1)
|
||||
),
|
||||
) mapFutureList videoViews(user),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage)
|
||||
|
||||
def byAuthor(author: String, page: Int): Fu[Paginator[Video]] =
|
||||
def byAuthor(user: Option[User], author: String, page: Int): Fu[Paginator[VideoView]] =
|
||||
Paginator(
|
||||
adapter = new BSONAdapter[Video](
|
||||
collection = videoColl,
|
||||
|
@ -108,11 +119,11 @@ private[video] final class VideoApi(
|
|||
),
|
||||
projection = BSONDocument(),
|
||||
sort = BSONDocument("metadata.likes" -> -1)
|
||||
),
|
||||
) mapFutureList videoViews(user),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage)
|
||||
|
||||
def similar(video: Video, max: Int): Fu[List[Video]] =
|
||||
def similar(user: Option[User], video: Video, max: Int): Fu[Seq[VideoView]] =
|
||||
videoColl.find(BSONDocument(
|
||||
"tags" -> BSONDocument("$in" -> video.tags),
|
||||
"_id" -> BSONDocument("$ne" -> video.id)
|
||||
|
@ -120,7 +131,7 @@ private[video] final class VideoApi(
|
|||
.cursor[Video]
|
||||
.collect[List]().map { videos =>
|
||||
videos.sortBy { v => -v.similarity(video) } take max
|
||||
}
|
||||
} flatMap videoViews(user)
|
||||
|
||||
object count {
|
||||
|
||||
|
@ -149,6 +160,18 @@ private[video] final class VideoApi(
|
|||
viewColl.db command Count(viewColl.name, BSONDocument(
|
||||
View.BSONFields.id -> View.makeId(video.id, user.id)
|
||||
).some) map (0!=)
|
||||
|
||||
def seenVideoIds(user: User, videos: Seq[Video]): Fu[Set[Video.ID]] =
|
||||
viewColl.find(
|
||||
BSONDocument(
|
||||
"_id" -> BSONDocument("$in" -> videos.map { v =>
|
||||
View.makeId(v.id, user.id)
|
||||
})
|
||||
),
|
||||
BSONDocument(View.BSONFields.videoId -> true, "_id" -> false)
|
||||
).cursor[BSONDocument].collect[List]() map { docs =>
|
||||
docs.flatMap(_.getAs[String](View.BSONFields.videoId)).toSet
|
||||
}
|
||||
}
|
||||
|
||||
object tag {
|
||||
|
|
|
@ -8,6 +8,8 @@ case class View(
|
|||
userId: String,
|
||||
date: DateTime)
|
||||
|
||||
case class VideoView(video: Video, view: Boolean)
|
||||
|
||||
object View {
|
||||
|
||||
def makeId(videoId: Video.ID, userId: String) = s"$videoId/$userId"
|
||||
|
|
|
@ -90,6 +90,16 @@
|
|||
transform: translateY(-100%);
|
||||
opacity: 1;
|
||||
}
|
||||
#video .card .view {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 8px;
|
||||
z-index: 2;
|
||||
opacity: 0.3;
|
||||
}
|
||||
#video .card .view.yes {
|
||||
opacity: 1;
|
||||
}
|
||||
#video .card .full-title {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
|
|
Loading…
Reference in a new issue