views.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. from django.db.models import Q
  2. from django.shortcuts import render, redirect
  3. from django.contrib.auth import logout
  4. from django.views.decorators.http import require_POST
  5. from django.contrib.auth.decorators import login_required
  6. from allauth.socialaccount.models import SocialToken
  7. from django.http import HttpResponse
  8. from django.contrib.auth.models import User
  9. from django.contrib import messages
  10. from apps.main.models import Playlist
  11. from django.template import loader
  12. # Create your views here.
  13. def index(request):
  14. if request.user.is_anonymous:
  15. return render(request, 'index.html')
  16. else:
  17. return redirect('home')
  18. @login_required
  19. def profile(request):
  20. user_playlists = request.user.profile.playlists.all()
  21. watching = user_playlists.filter(marked_as="watching")
  22. total_num_playlists = user_playlists.count()
  23. statistics = {
  24. "public_x": 0,
  25. "private_x": 0,
  26. "favorites_x": 0,
  27. "watching_x": 0,
  28. "imported_x": 0
  29. }
  30. if total_num_playlists != 0:
  31. # x means percentage
  32. statistics["public_x"] = round(user_playlists.filter(is_private_on_yt=False).count() / total_num_playlists, 1) * 100
  33. statistics["private_x"] = round(user_playlists.filter(is_private_on_yt=True).count() / total_num_playlists, 1) * 100
  34. statistics["favorites_x"] = round(user_playlists.filter(is_favorite=True).count() / total_num_playlists, 1) * 100
  35. statistics["watching_x"] = round(user_playlists.filter(marked_as="watching").count() / total_num_playlists, 1) * 100
  36. statistics["imported_x"] = round(user_playlists.filter(is_user_owned=False).count() / total_num_playlists, 1) * 100
  37. return render(request, 'profile.html', {"statistics": statistics,
  38. "watching": watching})
  39. @login_required
  40. def settings(request):
  41. return render(request, 'settings.html')
  42. @require_POST
  43. def update_settings(request):
  44. print(request.POST)
  45. user = request.user
  46. username_input = request.POST['username'].strip()
  47. message_content = "Saved!"
  48. message_type = "success"
  49. if username_input != user.username:
  50. if User.objects.filter(username__exact=username_input).count() != 0:
  51. message_type = "danger"
  52. message_content = f"Username {request.POST['username'].strip()} already taken"
  53. else:
  54. user.username = request.POST['username'].strip()
  55. # user.save()
  56. message_content = f"Username updated to {username_input}!"
  57. if 'open search in new tab' in request.POST:
  58. user.profile.open_search_new_tab = True
  59. else:
  60. user.profile.open_search_new_tab = False
  61. user.save()
  62. return HttpResponse(loader.get_template("intercooler/messages.html").render(
  63. {"message_type": message_type, "message_content": message_content, "refresh_page": True}))
  64. @login_required
  65. def delete_account(request):
  66. request.user.profile.delete()
  67. request.user.delete()
  68. request.session.flush()
  69. messages.success(request, "Account data deleted successfully.")
  70. return redirect('index')
  71. @login_required
  72. def log_out(request):
  73. request.session.flush() # delete all stored session keys
  74. logout(request) # log out authenticated user
  75. return redirect('/')
  76. def cancel_import(request):
  77. user_profile = request.user.profile
  78. if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
  79. user_social_token = SocialToken.objects.get(account__user=request.user)
  80. user_profile.access_token = user_social_token.token
  81. user_profile.refresh_token = user_social_token.token_secret
  82. user_profile.expires_at = user_social_token.expires_at
  83. # request.user.save()
  84. user_profile.imported_yt_playlists = False
  85. user_profile.show_import_page = False
  86. user_profile.save()
  87. return redirect('home')
  88. def import_user_yt_playlists(request):
  89. request.user.profile.show_import_page = True
  90. request.user.profile.save(update_fields=['show_import_page'])
  91. return render(request, 'import_in_progress.html')
  92. @login_required
  93. def start_import(request):
  94. '''
  95. Initializes only the user's playlist data in the database. Returns the progress bar, which will
  96. keep calling continue_import
  97. :param request:
  98. :return:
  99. '''
  100. user_profile = request.user.profile
  101. if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
  102. user_social_token = SocialToken.objects.get(account__user=request.user)
  103. user_profile.access_token = user_social_token.token
  104. user_profile.refresh_token = user_social_token.token_secret
  105. user_profile.expires_at = user_social_token.expires_at
  106. request.user.save()
  107. result = Playlist.objects.getAllPlaylistsFromYT(request.user)
  108. channel_found = True
  109. if result["status"] == -1:
  110. print("User has no YT channel")
  111. channel_found = False
  112. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  113. {"channel_found": channel_found}
  114. ))
  115. elif result["status"] == -2:
  116. request.user.profile.import_in_progress = False
  117. request.user.save()
  118. print("User has no playlists on YT")
  119. if request.user.profile.yt_channel_id == "":
  120. Playlist.objects.getUserYTChannelID(request.user)
  121. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  122. {"total_playlists": 0,
  123. "playlists_imported": 0,
  124. "done": True,
  125. "progress": 100,
  126. "channel_found": channel_found}))
  127. else:
  128. if request.user.profile.yt_channel_id == "":
  129. Playlist.objects.getUserYTChannelID(request.user)
  130. user_profile.import_in_progress = True
  131. user_profile.save()
  132. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  133. {"total_playlists": result["num_of_playlists"],
  134. "playlist_name": result["first_playlist_name"],
  135. "playlists_imported": 0,
  136. "progress": 0,
  137. "channel_found": channel_found}
  138. ))
  139. @login_required
  140. def continue_import(request):
  141. if request.user.profile.import_in_progress is False:
  142. return redirect('home')
  143. num_of_playlists = request.user.profile.playlists.all().count()
  144. try:
  145. remaining_playlists = request.user.profile.playlists.filter(is_in_db=False)
  146. playlists_imported = num_of_playlists - remaining_playlists.count() + 1
  147. playlist = remaining_playlists.order_by("created_at")[0]
  148. playlist_name = playlist.name
  149. playlist_id = playlist.playlist_id
  150. Playlist.objects.getAllVideosForPlaylist(request.user, playlist.playlist_id)
  151. except:
  152. playlist_id = -1
  153. if playlist_id != -1:
  154. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  155. {"total_playlists": num_of_playlists,
  156. "playlists_imported": playlists_imported,
  157. "playlist_name": playlist_name,
  158. "progress": round((playlists_imported / num_of_playlists) * 100, 1),
  159. "channel_found": True}))
  160. else:
  161. # request.user.profile.just_joined = False
  162. request.user.profile.import_in_progress = False
  163. request.user.profile.imported_yt_playlists = True
  164. request.user.profile.show_import_page = True # set back to true again so as to show users the welcome screen on 'home'
  165. request.user.save()
  166. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  167. {"total_playlists": num_of_playlists,
  168. "playlists_imported": num_of_playlists,
  169. "done": True,
  170. "progress": 100,
  171. "channel_found": True}))
  172. @login_required
  173. def user_playlists_updates(request, action):
  174. if action == 'check-for-updates':
  175. user_playlists_on_UnTube = request.user.profile.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True))
  176. result = Playlist.objects.getAllPlaylistsFromYT(request.user)
  177. youtube_playlist_ids = result["playlist_ids"]
  178. untube_playlist_ids = []
  179. for playlist in user_playlists_on_UnTube:
  180. untube_playlist_ids.append(playlist.playlist_id)
  181. deleted_playlist_ids = []
  182. deleted_playlist_names = []
  183. for pl_id in untube_playlist_ids:
  184. if pl_id not in youtube_playlist_ids: # ie this playlist was deleted on youtube
  185. deleted_playlist_ids.append(pl_id)
  186. pl = request.user.profile.playlists.get(playlist_id__exact=pl_id)
  187. deleted_playlist_names.append(f"{pl.name} (had {pl.video_count} videos)")
  188. pl.delete()
  189. if result["num_of_playlists"] == user_playlists_on_UnTube.count() and len(deleted_playlist_ids) == 0:
  190. print("No new updates")
  191. playlists = []
  192. else:
  193. playlists = request.user.profile.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False))
  194. print(
  195. f"New updates found! {playlists.count()} newly added and {len(deleted_playlist_ids)} playlists deleted!")
  196. print(deleted_playlist_names)
  197. return HttpResponse(loader.get_template('intercooler/user_playlist_updates.html').render(
  198. {"playlists": playlists,
  199. "deleted_playlist_names": deleted_playlist_names}))
  200. elif action == 'init-update':
  201. unimported_playlists = request.user.profile.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False)).count()
  202. return HttpResponse(f"""
  203. <div hx-get="/updates/user-playlists/start-update" hx-trigger="load" hx-target="#user-pl-updates">
  204. <div class="alert alert-dismissible fade show" role="alert" style="background-color: cadetblue">
  205. <div class="d-flex justify-content-center mt-4 mb-3 ms-2" id="loading-sign" >
  206. <img src="/static/svg-loaders/spinning-circles.svg" width="40" height="40">
  207. <h5 class="mt-2 ms-2 text-black">Importing {unimported_playlists} new playlists into UnTube, please wait!</h5>
  208. </div>
  209. </div>
  210. </div>
  211. """)
  212. elif action == 'start-update':
  213. unimported_playlists = request.user.profile.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False))
  214. for playlist in unimported_playlists:
  215. Playlist.objects.getAllVideosForPlaylist(request.user, playlist.playlist_id)
  216. return HttpResponse("""
  217. <div class="alert alert-success alert-dismissible fade show d-flex justify-content-center" role="alert">
  218. <h4 class="">Successfully imported new playlists into UnTube! Refresh :)</h4>
  219. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-la bel="Close"></button>
  220. </div>
  221. """)