Explorar el Código

Added refresh button

sleepytaco hace 3 años
padre
commit
211d61bf48

+ 6 - 6
apps/main/templates/all_playlists.html

@@ -37,7 +37,7 @@
         {% if playlists %}
 
         <div class="">
-            <input class="form-control" type="text"
+            <input   class="form-control border border-secondary bg-dark text-white-50" type="text"
        name="search" placeholder="Begin to search playlists..."
        hx-post="{% url 'search_playlists' playlist_type %}"
        hx-trigger="keyup changed delay:500ms"
@@ -50,16 +50,16 @@
             <div class="row row-cols-1 row-cols-md-3 g-4">
                 {% for playlist in playlists %}
                 <div class="col">
-                    <div class="card h-100" style="background-color: #1A4464;">
-                        <a style="background-color: #9CC5E5;" href="{% url 'playlist' playlist.playlist_id %}" class="list-group-item list-group-item-action" aria-current="true">
+                    <div class="card" style="background-color: #515355;">
+                        <a style="background-color: #1A4464;" href="{% url 'playlist' playlist.playlist_id %}" class="list-group-item list-group-item-action text-white-50" aria-current="true">
 
                             <div class="card-body">
 
-                                <h5 class="card-title">
+                                <h5 class="card-title text-white">
                                     {{ playlist.name }}
 
-                                    {% if playlist.is_private_on_yt %}<small><span class="badge bg-light text-dark">Private</span></small> {% endif %}
-                                    {% if playlist.is_from_yt %}<small><span class="badge bg-danger text-dark">YT</span></small> {% endif %}
+                                    {% if playlist.is_private_on_yt %}<small><span class="badge bg-secondary text-black-50">Private</span></small> {% endif %}
+                                    {% if playlist.is_from_yt %}<small><span class="badge bg-danger text-black-50">YT</span></small> {% endif %}
 
                                 </h5>
                                 <p class="card-text">

+ 82 - 7
apps/main/templates/intercooler/manage_playlists_create.html

@@ -3,13 +3,87 @@
 <br>
 
 <div class="container-fluid">
-<h2>Enter a Playlist link or list multiple Playlist links line by line</h2>
+<h2>Create a new YouTube Playlist</h2>
 <br>
     <div id="import-playlists-from">
-      <textarea name="import-playlist-textarea" class="form-control bg-dark text-white" id="video-notes-text-area" placeholder="Enter here" rows="5"
-                hx-post="{% url 'manage_save' 'manage_playlists_import_textarea' %}"
-                hx-trigger="keyup changed delay:500ms"
-                hx-indicator="#spinner">{{ manage_playlists_import_textarea }}</textarea>
+      <div class="mb-3">
+        <h4 for="playlistName" class="form-label">Playlist Name</h4>
+        <input type="email" class="form-control bg-dark text-white" placeholder="Enter playlist name" id="playlistName" name="playlistName" describedby="playlistNameHelp">
+        <div id="playlistNameHelp" class="form-text">Make sure the playlist name is unique!</div>
+      </div>
+
+
+        <div class="mb-3">
+          <h4 for="playlist-desc-text-area" class="form-label">Playlist Description</h4>
+          <textarea name="playlistDescription" class="form-control bg-dark text-white" id="playlist-desc-text-area" placeholder="Enter playlist description here" rows="5"
+            hx-post="{% url 'manage_save' 'manage_playlists_import_textarea' %}"
+            hx-trigger="keyup changed delay:500ms"
+            hx-indicator="#spinner"></textarea>
+        </div>
+
+      <h4 class="form-label">Playlist Type</h4>
+
+    <div class="mb-3">
+        <div class="form-check">
+          <input class="form-check-input" type="radio" name="playlistType" value="public" id="public" checked>
+          <h6 class="form-check-label" for="public">
+            Public
+          </h6>
+        </div>
+        <div class="form-check">
+          <input class="form-check-input" type="radio" name="playlistType" value="private" id="private">
+          <h6 class="form-check-label" for="private">
+            Private
+          </h6>
+        </div>
+    </div>
+
+              <h4 class="form-label">Add videos from your collection</h4>
+
+        <div class="d-flex justify-content-evenly mb-3">
+            <div class="container-fluid">
+                <input class="form-control bg-dark text-black-50 mb-2" type="text"
+                   name="searchForVideosToAddBar" placeholder="Begin to search your video collection..."
+                   hx-post="#"
+                   hx-trigger="keyup changed delay:500ms"
+                   hx-target="#search-results"
+                   hx-indicator=".htmx-indicator">
+                <select class="form-select bg-dark text-white" name="videoIdsFromSearch" multiple aria-label="multiple select example" size="10">
+                  <option selected>Open this select menu</option>
+                  <option value="1">One</option>
+                  <option value="2">Two</option>
+                  <option value="3">Three</option>
+                </select>
+            </div>
+            <div class="btn-group-vertical">
+                <button class="btn btn-danger"> < </button>
+                <button class="btn btn-success"> > </button>
+            </div>
+
+            <div class="container-fluid">
+                <h5 class="d-flex justify-content-start">
+                    All these will be added to the playlist
+                </h5>
+                <select class="form-select bg-dark text-white" name="videoIdsToBeAdded" multiple aria-label="multiple select example" size="10">
+                  <div id="videosToBeAddedBox">
+                    <option value="1" selected>One</option>
+                  <option value="2" selected>Two</option>
+                  <option value="3" selected>Three</option>
+                    </div>
+                </select>
+            </div>
+        </div>
+
+
+
+        <div class="mb-3">
+          <h4 for="playlist-video-links-text-area" class="form-label">Or add videos via video links</h4>
+          <textarea name="externalVideoLinks" class="form-control bg-dark text-white" id="playlist-video-links-text-area" placeholder="Enter video links line by line" rows="5"
+            hx-post="{% url 'manage_save' 'manage_playlists_import_textarea' %}"
+            hx-trigger="keyup changed delay:500ms"
+            hx-indicator="#spinner">{{ manage_playlists_import_textarea }}</textarea>
+        </div>
+
         <!--
         <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>
@@ -17,9 +91,10 @@
         <input class="form-check-input mx-3 big-checkbox" type="checkbox" name="h" id="checkbox"> <br>
         -->
     </div>
-      <br>
       <div class="d-flex justify-content-start">
-          <button type="button" hx-post="{% url 'manage_import_playlists' %}" hx-include="[id='import-playlists-from']" hx-target="#import-playlists-results" hx-indicator="#spinner" class="btn btn-success">Import!</button>
+          <button type="button" hx-post="{% url 'manage_create_playlist' %}" hx-include="[id='import-playlists-from']" hx-target="#import-playlists-results" hx-indicator="#spinner" class="btn btn-success">
+              Create Playlist!
+          </button>
 
             <div id="spinner" class="htmx-indicator ms-3 mt-2">
                 <div class="spinner-border text-light" role="status">

+ 1 - 1
apps/main/templates/intercooler/playlists.html

@@ -34,7 +34,7 @@
        name="search" placeholder="Begin to search playlists..."
                    value="{{ search_query }}"
        hx-post="{% url 'search_playlists' playlist_type %}"
-       hx-trigger="keyup changed delay:200ms"
+       hx-trigger="keyup changed delay:1s"
        hx-target="#search-results"
        hx-indicator=".htmx-indicator" autofocus onfocus="this.setSelectionRange(this.value.length,this.value.length);">
             <br>

+ 87 - 10
apps/main/templates/intercooler/updated_playlist.html

@@ -1,11 +1,14 @@
 
 {% load humanize %}
 {% load static %}
-
+    <div id="view_playlist">
     <div class="alert alert-success alert-dismissible fade show" role="alert">
-        {{ playlist_changed_text|linebreaksbr }}
-
+      <h4 class="alert-heading">Updates</h4>
+      <p>{{ playlist_changed_text|linebreaksbr }}</p>
+      <hr>
+      <p class="mb-0">Tip: Sort By Updates to see what changed in this playlist. Deleted videos will not show up there. Updates can be seen for 12 hrs.</p>
         <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
+
     </div>
 
     <div class="list-group-item list-group-item-action active">
@@ -72,6 +75,19 @@
             <div class="bd-highlight">
                 <div class="btn-toolbar mb-2 mb-md-0">
 
+                    <div class="btn-group me-2">
+                            <a hx-get="{% url 'update_playlist' playlist.playlist_id 'manual' %}" hx-target="#view_playlist" class="btn btn-secondary">
+                                <i class="fas fa-sync"></i>
+                            </a>
+                        </div>
+
+                        <div class="btn-group me-2">
+                            <button type="button" class="btn btn-danger">
+                                <i class="fas fa-dumpster-fire"></i>
+                            </button>
+                        </div>
+
+
                         <div class="btn-group me-2">
                             <button type="button" class="btn btn-outline-warning dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
                                 Mark As
@@ -102,21 +118,27 @@
                     <div id="deselect-all-btn" style="display: none">
                         <div class="btn-group me-2">
                         <button type="button" class="btn btn-outline-info" id="select-all-btn">De-select All</button>
-                    </div>
+                        </div>
                     </div>
                     <div class="btn-group me-2">
-                        <button type="submit" form="my-form" class="btn btn-outline-success" data-bs-toggle="dropdown" aria-expanded="false">
+                        <!-- <button type="submit" form="my-form" class="btn btn-outline-success" data-bs-toggle="dropdown" aria-expanded="false">
                             Move
-                        </button>
+                        </button> -->
+                           <button class="btn btn-outline-success" id="move-copy-vids-btn" type="button" data-bs-toggle="collapse" data-bs-target="#moveItemsToCollapse" aria-expanded="false" aria-controls="moveItemsToCollapse">
+                                Move/Copy Videos
+                           </button>
                     </div>
+
+
+
                     <div class="btn-group me-2">
-                        <button type="button" class="btn btn-outline-primary" data-bs-toggle="dropdown" aria-expanded="false">
-                            UnTube These
+                        <button type="button" class="btn btn-outline-warning" data-bs-toggle="dropdown" aria-expanded="false">
+                            Mark/Unmark Favorite
                         </button>
                     </div>
                     <div class="btn-group me-2">
-                        <button type="button" hx-post="{% url 'delete_videos' %}" hx-include="[id='video-checkboxes']" class="btn btn-outline-danger" data-bs-toggle="dropdown" aria-expanded="false">
-                            Delete
+                        <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirm' %}" hx-include="[id='video-checkboxes']" hx-target="#delete-videos-confirm-box" type="button" id="delete-vids-btn" class="btn btn-outline-danger" data-bs-toggle="collapse" data-bs-target="#deleteItemsCollapse" aria-expanded="false" aria-controls="deleteItemsCollapse">
+                            Delete Selected
                         </button>
                     </div>
                 </div>
@@ -136,6 +158,57 @@
 
         </div>
     </div>
+    <div id="row3" style="background-color: #0f5132">
+      <div class="collapse border-danger" id="moveItemsToCollapse">
+          <div class="card card-body bg-dark text-white-50">
+
+              <h5>Move or Copy videos to another playlist!</h5>
+
+              <div class="d-flex justify-content-start">
+                  <input class="form-control w-50 bg-dark text-white border border-secondary" placeholder="Enter playlist ID here">
+                  <div class="btn-group ms-2">
+                    <button type="button" class="btn btn-info" id="select-all-btn">Move!</button>
+                  </div>
+                  <div class="btn-group ms-2">
+                    <button type="button" class="btn btn-info" id="select-all-btn">Copy!</button>
+                  </div>
+              </div>
+
+              <div class="d-flex justify-content-start mt-3">
+                  <div class="btn-group">
+                      <a href="{% url 'all_playlists' 'all' %}" target="_blank" class="btn btn-sm btn-success" id="select-all-btn">Search for Playlists <i class="fas fa-external-link-alt" aria-hidden="true"></i></a>
+                  </div>
+              </div>
+
+          </div>
+        </div>
+    </div>
+
+    <div id="row4" style="background-color: #0f5132">
+          <div class="collapse border-danger" id="deleteItemsCollapse">
+          <div class="card card-body bg-dark text-white-50">
+
+              <div id="delete-videos-confirm-box">
+              <h5>Are you sure you want to delete these 40 items from your YouTube playlist? This cannot be undone.</h5>
+            </div>
+              <div class="d-flex justify-content-start">
+                  <div class="btn-group ms-2">
+                    <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirmed' %}" hx-include="[id='video-checkboxes']" type="button" class="btn btn-danger" id="select-all-btn">Yes!</button>
+                  </div>
+                  <div class="btn-group ms-2">
+                    <button type="button" class="btn btn-secondary" id="select-all-btn">Nvm</button>
+                  </div>
+                  <div class="btn-group ms-2">
+                    <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirm' %}" hx-include="[id='video-checkboxes']" hx-target="#delete-videos-confirm-box" type="button" class="btn btn-primary">
+                        <i class="fas fa-sync"></i>
+                    </button>
+                </div>
+              </div>
+
+          </div>
+        </div>
+    </div>
+
     <br>
     <div class="table-responsive" id="videos-div">
         <div class="list-group" id="video-checkboxes">
@@ -208,3 +281,7 @@
             </li>
 
         {% endfor %}
+        </div>
+    </div>
+
+    </div>

+ 1 - 1
apps/main/templates/intercooler/video_notes.html

@@ -8,7 +8,7 @@
                             <h1>Your Notes</h1>
                                                   <br>
 
-                            <textarea name="video-notes-text-area" class="form-control" id="video-notes-text-area" rows="17">{{ video.user_notes }}</textarea>
+                            <textarea name="video-notes-text-area" class="form-control bg-dark text-white-50" placeholder="Enter here..." id="video-notes-text-area" rows="17">{{ video.user_notes }}</textarea>
                           </div>
                     </div>
                     <br>

+ 3 - 1
apps/main/templates/intercooler/videos.html

@@ -39,7 +39,9 @@
                           {% if video.view_count %}<span class="badge bg-info">{{ video.view_count|intword|intcomma }} views</span>{% endif %}
 
                             {% if video.is_duplicate %}<span class="badge bg-primary">duplicate</span>{% endif %}
-                            {% if video.video_details_modified %}<span class="badge bg-danger">UPDATED - {% if video.was_deleted_on_yt %}WENT PRIVATE/DELETED{% else %}NEWLY ADDED{% endif %}</span>{% endif %}<br>
+                            {% if video.video_details_modified %}
+                                <span class="badge bg-danger">UPDATED - {% if video.was_deleted_on_yt %}WENT PRIVATE/DELETED{% else %}NEWLY ADDED{% endif %}</span>
+                            {% endif %}<br>
                             <br>
                         </div>
                 </div>

+ 74 - 12
apps/main/templates/view_playlist.html

@@ -6,10 +6,11 @@
 {% block content %}
 
 
+    <div id="view_playlist">
 
     {% if playlist.has_playlist_changed %}
 
-        <div hx-get="{% url 'update_playlist' playlist.playlist_id %}" hx-trigger="load" hx-swap="outerHTML">
+        <div hx-get="{% url 'update_playlist' playlist.playlist_id 'auto' %}" hx-trigger="load" hx-swap="outerHTML">
             <div class="alert alert-success alert-dismissible fade show" role="alert">
                 {{ playlist.playlist_changed_text|linebreaksbr|default:"Looks like the playlist on YouTube was modified!" }}
 
@@ -88,9 +89,9 @@
                 <div class="btn-toolbar mb-2 mb-md-0">
 
                         <div class="btn-group me-2">
-                            <button type="button" class="btn btn-secondary">
+                            <a hx-get="{% url 'update_playlist' playlist.playlist_id 'manual' %}" hx-target="#view_playlist" class="btn btn-secondary">
                                 <i class="fas fa-sync"></i>
-                            </button>
+                            </a>
                         </div>
 
                         <div class="btn-group me-2">
@@ -130,21 +131,28 @@
                     <div id="deselect-all-btn" style="display: none">
                         <div class="btn-group me-2">
                         <button type="button" class="btn btn-outline-info" id="select-all-btn">De-select All</button>
+                        </div>
                     </div>
-                    </div>
+
                     <div class="btn-group me-2">
-                        <button type="submit" form="my-form" class="btn btn-outline-success" data-bs-toggle="dropdown" aria-expanded="false">
+                        <!-- <button type="submit" form="my-form" class="btn btn-outline-success" data-bs-toggle="dropdown" aria-expanded="false">
                             Move
-                        </button>
+                        </button> -->
+                           <button class="btn btn-outline-success" id="move-copy-vids-btn" type="button" data-bs-toggle="collapse" data-bs-target="#moveItemsToCollapse" aria-expanded="false" aria-controls="moveItemsToCollapse">
+                                Move/Copy Videos
+                           </button>
                     </div>
+
+
+
                     <div class="btn-group me-2">
-                        <button type="button" class="btn btn-outline-primary" data-bs-toggle="dropdown" aria-expanded="false">
-                            UnTube These
+                        <button type="button" class="btn btn-outline-warning" data-bs-toggle="dropdown" aria-expanded="false">
+                            Mark/Unmark Favorite
                         </button>
                     </div>
                     <div class="btn-group me-2">
-                        <button type="button" hx-post="{% url 'delete_videos' %}" hx-include="[id='video-checkboxes']" class="btn btn-outline-danger" data-bs-toggle="dropdown" aria-expanded="false">
-                            Delete
+                        <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirm' %}" hx-include="[id='video-checkboxes']" hx-target="#delete-videos-confirm-box" type="button" id="delete-vids-btn" class="btn btn-outline-danger" data-bs-toggle="collapse" data-bs-target="#deleteItemsCollapse" aria-expanded="false" aria-controls="deleteItemsCollapse">
+                            Delete Selected
                         </button>
                     </div>
                 </div>
@@ -156,7 +164,7 @@
             <div class="btn-toolbar mb-2 mb-md-0">
 
                     <div class="btn-group me-2">
-                        <button type="button" class="btn btn-light" onclick="row1_show()">Manage</button>
+                        <button type="button" class="btn btn-light" onclick="row1_show()" id="manageBtn">Manage</button>
                     </div>
 
                 </div>
@@ -164,6 +172,57 @@
 
         </div>
     </div>
+        <div id="row3" style="background-color: #0f5132">
+          <div class="collapse border-danger" id="moveItemsToCollapse">
+              <div class="card card-body bg-dark text-white-50">
+
+                  <h5>Move or Copy videos to another playlist!</h5>
+
+                  <div class="d-flex justify-content-start">
+                      <input class="form-control w-50 bg-dark text-white border border-secondary" placeholder="Enter playlist ID here">
+                      <div class="btn-group ms-2">
+                        <button type="button" class="btn btn-info" id="select-all-btn">Move!</button>
+                      </div>
+                      <div class="btn-group ms-2">
+                        <button type="button" class="btn btn-info" id="select-all-btn">Copy!</button>
+                      </div>
+                  </div>
+
+                  <div class="d-flex justify-content-start mt-3">
+                      <div class="btn-group">
+                          <a href="{% url 'all_playlists' 'all' %}" target="_blank" class="btn btn-sm btn-success" id="select-all-btn">Search for Playlists <i class="fas fa-external-link-alt" aria-hidden="true"></i></a>
+                      </div>
+                  </div>
+
+              </div>
+            </div>
+        </div>
+
+        <div id="row4" style="background-color: #0f5132">
+          <div class="collapse border-danger" id="deleteItemsCollapse">
+              <div class="card card-body bg-dark text-white-50">
+
+                  <div id="delete-videos-confirm-box">
+                  <h5>Are you sure you want to delete these 40 items from your YouTube playlist? This cannot be undone.</h5>
+                </div>
+                  <div class="d-flex justify-content-start">
+                      <div class="btn-group ms-2">
+                        <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirmed' %}" hx-include="[id='video-checkboxes']" type="button" class="btn btn-danger" id="select-all-btn">Yes!</button>
+                      </div>
+                      <div class="btn-group ms-2">
+                        <button type="button" class="btn btn-secondary" id="select-all-btn">Nvm</button>
+                      </div>
+                      <div class="btn-group ms-2">
+                        <button hx-post="{% url 'delete_videos' playlist.playlist_id 'confirm' %}" hx-include="[id='video-checkboxes']" hx-target="#delete-videos-confirm-box" type="button" class="btn btn-primary">
+                            <i class="fas fa-sync"></i>
+                        </button>
+                    </div>
+                  </div>
+
+              </div>
+            </div>
+        </div>
+
     <br>
     <div class="table-responsive" id="videos-div">
         <div class="list-group" id="video-checkboxes">
@@ -197,7 +256,9 @@
                       <img src="{% if video.thumbnail_url %}{{ video.thumbnail_url }}{% else %}https://i.ytimg.com/vi/9219YrnwDXE/maxresdefault.jpg{% endif %}" class="img-fluid" alt="">
                   </div>
                     <div class="ms-4">
-                        <a class="link-dark" href="https://www.youtube.com/watch?v={{ video.video_id }}&list={{ video.playlist.playlist_id }}" target="_blank">{{ video.video_position }}. {{ video.name }}</a> <br>
+                        <a class="link-dark" href="https://www.youtube.com/watch?v={{ video.videoid }}&list={{ video.playlist.playlist_id }}" target="_blank">
+                            {{ video.video_position }}. {{ video.name|truncatewords:"16" }}
+                        </a> <br>
                         <span class="badge bg-secondary">{{ video.duration }}</span>
                         {% if video.has_cc %}<span class="badge bg-secondary">CC</span>{% endif %}
                         {% if video.published_at %}<span class="badge bg-secondary">{{ video.published_at }}</span>{% endif %}
@@ -242,4 +303,5 @@
     {% endif %}
         </div>
     </div>
+    </div>
 {% endblock %}

+ 6 - 4
apps/main/urls.py

@@ -10,11 +10,11 @@ urlpatterns = [
     ### STUFF RELATED TO WHOLE SITE
     path("search/UnTube/", views.search_UnTube, name="search_UnTube"),
 
-    ### STUFF RELATED TO ONE VIDEO
+    ### STUFF RELATED TO VIDEO(S)
     path("<slug:playlist_id>/<slug:video_id>/video-details", views.view_video, name='video_details'),
     path("<slug:playlist_id>/<slug:video_id>/video-details/notes", views.video_notes, name='video_notes'),
     path("<slug:playlist_id>/<slug:video_id>/video-details/favorite", views.mark_video_favortie, name='mark_video_favorite'),
-    path("delete-videos", views.delete_videos, name='delete_videos'),
+    path("from/<slug:playlist_id>/delete-videos/<slug:command>", views.delete_videos, name='delete_videos'),
 
     ### STUFF RELATED TO ONE PLAYLIST
     path("playlist/<slug:playlist_id>", views.view_playlist, name='playlist'),
@@ -22,7 +22,7 @@ urlpatterns = [
          name='order_playlist_by'),
     path("playlist/<slug:playlist_id>/mark-as/<slug:mark_as>", views.mark_playlist_as,
          name='mark_playlist_as'),
-    path("playlist/<slug:playlist_id>/update", views.update_playlist, name="update_playlist"),
+    path("playlist/<slug:playlist_id>/update/<slug:type>", views.update_playlist, name="update_playlist"),
 
     ### STUFF RELATED TO PLAYLISTS IN BULK
     path("search/playlists/<slug:playlist_type>", views.search_playlists, name="search_playlists"),
@@ -33,5 +33,7 @@ urlpatterns = [
     path("manage", views.manage_playlists, name='manage_playlists'),
     path("manage/save/<slug:what>", views.manage_save, name='manage_save'),  # to help auto save the input texts found in the below pages
     path("manage/view/<slug:page>", views.manage_view_page, name='manage_view_page'),  # views the import pl, create pl, create untube pl pages
-    path("manage/import", views.manage_import_playlists, name="manage_import_playlists")
+    path("manage/import", views.manage_import_playlists, name="manage_import_playlists"),
+    path("manage/create", views.manage_create_playlist, name="manage_create_playlist")
+
 ]

+ 69 - 20
apps/main/views.py

@@ -96,11 +96,15 @@ def view_playlist(request, playlist_id):
     user_playlists = user_profile.playlists.all()
 
     # specific playlist requested
-    playlist = user_profile.playlists.get(playlist_id__exact=playlist_id)
-    playlist.num_of_accesses += 1
-    playlist.save()
+    if user_profile.playlists.filter(playlist_id=playlist_id).count() != 0:
+        playlist = user_profile.playlists.get(playlist_id__exact=playlist_id)
+        playlist.num_of_accesses += 1
+        playlist.save()
+    else:
+        messages.error(request, "No such playlist found!")
+        return redirect('home')
 
-    videos = playlist.videos.all()
+    videos = playlist.videos.order_by("video_position")
 
     if not playlist.has_playlist_changed:
         print("Checking if playlist changed...")
@@ -265,8 +269,27 @@ def playlists_home(request):
 
 @login_required
 @require_POST
-def delete_videos(request):
-    print(request.POST)
+def delete_videos(request, playlist_id, command):
+    video_ids = request.POST.getlist("video-id", default=[])
+
+    if command == "confirm":
+        num_vids = len(video_ids)
+        extra_text = " "
+        if num_vids == 0:
+            return HttpResponse("<h5>Select some videos first!</h5>")
+        elif num_vids == request.user.profile.playlists.get(playlist_id=playlist_id).videos.all().count():
+            delete_text = "ALL VIDEOS"
+            extra_text = " This will not delete the playlist itself, will only make the playlist empty. "
+        else:
+            delete_text = f"{num_vids} videos"
+        return HttpResponse(f"<h5>Are you sure you want to delete {delete_text} from your YouTube playlist?{extra_text}This cannot be undone.</h5>")
+    elif command == "confirmed":
+        return HttpResponse(f'<div class="spinner-border text-light" role="status" hx-post="/from/{playlist_id}/delete-videos/start" hx-trigger="load" hx-swap="outerHTML"></div>')
+    elif command == "start":
+        for i in range(1000):
+            print(i)
+        return HttpResponse('DONE!')
+    print(len(video_ids), request.POST)
     return HttpResponse("Worked!")
 
 
@@ -389,9 +412,9 @@ def manage_view_page(request, page):
             .render(
             {"manage_playlists_import_textarea": request.user.profile.manage_playlists_import_textarea}))
     elif page == "create":
-        return HttpResponse("<br><hr><br><h2>Working on this.</h2>")
-    elif page == "untube":
-        return HttpResponse("<br><hr><br><h2>Coming soon. Maybe.</h2>")
+        return HttpResponse(loader.get_template("intercooler/manage_playlists_create.html")
+            .render(
+            {}))
     else:
         return redirect('home')
 
@@ -417,9 +440,11 @@ def manage_import_playlists(request):
     new_playlists = []
     old_playlists = []
     not_found_playlists = []
+
+    done = []
     for playlist_link in playlist_links:
-        if playlist_link != "":
-            pl_id = Playlist.objects.getPlaylistId(playlist_link)
+        if playlist_link.strip() != "" and playlist_link.strip() not in done:
+            pl_id = Playlist.objects.getPlaylistId(playlist_link.strip())
             if pl_id is None:
                 num_playlists_not_found += 1
                 continue
@@ -437,6 +462,7 @@ def manage_import_playlists(request):
                 playlist = request.user.profile.playlists.get(playlist_id__exact=pl_id)
                 new_playlists.append(playlist)
                 num_playlists_initialized_in_db += 1
+            done.append(playlist_link.strip())
 
     request.user.profile.manage_playlists_import_textarea = ""
     request.user.save()
@@ -453,25 +479,50 @@ def manage_import_playlists(request):
 
 
 @login_required
-def update_playlist(request, playlist_id):
-    deleted_video_ids, unavailable_videos, added_videos = Playlist.objects.updatePlaylist(request.user, playlist_id)
+@require_POST
+def manage_create_playlist(request):
+    print(request.POST)
+    return HttpResponse("")
+
+
+@login_required
+def update_playlist(request, playlist_id, type):
+
+    playlist = request.user.profile.playlists.get(playlist_id=playlist_id)
 
+    if type == "manual":
+        print("MANUAL")
+        return HttpResponse(
+            f"""<div hx-get="/playlist/{playlist_id}/update/auto" hx-trigger="load" hx-swap="outerHTML">
+                    <div class="d-flex justify-content-center mt-4 mb-3" id="loading-sign">
+                        <img src="/static/svg-loaders/circles.svg" width="40" height="40">
+                        <h5 class="mt-2 ms-2">Refreshing playlist '{ playlist.name }', please wait!</h5>
+                    </div>
+                </div>""")
+
+    print("Attempting to update playlist")
+    deleted_video_ids, unavailable_videos, added_videos = Playlist.objects.updatePlaylist(request.user, playlist_id)
+    print("Updated playlist")
     playlist = request.user.profile.playlists.get(playlist_id=playlist_id)
-    playlist_changed_text = ["Updates:"]
+    playlist_changed_text = []
 
     if len(added_videos) != 0:
         playlist_changed_text.append(f"{len(added_videos)} added")
-        for video in added_videos:
+        for video in added_videos[:3]:
             playlist_changed_text.append(f"--> {video.name}")
+
+        if len(added_videos) > 3:
+            playlist_changed_text.append(f"+ {len(added_videos) - 3} more")
+
     if len(unavailable_videos) != 0:
-        if len(playlist_changed_text) == 1:
+        if len(playlist_changed_text) == 0:
             playlist_changed_text.append(f"{len(unavailable_videos)} went unavailable")
         else:
             playlist_changed_text.append(f"\n{len(unavailable_videos)} went unavailable")
         for video in unavailable_videos:
             playlist_changed_text.append(f"--> {video.name}")
     if len(deleted_video_ids) != 0:
-        if len(playlist_changed_text) == 1:
+        if len(playlist_changed_text) == 0:
             playlist_changed_text.append(f"{len(deleted_video_ids)} deleted")
         else:
             playlist_changed_text.append(f"\n{len(deleted_video_ids)} deleted")
@@ -481,10 +532,8 @@ def update_playlist(request, playlist_id):
             playlist_changed_text.append(f"--> {video.name}")
             video.delete()
 
-    if len(playlist_changed_text) == 1:
+    if len(playlist_changed_text) == 0:
         playlist_changed_text = ["Successfully refreshed playlist! No new changes found!"]
-    else:
-        playlist_changed_text.append("\nTip: Sort By Updates to see what changed in this playlist.")
 
     return HttpResponse(loader.get_template("intercooler/updated_playlist.html")
         .render(

+ 9 - 1
apps/users/models.py

@@ -31,9 +31,17 @@ class Profile(models.Model):
     refresh_token = models.TextField(default="")
     expires_at = models.DateTimeField(blank=True, null=True)
 
-    # website contexts
+    # import playlist page
     manage_playlists_import_textarea = models.CharField(max_length=420, default="")
 
+    # create playlist page
+    create_playlist_name = models.CharField(max_length=50, default="")
+    create_playlist_desc = models.CharField(max_length=50, default="")
+    create_playlist_type = models.CharField(max_length=50, default="")
+    create_playlist_add_vids_from_collection = models.CharField(max_length=50, default="")
+    create_playlist_add_vids_from_links = models.CharField(max_length=50, default="")
+
+
 
 # as soon as one User object is created, create an associated profile object
 @receiver(post_save, sender=User)

+ 48 - 12
templates/base.html

@@ -31,7 +31,6 @@
 
         <script src="{% static 'clipboard.js/clipboard.min.js' %}"></script>
 
-
         <link href="https://fonts.googleapis.com/css2?family=Fredoka+One&family=Open+Sans&display=swap" rel="stylesheet">
 
         <script src="https://kit.fontawesome.com/5baac7e9b7.js" crossorigin="anonymous"></script>
@@ -85,9 +84,9 @@
 
                     <div class="navbar-nav justify-content-end">
                         <input class="form-control me-lg-2 bg-dark mb-1" id="unTubeSearchBar" type="text" placeholder="Search UnTube">
-                                <button type="button" class="btn btn-primary visually-hidden" id="unTubeSearchBtn" data-bs-toggle="modal" data-bs-target="#unTubeSearchBarResultsModal">
-                                  Launches search model
-                                </button>
+                        <button type="button" class="btn btn-outline-secondary" id="unTubeSearchBtn" data-bs-toggle="modal" data-bs-target="#unTubeSearchBarResultsModal">
+                          <i class="fas fa-search"></i>
+                        </button>
                     </div>
                     <a class="btn btn-outline-danger mb-1" href="{% url 'log_out' %}">
                       Log out
@@ -111,13 +110,13 @@
             <div class="modal-content bg-dark">
               <div class="modal-body bg-dark">
               <div id="untube-searchbar-results">
-                <input class="form-control me-lg-2 bg-dark text-white" id="unTubeSearchBar" type="text"
+                <input class="form-control me-lg-2 bg-dark text-white" id="unTubeSearchBarModal" type="text"
                            name="search" placeholder="Search UnTube"
                            hx-post="{% url 'search_UnTube' %}"
-                           hx-trigger="keyup changed delay:500ms"
+                           hx-trigger="keyup changed delay:1s"
                            hx-target="#untube-searchbar-results"
                        hx-include="[id='searchbar-radio-form']"
-                           hx-indicator=".htmx-indicator" autofocus>
+                           hx-indicator=".htmx-indicator">
                   <br>
                   <div id="searchbar-radio-form">
                     <div class="d-flex justify-content-center">
@@ -244,6 +243,11 @@
 
         <br>
 
+        <script src="{% static 'htmx/htmx.min.js' %}"></script>
+        <script src="{% static 'htmx/extensions/class-tools.js' %}"></script>
+        <script src="{% static 'jquery3.6.0/js/jquery-3.6.0.min.js' %}"></script>
+        <script src="{% static 'bootstrap5.0.1/js/bootstrap.bundle.js' %}"></script>
+
         <script>
 
 
@@ -253,8 +257,44 @@
           })
 
 
+
             var clipboard = new ClipboardJS('.copy-btn');
 
+            <!-- for view_playlist.html -->
+            var moveCopyBtn = document.getElementById('move-copy-vids-btn');
+            var moveCopyCollapse = document.getElementById('moveItemsToCollapse');
+            var bsMoveCopyCollapse = new bootstrap.Collapse(moveCopyCollapse, {
+                toggle: false
+            });
+            var deleteBtn = document.getElementById('delete-vids-btn');
+            var deleteCollapse = document.getElementById('deleteItemsCollapse');
+            var bsDeleteCollapse = new bootstrap.Collapse(deleteCollapse, {
+                toggle: false
+            });
+
+
+            document.getElementById('manageBtn').addEventListener('click', function () {
+                bsMoveCopyCollapse.hide();
+                bsDeleteCollapse.hide();
+            });
+            moveCopyCollapse.addEventListener('show.bs.collapse', function () {
+                    moveCopyBtn.classList = "btn btn-success";
+                    bsDeleteCollapse.hide();
+
+            });
+            moveCopyCollapse.addEventListener('hide.bs.collapse', function () {
+                    moveCopyBtn.classList = "btn btn-outline-success";
+            });
+            deleteCollapse.addEventListener('show.bs.collapse', function () {
+                    deleteBtn.classList = "btn btn-danger";
+                    bsMoveCopyCollapse.hide();
+            });
+            deleteCollapse.addEventListener('hide.bs.collapse', function () {
+                    deleteBtn.classList = "btn btn-outline-danger";
+            });
+
+            <!-- end -->
+
 
              // Get the input field
             var input = document.getElementById("unTubeSearchBar");
@@ -263,6 +303,7 @@
             input.addEventListener("click", function(event) {
 
                 document.getElementById("unTubeSearchBtn").click();
+                document.getElementById("unTubeSearchBarModal").focus();
 
             });
 
@@ -340,11 +381,6 @@
 
         </script>
 
-        <script src="{% static 'htmx/htmx.min.js' %}"></script>
-        <script src="{% static 'htmx/extensions/class-tools.js' %}"></script>
-        <script src="{% static 'jquery3.6.0/js/jquery-3.6.0.min.js' %}"></script>
-        <script src="{% static 'bootstrap5.0.1/js/bootstrap.bundle.js' %}"></script>
-
         <!--
         <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script>
         <script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script>