ソースを参照

Cleaned up site

sleepytaco 3 年 前
コミット
2881e1b487

+ 6 - 6
UnTube/settings.py

@@ -29,7 +29,7 @@ YOUTUBE_V3_API_KEY = SECRETS['YOUTUBE_V3_API_KEY']
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
 
-ALLOWED_HOSTS = ['untube-django.herokuapp.com', '127.0.0.1', 'bakaabu.pythonanywhere.com']
+ALLOWED_HOSTS = ['127.0.0.1', 'bakaabu.pythonanywhere.com']
 
 # Application definition
 INSTALLED_APPS = [
@@ -71,8 +71,8 @@ ROOT_URLCONF = 'UnTube.urls'
 TEMPLATES = [
     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        # 'DIRS': [BASE_DIR / 'templates'],
-        'DIRS': [os.path.join(BASE_DIR, "templates")],
+        'DIRS': [BASE_DIR / 'templates'],
+        # 'DIRS': [os.path.join(BASE_DIR, "templates")],
         'APP_DIRS': True,
         'OPTIONS': {
             'context_processors': [
@@ -122,8 +122,8 @@ DATABASES = {
     }
 }
 
-#DATABASES = {}
-#DATABASES['default'] = dj_database_url.config(conn_max_age=600)
+# DATABASES = {}
+# DATABASES['default'] = dj_database_url.config(conn_max_age=600)
 
 # DATABASE_URL = os.environ['DATABASE_URL']
 # conn = psycopg2.connect(DATABASE_URL, sslmode='require')
@@ -169,4 +169,4 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
 
 # django_heroku.settings(locals())
 # options = DATABASES['default'].get('OPTIONS', {})
-# options.pop('sslmode', None)
+# options.pop('sslmode', None)

+ 15 - 3
apps/main/models.py

@@ -66,6 +66,13 @@ def getThumbnailURL(thumbnails):
 
 class PlaylistManager(models.Manager):
 
+    def getPlaylistId(self, video_link):
+        temp = video_link.split("?")[-1].split("&")
+
+        for el in temp:
+            if "list=" in el:
+                return el.split("list=")[-1]
+
     # Returns True if the video count for a playlist on UnTube and video count on same playlist on YouTube is different
     def checkIfPlaylistChangedOnYT(self, user, pl_id):
         credentials = Credentials(
@@ -172,6 +179,7 @@ class PlaylistManager(models.Manager):
     # Set pl_id as None to retrive all the playlists from authenticated user. Playlists already imported will be skipped by default.
     # Set pl_id = <valid playlist id>, to import that specific playlist into the user's account
     def initPlaylist(self, user, pl_id):  # takes in playlist id and saves all of the vids in user's db
+
         current_user = user.profile
 
         credentials = Credentials(
@@ -248,6 +256,8 @@ class PlaylistManager(models.Manager):
                 if playlist.video_count != item['contentDetails']['itemCount']:
                     playlist.has_playlist_changed = True
                     playlist.save()
+
+                return -3
             else:  # no such playlist in database
                 ### MAKE THE PLAYLIST AND LINK IT TO CURRENT_USER
                 playlist = Playlist(  # create the playlist and link it to current user
@@ -425,7 +435,7 @@ class PlaylistManager(models.Manager):
                     playlist.has_unavailable_videos = True
 
                 playlist.is_in_db = True
-
+                playlist.is_user_owned = False
                 playlist.save()
 
         if pl_id is None:
@@ -433,6 +443,8 @@ class PlaylistManager(models.Manager):
             user.profile.import_in_progress = False
             user.save()
 
+        return 0
+
     def getAllPlaylistsFromYT(self, user):
         '''
         Retrieves all of user's playlists from YT and stores them in the Playlist model. Note: only stores
@@ -751,12 +763,12 @@ class Playlist(models.Model):
 
     # manage playlist
     marked_as = models.CharField(default="",
-                                 max_length=100)  # can be set to "none", "watching", "on hold", "plan to watch"
+                                 max_length=100)  # can be set to "none", "watching", "on-hold", "plan-to-watch"
     is_favorite = models.BooleanField(default=False, blank=True)  # to mark playlist as fav
     num_of_accesses = models.IntegerField(default="0")  # tracks num of times this playlist was opened by user
     has_playlist_changed = models.BooleanField(default=False)  # determines whether playlist was modified online or not
     is_private_on_yt = models.BooleanField(default=False)
-    is_from_yt = models.BooleanField(default=True)
+    is_user_owned = models.BooleanField(default=True)  # represents YouTube playlist owned by user
     has_duplicate_videos = models.BooleanField(default=False)  # duplicate videos will not be shown on site
 
     # for UI

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

@@ -12,7 +12,7 @@
             {% endfor %}
     {% endif %}
         <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">{{ playlist_type_display }} <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
+            <h1 class="h2">{{ playlist_type_display|title }} <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
 
             <div class="btn-toolbar mb-2 mb-md-0">
                 <div class="btn-group me-2">

+ 2 - 50
apps/main/templates/home.html

@@ -9,21 +9,6 @@
                   </div>
                 {% endfor %}
 
-    {% if user.profile.just_joined %}
-            {% if not channel_found %}
-                <br>
-
-                <div class="d-flex justify-content-center pt-3 pb-2 mb-3">
-                    <h2>Uh-oh, we were not able to find any YouTube channel linked to this Google account. Please create a YouTube channel to be able to import/export playlists back and forth between YouTube and UnTube.</h2>
-                </div>
-
-                <div class="d-flex justify-content-center pt-3 pb-2 mb-3">
-                    <a href="{% url 'home' %}" class="btn btn-lg btn-danger">Retry</a>
-                </div>
-            {% endif %}
-
-    {% else %}
-
         {% if import_successful %}
                             <br>
                 <br>
@@ -154,47 +139,14 @@
 
 
         <br>
+            <h3>Recently Accessed</h3>
+
         <br>
             <h3>Recently Added</h3>
         <br>
-          <h2>Add a playlist</h2>
-        <br>
-          <div class="table-responsive">
-              <form class="form" role="form" method="post" action="{% url 'home' %}">
-                                          {% csrf_token %}
-
-                  <label for="pl">Enter playlist id:<br></label>
-                  <input name="playlist-id" type="text" id="pl">
-                  <button type="submit" class="btn btn-info">Submit</button>
-                    <div class="spinner-border text-light" role="status">
-                      <span class="visually-hidden">Loading...</span>
-                    </div>
-                                    <input class="form-check-input mx-3 big-checkbox" type="checkbox" value="a" name="s" id="checkbox"> <br>
-                                    <input class="form-check-input mx-3 big-checkbox" type="checkbox" value="b" name="s" id="checkbox"> <br>
-                                    <input class="form-check-input mx-3 big-checkbox" type="checkbox" value="c" name="s" id="checkbox"> <br>
-                                    <input class="form-check-input mx-3 big-checkbox" type="checkbox" value="d" name="s" id="checkbox"> <br>
-
-              </form>
-
-          <br>
-              <div class="list-group">
-                      <a href="https://www.youtube.com/playlist?list={{ playlist.playlist_id }}" class="list-group-item list-group-item-action active">
-                        <b>{{ playlist.name }}</b> by {{ playlist.channel_name }}
-                          <span class="badge badge-dark">{{ playlist.video_count }} videos</span>
-                          <span class="badge badge-dark">{{ playlist.playlist_duration }}</span>
-                          <span class="badge badge-dark">{% if playlist.has_unavailable_videos %}Some videos in the playlist are deleted{% endif %}</span>
-                      </a>
-                  {% for video in videos %}
-                    <a href="https://www.youtube.com/watch?v={{ video.video_id }}&list={{ video.playlist.playlist_id }}" class="list-group-item {% if not video.is_up %}list-group-item-dark{% else %}list-group-item-action{% endif %}">{{ video.video_position }}. {{ video.name }}</a>
-                  {% endfor %}
-            </div>
-
-
-          </div>
 
 
         {% endif %}
 
-    {% endif %}
 
 {% endblock %}

+ 35 - 0
apps/main/templates/intercooler/manage_playlists_import.html

@@ -0,0 +1,35 @@
+<br>
+<hr>
+<br>
+
+  <div class="container-fluid">
+<h2>Enter a Playlist link or list multiple Playlist links line by line</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>
+        <!--
+        <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>
+      <br>
+      <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>
+
+        <div id="spinner" class="htmx-indicator">
+            <div class="spinner-border text-light" role="status">
+            </div>
+        </div>
+    <div id="import-playlists-results">
+
+    </div>
+
+
+  <br>
+
+
+  </div>

+ 93 - 0
apps/main/templates/intercooler/manage_playlists_import_results.html

@@ -0,0 +1,93 @@
+{% if new_playlists %}
+<h4 class="text-white align-content-center">Successfully imported the following {{ num_playlists_initialized_in_db }} playlists into your collection:</h4>
+<div class="row row-cols-1 row-cols-md-3 g-4">
+    {% for playlist in new_playlists %}
+    <div class="col">
+        <div class="card h-100" style="background-color: #1A4464;">
+            <a style="background-color: #1A4464;" href="{% url 'playlist' playlist.playlist_id %}" class="list-group-item list-group-item-action" aria-current="true">
+
+                <div class="card-body text-white">
+
+                    <h5 class="card-title">
+                        {{ playlist.name }} <small>by {{ playlist.channel_name }}</small>
+                        {% 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 %}
+                    </h5>
+                    <p class="card-text">
+                        {% if playlist.description %}
+                            {{ playlist.description }}
+                        {% else %}
+                            No description
+                        {% endif %}
+                    </p>
+                    <small>
+                        <span class="badge bg-primary rounded-pill">{{ playlist.video_count }} views</span>
+                        <span class="badge bg-primary rounded-pill">{{ playlist.playlist_duration }} </span>
+                    </small>
+                </div>
+            </a>
+        </div>
+    </div>
+    {% endfor %}
+</div>
+<br>
+
+{% endif %}
+{% if num_playlists_already_in_db != 0 %}
+    {% if num_playlists_already_in_db > 1 %}
+        <h4>These {{ num_playlists_already_in_db }} were already in your collection :)</h4>
+    {% else %}
+        <h4>This one playlist was already in your collection :)</h4>
+    {% endif %}
+    <div class="row row-cols-1 row-cols-md-3 g-4">
+        {% for playlist in old_playlists %}
+        <div class="col">
+            <div class="card h-100" style="background-color: #1a643b;">
+                <a style="background-color: #1a643b;" href="{% url 'playlist' playlist.playlist_id %}" class="list-group-item list-group-item-action" aria-current="true">
+
+                    <div class="card-body text-white">
+
+                        <h5 class="card-title">
+                        {{ playlist.name }} <small>by {{ playlist.channel_name }}</small>
+
+                            {% 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 %}
+                        </h5>
+                        <p class="card-text">
+                            Playlist ID: <small><span class="badge bg-dark text-white-50">{{ playlist.playlist_id }}</span></small>
+
+                        </p>
+                            <span class="badge bg-primary rounded-pill">{{ playlist.video_count }} videos</span>
+                            <span class="badge bg-primary rounded-pill">{{ playlist.playlist_duration }} </span>
+                    </div>
+                </a>
+            </div>
+        </div>
+        {% endfor %}
+    </div>
+    <br>
+{% endif %}
+{% if num_playlists_not_found != 0 %}
+    {% if num_playlists_not_found > 1  %}
+        <h4>Could not find the following {{ num_playlists_not_found }} playlists links :(</h4>
+    {% else %}
+        <h4>Could not find the following playlist link :(</h4>
+    {% endif %}
+    <div class="row row-cols-1 row-cols-md-3 g-4">
+        {% for playlist in not_found_playlists %}
+        <div class="col">
+            <div class="card" style="background-color: #b1235c;">
+
+                    <div class="card-body text-white">
+
+                        <h5 class="card-title">
+                            {{ playlist }}
+                        </h5>
+
+                    </div>
+                </a>
+            </div>
+        </div>
+        {% endfor %}
+    </div>
+{% endif %}

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

@@ -7,7 +7,7 @@
             {% endfor %}
     {% endif %}
         <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">{{ playlist_type_display }} <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
+            <h1 class="h2">{{ playlist_type_display|title }} <span class="badge bg-primary rounded-pill">{{ playlists.count }}</span></h1>
 
             <div class="btn-toolbar mb-2 mb-md-0">
                 <div class="btn-group me-2">

+ 62 - 0
apps/main/templates/manage_playlists.html

@@ -0,0 +1,62 @@
+
+{% extends 'base.html' %}
+{% block content %}
+    <br>
+
+<div class="row row-cols-1 row-cols-md-3 g-4" >
+    <div id="manage-import-playlists-btn" class="col">
+
+        <a  hx-get="{% url 'manage_view_page' 'import' %}" hx-trigger="click" hx-target="#manage-pl-div" class="text-decoration-none text-white">
+        <div class="card" style="background-color: #25641a;">
+            <div class="card-body">
+                <h4 class="card-title">Import Playlists</h4>
+                    <p class="card-text">Add public playlists to your own collection.</p>
+            </div>
+        </div>
+        </a>
+    </div>
+    <div id="manage-create-playlists-btn" class="col">
+        <a  hx-get="{% url 'manage_view_page' 'create' %}" hx-trigger="click" hx-target="#manage-pl-div" class="text-decoration-none text-white">
+        <div class="card" style="background-color: #64631a;">
+            <div class="card-body">
+                <h4 class="card-title">Create a New Playlist</h4>
+                    <p class="card-text">Make a new playlist and export it to YouTube.</p>
+            </div>
+        </div>
+        </a>
+    </div>
+
+    <div id="manage-untube-playlists-btn" class="col">
+        <a  hx-get="{% url 'manage_view_page' 'untube' %}" hx-trigger="click" hx-target="#manage-pl-div" class="text-decoration-none text-white">
+        <div class="card" style="background-color: #641a52;">
+            <div class="card-body">
+                <h4 class="card-title">Create an UnTube Playlist</h4>
+                <p class="card-text">UnTube playlists are playlists can contain YouTube videos and YouTube playlists which can then be shared with other users via a link. Coming soon. Maybe.</p>
+            </div>
+        </div>
+        </a>
+    </div>
+</div>
+<script>
+    document.getElementById('manage-import-playlists-btn').onclick = function() {
+        document.getElementById('manage-import-playlists-btn').className = "col border border-5 rounded-3 border-primary p-3";
+        document.getElementById('manage-create-playlists-btn').className = "col";
+        document.getElementById('manage-untube-playlists-btn').className = "col";
+    }
+
+    document.getElementById('manage-create-playlists-btn').onclick = function() {
+        document.getElementById('manage-import-playlists-btn').className = "col";
+        document.getElementById('manage-create-playlists-btn').className = "col border border-5 rounded-3 border-primary p-3";
+        document.getElementById('manage-untube-playlists-btn').className = "col";
+    }
+
+    document.getElementById('manage-untube-playlists-btn').onclick = function() {
+        document.getElementById('manage-import-playlists-btn').className = "col";
+        document.getElementById('manage-create-playlists-btn').className = "col";
+        document.getElementById('manage-untube-playlists-btn').className = "col border border-5 rounded-3 border-primary p-3";
+    }
+</script>
+<div id="manage-pl-div">
+
+</div>
+{% endblock %}

+ 8 - 8
apps/main/templates/playlists_home.html

@@ -14,7 +14,7 @@
         </a>
     </div>
     <div class="col">
-        <a href="{% url 'all_playlists' 'all' %}" class="text-decoration-none text-white">
+        <a href="{% url 'all_playlists' 'user-owned' %}" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #1A4464;">
             <div class="card-body">
                 <h4 class="card-title">Your YouTube Playlists</h4>
@@ -25,7 +25,7 @@
     </div>
 
     <div class="col">
-        <a href="{% url 'all_playlists' 'all' %}" class="text-decoration-none text-white">
+        <a href="{% url 'all_playlists' 'imported' %}" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #1a645e;">
             <div class="card-body">
                 <h4 class="card-title">Imported Playlists</h4>
@@ -35,7 +35,7 @@
         </a>
     </div>
     <div class="col">
-        <a href="{% url 'all_playlists' 'all' %}" class="text-decoration-none text-white">
+        <a href="{% url 'all_playlists' 'favorites' %}" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #aa8c2e;">
             <div class="card-body">
                 <h4 class="card-title">Favorite Playlists</h4>
@@ -55,17 +55,17 @@
         </a>
     </div>
     <div class="col">
-        <a href="{% url 'all_playlists' 'watching' %}" class="text-decoration-none text-white">
+        <a href="{% url 'all_playlists' 'plan-to-watch' %}" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #641a29;">
             <div class="card-body">
-                <h4 class="card-title">On-Hold</h4>
-                <p class="card-text">Stopped watching a playlist? Add it here.</p>
+                <h4 class="card-title">Plan to Watch</h4>
+                <p class="card-text">Plan to watch a playlist later? Add it here.</p>
             </div>
         </div>
         </a>
     </div>
     <div class="col">
-        <a href="{% url 'all_playlists' 'all' %}" class="text-decoration-none text-white">
+        <a href="#" class="text-decoration-none text-white">
         <div class="card h-100" style="background-color: #969291;">
             <div class="card-body">
                 <h5 class="card-title">Your UnTube Playlists</h5>
@@ -75,7 +75,7 @@
         </a>
     </div>
     <div class="col">
-        <a href="{% url 'all_playlists' 'all' %}" class="text-decoration-none text-white">
+        <a href="#" class="text-decoration-none text-white">
 
         <div class="card h-100" style="background-color: #d04623;">
             <div class="card-body">

+ 9 - 3
apps/main/templates/view_playlist.html

@@ -23,11 +23,17 @@
                 <h2 class="mb-1">{{ playlist.name }} <small><a><i class="fas fa-pen-square"></i></a></small> </h2>
                 <h6>by {{ playlist.channel_name }}</h6>
             </span>
-            <h4><span class="badge bg-success text-white" id="notice-div">{{ playlist.marked_as|title }}</span></h4>
+            <h4>
+                <span id="notice-div">
+                    {% if playlist.marked_as != "none" %}
+                    <span class="badge bg-success text-white" >{{ playlist.marked_as|title }}</span>
+                    {% endif %}
+                </span>
+            </h4>
         </div>
         <p class="mb-1">
             {% if playlist.description %}
-            <h5>{{ playlist.description }} {{ playlist. }}</h5>
+            <h5>{{ playlist.description }}</h5>
             {% else %}
             <h5>No description</h5>
             {% endif %}
@@ -78,8 +84,8 @@
                                 Mark As
                             </button>
                             <ul class="dropdown-menu">
+                                <li><button class="dropdown-item" hx-get="{% url 'mark_playlist_as' playlist.playlist_id 'none' %}" hx-trigger="click" hx-target="#notice-div">None</button></li>
                                 <li><button class="dropdown-item" hx-get="{% url 'mark_playlist_as' playlist.playlist_id 'watching' %}" hx-trigger="click" hx-target="#notice-div">Watching</button></li>
-                                <li><button class="dropdown-item" hx-get="{% url 'mark_playlist_as' playlist.playlist_id 'on-hold' %}" hx-trigger="click" hx-target="#notice-div">On-Hold</button></li>
                                 <li><button class="dropdown-item" hx-get="{% url 'mark_playlist_as' playlist.playlist_id 'plan-to-watch' %}" hx-trigger="click" hx-target="#notice-div">Plan to Watch</button></li>
                             </ul>
                         </div>

+ 6 - 0
apps/main/urls.py

@@ -27,4 +27,10 @@ urlpatterns = [
     path("search/playlists/<slug:playlist_type>", views.search_playlists, name="search_playlists"),
     path("playlists/<slug:playlist_type>", views.all_playlists, name='all_playlists'),
     path("playlists/<slug:playlist_type>/order-by/<slug:order_by>", views.order_playlists_by, name='order_playlists_by'),
+
+    ### STUFF RELATED TO MANAGING A PLAYLIST
+    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")
 ]

+ 128 - 22
apps/main/views.py

@@ -22,14 +22,11 @@ def home(request):
         if user_profile.import_in_progress:
             return render(request, "import_in_progress.html")
         else:
-            if user_profile.access_token == "" or user_profile.refresh_token == "":
+            if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
                 user_social_token = SocialToken.objects.get(account__user=request.user)
-                print("refresh toekn", user_social_token.token_secret)
-                print("access token", user_social_token.token)
                 user_profile.access_token = user_social_token.token
                 user_profile.refresh_token = user_social_token.token_secret
                 user_profile.expires_at = user_social_token.expires_at
-
                 request.user.save()
 
             user_profile.just_joined = False
@@ -112,15 +109,27 @@ def view_playlist(request, playlist_id):
 
 @login_required
 def all_playlists(request, playlist_type):
-    if playlist_type == "" or playlist_type.lower() == "all":
+    """
+    Possible playlist types for marked_as attribute: (saved in database like this)
+    "none", "watching", "plan-to-watch"
+    """
+    playlist_type = playlist_type.lower()
+
+    if playlist_type == "" or playlist_type == "all":
         playlists = request.user.profile.playlists.all()
         playlist_type_display = "All Playlists"
-    elif playlist_type.lower() == "favorites":
-        playlists = request.user.profile.playlists.filter(marked_as="favorite")
+    elif playlist_type == "user-owned":  # YT playlists owned by user
+        playlists = request.user.profile.playlists.all().filter(is_user_owned=True)
+        playlist_type_display = "Your YouTube Playlists"
+    elif playlist_type == "imported":  # YT playlists (public) owned by others
+        playlists = request.user.profile.playlists.all().filter(is_user_owned=False)
+        playlist_type_display = "Imported playlists"
+    elif playlist_type == "favorites":  # YT playlists (public) owned by others
+        playlists = request.user.profile.playlists.all().filter(is_favorite=True)
         playlist_type_display = "Favorites"
-    elif playlist_type.lower() == "watching":
-        playlists = request.user.profile.playlists.filter(marked_as="watching")
-        playlist_type_display = "Watching"
+    elif playlist_type.lower() in ["watching", "plan-to-watch"]:
+        playlists = request.user.profile.playlists.filter(marked_as=playlist_type.lower())
+        playlist_type_display = playlist_type.lower().replace("-", " ")
     elif playlist_type.lower() == "home":  # displays cards of all playlist types
         return render(request, 'playlists_home.html')
     else:
@@ -172,14 +181,19 @@ def order_playlists_by(request, playlist_type, order_by):
 def mark_playlist_as(request, playlist_id, mark_as):
     playlist = request.user.profile.playlists.get(playlist_id=playlist_id)
 
-    if mark_as in ["none", "watching", "on-hold", "plan-to-watch"]:
-        playlist.marked_as = mark_as.replace("-", " ")
+    marked_as_response = ""
+
+    if mark_as in ["watching", "on-hold", "plan-to-watch"]:
+        playlist.marked_as = mark_as
+        playlist.save()
+        marked_as_response = f'<span class="badge bg-success text-white" >{mark_as.replace("-", " ")}</span>'
+    elif mark_as == "none":
+        playlist.marked_as = mark_as
         playlist.save()
-        videos = playlist.videos.all()
     else:
         return render('home')
 
-    return HttpResponse(mark_as.replace("-", " "))
+    return HttpResponse(marked_as_response)
 
 
 @login_required
@@ -197,26 +211,41 @@ def delete_videos(request):
 @login_required
 @require_POST
 def search_playlists(request, playlist_type):
-    # TODO: make an AJAX call to /search to search for a name in user's playlists
     print(request.POST)  # prints <QueryDict: {'search': ['aa']}>
 
     search_query = request.POST["search"]
 
-    print(search_query)
-
     if playlist_type == "all":
         try:
-            playlists = request.user.profile.playlists.filter(name__startswith=search_query)
+            playlists = request.user.profile.playlists.all().filter(name__startswith=search_query)
         except:
             playlists = request.user.profile.playlists.all()
         playlist_type_display = "All Playlists"
-    elif playlist_type == "watching":
+    elif playlist_type == "user-owned":  # YT playlists owned by user
+        try:
+            playlists = request.user.profile.playlists.filter(Q(name__startswith=search_query) & Q(is_user_owned=True))
+        except:
+            playlists = request.user.profile.playlists.filter(is_user_owned=True)
+        playlist_type_display = "Your YouTube Playlists"
+    elif playlist_type == "imported":  # YT playlists (public) owned by others
+        try:
+            playlists = request.user.profile.playlists.filter(Q(name__startswith=search_query) & Q(is_user_owned=False))
+        except:
+            playlists = request.user.profile.playlists.filter(is_user_owned=False)
+        playlist_type_display = "Imported Playlists"
+    elif playlist_type == "favorites":  # YT playlists (public) owned by others
+        try:
+            playlists = request.user.profile.playlists.filter(Q(name__startswith=search_query) & Q(is_favorite=True))
+        except:
+            playlists = request.user.profile.playlists.filter(is_favorite=True)
+        playlist_type_display = "Your Favorites"
+    elif playlist_type in ["watching", "plan-to-watch"]:
         try:
             playlists = request.user.profile.playlists.filter(
                 Q(name__startswith=search_query) & Q(marked_as=playlist_type))
         except:
-            playlists = request.user.profile.playlists.all()
-        playlist_type_display = "Watching"
+            playlists = request.user.profile.playlists.all().filter(marked_as=playlist_type)
+        playlist_type_display = playlist_type.replace("-", " ")
 
     return HttpResponse(loader.get_template("intercooler/playlists.html")
                         .render({"playlists": playlists,
@@ -225,7 +254,7 @@ def search_playlists(request, playlist_type):
                                  "search_query": search_query}))
 
 
-#### MANAGE VIDEOS
+#### MANAGE VIDEOS #####
 def mark_video_favortie(request, playlist_id, video_id):
     video = request.user.profile.playlists.get(playlist_id=playlist_id).videos.get(video_id=video_id)
 
@@ -239,6 +268,8 @@ def mark_video_favortie(request, playlist_id, video_id):
         return HttpResponse('<i class="fas fa-heart"></i>')
 
 
+###########
+
 @login_required
 @require_POST
 def search_UnTube(request):
@@ -282,3 +313,78 @@ def search_UnTube(request):
                                  "search_query": search_query,
                                  "starts_with": starts_with,
                                  "contains": contains}))
+
+
+@login_required
+def manage_playlists(request):
+    return render(request, "manage_playlists.html")
+
+
+@login_required
+def manage_view_page(request, page):
+    if page == "import":
+        return HttpResponse(loader.get_template("intercooler/manage_playlists_import.html")
+            .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>")
+    else:
+        return redirect('home')
+
+
+@login_required
+@require_POST
+def manage_save(request, what):
+    if what == "manage_playlists_import_textarea":
+        request.user.profile.manage_playlists_import_textarea = request.POST["import-playlist-textarea"]
+        request.user.save()
+
+    return HttpResponse("")
+
+
+@login_required
+@require_POST
+def manage_import_playlists(request):
+    playlist_links = request.POST["import-playlist-textarea"].replace(",", "").split("\n")
+
+    num_playlists_already_in_db = 0
+    num_playlists_initialized_in_db = 0
+    num_playlists_not_found = 0
+    new_playlists = []
+    old_playlists = []
+    not_found_playlists = []
+    for playlist_link in playlist_links:
+        if playlist_link != "":
+            pl_id = Playlist.objects.getPlaylistId(playlist_link)
+            if pl_id is None:
+                num_playlists_not_found += 1
+                continue
+            status = Playlist.objects.initPlaylist(request.user, pl_id)
+            if status == -1 or status == -2:
+                print("\nNo such playlist found:", pl_id)
+                num_playlists_not_found += 1
+                not_found_playlists.append(playlist_link)
+            elif status == -3:
+                num_playlists_already_in_db += 1
+                playlist = request.user.profile.playlists.get(playlist_id__exact=pl_id)
+                old_playlists.append(playlist)
+            else:
+                print(status)
+                playlist = request.user.profile.playlists.get(playlist_id__exact=pl_id)
+                new_playlists.append(playlist)
+                num_playlists_initialized_in_db += 1
+
+    request.user.profile.manage_playlists_import_textarea = ""
+    request.user.save()
+
+    return HttpResponse(loader.get_template("intercooler/manage_playlists_import_results.html")
+        .render(
+        {"new_playlists": new_playlists,
+         "old_playlists": old_playlists,
+         "not_found_playlists": not_found_playlists,
+         "num_playlists_already_in_db": num_playlists_already_in_db,
+         "num_playlists_initialized_in_db": num_playlists_initialized_in_db,
+         "num_playlists_not_found": num_playlists_not_found
+         }))

+ 3 - 0
apps/users/models.py

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

+ 1 - 5
apps/users/views.py

@@ -54,10 +54,6 @@ def log_out(request):
     return redirect('/')
 
 
-def test(request):
-    return render(request, 'test.html')
-
-
 def start_import(request):
     '''
     Initializes only the user's playlist data in the database. Returns the progress bar, which will
@@ -67,7 +63,7 @@ def start_import(request):
     '''
     user_profile = request.user.profile
 
-    if user_profile.access_token == "" or user_profile.refresh_token == "":
+    if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
         user_social_token = SocialToken.objects.get(account__user=request.user)
         user_profile.access_token = user_social_token.token
         user_profile.refresh_token = user_social_token.token_secret

+ 4 - 4
templates/base.html

@@ -65,16 +65,16 @@
                             <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                                 <li><a class="dropdown-item" href="{% url 'all_playlists' 'favorites' %}">Favorites</a></li>
                                 <li><a class="dropdown-item" href="{% url 'all_playlists' 'watching' %}">Watching</a></li>
-                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'watching' %}">On Hold</a></li>
-                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'watching' %}">YouTube</a></li>
-                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'watching' %}">UnTube</a></li>
+                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'plan-to-watch' %}">Plan to Watch</a></li>
+                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'user-owned' %}">Your YT Playlists</a></li>
+                                <li><a class="dropdown-item" href="{% url 'all_playlists' 'imported' %}">Imported</a></li>
                                 <li><hr class="dropdown-divider"></li>
                                 <li><a class="dropdown-item" href="{% url 'all_playlists' 'all' %}">View all</a></li>
                             </ul>
                         </li>
 
                         <li class="nav-item">
-                            <a class="nav-link" href="{% url 'all_playlists' 'home' %}">Manage</a>
+                            <a class="nav-link" href="{% url 'manage_playlists' %}">Manage</a>
                         </li>
                         <li class="nav-item">
                             <a class="nav-link" data-bs-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample">