aboutsummaryrefslogtreecommitdiff
path: root/homepage/views.py
diff options
context:
space:
mode:
authorBobby <[email protected]>2024-09-03 12:20:35 -0400
committerBobby <[email protected]>2024-09-03 12:20:35 -0400
commit51a27b6f400625cb0137e1394de1056ea5fb682b (patch)
tree593b782d99784c690705eb397831a9a681d406a3 /homepage/views.py
parenta9e71a492486a25ec4273716080e0ca744a36646 (diff)
downloadyugen-51a27b6f400625cb0137e1394de1056ea5fb682b.tar.xz
yugen-51a27b6f400625cb0137e1394de1056ea5fb682b.zip
optimizations
Diffstat (limited to 'homepage/views.py')
-rw-r--r--homepage/views.py208
1 files changed, 119 insertions, 89 deletions
diff --git a/homepage/views.py b/homepage/views.py
index 9e0c6cc..15d8811 100644
--- a/homepage/views.py
+++ b/homepage/views.py
@@ -13,109 +13,139 @@ from homepage.utils import (
get_upcoming_anime,
get_next_season,
)
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from functools import lru_cache
-def index(request):
- homepage_data_cached = get_from_redis_cache("homepage_data")
-
- if not homepage_data_cached:
- trending_anime = get_trending_anime()
- popular_anime = get_popular_anime()
- top_anime = get_top_anime()
- top_airing_anime = get_top_airing_anime()
- upcoming_anime = get_upcoming_anime()
- next_season = get_next_season()
-
+@lru_cache(maxsize=1)
+def get_homepage_data():
+ homepage_data = get_from_redis_cache("homepage_data")
+
+ if not homepage_data:
homepage_data = {
- "trending_anime": trending_anime,
- "popular_anime": popular_anime,
- "top_anime": top_anime,
- "top_airing_anime": top_airing_anime,
- "upcoming_anime": upcoming_anime,
- "next_season": next_season
+ "trending_anime": get_trending_anime(),
+ "popular_anime": get_popular_anime(),
+ "top_anime": get_top_anime(),
+ "top_airing_anime": get_top_airing_anime(),
+ "upcoming_anime": get_upcoming_anime(),
+ "next_season": get_next_season()
}
-
- store_in_redis_cache("homepage_data", json.dumps(homepage_data))
+ store_in_redis_cache("homepage_data", json.dumps(homepage_data), 3600) # Cache for 1 hour
else:
- homepage_data = json.loads(homepage_data_cached)
- trending_anime = homepage_data["trending_anime"]
- popular_anime = homepage_data["popular_anime"]
- top_anime = homepage_data["top_anime"]
- top_airing_anime = homepage_data["top_airing_anime"]
- upcoming_anime = homepage_data["upcoming_anime"]
- next_season = homepage_data["next_season"]
-
- if request.user.preferences.show_history_on_home:
- user_history_data = gather_watch_history(request, limit=10)
+ homepage_data = json.loads(homepage_data)
+
+ return homepage_data
+def index(request):
+ homepage_data = get_homepage_data()
+
context = {
- "trending_anime": trending_anime["results"],
- "popular_anime": popular_anime["results"],
- "top_anime": top_anime["results"],
- "top_airing_anime": top_airing_anime["results"],
- "upcoming_anime": upcoming_anime["results"],
- "next_season": next_season,
- "user_history_data": user_history_data if request.user.preferences.show_history_on_home else None
+ "trending_anime": homepage_data["trending_anime"]["results"],
+ "popular_anime": homepage_data["popular_anime"]["results"],
+ "top_anime": homepage_data["top_anime"]["results"],
+ "top_airing_anime": homepage_data["top_airing_anime"]["results"],
+ "upcoming_anime": homepage_data["upcoming_anime"]["results"],
+ "next_season": homepage_data["next_season"],
}
+ if request.user.preferences.show_history_on_home:
+ context["user_history_data"] = gather_watch_history(request)
+
return render(request, "home/index.html", context)
-def gather_watch_history(request, limit=None):
+def gather_watch_history(request, limit=10):
user = request.user
+ latest_history = get_user_watch_history(user.id, limit)
+ anime_ids = [entry['anime_id'] for entry in latest_history]
+ anime_data_map = get_bulk_anime_data(anime_ids)
+
+ return [
+ {
+ "anime_id": entry['anime_id'],
+ "title": anime_data_map[entry['anime_id']]["title"],
+ "cover": anime_data_map[entry['anime_id']]["cover"],
+ "episode": entry['episode'] if entry['last_watched'] else 1,
+ "metadata": get_episode_metadata(anime_data_map[entry['anime_id']], entry['episode'] if entry['last_watched'] else 1)
+ }
+ for entry in latest_history
+ ]
+
+@lru_cache(maxsize=100)
+def get_user_watch_history(user_id, limit):
+ query = """
+ WITH ranked_history AS (
+ SELECT
+ id,
+ anime_id,
+ episode,
+ last_watched,
+ last_updated,
+ ROW_NUMBER() OVER (PARTITION BY anime_id ORDER BY last_updated DESC) AS rn
+ FROM user_profile_userhistory
+ WHERE user_id = %s
+ )
+ SELECT id, anime_id, episode, last_watched, last_updated
+ FROM ranked_history
+ WHERE rn = 1
+ ORDER BY last_updated DESC
+ LIMIT %s
+ """
with connection.cursor() as cursor:
- query = """
- WITH ranked_history AS (
- SELECT
- id,
- anime_id,
- episode,
- last_watched,
- last_updated,
- ROW_NUMBER() OVER (PARTITION BY anime_id ORDER BY last_updated DESC) AS rn
- FROM user_profile_userhistory
- WHERE user_id = %s
- )
- SELECT id, anime_id, episode, last_watched, last_updated
- FROM ranked_history
- WHERE rn = 1
- ORDER BY last_updated DESC
- """
- if limit:
- query += " LIMIT %s"
- cursor.execute(query, [user.id, limit])
- else:
- cursor.execute(query, [user.id])
-
+ cursor.execute(query, [user_id, limit])
columns = [col[0] for col in cursor.description]
- latest_history = [dict(zip(columns, row)) for row in cursor.fetchall()]
-
- user_history_data = []
-
- for history_entry in latest_history:
- anime_id = history_entry['anime_id']
- last_watched = history_entry['episode'] if history_entry['last_watched'] else 1
-
- anime_data = None
- try:
- anime_data = json.loads(get_from_redis_cache(f"anime_{anime_id}_anime_data"))
- except:
- base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/info/{anime_id}?provider=zoro"
- response = requests.get(base_url)
- anime_data = response.json()
- store_in_redis_cache(f"anime_{anime_id}_anime_data", json.dumps(anime_data))
-
- # attach metadata to episodes
- episode_metadata = get_episode_metadata(anime_data, last_watched)
-
- user_history_data.append({
- "anime_id": anime_id,
- "title": anime_data["title"],
- "cover": anime_data["cover"],
- "episode": last_watched,
- "metadata": episode_metadata
- })
-
- return user_history_data
+ return [dict(zip(columns, row)) for row in cursor.fetchall()]
+
+def get_bulk_anime_data(anime_ids):
+ anime_data_map = {}
+ missing_ids = []
+
+ # Check cache first (including potential caches from other functions)
+ for anime_id in anime_ids:
+ cached_data = get_cached_anime_data(anime_id)
+ if cached_data:
+ anime_data_map[anime_id] = cached_data
+ else:
+ missing_ids.append(anime_id)
+
+ # Fetch missing data in parallel
+ if missing_ids:
+ with ThreadPoolExecutor(max_workers=min(10, len(missing_ids))) as executor:
+ future_to_id = {executor.submit(fetch_anime_data, anime_id): anime_id for anime_id in missing_ids}
+ for future in as_completed(future_to_id):
+ anime_id = future_to_id[future]
+ try:
+ data = future.result()
+ anime_data_map[anime_id] = data
+ store_in_redis_cache(f"anime_{anime_id}_anime_data", json.dumps(data), 86400) # Cache for 24 hours
+ except Exception as exc:
+ print(f"Anime ID {anime_id} generated an exception: {exc}")
+
+ return anime_data_map
+
+def get_cached_anime_data(anime_id):
+ cache_keys = [
+ f"anime_{anime_id}_anime_data",
+ f"anime_{anime_id}_details", # Example of a cache key that might be used by another function
+ f"anime_info_{anime_id}" # Another example
+ ]
+
+ for key in cache_keys:
+ cached_data = get_from_redis_cache(key)
+ if cached_data:
+ return json.loads(cached_data)
+
+ return None
+
+@lru_cache(maxsize=1000)
+def fetch_anime_data(anime_id):
+ base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/info/{anime_id}?provider=zoro"
+ try:
+ response = requests.get(base_url, timeout=10)
+ response.raise_for_status()
+ return response.json()
+ except requests.RequestException as e:
+ print(f"Error fetching data for anime ID {anime_id}: {e}")
+ return None
def search_json(request):