123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- {% extends 'base.html' %}
- {% load humanize %}
- {% load static %}
- {% block content %}
- <script src="{% static 'htmx/extensions/class-tools.js' %}" type="application/javascript"></script>
- <div id="view_video">
- {% if playlist.has_playlist_changed %}
- {% else %}
- <div class="alert alert-dark alert-dismissible fade show" role="alert" id="user-label-alert" style="display:none;">
- <form method="post" action="{% url 'add_video_user_label' video.video_id %}" class="d-flex justify-content-center">
- {% csrf_token %}
- <span class="mt-2 me-1">Enter an optional label to identify this video with:</span>
- <input class="form-control w-25 me-2" type="text" placeholder="Enter here" name="user_label" value="{{ video.user_label }}" aria-label="user label">
- <button type="submit" class="btn btn-primary">Save</button>
- </form>
- <button type="button" class="btn-close mt-2 me-2" onclick='document.getElementById("user-label-alert").style.display = "none";' aria-label="Close"></button>
- </div>
- <div class="card text-white bg-dark" style="max-width: 100%;">
- <div class="row g-0">
- {% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}
- <div class="col-md-4 p-3">
- <img class="img-fluid rounded-3" src="{{ video.thumbnail_url }}" style="max-width:100%; height: auto; object-fit: cover;">
- <span class="d-flex justify-content-center">
- <a type="submit" onclick="window.open('{{ video.thumbnail_url }}')" class="btn btn-primary mt-3"><i class="fas fa-image fa-lg"></i></a>
- <a href="https://www.youtube.com/watch?v={{ video.video_id }}" class="btn btn-info ms-2 mt-3" target="_blank" id="share_link" style=""><i class="fas fa-external-link-alt" aria-hidden="true"></i></a>
- <input class="form-control me-1 visually-hidden" id="video-{{ video.video_id }}" value="https://www.youtube.com/watch?v={{ video.video_id }}">
- <button class="copy-btn btn btn-success ms-2 mt-3" data-clipboard-target="#video-{{ video.video_id }}">
- <i class="far fa-copy" aria-hidden="true"></i>
- </button>
- <button class="btn btn-dark mt-3 ms-2" type="button" hx-get="{% url 'mark_video_favorite' video.video_id %}" hx-target="#video-fav">
- <div id="video-fav">
- {% if video.is_favorite %}
- <i class="fas fa-heart" style="color: #fafa06"></i>
- {% else %}
- <i class="far fa-heart"></i>
- {% endif %}
- </div>
- </button>
- <button title="Mark or unmark video as plan to watch!" class="btn btn-warning mt-3 ms-2" type="button" hx-get="{% url 'mark_video_planned_to_watch' video.video_id %}" hx-target="#video-{{ forloop.counter }}-planned">
- <div id="video-{{ forloop.counter }}-planned">
- {% if video.is_planned_to_watch %}
- <i class="fas fa-clock" style="color: #000000"></i>
- {% else %}
- <i class="far fa-clock"></i>
- {% endif %}
- </div>
- </button>
- </span>
- </div>
- {% endif %}
- <div class="col{% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}-md-8{% endif %}">
- <div class="card-body">
- <div class="row d-flex justify-content-between">
- <h2 class="card-title text-white col-10">
- <a href="https://www.youtube.com/watch?v={{ video.video_id }}" target="_blank" style="color: white; text-decoration: none">{{ video.name }}</a>
- <button class="btn btn-light btn-sm ms-2" onclick='document.getElementById("user-label-alert").style.display = "block";'>
- <i class="fas fa-pencil-alt" aria-hidden="true"></i>
- </button>
- {% if video.is_unavailable_on_yt or video.was_deleted_on_yt %}
- <button class="btn btn-dark" type="button" hx-get="{% url 'mark_video_favorite' video.video_id %}" hx-target="#video-fav">
- <div id="video-fav">
- {% if video.is_favorite %}
- <i class="fas fa-heart" style="color: #fafa06"></i>
- {% else %}
- <i class="far fa-heart"></i>
- {% endif %}
- </div>
- </button>
- <button title="Mark or unmark video as plan to watch!" class="btn btn-warning" type="button" hx-get="{% url 'mark_video_planned_to_watch' video.video_id %}" hx-target="#video-{{ forloop.counter }}-planned">
- <div id="video-{{ forloop.counter }}-planned">
- {% if video.is_planned_to_watch %}
- <i class="fas fa-clock" style="color: #000000"></i>
- {% else %}
- <i class="far fa-clock"></i>
- {% endif %}
- </div>
- </button>
- {% endif %}
- <br><small class="h4">{% if video.user_label %}a.k.a <span style="border-bottom: 3px #ffffff dashed;"> {{ video.user_label }}</span>{% endif %}</small>
- </h2>
- </div>
- {% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}
- <h6>by <a href="{% url 'search' %}?mode=videos&channel={{ video.channel_name }}" style="text-decoration: none; color: white"><span style="border-bottom: 3px #e35959 dashed;">{{ video.channel_name }}</span></a></h6>
- <p class="card-text">
- {% if video.description %}
- <h5 class="overflow-auto" style="max-height: 350px;">
- {{ video.description|linebreaksbr|urlize }}
- </h5>
- {% else %}
- <h5>No description</h5>
- {% endif %}
- </p>
- {% endif %}
- <h6 class="h5 text-uppercase overflow-auto text-black-50">
- {% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}
- <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">
- <span class="badge bg-success mb-1">{{ video.duration }}</span>
- </a>
- <div class="collapse" id="{{ video.video_id }}DurationCollapse">
- <div class="card card-body bg-dark text-white text-capitalize border border-3 mt-2 mb-2 border-light">
- <div hx-get="{% url 'video_completion_times' video.video_id %}"
- hx-trigger="revealed"
- hx-swap="outerHTML">
- </div>
- </div>
- </div>
- {% endif %}
- <small>
- {% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}
- {% if video.has_cc %}<span class="badge bg-danger mb-1">CC</span>{% endif %}
- {% if video.published_at %}<span class="badge bg-secondary mb-1">Video uploaded on {{ video.published_at }}</span>{% endif %}
- <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>
- <span class="badge bg-warning text-black-50 mb-1"><i class="fas fa-thumbs-up" {% if video.liked %}style="color: dodgerblue"{% endif %}></i> {% if video.like_count == -1 %}HIDDEN{% else %}{{ video.like_count|intcomma }}{% endif %}</span>
- <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>
- <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>
- {% endif %}
- {% if video.is_unavailable_on_yt or video.was_deleted_on_yt %}<span class="badge bg-danger text-light mb-1">VIDEO WENT UNAVAILABLE ON YT</span>{% endif %}
- <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 or video.playlists.all.count == 0 %}s{% endif %}</a></span>
- {% if video.is_marked_as_watched %}
- <span class="badge bg-dark text-white" >
- <i class="fas fa-flag-checkered me-1"></i> marked watched
- </span>
- {% endif %}
- </small>
- </h6>
- <p class="card-text text-white-50"><small>Last updated {{ video.video_details_modified_at|naturalday }}</small> • <small>{{ video.num_of_accesses }} views </small></p> </div>
- </div>
- </div>
- </div>
- <br>
- {% endif %}
- </div>
- <div class="row">
- <div class="col-6">
- <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>
- </div>
- <div class="col-6">
- <div class="row">
- <div class="col-6">
- <h4>Your notes for this video
- </h4>
- </div>
- <div class="col d-flex justify-content-end pt-2">
- <span id="notes-save-status" class="text-success">
- </span>
- </div>
- </div>
- <div >
- <textarea name="video-notes-text-area"
- hx-post="{% url 'video_notes' video.video_id %}"
- hx-trigger="keyup changed delay:0.7s"
- hx-target="#notes-save-status"
- class="form-control"
- placeholder="Enter here. Automatically saved after every 1s of typing!"
- rows="13">{{ video.user_notes }}</textarea>
- <div>
- </div>
- </div>
- </div>
- </div>
- <br>
- {% if video.playlists.all.count != 0 %}
- <div class="">
- <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>
- <div id="found-in" class="row row-cols-1 row-cols-md-4 g-4 text-dark mt-0" data-masonry='{"percentPosition": true }'>
- {% include 'intercooler/playlists.html' with playlists=video.playlists.all watching=False bg_color="#357779" show_controls=True %}
- </div>
- </div>
- {% endif %}
- <script type="text/javascript">
- // from https://developers.google.com/youtube/iframe_api_reference#Examples
- var tag = document.createElement('script');
- tag.id = 'iframe-demo';
- tag.src = 'https://www.youtube.com/iframe_api';
- var firstScriptTag = document.getElementsByTagName('script')[0];
- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
- var player;
- function onYouTubeIframeAPIReady() {
- player = new YT.Player('ytplayer', {
- events: {
- 'onReady': onPlayerReady,
- 'onStateChange': onPlayerStateChange
- }
- });
- }
- function onPlayerReady(event) {
- document.getElementById('ytplayer').style.borderColor = '#FF6D00';
- }
- function changeBorderColor(playerStatus) {
- var color;
- if (playerStatus === -1) {
- color = "#37474F"; // unstarted = gray
- } else if (playerStatus === 0) {
- color = "#FFFF00"; // ended = yellow
- } else if (playerStatus === 1) {
- color = "#33691E"; // playing = green
- } else if (playerStatus === 2) {
- color = "#DD2C00"; // paused = red
- // console.log(player.playerInfo.currentTime + " secs elapsed!");
- } else if (playerStatus === 3) {
- color = "#AA00FF"; // buffering = purple
- } else if (playerStatus === 5) {
- color = "#FF6DOO"; // video cued = orange
- }
- if (color) {
- document.getElementById('ytplayer').style.borderColor = color;
- }
- }
- function onPlayerStateChange(event) {
- changeBorderColor(event.data);
- // can use the below info to create a stream room
- // player.playerInfo.currentTime returns player elapsed time
- // console.log(player)
- }
- </script>
- {% endblock %}
|