aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-08-26 16:17:15 -0400
committerBobby <[email protected]>2024-08-26 16:17:15 -0400
commit9fbfe142051da05f825b25f69a6944d9eb568bf6 (patch)
treea8a49959721daf061a021b82bf960d16b7fec6ec
parentcf95086a9deac841473dd91440f9d1c89ec42024 (diff)
downloadyugen-9fbfe142051da05f825b25f69a6944d9eb568bf6.tar.xz
yugen-9fbfe142051da05f825b25f69a6944d9eb568bf6.zip
mal list display
-rw-r--r--authentication/utils.py61
-rw-r--r--static/css/main.css17
-rw-r--r--templates/home/index.html8
-rw-r--r--templates/partials/datacard_render.html28
-rw-r--r--templates/partials/sidebarwidecard_render.html18
-rw-r--r--templates/partials/user_anime_list.html103
-rw-r--r--user_profile/views.py11
7 files changed, 223 insertions, 23 deletions
diff --git a/authentication/utils.py b/authentication/utils.py
index 05ab97b..bbc96e5 100644
--- a/authentication/utils.py
+++ b/authentication/utils.py
@@ -75,6 +75,67 @@ def exchange_code(code):
)
return response.json()
+def get_user_mal_list(access_token, limit=10, offset=0):
+ base_url = f"https://api.myanimelist.net/v2/users/@me/animelist?limit={limit}&offset={offset}&fields=my_list_status,anime&sort=list_updated_at"
+ headers = {"Authorization": f"Bearer {access_token}"}
+ response = requests.get(base_url, headers=headers)
+
+ if response.status_code == 200:
+ data = response.json()
+ if data["data"] and "paging" in data:
+ if "next" in data["paging"]:
+ page_next = data["paging"]["next"]
+ else:
+ page_next = None
+
+ if "previous" in data["paging"]:
+ page_previous = data["paging"]["previous"]
+ else:
+ page_previous = None
+ mal_ids = [anime["node"]["id"] for anime in data["data"]]
+ user_list = {anime["node"]["id"]: anime["node"]["my_list_status"] for anime in data["data"]}
+
+ query = f'''
+ query {{
+ Page {{
+ media(idMal_in: {mal_ids}) {{
+ id
+ title {{
+ romaji
+ english
+ native
+ }}
+ idMal
+ status
+ coverImage {{
+ large
+ }}
+ episodes
+ duration
+ averageScore
+ genres
+ seasonYear
+ }}
+ }}
+ }}
+ '''
+ response = requests.post(
+ "https://graphql.anilist.co",
+ json={"query": query},
+ )
+
+ user_anime_list = []
+ if response.status_code == 200:
+ data = response.json()
+ for anime in data["data"]["Page"]["media"]:
+ anime["my_list_status"] = user_list[anime["idMal"]]
+ user_anime_list.append(anime)
+ else:
+ print(response.json(), "Error in fetching Anilist Anime Details")
+
+ return user_anime_list, page_previous, page_next
+
+
def get_discord_user(access_token, token_type):
guilds = requests.get(
diff --git a/static/css/main.css b/static/css/main.css
index 40e5931..b90efe4 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -1501,10 +1501,27 @@ main {
background-color: rgb(29 78 216 / var(--tw-bg-opacity));
}
+.hover\:bg-neutral-900:hover {
+ --tw-bg-opacity: 1;
+ background-color: rgb(23 23 23 / var(--tw-bg-opacity));
+}
+
.hover\:bg-opacity-20:hover {
--tw-bg-opacity: 0.2;
}
+.hover\:bg-opacity-10:hover {
+ --tw-bg-opacity: 0.1;
+}
+
+.hover\:bg-opacity-100:hover {
+ --tw-bg-opacity: 1;
+}
+
+.hover\:bg-opacity-30:hover {
+ --tw-bg-opacity: 0.3;
+}
+
.hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
diff --git a/templates/home/index.html b/templates/home/index.html
index 0107f25..9498485 100644
--- a/templates/home/index.html
+++ b/templates/home/index.html
@@ -6,7 +6,7 @@
<section class="swiper rounded mt-2">
<div class="swiper-wrapper">
{% for anime in trending_anime %}
- {% if anime.title.english and anime.duration %}
+ {% if anime.duration %}
<div class="swiper-slide">
<div style="background-image: url('{{ anime.cover }}')" class="bg-center bg-cover h-96 relative">
<div class="absolute inset-0" style="background: linear-gradient(45deg, rgb(8, 8, 8) 15%, transparent 60%), linear-gradient(0deg, rgb(8, 8, 8) 0%, transparent 60%);"></div>
@@ -41,7 +41,13 @@
</span>
</div>
<h2 class="text-4xl font-bold text-transparent bg-clip-text mb-2" style="background: linear-gradient(-45deg, {{ anime.color }}, white); -webkit-background-clip: text; background-clip: text;">
+ {% if user.preferences.title_language == "english" and anime.title.english %}
{{ anime.title.english }}
+ {% elif user.preferences.title_language == "native" and anime.title.native %}
+ {{ anime.title.native }}
+ {% else %}
+ {{ anime.title.romaji }}
+ {% endif %}
</h2>
<p class="max-h-24 overflow-auto text-sm text-white mb-4 no-scrollbar">
{{ anime.description|safe }}
diff --git a/templates/partials/datacard_render.html b/templates/partials/datacard_render.html
index 3219217..6a198b4 100644
--- a/templates/partials/datacard_render.html
+++ b/templates/partials/datacard_render.html
@@ -1,9 +1,8 @@
{% for anime in data %}
- {% if anime.title.english %}
- <a href="{% url "watch:watch" anime.id %}" class="w-1/2 lg:w-1/4 xl:w-1/6 text-gray-500 px-1 mb-4 hover:text-white flex flex-col gap-2">
- <img src="{{ anime.image }}" alt="{{ anime.title.english }}" class="rounded-lg w-56 h-72 mx-auto object-cover"/>
- <div class="inline-flex gap-2 flex-wrap">
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+<a href="{% url "watch:watch" anime.id %}" class="w-1/2 lg:w-1/4 xl:w-1/6 text-gray-500 px-1 mb-4 hover:text-white flex flex-col gap-2">
+ <img src="{{ anime.image }}" alt="{{ anime.title.english }}" class="rounded-lg w-56 h-72 mx-auto object-cover"/>
+ <div class="inline-flex gap-2 flex-wrap">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" class="mr-1">
<path d="M3.604 7.197l7.138 -3.109a.96 .96 0 0 1 1.27 .527l4.924 11.902a1 1 0 0 1 -.514 1.304l-7.137 3.109a.96 .96 0 0 1 -1.271 -.527l-4.924 -11.903a1 1 0 0 1 .514 -1.304z"></path>
<path d="M15 4h1a1 1 0 0 1 1 1v3.5"></path>
@@ -11,20 +10,20 @@
</svg>
{{ anime.type }}
</span>
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-4">
<path fill-rule="evenodd" d="M6.75 2.25A.75.75 0 0 1 7.5 3v1.5h9V3A.75.75 0 0 1 18 3v1.5h.75a3 3 0 0 1 3 3v11.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V7.5a3 3 0 0 1 3-3H6V3a.75.75 0 0 1 .75-.75Zm13.5 9a1.5 1.5 0 0 0-1.5-1.5H5.25a1.5 1.5 0 0 0-1.5 1.5v7.5a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5v-7.5Z" clip-rule="evenodd" />
</svg>
{{ anime.releaseDate }}
</span>
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z"/>
</svg>
{{ anime.rating }}
</span>
- </div>
- <span class="text-sm font-bold flex gap-1 flex-row items-start">
+ </div>
+ <span class="text-sm font-bold flex gap-1 flex-row items-start">
{% if anime.status == "Ongoing" %}
<span class="text-green-500 pt-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-3">
@@ -45,9 +44,14 @@
</span>
{% endif %}
<span>
+ {% if user.preferences.title_language == "english" and anime.title.english %}
{{ anime.title.english }}
+ {% elif user.preferences.title_language == "native" and anime.title.native %}
+ {{ anime.title.native }}
+ {% else %}
+ {{ anime.title.romaji }}
+ {% endif %}
</span>
- </span>
- </a>
- {% endif %}
+ </span>
+</a>
{% endfor %} \ No newline at end of file
diff --git a/templates/partials/sidebarwidecard_render.html b/templates/partials/sidebarwidecard_render.html
index 9b23b99..1e80a9a 100644
--- a/templates/partials/sidebarwidecard_render.html
+++ b/templates/partials/sidebarwidecard_render.html
@@ -1,6 +1,6 @@
{% for anime in data %}
{% if anime.title.english %}
- <a href="{% url "watch:watch" anime.id %}" class="flex flex-row w-full gap-4 bg-white bg-opacity-10 p-2 rounded hover:bg-opacity-20">
+ <a href="{% url "watch:watch" anime.id %}" class="flex flex-row w-full gap-4 bg-white bg-opacity-10 p-2 rounded hover:bg-purple-600 hover:bg-opacity-30">
<img src="{{ anime.image }}" alt="{{ anime.title.english }}" class="rounded-lg w-32 h-auto object-cover"/>
<div class="flex flex-col gap-2">
<span class="text-sm font-bold flex gap-1 flex-row items-start">
@@ -24,14 +24,20 @@
</span>
{% endif %}
<span>
- {{ anime.title.english }}
+ {% if user.preferences.title_language == "english" and anime.title.english %}
+ {{ anime.title.english }}
+ {% elif user.preferences.title_language == "native" and anime.title.native %}
+ {{ anime.title.native }}
+ {% else %}
+ {{ anime.title.romaji }}
+ {% endif %}
</span>
</span>
<div class="text-sm text-gray-400 w-full overflow-auto no-scrollbar max-h-24 max-w-max mb-2">
{{ anime.description|safe }}
</div>
<div class="inline-flex gap-2 flex-wrap">
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" class="mr-1">
<path d="M3.604 7.197l7.138 -3.109a.96 .96 0 0 1 1.27 .527l4.924 11.902a1 1 0 0 1 -.514 1.304l-7.137 3.109a.96 .96 0 0 1 -1.271 -.527l-4.924 -11.903a1 1 0 0 1 .514 -1.304z"></path>
<path d="M15 4h1a1 1 0 0 1 1 1v3.5"></path>
@@ -39,14 +45,14 @@
</svg>
{{ anime.type }}
</span>
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-4">
<path fill-rule="evenodd" d="M6.75 2.25A.75.75 0 0 1 7.5 3v1.5h9V3A.75.75 0 0 1 18 3v1.5h.75a3 3 0 0 1 3 3v11.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V7.5a3 3 0 0 1 3-3H6V3a.75.75 0 0 1 .75-.75Zm13.5 9a1.5 1.5 0 0 0-1.5-1.5H5.25a1.5 1.5 0 0 0-1.5 1.5v7.5a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5v-7.5Z" clip-rule="evenodd" />
</svg>
{{ anime.releaseDate }}
</span>
{% if anime.rating %}
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z"/>
</svg>
@@ -54,7 +60,7 @@
</span>
{% endif %}
{% if anime.currentEpisode and anime.totalEpisodes %}
- <span class="text-xs font-bold bg-white bg-opacity-10 text-white px-2 py-1 rounded flex items-center gap-1">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 8.25h15m-16.5 7.5h15m-1.8-13.5-3.9 19.5m-2.1-19.5-3.9 19.5"/>
</svg>
diff --git a/templates/partials/user_anime_list.html b/templates/partials/user_anime_list.html
index 7369872..b3fd896 100644
--- a/templates/partials/user_anime_list.html
+++ b/templates/partials/user_anime_list.html
@@ -11,5 +11,104 @@
</a>
</div>
{% else %}
-Your list will show up here soon.
-{% endif %} \ No newline at end of file
+<section class="flex flex-row justify-between my-4">
+ {% if prev_offset %}
+ <a href="{% url 'user_profile:user_profile' %}?category=anime_list&offset={{ prev_offset }}" class="bg-purple-600 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2">
+ <span>Load Previous</span>
+ </a>
+ {% else %}
+ <a class="bg-purple-600 bg-opacity-20 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2 cursor-not-allowed">
+ <span>Load Previous</span>
+ </a>
+ {% endif %}
+ {% if next_offset %}
+ <a href="{% url 'user_profile:user_profile' %}?category=anime_list&offset={{ next_offset }}" class="bg-purple-600 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2">
+ <span>Load Next</span>
+ </a>
+ {% else %}
+ <a class="bg-purple-600 bg-opacity-20 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2 cursor-not-allowed">
+ <span>Load Next</span>
+ </a>
+ {% endif %}
+</section>
+<section class="flex flex-wrap justify-center mt-4 animate__animated animate__slideInUp">
+{% for anime in mal_list %}
+ <a href="{% url "watch:watch" anime.id %}" class="w-1/2 lg:w-1/4 xl:w-1/6 text-gray-500 px-1 mb-4 hover:text-white flex flex-col gap-2">
+ <img src="{{ anime.coverImage.large }}" alt="{{ anime.title.english }}" class="rounded-lg w-56 h-72 mx-auto object-cover"/>
+ <div class="inline-flex gap-2 flex-wrap">
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1 capitalize">
+ <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" class="mr-1">
+ <path d="M3.604 7.197l7.138 -3.109a.96 .96 0 0 1 1.27 .527l4.924 11.902a1 1 0 0 1 -.514 1.304l-7.137 3.109a.96 .96 0 0 1 -1.271 -.527l-4.924 -11.903a1 1 0 0 1 .514 -1.304z"></path>
+ <path d="M15 4h1a1 1 0 0 1 1 1v3.5"></path>
+ <path d="M20 6c.264 .112 .52 .217 .768 .315a1 1 0 0 1 .53 1.311l-2.298 5.374"></path>
+ </svg>
+ {{ anime.my_list_status.status }}
+ </span>
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 8.25h15m-16.5 7.5h15m-1.8-13.5-3.9 19.5m-2.1-19.5-3.9 19.5"/>
+ </svg>
+ {{ anime.my_list_status.num_episodes_watched }}
+ </span>
+ <span class="text-xs font-bold bg-white bg-opacity-10 p-1 rounded flex items-center gap-1">
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z"/>
+ </svg>
+ {{ anime.my_list_status.score }}
+ </span>
+ </div>
+ <span class="text-sm font-bold flex gap-1 flex-row items-start">
+ {% if anime.status == "Ongoing" %}
+ <span class="text-green-500 pt-1">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-3">
+ <circle cx="12" cy="12" r="12" />
+ </svg>
+ </span>
+ {% elif anime.status == "Not yet aired" %}
+ <span class="text-yellow-500 pt-1">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-3">
+ <circle cx="12" cy="12" r="12" />
+ </svg>
+ </span>
+ {% else %}
+ <span class="text-blue-500 pt-1">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-3">
+ <circle cx="12" cy="12" r="12" />
+ </svg>
+ </span>
+ {% endif %}
+ <span>
+ {% if user.preferences.title_language == "english" and anime.title.english %}
+ {{ anime.title.english }}
+ {% elif user.preferences.title_language == "native" and anime.title.native %}
+ {{ anime.title.native }}
+ {% else %}
+ {{ anime.title.romaji }}
+ {% endif %}
+ </span>
+ </span>
+ </a>
+{% endfor %}
+</section>
+<section class="flex flex-row justify-between my-4">
+ {% if prev_offset %}
+ <a href="{% url 'user_profile:user_profile' %}?category=anime_list&offset={{ prev_offset }}" class="bg-purple-600 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2">
+ <span>Load Previous</span>
+ </a>
+ {% else %}
+ <a class="bg-purple-600 bg-opacity-20 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2 cursor-not-allowed">
+ <span>Load Previous</span>
+ </a>
+ {% endif %}
+ {% if next_offset %}
+ <a href="{% url 'user_profile:user_profile' %}?category=anime_list&offset={{ next_offset }}" class="bg-purple-600 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2">
+ <span>Load Next</span>
+ </a>
+ {% else %}
+ <a class="bg-purple-600 bg-opacity-20 text-sm font-bold py-3 px-6 rounded-full flex items-center gap-2 cursor-not-allowed">
+ <span>Load Next</span>
+ </a>
+ {% endif %}
+</section>
+{% endif %}
+<!-- \ No newline at end of file
diff --git a/user_profile/views.py b/user_profile/views.py
index 92b5975..bc84632 100644
--- a/user_profile/views.py
+++ b/user_profile/views.py
@@ -2,7 +2,7 @@ import json
from django.shortcuts import render
from django.http import JsonResponse
from user_profile.models import UserPreferences
-from authentication.utils import get_mal_redirect_uri
+from authentication.utils import get_mal_redirect_uri, get_user_mal_list
def user_profile(request):
category = request.GET.get("category", "preferences")
@@ -19,7 +19,14 @@ def user_profile(request):
if category == "anime_list" and not request.user.mal_access_token:
mal_auth_uri, code_challenge = get_mal_redirect_uri()
context["mal_auth_uri"] = mal_auth_uri
-
+ else:
+ offset = request.GET.get("offset", 0)
+ mal_list, prev, next = get_user_mal_list(request.user.mal_access_token, limit=24, offset=offset)
+ context["mal_list"] = mal_list
+ if prev:
+ context["prev_offset"] = prev.split("offset=")[1].split("&")[0]
+ if next:
+ context["next_offset"] = next.split("offset=")[1].split("&")[0]
return render(request, "user_profile/user_profile.html", context)