view_video.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. {% extends 'base.html' %}
  2. {% load humanize %}
  3. {% load static %}
  4. {% block content %}
  5. <script src="{% static 'htmx/extensions/class-tools.js' %}" type="application/javascript"></script>
  6. <div id="view_video">
  7. {% if playlist.has_playlist_changed %}
  8. {% else %}
  9. <div class="card text-white bg-dark" style="max-width: 100%;">
  10. <div class="row g-0">
  11. <div class="col-md-4 p-3">
  12. <img class="img-fluid rounded-3" src="{{ video.thumbnail_url }}" style="max-width:100%; height: auto; object-fit: cover;">
  13. </div>
  14. <div class="col-md-8">
  15. <div class="card-body">
  16. <div class="row d-flex justify-content-between">
  17. <h2 class="card-title text-white col-10">
  18. <a href="https://www.youtube.com/watch?v={{ video.video_id }}" target="_blank" style="color: white; text-decoration: none">{{ video.name }}</a>
  19. <br><small class="h4">{% if video.user_label %}a.k.a <span style="border-bottom: 3px #ffffff dashed;"> {{ video.user_label }}</span>{% endif %}</small>
  20. </h2>
  21. <h4 class="col d-flex justify-content-end">
  22. <span id="notice-div">
  23. </span>
  24. <span id="">
  25. <input class="form-control me-1 visually-hidden" id="video-{{ video.video_id }}" value="https://www.youtube.com/watch?v={{ video.video_id }}">
  26. <button class="copy-btn btn btn-success me-1" data-clipboard-target="#video-{{ video.video_id }}">
  27. <i class="far fa-copy" aria-hidden="true"></i>
  28. </button>
  29. <button class="btn btn-dark" type="button" hx-get="{% url 'mark_video_favorite' video.video_id %}" hx-target="#video-fav">
  30. <div id="video-fav">
  31. {% if video.is_favorite %}
  32. <i class="fas fa-heart" style="color: #fafa06"></i>
  33. {% else %}
  34. <i class="far fa-heart"></i>
  35. {% endif %}
  36. </div>
  37. </button>
  38. </span>
  39. </h4>
  40. </div>
  41. <h6>by {{ video.channel_name }}</h6>
  42. <p class="card-text">
  43. {% if video.description %}
  44. <h5 class="overflow-auto" style="max-height: 350px;">
  45. {{ video.description|linebreaksbr|urlize }}
  46. </h5>
  47. {% else %}
  48. <h5>No description</h5>
  49. {% endif %}
  50. </p>
  51. <h6 class="h5 text-uppercase overflow-auto text-black-50">
  52. <a style="text-decoration: none" data-bs-toggle="collapse" href="#{{ video.video_id }}DurationCollapse" role="button" aria-expanded="false" aria-controls="{{ video.video_id }}DurationCollapse">
  53. <span class="badge bg-success mb-1">{{ video.duration }}</span>
  54. </a>
  55. <div class="collapse" id="{{ video.video_id }}DurationCollapse">
  56. <div class="card card-body bg-dark text-white text-capitalize border border-3 mt-2 mb-2 border-light">
  57. <div hx-get="{% url 'video_completion_times' video.video_id %}"
  58. hx-trigger="revealed"
  59. hx-swap="outerHTML">
  60. </div>
  61. </div>
  62. </div>
  63. <small>
  64. {% if video.has_cc %}<span class="badge bg-danger mb-1">CC</span>{% endif %}
  65. {% if video.published_at %}<span class="badge bg-secondary mb-1">Video uploaded on {{ video.published_at }}</span>{% endif %}
  66. <span class="badge bg-primary text-white mb-1"><i class="fas fa-eye"></i> {% if video.view_count == -1 %}HIDDEN{% else %}{{ video.view_count|intcomma }}{% endif %}</span>
  67. <span class="badge bg-warning text-black-50 mb-1"><i class="fas fa-thumbs-up"></i> {% if video.like_count == -1 %}HIDDEN{% else %}{{ video.like_count|intcomma }}{% endif %}</span>
  68. <span class="badge bg-warning text-black-50 mb-1"><i class="fas fa-thumbs-down"></i> {% if video.dislike_count == -1 %}HIDDEN{% else %}{{ video.dislike_count|intcomma }}{% endif %}</span>
  69. <span class="badge bg-info text-black-50 mb-1"><i class="fas fa-comments"></i> {% if video.comment_count == -1 %}HIDDEN{% else %}{{ video.comment_count|intcomma }}{% endif %} </span>
  70. {% if video.is_unavailable_on_yt or video.was_deleted_on_yt %}<span class="badge bg-light text-black-50 mb-1">UNAVAILABLE</span>{% endif %}
  71. <span class="badge bg-light text-black-50 mb-1"><a href="#found-in" style="text-decoration: none; color: grey"> Found in {{ video.playlists.all.count }} playlist{% if video.playlists.all.count > 1 %}s{% endif %}</a></span>
  72. {% if video.is_marked_as_watched %}
  73. <span class="badge bg-dark text-white" >
  74. <i class="fas fa-flag-checkered me-1"></i> marked watched
  75. </span>
  76. {% endif %}
  77. </small>
  78. </h6>
  79. <p class="card-text text-white-50"><small>Last updated {{ video.video_details_modified_at|naturalday }}</small> &bullet; <small>{{ video.num_of_accesses }} clicks </small></p> </div>
  80. </div>
  81. </div>
  82. </div>
  83. <br>
  84. {% endif %}
  85. </div>
  86. <div class="row">
  87. <div class="col-6">
  88. <iframe id="ytplayer" width="100%" height="100%" src="//www.youtube.com/embed/{{ video.video_id }}?enablejsapi=1" frameborder="0" style="border: solid 5px #37474F" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
  89. </div>
  90. <div class="col-6">
  91. <div class="row">
  92. <div class="col-6">
  93. <h4>Your notes for this video
  94. </h4>
  95. </div>
  96. <div class="col d-flex justify-content-end pt-2">
  97. <span id="notes-save-status" class="text-success">
  98. </span>
  99. </div>
  100. </div>
  101. <div >
  102. <textarea name="video-notes-text-area"
  103. hx-post="{% url 'video_notes' video.video_id %}"
  104. hx-trigger="keyup changed delay:1.5s"
  105. hx-target="#notes-save-status"
  106. class="form-control"
  107. id="video-notes-text-area"
  108. placeholder="Enter here"
  109. rows="13">
  110. {{ video.user_notes }}
  111. </textarea>
  112. <div>
  113. </div>
  114. </div>
  115. </div>
  116. </div>
  117. <br>
  118. <div class="">
  119. <h3><span style="border-bottom: 3px #497ce2 dashed;">Video found in the following playlist{% if video.playlists.all.count > 1 %}s{% endif %}</span><i class="fas fa-binoculars ms-2" style="color: #4669d2"></i></h3>
  120. <div id="found-in" class="row row-cols-1 row-cols-md-4 g-4 text-dark mt-0" data-masonry='{"percentPosition": true }'>
  121. {% for playlist in video.playlists.all %}
  122. <div class="col">
  123. <div class="card" style="background-color: #EFEFEF;">
  124. <img class="bd-placeholder-img card-img-top" src="{{ playlist.thumbnail_url }}" style="max-width:100%; height: 200px; object-fit: cover;" alt="{{ playlist.name }} thumbnail">
  125. <div class="card-body">
  126. <h5 class="card-title"><a href="{% url 'playlist' playlist.playlist_id %}" class="stretched-link" style="text-decoration: none; color: black">{{ playlist.name }}</a></h5>
  127. <p class="card-text">
  128. <span class="badge bg-{% if playlist.get_watch_time_left == "0secs." %}success{% else %}primary{% endif %} text-white">{{ playlist.get_watched_videos_count }}/{{ playlist.get_watchable_videos_count }} viewed</span>
  129. {% if playlist.get_watch_time_left != "0secs." %}<span class="badge bg-dark text-white">{{ playlist.get_watch_time_left }} left</span>{% endif %}
  130. </p>
  131. <p class="card-text">
  132. {% if playlist.tags.all %}
  133. <small>
  134. <i class="fas fa-tags fa-sm" style="color: black"></i>
  135. {% for tag in playlist.tags.all %}
  136. <span class="badge rounded-pill bg-primary mb-lg-1">
  137. {{ tag.name }}
  138. </span>
  139. {% endfor %}
  140. </small>
  141. {% endif %}
  142. </p>
  143. <p class="card-text"><small class="text-muted">Last watched {{ playlist.last_watched|naturalday }}</small></p>
  144. </div>
  145. </div>
  146. </div>
  147. {% endfor %}
  148. </div>
  149. </div>
  150. <script type="text/javascript">
  151. // from https://developers.google.com/youtube/iframe_api_reference#Examples
  152. var tag = document.createElement('script');
  153. tag.id = 'iframe-demo';
  154. tag.src = 'https://www.youtube.com/iframe_api';
  155. var firstScriptTag = document.getElementsByTagName('script')[0];
  156. firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  157. var player;
  158. function onYouTubeIframeAPIReady() {
  159. player = new YT.Player('ytplayer', {
  160. events: {
  161. 'onReady': onPlayerReady,
  162. 'onStateChange': onPlayerStateChange
  163. }
  164. });
  165. }
  166. function onPlayerReady(event) {
  167. document.getElementById('ytplayer').style.borderColor = '#FF6D00';
  168. }
  169. function changeBorderColor(playerStatus) {
  170. var color;
  171. if (playerStatus === -1) {
  172. color = "#37474F"; // unstarted = gray
  173. } else if (playerStatus === 0) {
  174. color = "#FFFF00"; // ended = yellow
  175. } else if (playerStatus === 1) {
  176. color = "#33691E"; // playing = green
  177. } else if (playerStatus === 2) {
  178. color = "#DD2C00"; // paused = red
  179. // console.log(player.playerInfo.currentTime + " secs elapsed!");
  180. } else if (playerStatus === 3) {
  181. color = "#AA00FF"; // buffering = purple
  182. } else if (playerStatus === 5) {
  183. color = "#FF6DOO"; // video cued = orange
  184. }
  185. if (color) {
  186. document.getElementById('ytplayer').style.borderColor = color;
  187. }
  188. }
  189. function onPlayerStateChange(event) {
  190. changeBorderColor(event.data);
  191. // can use the below info to create a stream room
  192. // player.playerInfo.currentTime returns player elapsed time
  193. // console.log(player)
  194. }
  195. </script>
  196. {% endblock %}