|
@@ -69,280 +69,6 @@ class PlaylistManager(models.Manager):
|
|
|
|
|
|
return 0
|
|
|
|
|
|
- def initPlaylist(self, user, pl_id): # takes in playlist id and saves all of the vids in user's db
|
|
|
-
|
|
|
- credentials = self.getCredentials(user)
|
|
|
-
|
|
|
- with build('youtube', 'v3', credentials=credentials) as youtube:
|
|
|
- pl_request = youtube.playlists().list(
|
|
|
- part='contentDetails, snippet, id, player, status',
|
|
|
- id=pl_id, # get playlist details for this playlist id
|
|
|
- maxResults=50
|
|
|
- )
|
|
|
-
|
|
|
- # execute the above request, and store the response
|
|
|
- try:
|
|
|
- pl_response = pl_request.execute()
|
|
|
- except googleapiclient.errors.HttpError:
|
|
|
- print("YouTube channel not found if mine=True")
|
|
|
- print("YouTube playlist not found if id=playlist_id")
|
|
|
- return -1
|
|
|
-
|
|
|
- print("Playlist", pl_response)
|
|
|
-
|
|
|
- if pl_response["pageInfo"]["totalResults"] == 0:
|
|
|
- print("No playlists created yet on youtube.")
|
|
|
- return -2
|
|
|
-
|
|
|
- playlist_items = []
|
|
|
-
|
|
|
- for item in pl_response["items"]:
|
|
|
- playlist_items.append(item)
|
|
|
-
|
|
|
- while True:
|
|
|
- try:
|
|
|
- pl_request = youtube.playlists().list_next(pl_request, pl_response)
|
|
|
- pl_response = pl_request.execute()
|
|
|
- for item in pl_response["items"]:
|
|
|
- playlist_items.append(item)
|
|
|
- except AttributeError:
|
|
|
- break
|
|
|
-
|
|
|
- for item in playlist_items:
|
|
|
- playlist_id = item["id"]
|
|
|
-
|
|
|
- # check if this playlist already exists in user's untube database
|
|
|
- if user.playlists.filter(playlist_id=playlist_id).exists():
|
|
|
- playlist = user.playlists.get(playlist_id__exact=playlist_id)
|
|
|
- print(f"PLAYLIST {playlist.name} ALREADY EXISTS IN DB")
|
|
|
-
|
|
|
- # POSSIBLE CASES:
|
|
|
- # 1. PLAYLIST HAS DUPLICATE VIDEOS, DELETED VIDS, UNAVAILABLE VIDS
|
|
|
-
|
|
|
- # check if playlist count changed on youtube
|
|
|
- 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
|
|
|
- playlist_id=playlist_id,
|
|
|
- name=item['snippet']['title'],
|
|
|
- description=item['snippet']['description'],
|
|
|
- published_at=item['snippet']['publishedAt'],
|
|
|
- thumbnail_url=getThumbnailURL(item['snippet']['thumbnails']),
|
|
|
- video_count=item['contentDetails']['itemCount'],
|
|
|
- is_private_on_yt=True if item['status']['privacyStatus'] == 'private' else False,
|
|
|
- playlist_yt_player_HTML=item['player']['embedHtml'],
|
|
|
- untube_user=user
|
|
|
- )
|
|
|
-
|
|
|
- playlist.save()
|
|
|
-
|
|
|
- playlist = user.playlists.get(playlist_id=playlist_id)
|
|
|
-
|
|
|
- ### GET ALL VIDEO IDS FROM THE PLAYLIST
|
|
|
- video_ids = [] # stores list of all video ids for a given playlist
|
|
|
- with build('youtube', 'v3', credentials=credentials) as youtube:
|
|
|
- pl_request = youtube.playlistItems().list(
|
|
|
- part='contentDetails, snippet, status',
|
|
|
- playlistId=playlist_id, # get all playlist videos details for this playlist id
|
|
|
- maxResults=50
|
|
|
- )
|
|
|
-
|
|
|
- # execute the above request, and store the response
|
|
|
- pl_response = pl_request.execute()
|
|
|
-
|
|
|
- print("Playlist Items", pl_response)
|
|
|
-
|
|
|
- if playlist.channel_id == "":
|
|
|
- playlist.channel_id = item['snippet']['channelId']
|
|
|
- playlist.channel_name = item['snippet']['channelTitle']
|
|
|
-
|
|
|
- if user.profile.yt_channel_id.strip() != item['snippet']['channelId']:
|
|
|
- playlist.is_user_owned = False
|
|
|
-
|
|
|
- playlist.save()
|
|
|
-
|
|
|
- for item in pl_response['items']:
|
|
|
- video_id = item['contentDetails']['videoId']
|
|
|
-
|
|
|
- if not playlist.videos.filter(video_id=video_id).exists(): # video DNE
|
|
|
- if (item['snippet']['title'] == "Deleted video" and
|
|
|
- item['snippet']['description'] == "This video is unavailable.") or (
|
|
|
- item['snippet']['title'] == "Private video" and item['snippet'][
|
|
|
- 'description'] == "This video is private."):
|
|
|
- video = Video(
|
|
|
- playlist_item_id=item["id"],
|
|
|
- video_id=video_id,
|
|
|
- name=item['snippet']['title'],
|
|
|
- is_unavailable_on_yt=True,
|
|
|
- video_position=item['snippet']['position'] + 1
|
|
|
- )
|
|
|
- video.save()
|
|
|
- else:
|
|
|
- video = Video(
|
|
|
- playlist_item_id=item["id"],
|
|
|
- video_id=video_id,
|
|
|
- published_at=item['contentDetails']['videoPublishedAt'] if 'videoPublishedAt' in
|
|
|
- item[
|
|
|
- 'contentDetails'] else None,
|
|
|
- name=item['snippet']['title'],
|
|
|
- thumbnail_url=getThumbnailURL(item['snippet']['thumbnails']),
|
|
|
- channel_id=item['snippet']['videoOwnerChannelId'],
|
|
|
- channel_name=item['snippet']['videoOwnerChannelTitle'],
|
|
|
- description=item['snippet']['description'],
|
|
|
- video_position=item['snippet']['position'] + 1,
|
|
|
- )
|
|
|
- video.save()
|
|
|
- video_ids.append(video_id)
|
|
|
- else: # video found in db
|
|
|
- video = playlist.videos.get(video_id=video_id)
|
|
|
-
|
|
|
- # check if the video became unavailable on youtube
|
|
|
- if (item['snippet']['title'] == "Deleted video" and
|
|
|
- item['snippet']['description'] == "This video is unavailable.") or (
|
|
|
- item['snippet']['title'] == "Private video" and \
|
|
|
- item['snippet']['description'] == "This video is private."):
|
|
|
- video.was_deleted_on_yt = True
|
|
|
-
|
|
|
- video.is_duplicate = True
|
|
|
- playlist.has_duplicate_videos = True
|
|
|
- video.save()
|
|
|
-
|
|
|
- while True:
|
|
|
- try:
|
|
|
- pl_request = youtube.playlistItems().list_next(pl_request, pl_response)
|
|
|
- pl_response = pl_request.execute()
|
|
|
- for item in pl_response['items']:
|
|
|
- video_id = item['contentDetails']['videoId']
|
|
|
-
|
|
|
- if not playlist.videos.filter(video_id=video_id).exists(): # video DNE
|
|
|
- if (item['snippet']['title'] == "Deleted video" and
|
|
|
- item['snippet']['description'] == "This video is unavailable.") or (
|
|
|
- item['snippet']['title'] == "Private video" and \
|
|
|
- item['snippet']['description'] == "This video is private."):
|
|
|
-
|
|
|
- video = Video(
|
|
|
- playlist_item_id=item["id"],
|
|
|
- video_id=video_id,
|
|
|
- published_at=item['contentDetails'][
|
|
|
- 'videoPublishedAt'] if 'videoPublishedAt' in item[
|
|
|
- 'contentDetails'] else None,
|
|
|
- name=item['snippet']['title'],
|
|
|
- is_unavailable_on_yt=True,
|
|
|
- video_position=item['snippet']['position'] + 1
|
|
|
- )
|
|
|
- video.save()
|
|
|
- else:
|
|
|
- video = Video(
|
|
|
- playlist_item_id=item["id"],
|
|
|
- video_id=video_id,
|
|
|
- published_at=item['contentDetails'][
|
|
|
- 'videoPublishedAt'] if 'videoPublishedAt' in item[
|
|
|
- 'contentDetails'] else None,
|
|
|
- name=item['snippet']['title'],
|
|
|
- thumbnail_url=getThumbnailURL(item['snippet']['thumbnails']),
|
|
|
- channel_id=item['snippet']['videoOwnerChannelId'],
|
|
|
- channel_name=item['snippet']['videoOwnerChannelTitle'],
|
|
|
- video_position=item['snippet']['position'] + 1,
|
|
|
- )
|
|
|
- video.save()
|
|
|
- video_ids.append(video_id)
|
|
|
- else: # video found in db
|
|
|
- video = playlist.videos.get(video_id=video_id)
|
|
|
-
|
|
|
- # check if the video became unavailable on youtube
|
|
|
- if (item['snippet']['title'] == "Deleted video" and
|
|
|
- item['snippet']['description'] == "This video is unavailable.") or (
|
|
|
- item['snippet']['title'] == "Private video" and \
|
|
|
- item['snippet']['description'] == "This video is private."):
|
|
|
- video.was_deleted_on_yt = True
|
|
|
-
|
|
|
- video.is_duplicate = True
|
|
|
- playlist.has_duplicate_videos = True
|
|
|
- video.save()
|
|
|
- except AttributeError:
|
|
|
- break
|
|
|
-
|
|
|
- # API expects the video ids to be a string of comma seperated values, not a python list
|
|
|
- video_ids_strings = getVideoIdsStrings(video_ids)
|
|
|
-
|
|
|
- print(video_ids)
|
|
|
- print(video_ids_strings)
|
|
|
-
|
|
|
- # store duration of all the videos in the playlist
|
|
|
- vid_durations = []
|
|
|
-
|
|
|
- for video_ids_string in video_ids_strings:
|
|
|
- # query the videos resource using API with the string above
|
|
|
- vid_request = youtube.videos().list(
|
|
|
- part="contentDetails,player,snippet,statistics", # get details of eac video
|
|
|
- id=video_ids_string,
|
|
|
- maxResults=50
|
|
|
- )
|
|
|
-
|
|
|
- vid_response = vid_request.execute()
|
|
|
-
|
|
|
- print("Videos()", pl_response)
|
|
|
-
|
|
|
- for item in vid_response['items']:
|
|
|
- duration = item['contentDetails']['duration']
|
|
|
- vid = playlist.videos.get(video_id=item['id'])
|
|
|
-
|
|
|
- if (item['snippet']['title'] == "Deleted video" and
|
|
|
- item['snippet'][
|
|
|
- 'description'] == "This video is unavailable.") or (
|
|
|
- item['snippet']['title'] == "Private video" and item['snippet'][
|
|
|
- 'description'] == "This video is private."):
|
|
|
- playlist.has_unavailable_videos = True
|
|
|
- vid_durations.append(duration)
|
|
|
- vid.video_details_modified = True
|
|
|
- vid.video_details_modified_at = datetime.datetime.now(tz=pytz.utc)
|
|
|
- vid.save(update_fields=['video_details_modified', 'video_details_modified_at',
|
|
|
- 'was_deleted_on_yt', 'is_unavailable_on_yt'])
|
|
|
- continue
|
|
|
-
|
|
|
- vid.name = item['snippet']['title']
|
|
|
- vid.description = item['snippet']['description']
|
|
|
- vid.thumbnail_url = getThumbnailURL(item['snippet']['thumbnails'])
|
|
|
- vid.duration = duration.replace("PT", "")
|
|
|
- vid.duration_in_seconds = calculateDuration([duration])
|
|
|
- vid.has_cc = True if item['contentDetails']['caption'].lower() == 'true' else False
|
|
|
- vid.view_count = item['statistics']['viewCount'] if 'viewCount' in item[
|
|
|
- 'statistics'] else -1
|
|
|
- vid.like_count = item['statistics']['likeCount'] if 'likeCount' in item[
|
|
|
- 'statistics'] else -1
|
|
|
- vid.dislike_count = item['statistics']['dislikeCount'] if 'dislikeCount' in item[
|
|
|
- 'statistics'] else -1
|
|
|
- vid.comment_count = item['statistics']['commentCount'] if 'commentCount' in item[
|
|
|
- 'statistics'] else -1
|
|
|
- vid.yt_player_HTML = item['player']['embedHtml'] if 'embedHtml' in item['player'] else ''
|
|
|
- vid.save()
|
|
|
-
|
|
|
- vid_durations.append(duration)
|
|
|
-
|
|
|
- playlist_duration_in_seconds = calculateDuration(vid_durations)
|
|
|
-
|
|
|
- playlist.playlist_duration_in_seconds = playlist_duration_in_seconds
|
|
|
- playlist.playlist_duration = getHumanizedTimeString(playlist_duration_in_seconds)
|
|
|
-
|
|
|
- if len(video_ids) != len(vid_durations): # that means some videos in the playlist are deleted
|
|
|
- playlist.has_unavailable_videos = True
|
|
|
-
|
|
|
- playlist.is_in_db = True
|
|
|
- # playlist.is_user_owned = False
|
|
|
- playlist.save()
|
|
|
-
|
|
|
- if pl_id is None:
|
|
|
- user.profile.show_import_page = False
|
|
|
- user.profile.import_in_progress = False
|
|
|
- user.save()
|
|
|
-
|
|
|
- return 0
|
|
|
-
|
|
|
# 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 initializePlaylist(self, user, pl_id=None):
|
|
@@ -423,7 +149,7 @@ class PlaylistManager(models.Manager):
|
|
|
# check if playlist count changed on youtube
|
|
|
if playlist.video_count != item['contentDetails']['itemCount']:
|
|
|
playlist.has_playlist_changed = True
|
|
|
- playlist.save()
|
|
|
+ playlist.save(update_fields=['has_playlist_changed'])
|
|
|
|
|
|
if pl_id is not None:
|
|
|
result["status"] = -3
|
|
@@ -1327,8 +1053,7 @@ class Video(models.Model):
|
|
|
is_pinned = models.BooleanField(default=False)
|
|
|
is_marked_as_watched = models.BooleanField(default=False) # mark video as watched
|
|
|
is_favorite = models.BooleanField(default=False, blank=True) # mark video as favorite
|
|
|
- num_of_accesses = models.CharField(max_length=69,
|
|
|
- default="0") # tracks num of times this video was clicked on by user
|
|
|
+ num_of_accesses = models.IntegerField(default=0) # tracks num of times this video was clicked on by user
|
|
|
user_label = models.CharField(max_length=100, default="") # custom user given name for this video
|
|
|
user_notes = models.CharField(max_length=420, default="") # user can take notes on the video and save them
|
|
|
|