2
0

views.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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,
  41. 1) * 100
  42. statistics["private_x"] = round(user_playlists.filter(is_private_on_yt=True).count() / total_num_playlists,
  43. 1) * 100
  44. statistics["favorites_x"] = round(user_playlists.filter(is_favorite=True).count() / total_num_playlists,
  45. 1) * 100
  46. statistics["watching_x"] = round(user_playlists.filter(marked_as="watching").count() / total_num_playlists,
  47. 1) * 100
  48. statistics["imported_x"] = round(user_playlists.filter(is_user_owned=False).count() / total_num_playlists,
  49. 1) * 100
  50. return render(request, 'profile.html', {
  51. "total_num_playlists": total_num_playlists,
  52. "statistics": statistics,
  53. "watching": watching})
  54. @login_required
  55. def settings(request):
  56. return render(request, 'settings.html')
  57. @require_POST
  58. def update_settings(request):
  59. print(request.POST)
  60. user = request.user
  61. username_input = request.POST['username'].strip()
  62. message_content = "Saved!"
  63. #message_type = "success"
  64. if username_input != user.username:
  65. if User.objects.filter(username__exact=username_input).count() != 0:
  66. #message_type = "danger"
  67. message_content = f"Username {request.POST['username'].strip()} already taken"
  68. messages.error(request, message_content)
  69. else:
  70. user.username = request.POST['username'].strip()
  71. # user.save()
  72. message_content = f"Username updated to {username_input}!"
  73. messages.success(request, message_content)
  74. if 'open search in new tab' in request.POST:
  75. user.profile.open_search_new_tab = True
  76. else:
  77. user.profile.open_search_new_tab = False
  78. if 'enable gradient bg' in request.POST:
  79. user.profile.enable_gradient_bg = True
  80. else:
  81. user.profile.enable_gradient_bg = False
  82. if 'auto refresh playlists' in request.POST:
  83. user.profile.auto_check_for_updates = True
  84. else:
  85. user.profile.auto_check_for_updates = False
  86. if 'confirm before deleting' in request.POST:
  87. user.profile.confirm_before_deleting = True
  88. else:
  89. user.profile.confirm_before_deleting = False
  90. if 'hide videos' in request.POST:
  91. user.profile.hide_unavailable_videos = True
  92. else:
  93. user.profile.hide_unavailable_videos = False
  94. user.save()
  95. if message_content == "Saved!":
  96. messages.success(request, message_content)
  97. return redirect('settings')
  98. @login_required
  99. def delete_account(request):
  100. request.user.playlists.all().delete()
  101. request.user.videos.all().delete()
  102. request.user.playlist_tags.all().delete()
  103. request.user.profile.delete()
  104. request.user.delete()
  105. request.session.flush()
  106. messages.success(request, "Account data deleted successfully.")
  107. return redirect('index')
  108. @login_required
  109. def log_out(request):
  110. request.session.flush() # delete all stored session keys
  111. logout(request) # log out authenticated user
  112. if "troll" in request.GET:
  113. print("TROLLED")
  114. messages.success(request, "Hee Hee")
  115. else:
  116. messages.success(request, "Successfully logged out. Hope to see you back again!")
  117. return redirect('/')
  118. def cancel_import(request):
  119. user_profile = request.user.profile
  120. if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
  121. user_social_token = SocialToken.objects.get(account__user=request.user)
  122. user_profile.access_token = user_social_token.token
  123. user_profile.refresh_token = user_social_token.token_secret
  124. user_profile.expires_at = user_social_token.expires_at
  125. # request.user.save()
  126. user_profile.imported_yt_playlists = False
  127. user_profile.show_import_page = False
  128. user_profile.save()
  129. return redirect('home')
  130. def import_user_yt_playlists(request):
  131. request.user.profile.show_import_page = True
  132. request.user.profile.save(update_fields=['show_import_page'])
  133. return render(request, 'import_in_progress.html')
  134. @login_required
  135. def start_import(request):
  136. """
  137. Initializes only the user's playlist data in the database. Returns the progress bar, which will
  138. keep calling continue_import
  139. :param request:
  140. :return:
  141. """
  142. user_profile = request.user.profile
  143. if user_profile.access_token.strip() == "" or user_profile.refresh_token.strip() == "":
  144. user_social_token = SocialToken.objects.get(account__user=request.user)
  145. user_profile.access_token = user_social_token.token
  146. user_profile.refresh_token = user_social_token.token_secret
  147. user_profile.expires_at = user_social_token.expires_at
  148. request.user.save()
  149. result = Playlist.objects.initializePlaylist(request.user)
  150. if result["status"] == -1:
  151. print("User has no YT channel")
  152. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  153. {
  154. "channel_found": False,
  155. "error_message": result["error_message"]
  156. }
  157. ))
  158. elif result["status"] == -2:
  159. user_profile.import_in_progress = False
  160. user_profile.imported_yt_playlists = True
  161. user_profile.show_import_page = True
  162. user_profile.save()
  163. print("User has no playlists on YT")
  164. if request.user.profile.yt_channel_id == "":
  165. Playlist.objects.getUserYTChannelID(request.user)
  166. Playlist.objects.initializePlaylist(request.user, "LL")
  167. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  168. {"total_playlists": 0,
  169. "playlists_imported": 0,
  170. "done": True,
  171. "progress": 100,
  172. "channel_found": True}))
  173. else:
  174. if request.user.profile.yt_channel_id == "":
  175. Playlist.objects.getUserYTChannelID(request.user)
  176. Playlist.objects.initializePlaylist(request.user, "LL")
  177. user_profile.import_in_progress = True
  178. user_profile.save()
  179. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  180. {"total_playlists": result["num_of_playlists"],
  181. "playlist_name": result["first_playlist_name"],
  182. "playlists_imported": 0,
  183. "progress": 0,
  184. "channel_found": True}
  185. ))
  186. @login_required
  187. def continue_import(request):
  188. if request.user.profile.import_in_progress is False:
  189. return redirect('home')
  190. num_of_playlists = request.user.playlists.filter(Q(is_user_owned=True)).exclude(playlist_id="LL").count()
  191. print("NUM OF PLAYLISTS", num_of_playlists)
  192. try:
  193. remaining_playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False)).exclude(
  194. playlist_id="LL")
  195. print(remaining_playlists.count(), "REMAINING PLAYLISTS")
  196. playlists_imported = num_of_playlists - remaining_playlists.count() + 1
  197. playlist = remaining_playlists.order_by("created_at")[0]
  198. playlist_name = playlist.name
  199. playlist_id = playlist.playlist_id
  200. Playlist.objects.getAllVideosForPlaylist(request.user, playlist_id)
  201. except:
  202. print("NO REMAINING PLAYLISTS")
  203. playlist_id = -1
  204. if playlist_id != -1:
  205. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  206. {"total_playlists": num_of_playlists,
  207. "playlists_imported": playlists_imported,
  208. "playlist_name": playlist_name,
  209. "progress": round((playlists_imported / num_of_playlists) * 100, 1),
  210. "channel_found": True}))
  211. else:
  212. # request.user.profile.just_joined = False
  213. request.user.profile.import_in_progress = False
  214. request.user.profile.imported_yt_playlists = True
  215. request.user.profile.show_import_page = True # set back to true again so as to show users the welcome screen on 'home'
  216. request.user.save()
  217. user_pl_count = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True)).exclude(
  218. playlist_id="LL").count()
  219. return HttpResponse(loader.get_template('intercooler/progress_bar.html').render(
  220. {"total_playlists": user_pl_count,
  221. "playlists_imported": user_pl_count,
  222. "done": True,
  223. "progress": 100,
  224. "channel_found": True}))
  225. @login_required
  226. def user_playlists_updates(request, action):
  227. """
  228. Gets all user created playlist's ids from YouTube and checks them with the user playlists imported on UnTube.
  229. If any playlist id is on UnTube but not on YouTube, deletes the playlist from YouTube.
  230. If any new playlist id, imports it to UnTube
  231. """
  232. if action == 'check-for-updates':
  233. user_playlists_on_UnTube = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=True)).exclude(
  234. playlist_id="LL")
  235. result = Playlist.objects.initializePlaylist(request.user)
  236. print(result)
  237. youtube_playlist_ids = result["playlist_ids"]
  238. untube_playlist_ids = []
  239. for playlist in user_playlists_on_UnTube:
  240. untube_playlist_ids.append(playlist.playlist_id)
  241. deleted_playlist_ids = []
  242. deleted_playlist_names = []
  243. for pl_id in untube_playlist_ids:
  244. if pl_id not in youtube_playlist_ids: # ie this playlist was deleted on youtube
  245. deleted_playlist_ids.append(pl_id)
  246. pl = request.user.playlists.get(playlist_id__exact=pl_id)
  247. deleted_playlist_names.append(f"{pl.name} (had {pl.video_count} videos)")
  248. pl.delete()
  249. if result["num_of_playlists"] == user_playlists_on_UnTube.count() and len(deleted_playlist_ids) == 0:
  250. print("No new updates")
  251. playlists = []
  252. else:
  253. playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False)).exclude(playlist_id="LL")
  254. print(
  255. f"New updates found! {playlists.count()} newly added and {len(deleted_playlist_ids)} playlists deleted!")
  256. print(deleted_playlist_names)
  257. return HttpResponse(loader.get_template('intercooler/user_playlist_updates.html').render(
  258. {"playlists": playlists,
  259. "deleted_playlist_names": deleted_playlist_names}))
  260. elif action == 'init-update':
  261. unimported_playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False)).exclude(playlist_id="LL").count()
  262. return HttpResponse(f"""
  263. <div hx-get="/updates/user-playlists/start-update" hx-trigger="load" hx-target="#user-pl-updates">
  264. <div class="alert alert-dismissible fade show" role="alert" style="background-color: cadetblue">
  265. <div class="d-flex justify-content-center mt-4 mb-3 ms-2" id="loading-sign" >
  266. <img src="/static/svg-loaders/spinning-circles.svg" width="40" height="40">
  267. <h5 class="mt-2 ms-2 text-black">Importing {unimported_playlists} new playlists into UnTube, please wait!</h5>
  268. </div>
  269. </div>
  270. </div>
  271. """)
  272. elif action == 'start-update':
  273. unimported_playlists = request.user.playlists.filter(Q(is_user_owned=True) & Q(is_in_db=False)).exclude(playlist_id="LL")
  274. for playlist in unimported_playlists:
  275. Playlist.objects.getAllVideosForPlaylist(request.user, playlist.playlist_id)
  276. return HttpResponse("""
  277. <div class="alert alert-success alert-dismissible fade show d-flex justify-content-center" role="alert">
  278. <h4 class="">Successfully imported new playlists into UnTube! Refresh :)</h4>
  279. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-la bel="Close"></button>
  280. </div>
  281. """)
  282. @login_required
  283. def get_user_liked_videos_playlist(request):
  284. if not request.user.playlists.filter(Q(playlist_id="LL") & Q(is_in_db=True)).exists():
  285. Playlist.objects.initializePlaylist(request.user, "LL")
  286. Playlist.objects.getAllVideosForPlaylist(request.user, "LL")
  287. messages.success(request, "Successfully imported your Liked Videos playlist!")
  288. return HttpResponse("""
  289. <script>
  290. window.location.reload();
  291. </script>
  292. """)
  293. ### FOR INDEX.HTML
  294. @require_POST
  295. def like_untube(request):
  296. untube = Untube.objects.all().first()
  297. untube.page_likes += 1
  298. untube.save()
  299. request.session['liked_untube'] = True
  300. request.session.save()
  301. return HttpResponse(f"""
  302. <a hx-post="/unlike-untube/" hx-swap="outerHTML" style="text-decoration: none; color: black">
  303. <i class="fas fa-heart" style="color: #d02e2e"></i> {untube.page_likes} likes (p.s glad you liked it!)
  304. </a>
  305. """)
  306. @require_POST
  307. def unlike_untube(request):
  308. untube = Untube.objects.all().first()
  309. untube.page_likes -= 1
  310. untube.save()
  311. request.session['liked_untube'] = False
  312. request.session.save()
  313. return HttpResponse(f"""
  314. <a hx-post="/like-untube/" hx-swap="outerHTML" style="text-decoration: none; color: black">
  315. <i class="fas fa-heart"></i> {untube.page_likes} likes (p.s :/)
  316. </a>
  317. """)