- @video.title
- @video.author
- @video.targets.map(lila.video.Target.name).mkString(", ")
+ @vv.video.title
+ @vv.video.author
+ @vv.video.targets.map(lila.video.Target.name).mkString(", ")
- @video.tags.map { tag =>
+ @vv.video.tags.map { tag =>
@tag.capitalize
}
diff --git a/app/views/video/index.scala.html b/app/views/video/index.scala.html
index 39aad7a4fb..f957b1ddf7 100644
--- a/app/views/video/index.scala.html
+++ b/app/views/video/index.scala.html
@@ -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",
diff --git a/app/views/video/search.scala.html b/app/views/video/search.scala.html
index e92613f8bd..0bbc2b78ca 100644
--- a/app/views/video/search.scala.html
+++ b/app/views/video/search.scala.html
@@ -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",
diff --git a/app/views/video/show.scala.html b/app/views/video/show.scala.html
index 55cf395b79..b4290163c9 100644
--- a/app/views/video/show.scala.html
+++ b/app/views/video/show.scala.html
@@ -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) {
}
- @similar.map { video =>
- @card(video, control)
+ @similar.map { vv =>
+ @card(vv, control)
}
diff --git a/modules/video/src/main/VideoApi.scala b/modules/video/src/main/VideoApi.scala
index 512a5e59ce..6cf1f68c09 100644
--- a/modules/video/src/main/VideoApi.scala
+++ b/modules/video/src/main/VideoApi.scala
@@ -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 {
diff --git a/modules/video/src/main/View.scala b/modules/video/src/main/View.scala
index 59efe8aef4..0c2bd6f305 100644
--- a/modules/video/src/main/View.scala
+++ b/modules/video/src/main/View.scala
@@ -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"
diff --git a/public/stylesheets/video.css b/public/stylesheets/video.css
index 39f05a2bf1..da0aa5c7b7 100644
--- a/public/stylesheets/video.css
+++ b/public/stylesheets/video.css
@@ -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;