views.py 12 KB

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