aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--requirements.txt1
-rw-r--r--static/css/main.css56
-rw-r--r--templates/watch/watch.html96
-rw-r--r--watch/views.py41
-rw-r--r--yugen/settings.py4
5 files changed, 196 insertions, 2 deletions
diff --git a/requirements.txt b/requirements.txt
index 71ad648..2cf0e02 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ django
python-dotenv
psycopg2-binary
requests
+django-cors-headers
diff --git a/static/css/main.css b/static/css/main.css
index 65d12be..09a4a9b 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -749,6 +749,10 @@ video {
display: none;
}
+.aspect-video {
+ aspect-ratio: 16 / 9;
+}
+
.size-3 {
width: 0.75rem;
height: 0.75rem;
@@ -804,6 +808,18 @@ video {
height: 100%;
}
+.h-screen {
+ height: 100vh;
+}
+
+.h-\[56\.25\%\] {
+ height: 56.25%;
+}
+
+.h-0 {
+ height: 0px;
+}
+
.max-h-24 {
max-height: 6rem;
}
@@ -857,6 +873,14 @@ video {
width: max-content;
}
+.w-1\/4 {
+ width: 25%;
+}
+
+.w-3\/4 {
+ width: 75%;
+}
+
.max-w-7xl {
max-width: 80rem;
}
@@ -978,6 +1002,10 @@ video {
overflow: auto;
}
+.overflow-y-auto {
+ overflow-y: auto;
+}
+
.break-words {
overflow-wrap: break-word;
}
@@ -1289,6 +1317,26 @@ video {
background-color: rgb(250 204 21 / var(--tw-bg-opacity));
}
+.bg-gray-500 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(107 114 128 / var(--tw-bg-opacity));
+}
+
+.bg-gray-700 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(55 65 81 / var(--tw-bg-opacity));
+}
+
+.bg-gray-800 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
+}
+
+.bg-gray-900 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity));
+}
+
.bg-opacity-10 {
--tw-bg-opacity: 0.1;
}
@@ -1405,6 +1453,10 @@ video {
padding-top: 0.25rem;
}
+.pb-\[56\.25\%\] {
+ padding-bottom: 56.25%;
+}
+
.text-center {
text-align: center;
}
@@ -2133,6 +2185,10 @@ main {
display: none;
}
+ .lg\:h-auto {
+ height: auto;
+ }
+
.lg\:w-1\/2 {
width: 50%;
}
diff --git a/templates/watch/watch.html b/templates/watch/watch.html
index 7708ade..4961e61 100644
--- a/templates/watch/watch.html
+++ b/templates/watch/watch.html
@@ -1,5 +1,99 @@
{% extends "partials/base.html" %}
+{% block css %}
+<link rel="stylesheet" href="https://cdn.vidstack.io/player/theme.css" />
+<link rel="stylesheet" href="https://cdn.vidstack.io/player/audio.css" />
+<link rel="stylesheet" href="https://cdn.vidstack.io/player/video.css" />
+{% endblock css %}
{% block content %}
-Watch {{ anime_id }}/{{ episode }}
+<div class="flex flex-col lg:flex-row mt-4 gap-2">
+ <!-- Video Player Section (75%) -->
+ <div class="w-full lg:w-3/4">
+ <!-- Set a fixed height based on the 16:9 aspect ratio -->
+ <!-- This grey div is a placeholder for the video player -->
+ {% comment %} <div class="w-full h-0 lg:h-auto aspect-video bg-gray-500 flex items-center justify-center rounded"> {% endcomment %}
+ <div id="video-player" class="aspect-video">
+ </div>
+ </div>
+
+ <!-- Episode List Section (25%) -->
+ <div class="w-full lg:w-1/4 px-2 overflow-y-auto">
+ <h2 class="text-white text-xl font-bold mb-4">Episodes</h2>
+ <ul class="space-y-2">
+ <!-- Example Episode Items -->
+ <li class="bg-gray-700 text-white p-2 rounded">Episode 1: The Beginning</li>
+ <li class="bg-gray-700 text-white p-2 rounded">Episode 2: The Journey</li>
+ <li class="bg-gray-700 text-white p-2 rounded">Episode 3: The Encounter</li>
+ <!-- Add more episodes here -->
+ </ul>
+ </div>
+</div>
+
+{{ anime }}
+
{% endblock content %}
+{% block scripts %}
+<script type="module">
+ import { VidstackPlayer, VidstackPlayerLayout } from 'https://cdn.vidstack.io/player';
+
+ const layout = new VidstackPlayerLayout({
+ {% for track in episode.subtitles %}
+ {% if track.lang == "Thumbnails" %}
+ thumbnails: '{{ track.url }}',
+ {% endif %}
+ {% endfor %}
+ });
+
+ // thumbnails: 'https://files.vidstack.io/sprite-fight/thumbnails.vtt',
+ const player = await VidstackPlayer.create({
+ target: '#video-player',
+ autoStartLoad: true,
+ src: '{{ stream_url }}',
+ viewType: 'video',
+ streamType: 'on-demand',
+ logLevel: 'warn',
+ crossOrigin: true,
+ playsInline: true,
+ title: '{% 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 %} — Episode {{ current_episode }} ({% if request.GET.mode == "dub" %}Dub{% else %}Sub{% endif %})',
+ subtitlePreference: {
+ lang: 'English',
+ },
+ layout,
+ tracks: [
+ {% for track in episode.subtitles %}
+ {% if track.lang != "Thumbnails" %}
+ {
+ src: '{{ track.url }}',
+ label: '{{ track.lang }}',
+ kind: 'subtitles',
+ type: 'vtt',
+ lang: '{{ track.lang }}',
+ default: {% if forloop.first %}true{% else %}false{% endif %},
+ },
+ {% endif %}
+ {% endfor %}
+ ],
+ });
+
+ player.addEventListener('auto-play', (event) => {
+ const requestEvent = event.request;
+ });
+
+ // autoplay has failed.
+ player.addEventListener('auto-play-fail', (event) => {
+ const requestEvent = event.request;
+ console.log(event.detail.muted); // was media muted?
+ console.log(event.detail.error); // media error
+ });
+ /*const url = '{{ stream_url }}';
+
+ const player = await VidstackPlayer.create({
+ target: '#video-player',
+ title: '{{ anime.title }}',
+ src: url,
+ layout: new VidstackPlayerLayout({
+ thumbnails: 'https://files.vidstack.io/sprite-fight/thumbnails.vtt',
+ }),
+ });*/
+ </script>
+{% endblock scripts %}
diff --git a/watch/views.py b/watch/views.py
index cd85a8a..157cc18 100644
--- a/watch/views.py
+++ b/watch/views.py
@@ -1,6 +1,45 @@
+import os
+import dotenv
from django.shortcuts import render, redirect
+import requests
+
+dotenv.load_dotenv()
def watch(request, anime_id, episode=None):
if not episode or episode < 1:
return redirect("watch:watch_episode", anime_id=anime_id, episode=1)
- return render(request, "watch/watch.html", {"anime_id": anime_id, "episode": episode}) \ No newline at end of file
+
+ mode = request.GET.get("mode", "sub")
+
+ base_url = f"{os.getenv("CONSUMET_URL")}/meta/anilist/data/{anime_id}?provider=zoro"
+ response = requests.get(base_url)
+ anime_data = response.json()
+
+ base_url = f"{os.getenv("CONSUMET_URL")}/anime/zoro/{anime_data["title"]["english"]}?page=1"
+ response = requests.get(base_url)
+ anime_search_result = response.json()["results"][0]
+ anime_fetch_id = anime_search_result["id"]
+
+ base_url = f"{os.getenv("CONSUMET_URL")}/anime/zoro/info?id={anime_fetch_id}"
+ response = requests.get(base_url)
+ anime_info = response.json()
+ episodes = anime_info["episodes"]
+
+ if episode > anime_info["totalEpisodes"]:
+ return redirect("watch:watch_episode", anime_id=anime_id, episode=episodes)
+
+ # episode_d = [episode for episode in episodes if episode["number"] == episode]
+
+ ed = None
+ for e in episodes:
+ if e["number"] == episode:
+ ed = e
+ break
+
+ base_url = f"{os.getenv("CONSUMET_URL")}/anime/zoro/watch?episodeId={ed['id'].replace("sub", "").replace("dub", "").replace("both", "")}{mode}"
+ response = requests.get(base_url)
+ episode_data = response.json()
+
+ print(episode_data)
+
+ return render(request, "watch/watch.html", { "anime": anime_data, "episode": episode_data, "episodes": episodes, "current_episode": episode, "stream_url": episode_data["sources"][0]["url"] }) \ No newline at end of file
diff --git a/yugen/settings.py b/yugen/settings.py
index f1d9422..748582f 100644
--- a/yugen/settings.py
+++ b/yugen/settings.py
@@ -42,6 +42,7 @@ INSTALLED_APPS = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
+ "corsheaders",
"homepage",
"authentication",
"watch",
@@ -51,6 +52,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
+ "corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
@@ -61,6 +63,8 @@ MIDDLEWARE = [
"middleware.preferences.PreferencesMiddleware",
]
+CORS_ORIGIN_ALLOW_ALL = True
+
ROOT_URLCONF = "yugen.urls"
TEMPLATES = [