Browse Source

fixed some ui stuff and added more ui stuff

sleepytaco 3 years ago
parent
commit
e441fcc75d

+ 91 - 3
apps/main/models.py

@@ -1070,6 +1070,12 @@ class PlaylistManager(models.Manager):
         playlist_items = user.playlists.get(playlist_id=from_playlist_id).playlist_items.select_related('video').filter(
         playlist_items = user.playlists.get(playlist_id=from_playlist_id).playlist_items.select_related('video').filter(
             playlist_item_id__in=playlist_item_ids)
             playlist_item_id__in=playlist_item_ids)
 
 
+        result = {
+            "status": 0,
+            "num_moved_copied": 0,
+            "playlistContainsMaximumNumberOfVideos": False,
+        }
+
         with build('youtube', 'v3', credentials=credentials) as youtube:
         with build('youtube', 'v3', credentials=credentials) as youtube:
             for playlist_id in to_playlist_ids:
             for playlist_id in to_playlist_ids:
                 for playlist_item in playlist_items:
                 for playlist_item in playlist_items:
@@ -1097,14 +1103,96 @@ class PlaylistManager(models.Manager):
                         # errors i ran into:
                         # errors i ran into:
                         # runs into HttpError 400 "Invalid playlist snippet." when the description contains <, >
                         # runs into HttpError 400 "Invalid playlist snippet." when the description contains <, >
                         print("ERROR UPDATING PLAYLIST DETAILS", e.status_code, e.error_details)
                         print("ERROR UPDATING PLAYLIST DETAILS", e.status_code, e.error_details)
-                        return [-1, e.status_code]
+                        if e.status_code == 400:
+                            pl_request = youtube.playlistItems().insert(
+                                part="snippet",
+                                body={
+                                    "snippet": {
+                                        "playlistId": playlist_id,
+                                        "resourceId": {
+                                            "kind": "youtube#video",
+                                            "videoId": playlist_item.video.video_id,
+                                        }
+                                    },
+                                }
+                            )
 
 
-                    print(pl_response)
+                            try:
+                                pl_response = pl_request.execute()
+                            except googleapiclient.errors.HttpError as e:
+                                result['status'] = -1
+                        elif e.status_code == 403:
+                            result["playlistContainsMaximumNumberOfVideos"] = True
+                        else:
+                            result['status'] = -1
+                    result["num_moved_copied"] += 1
 
 
         if action == "move":  # delete from the current playlist
         if action == "move":  # delete from the current playlist
             self.deletePlaylistItems(user, from_playlist_id, playlist_item_ids)
             self.deletePlaylistItems(user, from_playlist_id, playlist_item_ids)
 
 
-        return [0]
+        return result
+
+    def addVideosToPlaylist(self, user, playlist_id, video_ids):
+        """
+        Takes in playlist itemids for the videos in a particular playlist
+        """
+        credentials = self.getCredentials(user)
+
+        playlist = user.playlists.get(playlist_id=playlist_id)
+
+        result = {
+            "num_added": 0,
+            "playlistContainsMaximumNumberOfVideos": False,
+        }
+
+        added = 0
+        with build('youtube', 'v3', credentials=credentials) as youtube:
+
+            for video_id in video_ids:
+                pl_request = youtube.playlistItems().insert(
+                    part="snippet",
+                    body={
+                        "snippet": {
+                            "playlistId": playlist_id,
+                            "position": 0,
+                            "resourceId": {
+                                "kind": "youtube#video",
+                                "videoId": video_id,
+                            }
+                        },
+                    }
+                )
+
+                try:
+                    pl_response = pl_request.execute()
+                except googleapiclient.errors.HttpError as e:  # failed to update add video to playlis
+                    print("ERROR ADDDING VIDEOS TO PLAYLIST", e.status_code, e.error_details)
+                    if e.status_code == 400: # manualSortRequired - see errors https://developers.google.com/youtube/v3/docs/playlistItems/insert
+                        pl_request = youtube.playlistItems().insert(
+                            part="snippet",
+                            body={
+                                "snippet": {
+                                    "playlistId": playlist_id,
+                                    "resourceId": {
+                                        "kind": "youtube#video",
+                                        "videoId": video_id,
+                                    }
+                                },
+                            }
+                        )
+                        try:
+                            pl_response = pl_request.execute()
+                        except googleapiclient.errors.HttpError as e:  # failed to update playlist details
+                            pass
+                    elif e.status_code == 403:
+                        result["playlistContainsMaximumNumberOfVideos"] = True
+                    continue
+                added += 1
+        result["num_added"] = added
+        if added > 0:
+            playlist.has_playlist_changed = True
+            playlist.save(update_fields=['has_playlist_changed'])
+        return result
 
 
 
 
 class Tag(models.Model):
 class Tag(models.Model):

+ 5 - 3
apps/main/templates/all_playlists.html

@@ -6,6 +6,7 @@
         <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 mb-3">
         <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 mb-3">
             <h1 class="h2"><span style="border-bottom: 3px #e24949 dashed;">{{ library_type_display|title }}</span> <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
             <h1 class="h2"><span style="border-bottom: 3px #e24949 dashed;">{{ library_type_display|title }}</span> <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
 
 
+
             {% if playlists %}
             {% if playlists %}
             <div class="btn-toolbar mb-2 mb-md-0">
             <div class="btn-toolbar mb-2 mb-md-0">
                 <!--
                 <!--
@@ -13,7 +14,6 @@
                     <button type="button" class="btn btn-outline-info">Grid</button>
                     <button type="button" class="btn btn-outline-info">Grid</button>
                     <button type="button" class="btn btn-outline-info">List</button>
                     <button type="button" class="btn btn-outline-info">List</button>
                 </div>
                 </div>
-                -->
                 <div class="btn-group">
                 <div class="btn-group">
                   <button type="button" class="btn btn-success dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
                   <button type="button" class="btn btn-success dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
                     Sort By
                     Sort By
@@ -24,7 +24,7 @@
                     <li class="dropdown-item"><a hx-get="{% url 'order_playlists_by' library_type 'recently-accessed' %}" hx-trigger="click" hx-target="#search-results">Recently Accessed</a></li>
                     <li class="dropdown-item"><a hx-get="{% url 'order_playlists_by' library_type 'recently-accessed' %}" hx-trigger="click" hx-target="#search-results">Recently Accessed</a></li>
                   </ul>
                   </ul>
                 </div>
                 </div>
-
+                -->
             </div>
             </div>
             {% endif %}
             {% endif %}
 
 
@@ -38,7 +38,7 @@
                    hx-target="#search-results"
                    hx-target="#search-results"
                    hx-indicator=".htmx-indicator"
                    hx-indicator=".htmx-indicator"
                     aria-describedby="searchHelp">
                     aria-describedby="searchHelp">
-            <div id="searchHelp" class="form-text">For a more extensive playlist search, <a href="{% url 'search' %}?mode=playlists&type={{ library_type }}">click here</a>.</div>
+            <div id="searchHelp" class="form-text">For a more extensive playlist search and filtering, <a href="{% url 'search' %}?mode=playlists&type={{ library_type }}">click here</a>.</div>
 
 
             <br>
             <br>
 
 
@@ -62,6 +62,8 @@
                         You can mark a playlist as plan to watch by heading over to the playlist and marking it from the dropdown.
                         You can mark a playlist as plan to watch by heading over to the playlist and marking it from the dropdown.
                     {% elif library_type == "favorites" %}
                     {% elif library_type == "favorites" %}
                         You can mark a playlist as favorite by heading over to the playlist page and pressing the star icon.
                         You can mark a playlist as favorite by heading over to the playlist page and pressing the star icon.
+                    {% elif library_type == "yt-mix" %}
+                        No YouTube mixes imported. Head over to Manage to import the ones you like.
                     {% elif library_type == "user-owned" %}
                     {% elif library_type == "user-owned" %}
                         {% if user.profile.imported_yt_playlists %}
                         {% if user.profile.imported_yt_playlists %}
                             Looks like you have no playlists on YouTube.
                             Looks like you have no playlists on YouTube.

+ 19 - 5
apps/main/templates/favorites.html

@@ -5,10 +5,17 @@
     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
         <h1 class="h2">Favorite Playlists
         <h1 class="h2">Favorite Playlists
             <span class="badge bg-primary rounded-pill">{{ playlists.count|default:"0" }}</span>
             <span class="badge bg-primary rounded-pill">{{ playlists.count|default:"0" }}</span>
-            {% if playlists %}
-                <a href="{% url 'search' %}?mode=playlists&type=favorites" style="text-decoration: none; color: black"><i class="fas fa-search"></i></a>
-            {% endif %}
+
         </h1>
         </h1>
+        {% if playlists %}
+                    <form method="get" action="{% url 'search' %}" >
+                    <input size="50" class="form-control border border-secondary" type="text"
+                   name="query" placeholder="Search your favorite playlists...">
+                    <input type="text" class="visually-hidden" name="mode" value="playlists">
+                    <input type="text" class="visually-hidden" name="type" value="favorites">
+                    <button type="submit" class="visually-hidden"></button>
+                    </form>
+            {% endif %}
     </div>
     </div>
 
 
     <div>
     <div>
@@ -27,10 +34,17 @@
     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
         <h1 class="h2">Favorite Videos
         <h1 class="h2">Favorite Videos
             <span class="badge bg-primary rounded-pill">{{ videos.count }}</span>
             <span class="badge bg-primary rounded-pill">{{ videos.count }}</span>
+
+        </h1>
             {% if videos %}
             {% if videos %}
-                <a href="{% url 'search' %}?mode=videos&type=favorite" style="text-decoration: none; color: black"><i class="fas fa-search"></i></a>
+                    <form method="get" action="{% url 'search' %}" >
+                    <input size="50" class="form-control border border-secondary" type="text"
+                   name="query" placeholder="Search your favorite videos...">
+                    <input type="text" class="visually-hidden" name="mode" value="videos">
+                    <input type="text" class="visually-hidden" name="type" value="favorite">
+                    <button type="submit" class="visually-hidden"></button>
+                    </form>
             {% endif %}
             {% endif %}
-        </h1>
     </div>
     </div>
 
 
     <div>
     <div>

+ 4 - 4
apps/main/templates/home.html

@@ -48,7 +48,7 @@
             <div class="col-6 mb-4">
             <div class="col-6 mb-4">
                 <div class="card bg-transparent text-dark">
                 <div class="card bg-transparent text-dark">
                     <div class="card-body">
                     <div class="card-body">
-                        <h6 class="d-flex align-items-center mb-3"><span class="text-warning me-2">{{ user.playlists.count }}</span>Playlists Statistics{% if user.playlists.count == 0 %}: You have no playlists in your UnTube!{% endif %}</h6>
+                        <h6 class="d-flex justify-content-center align-items-center mb-3">You have a total of <span class="text-warning ms-1 me-1">{{ user.playlists.count }}</span> Playlists in your UnTube collection</h6>
                         <div class="d-flex align-items-center mb-3">
                         <div class="d-flex align-items-center mb-3">
 
 
                             <canvas id="overall-playlists-distribution" data-url="{% url 'overall_playlists_distribution' %}">
                             <canvas id="overall-playlists-distribution" data-url="{% url 'overall_playlists_distribution' %}">
@@ -62,7 +62,7 @@
             <div class="col-6 mb-4">
             <div class="col-6 mb-4">
                 <div class="card bg-transparent text-dark">
                 <div class="card bg-transparent text-dark">
                     <div class="card-body">
                     <div class="card-body">
-                        <h6 class="d-flex align-items-center mb-3">A total of <span class="text-warning me-1 ms-1" id="num-channels">{{ channels.count|intword|intcomma }} channels</span> and <span class="text-warning ms-1 me-1" id="num-channels"> {{ videos.count|intword|intcomma }} videos</span> found in your UnTube collection </h6>
+                        <h6 class="d-flex justify-content-center align-items-center mb-3">A total of <span class="text-warning me-1 ms-1" id="num-channels">{{ channels.count|intword|intcomma }} channels</span> and <span class="text-warning ms-1 me-1" id="num-channels"> {{ videos.count|intword|intcomma }} videos</span> found in your UnTube collection </h6>
                         {% if channels.count > 100 %}<h6 class="d-flex justify-content-center">(Only top 100 channels shown below)</h6>{% endif %}
                         {% if channels.count > 100 %}<h6 class="d-flex justify-content-center">(Only top 100 channels shown below)</h6>{% endif %}
                         <div class="d-flex align-items-center mb-3">
                         <div class="d-flex align-items-center mb-3">
 
 
@@ -169,7 +169,7 @@
                 <div class="card bg-transparent text-dark">
                 <div class="card bg-transparent text-dark">
                     <div class="card-body">
                     <div class="card-body">
 
 
-                        <h6 class="d-flex align-items-center mb-3"><span class="text-warning me-2">{{ watching.count }}</span>
+                        <h6 class="d-flex justify-content-center align-items-center mb-3"><span class="text-warning me-2">{{ watching.count }}</span>
                             {% if watching.count > 0 %}
                             {% if watching.count > 0 %}
                                 Playlist{% if watching.count > 1 %}s{% endif %} Watching: Percent Complete Chart
                                 Playlist{% if watching.count > 1 %}s{% endif %} Watching: Percent Complete Chart
 
 
@@ -260,7 +260,7 @@
                     <div class="row flex-row g-3 flex-nowrap">
                     <div class="row flex-row g-3 flex-nowrap">
                         {% for playlist in watching %}
                         {% for playlist in watching %}
                             <div class="col">
                             <div class="col">
-                                <div class="card overflow-auto" style="background-color: #c2c68f; width: 275px; height: auto">
+                                <div class="card overflow-auto" style="background-color: #9363af; width: 275px; height: auto">
                                     <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">
                                     <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">
 
 
                                     <div class="card-body">
                                     <div class="card-body">

+ 2 - 2
apps/main/templates/intercooler/playlist_items.html

@@ -50,7 +50,7 @@
                             {{ playlist_item.video_position|add:"1" }}.
                             {{ playlist_item.video_position|add:"1" }}.
                             <a class="link-dark" href="{% url 'video' playlist_item.video.video_id %}">
                             <a class="link-dark" href="{% url 'video' playlist_item.video.video_id %}">
                                 {{ playlist_item.video.name|truncatewords:"16" }}
                                 {{ playlist_item.video.name|truncatewords:"16" }}
-                            </a> by {{ playlist_item.video.channel_name }} <br>
+                            </a> by <a href="{% url 'search' %}?mode=videos&channel={{ playlist_item.video.channel_name }}" style="text-decoration: none; color: black"><span style="border-bottom: 3px #e35959 dashed;"> {{ playlist_item.video.channel_name }}</span></a> <br>
                             <a style="text-decoration: none" hx-get="{% url 'video_completion_times' playlist_item.video.video_id %}" hx-trigger="click once" hx-target="#{{ playlist_item.playlist_item_id }}-completion-times" data-bs-toggle="collapse" href="#{{ playlist_item.playlist_item_id }}DurationCollapse" role="button" aria-expanded="false" aria-controls="{{ playlist_item.playlist_item_id }}DurationCollapse">
                             <a style="text-decoration: none" hx-get="{% url 'video_completion_times' playlist_item.video.video_id %}" hx-trigger="click once" hx-target="#{{ playlist_item.playlist_item_id }}-completion-times" data-bs-toggle="collapse" href="#{{ playlist_item.playlist_item_id }}DurationCollapse" role="button" aria-expanded="false" aria-controls="{{ playlist_item.playlist_item_id }}DurationCollapse">
                                     <span class="badge bg-secondary">{{ playlist_item.video.duration }}</span>
                                     <span class="badge bg-secondary">{{ playlist_item.video.duration }}</span>
                                 </a>
                                 </a>
@@ -63,7 +63,7 @@
                             </div>
                             </div>
 
 
                             {% if playlist_item.video.has_cc %}<span class="badge bg-secondary">CC</span>{% endif %}
                             {% if playlist_item.video.has_cc %}<span class="badge bg-secondary">CC</span>{% endif %}
-                            {% if playlist_item.video.published_at %}<span class="badge bg-secondary">{{ playlist_item.video.published_at }}</span>{% endif %}
+                            {% if playlist_item.published_at %}<span class="badge bg-secondary">added to playlist on {{ playlist_item.published_at }}</span>{% endif %}
                             <span class="badge bg-info text-black-50"><i class="fas fa-eye"></i> {% if playlist_item.video.view_count == -1 %}HIDDEN{% else %}{{ playlist_item.video.view_count|intword|intcomma }}{% endif %}</span>
                             <span class="badge bg-info text-black-50"><i class="fas fa-eye"></i> {% if playlist_item.video.view_count == -1 %}HIDDEN{% else %}{{ playlist_item.video.view_count|intword|intcomma }}{% endif %}</span>
                             <span class="badge bg-warning text-black-50"><i class="fas fa-thumbs-up"></i> {% if playlist_item.video.like_count == -1 %}HIDDEN{% else %}{{ playlist_item.video.like_count|intword|intcomma }}{% endif %}</span>
                             <span class="badge bg-warning text-black-50"><i class="fas fa-thumbs-up"></i> {% if playlist_item.video.like_count == -1 %}HIDDEN{% else %}{{ playlist_item.video.like_count|intword|intcomma }}{% endif %}</span>
 
 

+ 12 - 4
apps/main/templates/intercooler/playlists.html

@@ -3,16 +3,16 @@
     {% for playlist in playlists %}
     {% for playlist in playlists %}
         <div class="col">
         <div class="col">
 
 
-            <div class="card overflow-auto" style="background-color: {{ bg_color|default:"#c2c68f" }};">
+            <div class="card overflow-auto" style="background-color: {{ bg_color|default:"#9363af" }};">
                 <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">
                 <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">
 
 
                 <div class="card-body">
                 <div class="card-body">
-                    <h5 class="card-title"><a href="{% url 'playlist' playlist.playlist_id %}" class="stretched-link" style="text-decoration: none; color: black">{{ playlist.name }}</a></h5>
+                    <h5 class="card-title"><a href="{% url 'playlist' playlist.playlist_id %}" class="stretched-link" style="text-decoration: none; color: white">{{ playlist.name }}</a></h5>
                     <p class="card-text">
                     <p class="card-text">
                         <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>
                         <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>
                         {% if playlist.get_watch_time_left != "0secs." %}<span class="badge bg-dark text-white">{{ playlist.get_watch_time_left }} left</span>{% endif %}
                         {% if playlist.get_watch_time_left != "0secs." %}<span class="badge bg-dark text-white">{{ playlist.get_watch_time_left }} left</span>{% endif %}
                     </p>
                     </p>
-                    <p class="card-text"><small class="text-muted">Last watched {{ playlist.last_watched|naturaltime }}</small></p>
+                    <p class="card-text"><small class="text-black">Last watched {{ playlist.last_watched|naturaltime }}</small></p>
                 </div>
                 </div>
             </div>
             </div>
         </div>
         </div>
@@ -26,7 +26,15 @@
                     <img  class="bd-placeholder-img card-img-top" src="{% if playlist.thumbnail_url %}{{ playlist.thumbnail_url }}{% else %}https://i.ytimg.com/vi/9219YrnwDXE/maxresdefault.jpg{% endif %}" style="max-width:100%; height: 200px;   object-fit: cover;" alt="{{ playlist.name }} thumbnail">
                     <img  class="bd-placeholder-img card-img-top" src="{% if playlist.thumbnail_url %}{{ playlist.thumbnail_url }}{% else %}https://i.ytimg.com/vi/9219YrnwDXE/maxresdefault.jpg{% endif %}" style="max-width:100%; height: 200px;   object-fit: cover;" alt="{{ playlist.name }} thumbnail">
                 </a>
                 </a>
                 <div class="card-body">
                 <div class="card-body">
-                    <h5 class="card-title"><a href="{% url 'playlist' playlist.playlist_id %}" style="text-decoration: none; color: black">{{ playlist.name }}</a></h5>
+                    <h5 class="card-title">
+                        <a href="{% url 'playlist' playlist.playlist_id %}" style="text-decoration: none; color: white">
+                            {% if playlist.user_label %}
+                                <span style="border-bottom: 3px #eeeaea dashed;">{{ playlist.user_label }}</span>
+                            {% else %}
+                            {{ playlist.name }}
+                            {% endif %}
+                        </a>
+                    </h5>
 
 
                     <p class="card-text text-uppercase">
                     <p class="card-text text-uppercase">
                         {% if playlist.is_user_owned %}<span class="badge bg-light text-black-50">OWNED</span>{% else %}<span class="badge bg-light text-black-50">IMPORTED</span>{% endif %}
                         {% if playlist.is_user_owned %}<span class="badge bg-light text-black-50">OWNED</span>{% else %}<span class="badge bg-light text-black-50">IMPORTED</span>{% endif %}

+ 11 - 2
apps/main/templates/intercooler/video_cards.html

@@ -2,14 +2,22 @@
 {% for video in videos %}
 {% for video in videos %}
     <div class="col">
     <div class="col">
 
 
-        <div class="card" style="max-width: 540px; background-color: #1A4464;">
+        <div class="card overflow-auto" style="max-width: 540px; background-color: #1A4464;">
             <div class="row g-0">
             <div class="row g-0">
                 <div class="col-md-4">
                 <div class="col-md-4">
                     <img src="{{ video.thumbnail_url }}" class="img-fluid" style="width: 100%; height: 15vw; object-fit: cover;">
                     <img src="{{ video.thumbnail_url }}" class="img-fluid" style="width: 100%; height: 15vw; object-fit: cover;">
                 </div>
                 </div>
                 <div class="col-md-8">
                 <div class="col-md-8">
                     <div class="card-body">
                     <div class="card-body">
-                        <h5 class="card-title"><a href="{% url 'video' video.video_id %}" style="text-decoration: none; color: white"> {{ video.name|truncatewords:"15" }}</a></h5>
+                        <h5 class="card-title"><a href="{% url 'video' video.video_id %}" style="text-decoration: none; color: white">
+                            {% if video.user_label %}
+                                <span style="border-bottom: 3px #eeeaea dashed;">{{ video.user_label }}</span>
+                            {% else %}
+                            {{ video.name|truncatewords:"15" }}
+                            {% endif %}
+                        </a>
+                        </h5>
+                        {% if not video.is_unavailable_on_yt and not video.was_deleted_on_yt %}
                         <h5 class="card-text">
                         <h5 class="card-text">
                             <small>
                             <small>
                                 <span class="badge bg-dark text-white-50">{{ video.duration }}</span>
                                 <span class="badge bg-dark text-white-50">{{ video.duration }}</span>
@@ -20,6 +28,7 @@
 
 
                             </small>
                             </small>
                         </h5>
                         </h5>
+                        {% endif %}
 
 
                         <span class="card-text d-flex justify-content-start">
                         <span class="card-text d-flex justify-content-start">
                             <a href="https://www.youtube.com/watch?v={{ video.video_id }}" class="btn btn-info me-1" target="_blank" id="share_link" style=""><i class="fas fa-external-link-alt" aria-hidden="true"></i></a>
                             <a href="https://www.youtube.com/watch?v={{ video.video_id }}" class="btn btn-info me-1" target="_blank" id="share_link" style=""><i class="fas fa-external-link-alt" aria-hidden="true"></i></a>

+ 2 - 2
apps/main/templates/library.html

@@ -64,11 +64,11 @@
         </a>
         </a>
     </div>
     </div>
     <div class="col">
     <div class="col">
-        <a href="#" class="text-decoration-none text-white">
+        <a href="{% url 'library' 'yt-mix' %}" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #bd39a7;">
         <div class="card h-100" style="background-color: #bd39a7;">
             <div class="card-body">
             <div class="card-body">
                 <h5 class="card-title">Your YouTube Mixes</h5>
                 <h5 class="card-title">Your YouTube Mixes</h5>
-                <p class="card-text">YouTube creates nice mixes that relate to songs you're currently jamming to. You can import those YT Mixes by going over to manage playlists. Any mixes you import will all be here.</p>
+                <p class="card-text">YouTube creates nice mixes that relate to songs you're currently jamming to. You can import those YT Mixes by going over to Manage. Any YouTube mixes you import will all be here.</p>
             </div>
             </div>
         </div>
         </div>
         </a>
         </a>

+ 0 - 6
apps/main/templates/manage_playlists_import.html

@@ -13,12 +13,6 @@
                 hx-post="{% url 'manage_save' 'manage_playlists_import_textarea' %}"
                 hx-post="{% url 'manage_save' 'manage_playlists_import_textarea' %}"
                 hx-trigger="keyup changed delay:500ms"
                 hx-trigger="keyup changed delay:500ms"
                 hx-indicator="#spinner">{{ manage_playlists_import_textarea }}</textarea>
                 hx-indicator="#spinner">{{ manage_playlists_import_textarea }}</textarea>
-        <!--
-        <input class="form-check-input mx-3 big-checkbox" type="checkbox" name="e" id="checkbox"> <br>
-        <input class="form-check-input mx-3 big-checkbox" type="checkbox" name="f" id="checkbox"> <br>
-        <input class="form-check-input mx-3 big-checkbox" type="checkbox" name="g" id="checkbox"> <br>
-        <input class="form-check-input mx-3 big-checkbox" type="checkbox" name="h" id="checkbox"> <br>
-        -->
     </div>
     </div>
       <br>
       <br>
       <div class="d-flex justify-content-start">
       <div class="d-flex justify-content-start">

File diff suppressed because it is too large
+ 565 - 465
apps/main/templates/view_playlist.html


+ 0 - 9
apps/main/templates/view_playlist_settings.html

@@ -128,16 +128,7 @@
                         <input type="text" class="form-control" name="username" id="username" value="{{ playlist.name }}" disabled>
                         <input type="text" class="form-control" name="username" id="username" value="{{ playlist.name }}" disabled>
                     </div>
                     </div>
                   </div>
                   </div>
-                    <hr>
 
 
-                    <div class="row">
-                    <div class="col-sm-3">
-                      <h6 class="mb-0">Playlist User Label</h6>
-                    </div>
-                    <div class="col-sm-9 text-white-50">
-                        <input type="text" class="form-control" name="user_label" id="user_label" placeholder="Enter a personal label you want to identify this playlist with" value="{{ playlist.user_label }}">
-                    </div>
-                  </div>
                       <hr>
                       <hr>
                       <div class="row">
                       <div class="row">
                         <div class="col-sm-3">
                         <div class="col-sm-3">

+ 88 - 124
apps/main/templates/view_video.html

@@ -19,7 +19,7 @@
                     <button type="submit" class="btn btn-primary">Save</button>
                     <button type="submit" class="btn btn-primary">Save</button>
 
 
                 </form>
                 </form>
-                              <button type="button" class="btn-close mt-2 me-2" onclick='document.getElementById("user-label-alert").style.display = "none";' aria-label="Close"></button>
+                <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>
             <div class="card text-white bg-dark" style="max-width: 100%;">
             <div class="card text-white bg-dark" style="max-width: 100%;">
@@ -27,8 +27,22 @@
                     <div class="col-md-4 p-3">
                     <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;">
                         <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">
                         <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 me-2"></i> Download Thumbnail</a>
-                            </span>
+                            <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>
+                        </span>
                     </div>
                     </div>
                     <div class="col-md-8">
                     <div class="col-md-8">
                         <div class="card-body">
                         <div class="card-body">
@@ -36,34 +50,13 @@
                                 <h2 class="card-title text-white col-10">
                                 <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>
                                     <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";'>
                                     <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>
+                                        <i class="fas fa-pencil-alt" aria-hidden="true"></i>
+                                    </button>
 
 
                                     <br><small class="h4">{% if video.user_label %}a.k.a <span style="border-bottom: 3px #ffffff dashed;"> {{ video.user_label }}</span>{% endif %}</small>
                                     <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>
                                 </h2>
-                                <h4 class="col d-flex justify-content-end">
-                                    <span id="notice-div">
-
-                                    </span>
-                                    <span id="">
-
-                                        <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  me-1" data-clipboard-target="#video-{{ video.video_id }}">
-                                            <i class="far fa-copy" aria-hidden="true"></i>
-                                        </button>
-                                        <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>
-                                    </span>
-                                </h4>
                             </div>
                             </div>
-                            <h6>by {{ video.channel_name }}</h6>
+                            <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">
                             <p class="card-text">
                                 {% if video.description %}
                                 {% if video.description %}
                                     <h5 class="overflow-auto" style="max-height: 350px;">
                                     <h5 class="overflow-auto" style="max-height: 350px;">
@@ -83,27 +76,27 @@
                                 <div class="collapse" id="{{ video.video_id }}DurationCollapse">
                                 <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 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 %}"
                                         <div hx-get="{% url 'video_completion_times' video.video_id %}"
-                                hx-trigger="revealed"
-                                hx-swap="outerHTML">
+                                            hx-trigger="revealed"
+                                            hx-swap="outerHTML">
 
 
                                         </div>
                                         </div>
                                     </div>
                                     </div>
                                 </div>
                                 </div>
                                 <small>
                                 <small>
-                                {% 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"></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>
-                                {% 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 %}
-                                <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>
-                                {% 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 %}
+                                    {% 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"></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>
+                                    {% 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 %}
+                                    <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>
+                                    {% 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>
                                 </small>
 
 
@@ -130,7 +123,7 @@
         <div class="col-6">
         <div class="col-6">
             <div class="row">
             <div class="row">
                 <div class="col-6">
                 <div class="col-6">
-                        <h4>Your notes for this video
+                    <h4>Your notes for this video
 
 
                     </h4>
                     </h4>
                 </div>
                 </div>
@@ -143,13 +136,13 @@
 
 
             <div >
             <div >
                 <textarea name="video-notes-text-area"
                 <textarea name="video-notes-text-area"
-                          hx-post="{% url 'video_notes' video.video_id %}"
-                          hx-trigger="keyup changed delay:1.5s"
-                          hx-target="#notes-save-status"
-                          class="form-control"
-                          id="video-notes-text-area"
-                          placeholder="Enter here"
-                          rows="13">
+                    hx-post="{% url 'video_notes' video.video_id %}"
+                    hx-trigger="keyup changed delay:1.5s"
+                    hx-target="#notes-save-status"
+                    class="form-control"
+                    id="video-notes-text-area"
+                    placeholder="Enter here"
+                    rows="13">
                     {{ video.user_notes }}
                     {{ video.user_notes }}
                 </textarea>
                 </textarea>
 
 
@@ -161,41 +154,12 @@
         </div>
         </div>
     </div>
     </div>
 
 
-      <br>
+    <br>
 
 
     <div class="">
     <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>
         <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 }'>
         <div id="found-in" class="row row-cols-1 row-cols-md-4 g-4 text-dark mt-0" data-masonry='{"percentPosition": true }'>
-            {% for playlist in video.playlists.all %}
-                <div class="col">
-
-                    <div class="card" style="background-color: #EFEFEF;">
-                        <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">
-
-                        <div class="card-body">
-                            <h5 class="card-title"><a href="{% url 'playlist' playlist.playlist_id %}" class="stretched-link" style="text-decoration: none; color: black">{{ playlist.name }}</a></h5>
-                            <p class="card-text">
-                                <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>
-                                {% if playlist.get_watch_time_left != "0secs." %}<span class="badge bg-dark text-white">{{ playlist.get_watch_time_left }} left</span>{% endif %}
-                            </p>
-                            <p class="card-text">
-                                {% if playlist.tags.all %}
-                                    <small>
-                                        <i class="fas fa-tags fa-sm" style="color: black"></i>
-                                        {% for tag in playlist.tags.all %}
-                                            <span class="badge rounded-pill bg-primary mb-lg-1">
-                                                {{ tag.name }}
-                                            </span>
-                                        {% endfor %}
-                                    </small>
-                                {% endif %}
-                            </p>
-                            <p class="card-text"><small class="text-muted">Last watched {{ playlist.last_watched|naturalday }}</small></p>
-                        </div>
-                    </div>
-                </div>
-
-            {% endfor %}
+            {% include 'intercooler/playlists.html' with playlists=video.playlists.all watching=False bg_color="#357779" show_controls=True %}
         </div>
         </div>
     </div>
     </div>
 
 
@@ -203,51 +167,51 @@
 
 
     <script type="text/javascript">
     <script type="text/javascript">
         // from https://developers.google.com/youtube/iframe_api_reference#Examples
         // 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
+        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 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)
         }
         }
-      }
-      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>
     </script>
 
 
 {% endblock %}
 {% endblock %}

+ 2 - 0
apps/main/urls.py

@@ -20,6 +20,8 @@ urlpatterns = [
 
 
     ### STUFF RELATED TO ONE PLAYLIST
     ### STUFF RELATED TO ONE PLAYLIST
     path("playlist/<slug:playlist_id>", views.view_playlist, name='playlist'),
     path("playlist/<slug:playlist_id>", views.view_playlist, name='playlist'),
+    path("playlist/<slug:playlist_id>/add-user-label", views.add_playlist_user_label, name='add_playlist_user_label'),
+
     path('playlist/<slug:playlist_id>/<slug:video_id>/video-details/watched', views.mark_video_watched,
     path('playlist/<slug:playlist_id>/<slug:video_id>/video-details/watched', views.mark_video_watched,
          name='mark_video_watched'),
          name='mark_video_watched'),
     path("playlist/<slug:playlist_id>/settings", views.view_playlist_settings, name="view_playlist_settings"),
     path("playlist/<slug:playlist_id>/settings", views.view_playlist_settings, name="view_playlist_settings"),

+ 16 - 15
apps/main/views.py

@@ -218,6 +218,9 @@ def library(request, library_type):
         library_type_display = library_type.lower().replace("-", " ")
         library_type_display = library_type.lower().replace("-", " ")
         if library_type.lower() == "watching":
         if library_type.lower() == "watching":
             watching = True
             watching = True
+    elif library_type.lower() == "yt-mix":
+        playlists = request.user.playlists.all().filter(Q(is_yt_mix=True) & Q(is_in_db=True))
+        library_type_display = "Your YouTube Mixes"
     elif library_type.lower() == "home":  # displays cards of all playlist types
     elif library_type.lower() == "home":  # displays cards of all playlist types
         return render(request, 'library.html')
         return render(request, 'library.html')
     elif library_type.lower() == "random":  # randomize playlist
     elif library_type.lower() == "random":  # randomize playlist
@@ -410,11 +413,7 @@ def delete_videos(request, playlist_id, command):
     extra_text = " "
     extra_text = " "
     if num_vids == 0:
     if num_vids == 0:
         return HttpResponse("""
         return HttpResponse("""
-        <div hx-ext="class-tools">
-            <div classes="add visually-hidden:3s">
-                <h5>Select some videos first!</h5><hr>
-            </div>
-        </div>
+            <h5>Select some videos first!</h5><hr>
         """)
         """)
 
 
     if 'confirm before deleting' in request.POST:
     if 'confirm before deleting' in request.POST:
@@ -687,14 +686,6 @@ def update_playlist_settings(request, playlist_id):
 
 
     print(request.POST)
     print(request.POST)
     playlist = request.user.playlists.get(playlist_id=playlist_id)
     playlist = request.user.playlists.get(playlist_id=playlist_id)
-    if "user_label" in request.POST:
-        playlist.user_label = request.POST["user_label"]
-        playlist.save(update_fields=['user_label'])
-
-        return HttpResponse(loader.get_template("intercooler/messages.html")
-            .render(
-            {"message_type": message_type,
-             "message_content": message_content}))
 
 
     if 'confirm before deleting' in request.POST:
     if 'confirm before deleting' in request.POST:
         playlist.confirm_before_deleting = True
         playlist.confirm_before_deleting = True
@@ -1065,12 +1056,12 @@ def playlist_move_copy_videos(request, playlist_id, action):
                 </div>
                 </div>
                 """
                 """
     if action == "move":
     if action == "move":
-        status = Playlist.objects.moveCopyVideosFromPlaylist(request.user,
+        result = Playlist.objects.moveCopyVideosFromPlaylist(request.user,
                                                              from_playlist_id=playlist_id,
                                                              from_playlist_id=playlist_id,
                                                              to_playlist_ids=playlist_ids,
                                                              to_playlist_ids=playlist_ids,
                                                              playlist_item_ids=playlist_item_ids,
                                                              playlist_item_ids=playlist_item_ids,
                                                              action="move")
                                                              action="move")
-        if status[0] == -1:
+        if result['status'] == -1:
             if status[1] == 404:
             if status[1] == 404:
                 return HttpResponse(
                 return HttpResponse(
                     "<span class='text-danger'>You cannot copy/move unavailable videos! De-select them and try again.</span>")
                     "<span class='text-danger'>You cannot copy/move unavailable videos! De-select them and try again.</span>")
@@ -1133,3 +1124,13 @@ def add_video_user_label(request, video_id):
         video.user_label = bleach.clean(request.POST["user_label"])
         video.user_label = bleach.clean(request.POST["user_label"])
         video.save(update_fields=['user_label'])
         video.save(update_fields=['user_label'])
     return redirect('video', video_id=video_id)
     return redirect('video', video_id=video_id)
+
+
+@login_required
+@require_POST
+def add_playlist_user_label(request, playlist_id):
+    playlist = request.user.playlists.get(playlist_id=playlist_id)
+    if "user_label" in request.POST:
+        playlist.user_label = bleach.clean(request.POST["user_label"].strip())
+        playlist.save(update_fields=['user_label'])
+    return redirect('playlist', playlist_id=playlist_id)

+ 4 - 4
apps/search/templates/intercooler/search_untube_results.html

@@ -1,8 +1,8 @@
 {% load humanize %}
 {% load humanize %}
 
 
 {% if view_mode == "playlists" %}
 {% if view_mode == "playlists" %}
-    <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
-        <h1 class="h2">{% if search_query == "" %}{{ playlist_type }}{% endif %} Playlists {% if search_query != "" %}results for '{{ search_query|escape }}' {% endif %} <span class="badge bg-primary rounded-pill">{{ playlists.count|default:"0" }}</span></h1>
+    <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center overflow-auto pt-3 pb-2 mb-3 border-bottom">
+        <h1 class="h2">{{ playlist_type }} Playlists {% if search_query != "" %}results for '{{ search_query|escape }}' {% endif %} <span class="badge bg-primary rounded-pill">{{ playlists.count|default:"0" }}</span></h1>
     </div>
     </div>
 
 
     <div class="row row-cols-1 row-cols-md-4 g-4">
     <div class="row row-cols-1 row-cols-md-4 g-4">
@@ -14,8 +14,8 @@
     </div>
     </div>
 {% else %}
 {% else %}
 
 
-    <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
-        <h1 class="h2">{% if search_query == "" %}{{ videos_type }}{% endif %} Videos {% if search_query != "" %}results for '{{ search_query|escape }}' {% endif %} <span class="badge bg-primary rounded-pill">{{ videos.count }}</span> {% if videos.count > 100 %}<small>(only top 100 results shown)</small>{% endif %}</h1>
+    <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center overflow-auto pt-3 pb-2 mb-3 border-bottom">
+        <h1 class="h2">{{ videos_type }} Videos {% if search_query != "" %}results for '{{ search_query|escape }}' {% endif %} <span class="badge bg-primary rounded-pill">{{ videos.count }}</span> {% if videos.count > 100 %}<small>(only top 100 results shown)</small>{% endif %}</h1>
     </div>
     </div>
 
 
     <div>
     <div>

+ 4 - 3
apps/search/templates/search_untube_page.html

@@ -36,9 +36,9 @@
                     <div class="col">
                     <div class="col">
                         Filter by playlist tags:
                         Filter by playlist tags:
                         <select class="visually-hidden" onchange="triggerSubmit()"
                         <select class="visually-hidden" onchange="triggerSubmit()"
-                            id="choices-playlist-tags" name="playlist-tags" placeholder="Add playlist tags to search within" multiple>
+                            id="choices-playlist-tags" name="playlist-tags" placeholder="Select playlist tags" multiple>
                             {% for tag in user.playlist_tags.all %}
                             {% for tag in user.playlist_tags.all %}
-                                <option value="{{ tag.name }}" hx-post="{% url 'search_UnTube' %}" {% if pl_tag == tag.name %}selected{% endif %}>{{ tag.name }}</option>
+                                <option value="{{ tag.name }}" {% if pl_tag == tag.name %}selected{% endif %}>{{ tag.name }}</option>
                             {% endfor %}
                             {% endfor %}
                         </select>
                         </select>
 
 
@@ -78,7 +78,7 @@
                         <select class="visually-hidden" onchange="triggerSubmit()"
                         <select class="visually-hidden" onchange="triggerSubmit()"
                             id="choices-channels" name="channel-names" placeholder="Select channels to search within" multiple>
                             id="choices-channels" name="channel-names" placeholder="Select channels to search within" multiple>
                             {% for channel in user.profile.get_channels_list %}
                             {% for channel in user.profile.get_channels_list %}
-                                <option value="{{ channel }}" hx-post="{% url 'search_UnTube' %}">{{ channel }}</option>
+                                <option value="{{ channel }}" {% if channel == vid_channel_name %}selected{% endif %}>{{ channel }}</option>
                             {% endfor %}
                             {% endfor %}
                         </select>
                         </select>
                     </div>
                     </div>
@@ -91,6 +91,7 @@
                                     <option value="All" {% if item_type == "all" %}selected{% endif %}>All</option>
                                     <option value="All" {% if item_type == "all" %}selected{% endif %}>All</option>
                                     <option value="Favorite" {% if item_type == "favorite" %}selected{% endif %}>Favorite</option>
                                     <option value="Favorite" {% if item_type == "favorite" %}selected{% endif %}>Favorite</option>
                                     <option value="Watched" {% if item_type == "watched" %}selected{% endif %}>Watched</option>
                                     <option value="Watched" {% if item_type == "watched" %}selected{% endif %}>Watched</option>
+                                     <option value="Unavailable" {% if item_type == "unavailable" %}selected{% endif %}>Unavailable</option>
                                 </select>
                                 </select>
                             </div>
                             </div>
                             <div class="ms-3">
                             <div class="ms-3">

+ 31 - 9
apps/search/views.py

@@ -33,12 +33,18 @@ def search(request):
         else:
         else:
             pl_tag = ""
             pl_tag = ""
 
 
+        if 'channel' in request.GET:
+            vid_channel_name = request.GET["channel"]
+        else:
+            vid_channel_name = ""
+
         return render(request, 'search_untube_page.html',
         return render(request, 'search_untube_page.html',
                       {"playlists": request.user.playlists.all(),
                       {"playlists": request.user.playlists.all(),
                        "mode": mode,
                        "mode": mode,
                        "item_type": item_type,
                        "item_type": item_type,
                        "query": query,
                        "query": query,
-                       "pl_tag": pl_tag})
+                       "pl_tag": pl_tag,
+                       "vid_channel_name": vid_channel_name})
     else:
     else:
         return redirect('home')
         return redirect('home')
 
 
@@ -73,8 +79,12 @@ def search_UnTube(request):
             for tag in tags:
             for tag in tags:
                 all_playlists = all_playlists.filter(tags__name=tag)
                 all_playlists = all_playlists.filter(tags__name=tag)
 
 
-        playlists = all_playlists.filter(Q(name__icontains=search_query) | Q(
-            user_label__icontains=search_query))
+        playlists = all_playlists.filter(Q(name__istartswith=search_query) | Q(
+            user_label__istartswith=search_query))
+
+        if not playlists.exists():
+            playlists = all_playlists.filter(Q(name__icontains=search_query) | Q(
+                user_label__icontains=search_query))
 
 
         if search_query.strip() == "":
         if search_query.strip() == "":
             playlists = all_playlists
             playlists = all_playlists
@@ -100,13 +110,19 @@ def search_UnTube(request):
             all_videos = all_videos.filter(is_favorite=True)
             all_videos = all_videos.filter(is_favorite=True)
         elif videos_type == "Watched":
         elif videos_type == "Watched":
             all_videos = all_videos.filter(is_marked_as_watched=True)
             all_videos = all_videos.filter(is_marked_as_watched=True)
+        elif videos_type == "Unavailable":
+            all_videos = all_videos.filter(Q(is_unavailable_on_yt=False) & Q(was_deleted_on_yt=True))
 
 
         if 'channel-names' in request.POST:
         if 'channel-names' in request.POST:
             channels = request.POST.getlist('channel-names')
             channels = request.POST.getlist('channel-names')
             all_videos = all_videos.filter(channel_name__in=channels)
             all_videos = all_videos.filter(channel_name__in=channels)
 
 
         videos = all_videos.filter(
         videos = all_videos.filter(
-            Q(name__icontains=search_query) | Q(user_label__icontains=search_query))
+            Q(name__istartswith=search_query) | Q(user_label__istartswith=search_query))
+
+        if not videos.exists():
+            videos = all_videos.filter(Q(name__icontains=search_query) | Q(
+                user_label__icontains=search_query))
 
 
         if search_query.strip() == "":
         if search_query.strip() == "":
             videos = all_videos
             videos = all_videos
@@ -144,35 +160,41 @@ def search_playlists(request, playlist_type):
     playlists = None
     playlists = None
     if playlist_type == "all":
     if playlist_type == "all":
         try:
         try:
-            playlists = request.user.playlists.all().filter(Q(name__startswith=search_query) & Q(is_in_db=True))
+            playlists = request.user.playlists.all().filter(Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(is_in_db=True))
         except:
         except:
             playlists = request.user.playlists.all()
             playlists = request.user.playlists.all()
     elif playlist_type == "user-owned":  # YT playlists owned by user
     elif playlist_type == "user-owned":  # YT playlists owned by user
         try:
         try:
             playlists = request.user.playlists.filter(
             playlists = request.user.playlists.filter(
-                Q(name__startswith=search_query) & Q(is_user_owned=True) & Q(is_in_db=True))
+                Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(is_user_owned=True) & Q(is_in_db=True))
         except:
         except:
             playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True))
             playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True))
     elif playlist_type == "imported":  # YT playlists (public) owned by others
     elif playlist_type == "imported":  # YT playlists (public) owned by others
         try:
         try:
             playlists = request.user.playlists.filter(
             playlists = request.user.playlists.filter(
-                Q(name__startswith=search_query) & Q(is_user_owned=False) & Q(is_in_db=True))
+                Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(is_user_owned=False) & Q(is_in_db=True))
         except:
         except:
             playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True))
             playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True))
     elif playlist_type == "favorites":  # YT playlists (public) owned by others
     elif playlist_type == "favorites":  # YT playlists (public) owned by others
         try:
         try:
             playlists = request.user.playlists.filter(
             playlists = request.user.playlists.filter(
-                Q(name__startswith=search_query) & Q(is_favorite=True) & Q(is_in_db=True))
+                Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(is_favorite=True) & Q(is_in_db=True))
         except:
         except:
             playlists = request.user.playlists.filter(Q(is_favorite=True) & Q(is_in_db=True))
             playlists = request.user.playlists.filter(Q(is_favorite=True) & Q(is_in_db=True))
     elif playlist_type in ["watching", "plan-to-watch"]:
     elif playlist_type in ["watching", "plan-to-watch"]:
         try:
         try:
             playlists = request.user.playlists.filter(
             playlists = request.user.playlists.filter(
-                Q(name__startswith=search_query) & Q(marked_as=playlist_type) & Q(is_in_db=True))
+                Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(marked_as=playlist_type) & Q(is_in_db=True))
         except:
         except:
             playlists = request.user.playlists.all().filter(Q(marked_as=playlist_type) & Q(is_in_db=True))
             playlists = request.user.playlists.all().filter(Q(marked_as=playlist_type) & Q(is_in_db=True))
         if playlist_type == "watching":
         if playlist_type == "watching":
             watching = True
             watching = True
+    elif playlist_type == "yt-mix":  # YT playlists owned by user
+        try:
+            playlists = request.user.playlists.filter(
+                Q(name__startswith=search_query) | Q(user_label__startswith=search_query) & Q(is_yt_mix=True) & Q(is_in_db=True))
+        except:
+            playlists = request.user.playlists.filter(Q(is_yt_mix=True) & Q(is_in_db=True))
 
 
     return HttpResponse(loader.get_template("intercooler/playlists.html")
     return HttpResponse(loader.get_template("intercooler/playlists.html")
                         .render({"playlists": playlists,
                         .render({"playlists": playlists,

Some files were not shown because too many files changed in this diff