js another wed
This commit is contained in:
1 parent
2658c72a38
commit
812f775754
13 files changed
+810
-1137
No files matched your search
+147
-109
@@ -10,7 +10,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=DM+Sans:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
@@ -19,20 +19,22 @@
|
||||
/>
|
||||
<style>
|
||||
:root {
|
||||
--accent-color: #ff9500; /* Distinct Orange */
|
||||
--background-color: #121212;
|
||||
--background-color-secondary: #1e1e1e;
|
||||
--accent-color: #ff9500;
|
||||
--accent-glow: rgba(255, 149, 0, 0.35);
|
||||
--background-color: #0e0e0e;
|
||||
--background-color-secondary: #181818;
|
||||
--surface: #1c1c1c;
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #aaaaaa;
|
||||
--border-color: rgba(255, 255, 255, 0.15);
|
||||
--text-secondary: #999999;
|
||||
--border-color: rgba(255, 255, 255, 0.08);
|
||||
--shadow-medium: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||
--shadow-heavy: 0 20px 50px rgba(0, 0, 0, 0.7);
|
||||
--transition-smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
--radius-card: 14px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto, sans-serif;
|
||||
font-family: "Outfit", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
background-color: var(--background-color);
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
@@ -44,17 +46,17 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- Liquid Glass Navbar --- */
|
||||
/* --- Navbar --- */
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
padding: 20px 6%;
|
||||
padding: 22px 6%;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0.8) 0%,
|
||||
rgba(0, 0, 0, 0.85) 0%,
|
||||
transparent 100%
|
||||
);
|
||||
backdrop-filter: blur(0px);
|
||||
@@ -68,19 +70,20 @@
|
||||
}
|
||||
|
||||
.navbar.scrolled {
|
||||
background: rgba(18, 18, 18, 0.85);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
padding: 15px 6%;
|
||||
background: rgba(14, 14, 14, 0.92);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-bottom: 1px solid rgba(255, 149, 0, 0.08);
|
||||
padding: 14px 6%;
|
||||
box-shadow: 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
|
||||
.navbar svg {
|
||||
display: block;
|
||||
margin: 0;
|
||||
height: 40px;
|
||||
height: 38px;
|
||||
width: auto;
|
||||
opacity: 0.9;
|
||||
opacity: 0.92;
|
||||
transition: opacity 0.4s ease-out;
|
||||
}
|
||||
|
||||
@@ -91,8 +94,8 @@
|
||||
/* --- Hero Section Cinematic Carousel --- */
|
||||
#hero-section {
|
||||
position: relative;
|
||||
height: 65vh;
|
||||
min-height: 600px;
|
||||
height: 68vh;
|
||||
min-height: 580px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -197,39 +200,41 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
padding: 14px 32px;
|
||||
border-radius: 8px;
|
||||
gap: 10px;
|
||||
padding: 13px 30px;
|
||||
border-radius: 10px;
|
||||
font-family: "Outfit", sans-serif;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
font-size: 1.1rem;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s var(--transition-smooth);
|
||||
border: 1px solid transparent;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.hero-btn.play-btn {
|
||||
background-color: #ff9500;
|
||||
background-color: var(--accent-color);
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 20px var(--accent-glow);
|
||||
}
|
||||
|
||||
.hero-btn.play-btn:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: var(--accent-color);
|
||||
color: #fff;
|
||||
box-shadow: 0 0 30px rgba(255, 149, 0, 0.4);
|
||||
transform: scale(1.05) translateY(-1px);
|
||||
box-shadow: 0 8px 32px rgba(255, 149, 0, 0.55);
|
||||
}
|
||||
|
||||
.hero-btn.info-btn {
|
||||
background-color: rgba(100, 100, 100, 0.4);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
backdrop-filter: blur(10px);
|
||||
backdrop-filter: blur(12px);
|
||||
border-color: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.hero-btn.info-btn:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
transform: scale(1.05);
|
||||
background-color: rgba(255, 255, 255, 0.18);
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
transform: scale(1.05) translateY(-1px);
|
||||
}
|
||||
|
||||
.hero-dots {
|
||||
@@ -266,13 +271,13 @@
|
||||
@media (max-width: 768px) {
|
||||
.navbar {
|
||||
justify-content: center;
|
||||
padding: 15px 6%;
|
||||
padding: 14px 6%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#hero-section {
|
||||
height: 55vh;
|
||||
min-height: 400px;
|
||||
height: 58vh;
|
||||
min-height: 380px;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
@@ -283,25 +288,25 @@
|
||||
|
||||
.hero-logo {
|
||||
object-position: center bottom;
|
||||
max-width: 80%;
|
||||
margin-bottom: 20px;
|
||||
max-width: 78%;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
margin-top: -10px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
||||
.hero-background::after {
|
||||
background: radial-gradient(
|
||||
circle at 50% 35%,
|
||||
transparent 0%,
|
||||
rgba(18, 18, 18, 0.2) 40%,
|
||||
rgba(14, 14, 14, 0.2) 40%,
|
||||
var(--background-color) 120%
|
||||
),
|
||||
linear-gradient(
|
||||
to right,
|
||||
var(--background-color) 0%,
|
||||
rgba(18, 18, 18, 0.4) 50%,
|
||||
rgba(14, 14, 14, 0.4) 50%,
|
||||
transparent 100%
|
||||
),
|
||||
linear-gradient(to top, var(--background-color) 0%, transparent 40%);
|
||||
@@ -311,40 +316,38 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* --- UPDATED MOBILE CARD SIZES --- */
|
||||
.horizontal-scroll-container {
|
||||
gap: 12px !important; /* Tighter gap so more fit on screen */
|
||||
gap: 10px !important;
|
||||
margin-bottom: -40px;
|
||||
}
|
||||
|
||||
.poster-container {
|
||||
max-width: 150px; /* Reduced Width (Fits ~3-4 cards per row) */
|
||||
max-width: 140px;
|
||||
}
|
||||
|
||||
.poster-title {
|
||||
font-size: 0.8rem; /* Smaller Font */
|
||||
margin-top: 8px;
|
||||
font-size: 0.78rem;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.episode-indicator {
|
||||
font-size: 0.65rem; /* Smaller badge */
|
||||
padding: 2px 6px;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
font-size: 0.62rem;
|
||||
padding: 2px 5px;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.poster-image-wrapper {
|
||||
max-width: 150px;
|
||||
max-width: 140px;
|
||||
}
|
||||
|
||||
.poster-info-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 0.8rem;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
font-size: 0.75rem;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
/* -------------------------------- */
|
||||
|
||||
.hero-buttons {
|
||||
justify-content: center;
|
||||
@@ -356,6 +359,31 @@
|
||||
transform: translateX(-50%) translateY(-450%);
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 1440p desktop tweaks */
|
||||
@media (min-width: 1400px) {
|
||||
.poster-container {
|
||||
width: 210px;
|
||||
}
|
||||
#hero-section {
|
||||
height: 62vh;
|
||||
min-height: 640px;
|
||||
}
|
||||
.hero-content {
|
||||
max-width: 44%;
|
||||
}
|
||||
.hero-logo {
|
||||
max-width: 420px;
|
||||
}
|
||||
}
|
||||
|
||||
.loader {
|
||||
@@ -379,33 +407,36 @@
|
||||
|
||||
/* --- Content Sections --- */
|
||||
.content-section {
|
||||
margin-bottom: 50px;
|
||||
margin-bottom: 48px;
|
||||
padding: 0 0 0 6%;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.content-section:first-of-type {
|
||||
margin-top: -60px;
|
||||
margin-top: -70px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.5rem;
|
||||
font-size: 1.35rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.01em;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
font-family: "Outfit", sans-serif;
|
||||
}
|
||||
|
||||
.section-title::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 4px;
|
||||
height: 24px;
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 2px;
|
||||
width: 3px;
|
||||
height: 20px;
|
||||
background: linear-gradient(to bottom, var(--accent-color), rgba(255,149,0,0.3));
|
||||
border-radius: 3px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.horizontal-scroll-container {
|
||||
@@ -434,28 +465,28 @@
|
||||
/* --- Poster Cards --- */
|
||||
.poster-container {
|
||||
flex-shrink: 0;
|
||||
width: 220px; /* Desktop Width */
|
||||
width: 200px;
|
||||
position: relative;
|
||||
transition: z-index 0.3s, transform 0.3s;
|
||||
}
|
||||
|
||||
.poster-image-wrapper {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
border-radius: var(--radius-card);
|
||||
overflow: hidden;
|
||||
aspect-ratio: 2/3;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
|
||||
transition: transform 0.4s var(--transition-smooth),
|
||||
box-shadow 0.4s var(--transition-smooth), border-color 0.3s;
|
||||
border: 2px solid transparent;
|
||||
background-color: #2a2a2a;
|
||||
border: 1.5px solid transparent;
|
||||
background-color: var(--surface);
|
||||
}
|
||||
|
||||
.poster-image-wrapper img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: filter 0.3s;
|
||||
transition: filter 0.3s, transform 0.4s var(--transition-smooth);
|
||||
}
|
||||
|
||||
.poster-container:hover {
|
||||
@@ -463,28 +494,31 @@
|
||||
}
|
||||
|
||||
.poster-container:hover .poster-image-wrapper {
|
||||
transform: scale(1) translateY(-5px);
|
||||
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.6);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
transform: scale(1) translateY(-6px);
|
||||
box-shadow: 0 18px 45px rgba(0, 0, 0, 0.65), 0 0 0 1px rgba(255,149,0,0.15);
|
||||
border-color: rgba(255, 149, 0, 0.2);
|
||||
}
|
||||
|
||||
.poster-container:hover .poster-image-wrapper img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
.poster-title {
|
||||
margin-top: 15px;
|
||||
font-size: 1rem;
|
||||
margin-top: 12px;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
transition: color 0.3s, opacity 0.3s;
|
||||
padding: 0 5px;
|
||||
transition: color 0.3s;
|
||||
padding: 0 4px;
|
||||
font-family: "DM Sans", sans-serif;
|
||||
}
|
||||
|
||||
.poster-container:hover .poster-title {
|
||||
color: var(--text-primary);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
@@ -492,53 +526,56 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
height: 3px;
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.progress-bar-inner {
|
||||
height: 100%;
|
||||
background-color: var(--accent-color);
|
||||
box-shadow: 0 0 10px var(--accent-color);
|
||||
background: linear-gradient(to right, var(--accent-color), #ffb340);
|
||||
box-shadow: 0 0 8px var(--accent-glow);
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
.episode-indicator {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
left: auto;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
background-color: rgba(0, 0, 0, 0.72);
|
||||
color: #fff;
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
padding: 3px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
z-index: 2;
|
||||
backdrop-filter: blur(4px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
letter-spacing: 0.5px;
|
||||
backdrop-filter: blur(6px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
letter-spacing: 0.4px;
|
||||
font-family: "Outfit", sans-serif;
|
||||
}
|
||||
|
||||
.poster-info-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
right: auto;
|
||||
z-index: 3;
|
||||
background-color: rgba(30, 30, 30, 0.8);
|
||||
background-color: rgba(20, 20, 20, 0.82);
|
||||
color: #fff;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transform: translateY(-8px);
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.poster-container:hover .poster-info-btn {
|
||||
@@ -547,8 +584,9 @@
|
||||
}
|
||||
|
||||
.poster-info-btn:hover {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
background-color: var(--accent-color);
|
||||
border-color: var(--accent-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* --- Context Menu --- */
|
||||
@@ -573,12 +611,12 @@
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
width: 380px;
|
||||
width: 340px;
|
||||
max-width: 90%;
|
||||
background-color: #1e1e1e;
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--shadow-heavy);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background-color: #1c1c1c;
|
||||
border-radius: 18px;
|
||||
box-shadow: var(--shadow-heavy), 0 0 0 1px rgba(255,255,255,0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
transform: scale(0.95) translateY(20px);
|
||||
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
overflow: hidden;
|
||||
|
||||
+148
-31
@@ -1083,7 +1083,7 @@
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.4s ease, transform 0.4s ease;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.06) inset;
|
||||
}
|
||||
#startup-status.visible {
|
||||
opacity: 1;
|
||||
@@ -1095,6 +1095,7 @@
|
||||
border-radius: 50%;
|
||||
background: #ff9500;
|
||||
box-shadow: 0 0 10px #ff9500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#startup-status .status-dot.active {
|
||||
animation: blink 1s infinite;
|
||||
@@ -1105,14 +1106,14 @@
|
||||
animation: none;
|
||||
}
|
||||
#startup-status span {
|
||||
color: #fff;
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255,255,255,0.85);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.02em;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
@keyframes blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
||||
/* --- UPDATED: Ambient U-Glow --- */
|
||||
@@ -1313,8 +1314,9 @@
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: var(--color-bg-overlay);
|
||||
backdrop-filter: blur(8px);
|
||||
background: rgba(0,0,0,0.8);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
display: flex;
|
||||
place-items: center;
|
||||
justify-content: center;
|
||||
@@ -1329,33 +1331,37 @@
|
||||
pointer-events: auto;
|
||||
}
|
||||
.modal-content {
|
||||
background: var(--color-bg-modal);
|
||||
padding: var(--spacing-lg) var(--spacing-lg);
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
||||
background: #1c1c1e;
|
||||
background-image: linear-gradient(145deg, rgba(255,255,255,0.03) 0%, transparent 60%);
|
||||
padding: 28px 28px 24px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(255,255,255,0.04) inset;
|
||||
text-align: center;
|
||||
max-width: 28rem;
|
||||
width: 100%;
|
||||
transform: scale(0.95);
|
||||
transition: transform var(--transition-medium);
|
||||
transform: scale(0.94) translateY(12px);
|
||||
transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
.modal-overlay.active .modal-content {
|
||||
transform: scale(1);
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
.modal-content h2 {
|
||||
margin-bottom: var(--spacing);
|
||||
font-size: 1.75rem;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 400;
|
||||
color: var(--text-primary);
|
||||
font-family: "Bitcount Grid Single";
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
.modal-content p {
|
||||
margin-bottom: var(--spacing-lg);
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.65;
|
||||
color: var(--text-secondary);
|
||||
font-family: Tahoma;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
.modal-content a {
|
||||
color: var(--accent);
|
||||
@@ -1372,36 +1378,42 @@
|
||||
.ip-input-container { margin-bottom: var(--spacing-lg); }
|
||||
.ip-input {
|
||||
width: 90%;
|
||||
background: var(--color-bg-input);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius);
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 10px;
|
||||
padding: var(--spacing) calc(var(--spacing) * 1.25);
|
||||
font-size: 1.1rem;
|
||||
font-size: 1.05rem;
|
||||
color: var(--text-primary);
|
||||
text-align: center;
|
||||
outline: none;
|
||||
transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
|
||||
font-family: "Inter", sans-serif;
|
||||
transition: box-shadow var(--transition-fast), border-color var(--transition-fast), background var(--transition-fast);
|
||||
}
|
||||
.ip-input:focus {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 0.25rem var(--accent-fade);
|
||||
background: rgba(255, 149, 0, 0.06);
|
||||
box-shadow: 0 0 0 3px var(--accent-fade);
|
||||
}
|
||||
.ip-input::placeholder { color: rgba(255,255,255,0.25); }
|
||||
|
||||
.connect-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: var(--spacing) 0;
|
||||
padding: 14px 0;
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
font-size: 1.1rem;
|
||||
border-radius: 10px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), box-shadow var(--transition-fast);
|
||||
letter-spacing: 0.02em;
|
||||
font-family: "Inter", sans-serif;
|
||||
transition: background var(--transition-fast), box-shadow var(--transition-fast), transform 0.1s;
|
||||
}
|
||||
.connect-button:hover { background: var(--accent-light); }
|
||||
.connect-button:focus { outline: none; box-shadow: 0 0 0 0.25rem var(--accent-fade); }
|
||||
.connect-button:hover { background: var(--accent-light); box-shadow: 0 4px 16px rgba(255,149,0,0.35); }
|
||||
.connect-button:active { transform: scale(0.98); }
|
||||
.connect-button:focus { outline: none; box-shadow: 0 0 0 3px var(--accent-fade); }
|
||||
|
||||
.status-indicator {
|
||||
margin-top: var(--spacing-sm);
|
||||
@@ -1577,6 +1589,71 @@
|
||||
.toast-message.success .toast-icon { color: #34c759; }
|
||||
.toast-message.error .toast-icon { color: #ff3b30; }
|
||||
.toast-message.info .toast-icon { color: #007aff; }
|
||||
/* --- TUNNEL WARNING MODAL --- */
|
||||
.tunnel-warning-content {
|
||||
max-width: 30rem !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
.tunnel-warning-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 149, 0, 0.12);
|
||||
border: 1px solid rgba(255, 149, 0, 0.25);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.tunnel-warning-icon i {
|
||||
font-size: 1.5rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
.tunnel-warning-content h2 {
|
||||
text-align: left !important;
|
||||
font-size: 1.4rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
.tunnel-warning-content p {
|
||||
text-align: left !important;
|
||||
margin-bottom: 10px !important;
|
||||
font-size: 0.95rem !important;
|
||||
}
|
||||
.tunnel-subtext {
|
||||
color: rgba(179, 179, 181, 0.7) !important;
|
||||
font-size: 0.85rem !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
.tunnel-warning-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.tunnel-refresh-btn {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.tunnel-dismiss-btn {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
border-radius: var(--radius);
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
padding: var(--spacing) 0;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast), color var(--transition-fast);
|
||||
font-family: "Inter", sans-serif;
|
||||
width: 100%;
|
||||
}
|
||||
.tunnel-dismiss-btn:hover {
|
||||
background: rgba(255,255,255,0.07);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<!-- Initialize Alpine Global Player State -->
|
||||
@@ -1839,6 +1916,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tunnel Warning Modal -->
|
||||
<div id="tunnel-warning-modal" class="modal-overlay">
|
||||
<div class="modal-content tunnel-warning-content">
|
||||
<div class="tunnel-warning-icon">
|
||||
<i class="fas fa-plug-circle-exclamation"></i>
|
||||
</div>
|
||||
<h2>Service Disruption</h2>
|
||||
<p>
|
||||
Some features are temporarily unavailable. Our backend service is experiencing connectivity issues — live streaming, search suggestions, and syncing may not work as expected.
|
||||
</p>
|
||||
<p class="tunnel-subtext">
|
||||
This is usually resolved automatically. Try refreshing in a few minutes, or continue browsing with limited functionality.
|
||||
</p>
|
||||
<div class="tunnel-warning-actions">
|
||||
<button id="tunnel-refresh-btn" class="connect-button tunnel-refresh-btn">
|
||||
<i class="fas fa-rotate-right"></i> Refresh Page
|
||||
</button>
|
||||
<button id="tunnel-dismiss-btn" class="tunnel-dismiss-btn">
|
||||
Continue Anyway
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fullscreen Iframe Popup -->
|
||||
<div id="iframe-popup-overlay">
|
||||
<div class="popup-content-wrapper">
|
||||
@@ -2329,6 +2430,10 @@
|
||||
setTimeout(() => {
|
||||
serverModal.classList.remove("active");
|
||||
}, 1000);
|
||||
// Check tunnel health
|
||||
if (data.tunnel_active === false) {
|
||||
setTimeout(() => showTunnelWarning(), 1200);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2353,6 +2458,18 @@
|
||||
}
|
||||
});
|
||||
|
||||
function showTunnelWarning() {
|
||||
const modal = document.getElementById("tunnel-warning-modal");
|
||||
if (!modal) return;
|
||||
modal.classList.add("active");
|
||||
document.getElementById("tunnel-refresh-btn").addEventListener("click", () => {
|
||||
window.location.reload();
|
||||
});
|
||||
document.getElementById("tunnel-dismiss-btn").addEventListener("click", () => {
|
||||
modal.classList.remove("active");
|
||||
});
|
||||
}
|
||||
|
||||
async function initApp() {
|
||||
const isDeployed = window.location.protocol.startsWith("http");
|
||||
await delay(500);
|
||||
|
||||
@@ -154,7 +154,6 @@
|
||||
background-color: var(--brand-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
/* New Find Icon Button */
|
||||
.btn-icon-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -697,7 +696,7 @@
|
||||
|
||||
async function loadJikanMetadata() {
|
||||
const detRes = await fetch(
|
||||
`https://api.jikan.moe/v4/manga/${state.mangaId}/full`,
|
||||
`${serverUrl}/jikan/manga/${state.mangaId}/full`,
|
||||
);
|
||||
if (!detRes.ok) throw new Error("Jikan API Error");
|
||||
const data = (await detRes.json()).data;
|
||||
@@ -740,7 +739,11 @@
|
||||
|
||||
async function loadFusedChapters() {
|
||||
try {
|
||||
const chRes = await fetch(`${serverUrl}/chapters/${state.mangaId}`);
|
||||
const isFinished = state.mangaDetails && (
|
||||
state.mangaDetails.status.toLowerCase() === "finished" ||
|
||||
state.mangaDetails.status.toLowerCase() === "completed"
|
||||
);
|
||||
const chRes = await fetch(`${serverUrl}/chapters/${state.mangaId}?finished=${isFinished}`);
|
||||
if (!chRes.ok) return;
|
||||
const chData = await chRes.json();
|
||||
let modulesMap = chData.modules || {};
|
||||
@@ -1023,7 +1026,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// --- New Logic: Find & Animate ---
|
||||
// --- Logic: Find & Animate ---
|
||||
function findChapterInList(chapterNum) {
|
||||
// 1. Find index in currently filtered chapter list
|
||||
const index = state.chapters.findIndex(
|
||||
|
||||
+415
-984
File diff suppressed because it is too large.
Load diff
+24
-5
@@ -838,12 +838,19 @@ body {
|
||||
display: none; /* Hide the main title */
|
||||
}
|
||||
.episode-list.grid-view.thumbnails-hidden .episode-title-romanji {
|
||||
font-size: 0.9rem; /* Match the desired font size */
|
||||
display: none; /* Hide the "Episode X" romanji text in compact mode */
|
||||
}
|
||||
/* Episode number badge shown only in no-thumbnail tile mode */
|
||||
.episode-list.grid-view.thumbnails-hidden .ep-number-badge {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
font-weight: 800;
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
display: block; /* Make the romanji title visible */
|
||||
color: var(--text-primary); /* Ensure it's visible, not muted */
|
||||
font-weight: 700; /* Make it bolder */
|
||||
line-height: 1;
|
||||
}
|
||||
.ep-number-badge {
|
||||
display: none; /* Hidden in all other modes */
|
||||
}
|
||||
.episode-list.grid-view.thumbnails-hidden .episode-progress-wrapper,
|
||||
.episode-list.grid-view.thumbnails-hidden .episode-action-buttons {
|
||||
@@ -1240,6 +1247,17 @@ body {
|
||||
.popup-close:hover { background: #fff; color: #000; transform: rotate(90deg) scale(1.1); }
|
||||
iframe { width: 100%; height: 100%; border: none; }
|
||||
|
||||
/* Shrink player modal on 1080p / shorter screens */
|
||||
@media (max-height: 900px) and (min-width: 1024px) {
|
||||
.episode-popup-content {
|
||||
width: 88%;
|
||||
max-width: 1200px;
|
||||
aspect-ratio: unset;
|
||||
height: 82vh;
|
||||
max-height: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
12. RX GATE MODAL (PHASE 1 MODERNIZATION)
|
||||
========================================= */
|
||||
@@ -1849,6 +1867,7 @@ iframe { width: 100%; height: 100%; border: none; }
|
||||
<div class="episode-info">
|
||||
<div class="episode-title">${ep.attributes.canonicalTitle || 'Episode ' + num}</div>
|
||||
<div class="episode-title-romanji">Episode ${num}</div>
|
||||
<span class="ep-number-badge">${num}</span>
|
||||
${progressHtml}
|
||||
</div>
|
||||
<div class="episode-action-buttons"><i class="fas ${isFinished ? 'fa-rotate-right' : 'fa-play'}"></i></div>
|
||||
|
||||
@@ -582,7 +582,6 @@ async def websocket_tunnel(websocket: WebSocket, token: str = Query(...)):
|
||||
|
||||
# --- Core Endpoints ---
|
||||
|
||||
|
||||
# --- MISSING HELPERS & GRAPHQL QUERIES ---
|
||||
|
||||
def _get_cover_url_from_manga(manga: Dict[str, Any]) -> Optional[str]:
|
||||
@@ -666,6 +665,36 @@ async def proxy_image(url: str):
|
||||
res = await tunnel_request("GET", url)
|
||||
return Response(content=base64.b64decode(res["body"]), media_type=res["headers"].get("content-type"))
|
||||
|
||||
|
||||
# --- JIKAN METADATA & CACHING ---
|
||||
@app.get("/jikan/manga/{mal_id}/full")
|
||||
async def get_jikan_manga_full(mal_id: int):
|
||||
cache_key = f"jikan_manga_full_{mal_id}"
|
||||
|
||||
# Default valid 1 day TTL
|
||||
cached = load_named_cache(cache_key, ttl=86400)
|
||||
if not cached:
|
||||
# Check if there's a cache valid within 1 week (For Finished Series)
|
||||
cached_week = load_named_cache(cache_key, ttl=604800)
|
||||
if cached_week and cached_week.get("publishing") is False:
|
||||
cached = cached_week
|
||||
|
||||
if cached:
|
||||
return {"data": cached}
|
||||
|
||||
# Fetch from Jikan via tunnel/proxy if no valid cache
|
||||
url = f"https://api.jikan.moe/v4/manga/{mal_id}/full"
|
||||
r = await hybrid_client.get(url, timeout=15)
|
||||
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=r.status_code, detail="Jikan API error")
|
||||
|
||||
data = r.json().get("data", {})
|
||||
save_named_cache(cache_key, data)
|
||||
|
||||
return {"data": data}
|
||||
|
||||
|
||||
# --- MangaDex Tunnel Support ---
|
||||
MANGADEX_API_URL = "https://api.mangadex.org"
|
||||
|
||||
@@ -705,10 +734,27 @@ async def list_mangadex(
|
||||
|
||||
@app.get("/mangadex/manga/{manga_id}")
|
||||
async def get_mangadex_manga_details(manga_id: str):
|
||||
cache_key = f"mangadex_manga_{manga_id}"
|
||||
|
||||
# Fast access caching
|
||||
cached = load_named_cache(cache_key, ttl=86400)
|
||||
if not cached:
|
||||
cached_week = load_named_cache(cache_key, ttl=604800)
|
||||
# Check MangaDex "status" string
|
||||
if cached_week and cached_week.get("attributes", {}).get("status") in ["completed", "cancelled"]:
|
||||
cached = cached_week
|
||||
|
||||
if cached:
|
||||
if "image_url" not in cached:
|
||||
cached["image_url"] = _get_cover_url_from_manga(cached)
|
||||
return cached
|
||||
|
||||
url = f"{MANGADEX_API_URL}/manga/{manga_id}?includes[]=cover_art&includes[]=author&includes[]=artist"
|
||||
res = await tunnel_request("GET", url)
|
||||
data = json.loads(base64.b64decode(res["body"])).get("data")
|
||||
if data: data["image_url"] = _get_cover_url_from_manga(data)
|
||||
if data:
|
||||
data["image_url"] = _get_cover_url_from_manga(data)
|
||||
save_named_cache(cache_key, data)
|
||||
return data
|
||||
|
||||
@app.get("/mangadex/manga/{manga_id}/chapters")
|
||||
@@ -991,14 +1037,25 @@ async def get_manga_banner(mal_id: int, cover: bool = False):
|
||||
# --- RESTORED MODULE INTERFACING & DOWNLOADS ---
|
||||
|
||||
@app.get("/chapters/{mal_id}")
|
||||
async def get_manga_chapters_module(mal_id: int):
|
||||
async def get_manga_chapters_module(mal_id: str, finished: bool = Query(False)):
|
||||
cache_key = f"manga_chapters_{mal_id}"
|
||||
|
||||
# Condition: 1 week (604800) if finished boolean passed by frontend, else 4 hours (14400)
|
||||
ttl = 604800 if finished else 14400
|
||||
|
||||
cached = load_named_cache(cache_key, ttl=ttl)
|
||||
if cached:
|
||||
return {"modules": cached}
|
||||
|
||||
all_modules_results = {}
|
||||
|
||||
for mid, mdata in loaded_modules.items():
|
||||
if module_states.get(mid) and "MANGA_READER" in mdata["info"].get("type",[]):
|
||||
try:
|
||||
mdata["instance"].httpx = hybrid_client
|
||||
chaps = await mdata["instance"].get_chapters(mal_id)
|
||||
# Standard ID Parsing: Jikan IDs expect INT, UUIDs remain STR for Mangadex
|
||||
parsed_id = int(mal_id) if mal_id.isdigit() else mal_id
|
||||
chaps = await mdata["instance"].get_chapters(parsed_id)
|
||||
if chaps is not None:
|
||||
all_modules_results[mid] = chaps
|
||||
except Exception as e:
|
||||
@@ -1006,6 +1063,7 @@ async def get_manga_chapters_module(mal_id: int):
|
||||
pass
|
||||
|
||||
if all_modules_results:
|
||||
save_named_cache(cache_key, all_modules_results)
|
||||
return {"modules": all_modules_results}
|
||||
|
||||
raise HTTPException(status_code=404, detail="No chapters found from any module")
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"comix": [{"title": "S3 Start", "url": "emqg8:solo-leveling:8872908", "chapter_number": "201", "is_external": false}, {"title": "Chapter 200", "url": "emqg8:solo-leveling:2749754", "chapter_number": "200", "is_external": false}, {"title": "Chapter 199", "url": "emqg8:solo-leveling:2749680", "chapter_number": "199", "is_external": false}, {"title": "Chapter 198", "url": "emqg8:solo-leveling:2749654", "chapter_number": "198", "is_external": false}, {"title": "Chapter 197", "url": "emqg8:solo-leveling:2749621", "chapter_number": "197", "is_external": false}, {"title": "Chapter 196", "url": "emqg8:solo-leveling:2749588", "chapter_number": "196", "is_external": false}, {"title": "Chapter 195", "url": "emqg8:solo-leveling:2749516", "chapter_number": "195", "is_external": false}, {"title": "Chapter 194", "url": "emqg8:solo-leveling:2749486", "chapter_number": "194", "is_external": false}, {"title": "Chapter 193", "url": "emqg8:solo-leveling:2749419", "chapter_number": "193", "is_external": false}, {"title": "Chapter 192", "url": "emqg8:solo-leveling:2749352", "chapter_number": "192", "is_external": false}, {"title": "Chapter 191", "url": "emqg8:solo-leveling:2749287", "chapter_number": "191", "is_external": false}, {"title": "Chapter 190", "url": "emqg8:solo-leveling:2749249", "chapter_number": "190", "is_external": false}, {"title": "Chapter 189", "url": "emqg8:solo-leveling:2749217", "chapter_number": "189", "is_external": false}, {"title": "Chapter 188", "url": "emqg8:solo-leveling:2749148", "chapter_number": "188", "is_external": false}, {"title": "Chapter 187", "url": "emqg8:solo-leveling:2749064", "chapter_number": "187", "is_external": false}, {"title": "Chapter 186", "url": "emqg8:solo-leveling:2748994", "chapter_number": "186", "is_external": false}, {"title": "Chapter 185", "url": "emqg8:solo-leveling:2748965", "chapter_number": "185", "is_external": false}, {"title": "Chapter 184", "url": "emqg8:solo-leveling:2748933", "chapter_number": "184", "is_external": false}, {"title": "Chapter 183", "url": "emqg8:solo-leveling:2748875", "chapter_number": "183", "is_external": false}, {"title": "Chapter 182", "url": "emqg8:solo-leveling:2748842", "chapter_number": "182", "is_external": false}, {"title": "Chapter 181", "url": "emqg8:solo-leveling:2748772", "chapter_number": "181", "is_external": false}, {"title": "Chapter 180", "url": "emqg8:solo-leveling:2748744", "chapter_number": "180", "is_external": false}, {"title": "Chapter 179", "url": "emqg8:solo-leveling:2748672", "chapter_number": "179", "is_external": false}, {"title": "Chapter 178", "url": "emqg8:solo-leveling:2748640", "chapter_number": "178", "is_external": false}, {"title": "Chapter 177", "url": "emqg8:solo-leveling:2748574", "chapter_number": "177", "is_external": false}, {"title": "Chapter 176", "url": "emqg8:solo-leveling:2748545", "chapter_number": "176", "is_external": false}, {"title": "Chapter 175", "url": "emqg8:solo-leveling:2748506", "chapter_number": "175", "is_external": false}, {"title": "Chapter 174", "url": "emqg8:solo-leveling:2748447", "chapter_number": "174", "is_external": false}, {"title": "Chapter 173", "url": "emqg8:solo-leveling:2748393", "chapter_number": "173", "is_external": false}, {"title": "Chapter 172", "url": "emqg8:solo-leveling:2748295", "chapter_number": "172", "is_external": false}, {"title": "Chapter 171", "url": "emqg8:solo-leveling:2748234", "chapter_number": "171", "is_external": false}, {"title": "Chapter 170", "url": "emqg8:solo-leveling:2748161", "chapter_number": "170", "is_external": false}, {"title": "Chapter 169", "url": "emqg8:solo-leveling:2748137", "chapter_number": "169", "is_external": false}, {"title": "Chapter 168", "url": "emqg8:solo-leveling:2748062", "chapter_number": "168", "is_external": false}, {"title": "Chapter 167", "url": "emqg8:solo-leveling:2747987", "chapter_number": "167", "is_external": false}, {"title": "Chapter 166", "url": "emqg8:solo-leveling:2747949", "chapter_number": "166", "is_external": false}, {"title": "Chapter 165", "url": "emqg8:solo-leveling:2747890", "chapter_number": "165", "is_external": false}, {"title": "Chapter 164", "url": "emqg8:solo-leveling:2747817", "chapter_number": "164", "is_external": false}, {"title": "Chapter 163", "url": "emqg8:solo-leveling:2747751", "chapter_number": "163", "is_external": false}, {"title": "Chapter 162", "url": "emqg8:solo-leveling:2747670", "chapter_number": "162", "is_external": false}, {"title": "Chapter 161", "url": "emqg8:solo-leveling:2747640", "chapter_number": "161", "is_external": false}, {"title": "Chapter 160", "url": "emqg8:solo-leveling:2747606", "chapter_number": "160", "is_external": false}, {"title": "Chapter 159", "url": "emqg8:solo-leveling:2747545", "chapter_number": "159", "is_external": false}, {"title": "Chapter 158", "url": "emqg8:solo-leveling:2747511", "chapter_number": "158", "is_external": false}, {"title": "Chapter 157", "url": "emqg8:solo-leveling:2747486", "chapter_number": "157", "is_extLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"mal_id": 121496, "url": "https://myanimelist.net/manga/121496/Solo_Leveling", "images": {"jpg": {"image_url": "https://myanimelist.net/images/manga/3/222295.jpg", "small_image_url": "https://myanimelist.net/images/manga/3/222295t.jpg", "large_image_url": "https://myanimelist.net/images/manga/3/222295l.jpg"}, "webp": {"image_url": "https://myanimelist.net/images/manga/3/222295.webp", "small_image_url": "https://myanimelist.net/images/manga/3/222295t.webp", "large_image_url": "https://myanimelist.net/images/manga/3/222295l.webp"}}, "approved": true, "titles": [{"type": "Default", "title": "Solo Leveling"}, {"type": "Synonym", "title": "Na Honjaman Level Up"}, {"type": "Synonym", "title": "I Level Up Alone"}, {"type": "Japanese", "title": "\ub098 \ud63c\uc790\ub9cc \ub808\ubca8\uc5c5"}, {"type": "English", "title": "Solo Leveling"}], "title": "Solo Leveling", "title_english": "Solo Leveling", "title_japanese": "\ub098 \ud63c\uc790\ub9cc \ub808\ubca8\uc5c5", "title_synonyms": ["Na Honjaman Level Up", "I Level Up Alone"], "type": "Manhwa", "chapters": 201, "volumes": null, "status": "Finished", "publishing": false, "published": {"from": "2018-03-04T00:00:00+00:00", "to": "2023-05-31T00:00:00+00:00", "prop": {"from": {"day": 4, "month": 3, "year": 2018}, "to": {"day": 31, "month": 5, "year": 2023}}, "string": "Mar 4, 2018 to May 31, 2023"}, "score": 8.58, "scored": 8.58, "scored_by": 366082, "rank": 122, "popularity": 5, "members": 613063, "favorites": 47318, "synopsis": "Ten years ago, \"the Gate\" appeared and connected the real world with the realm of magic and monsters. To combat these vile beasts, ordinary people received superhuman powers and became known as \"Hunters.\" Twenty-year-old Sung Jin-Woo is one such Hunter, but he is known as the \"World's Weakest,\" owing to his pathetic power compared to even a measly E-Rank. Still, he hunts monsters tirelessly in low-rank Gates to pay for his mother's medical bills. \n\nHowever, this miserable lifestyle changes when Jin-Woo\u2014believing himself to be the only one left to die in a mission gone terribly wrong\u2014awakens in a hospital three days later to find a mysterious screen floating in front of him. This \"Quest Log\" demands that Jin-Woo completes an unrealistic and intense training program, or face an appropriate penalty. Initially reluctant to comply because of the quest's rigor, Jin-Woo soon finds that it may just transform him into one of the world's most fearsome Hunters. \n\n[Written by MAL Rewrite]", "background": "Solo Leveling is a webtoon series which has been officially published in book format by D&C Media (\ub514\uc564\uc528\ubbf8\ub514\uc5b4) since September 26, 2019. It originally ended with 179 chapters on December 29, 2021, and side stories began serialization on January 20, 2023. The side stories are drawn by Disciples after the death of original artist Sung-rak Jang. The series has been published digitally in English by Tappytoon since June 4, 2020, and in print by Yen Press since March 2, 2021. It has also been published in French by Delcourt since April 7, 2021; and in Italian by Edizioni Star Comics since April 21, 2021.", "authors": [{"mal_id": 49667, "type": "people", "name": "Chugong", "url": "https://myanimelist.net/people/49667/Chugong"}, {"mal_id": 49668, "type": "people", "name": "Jang, Sung-rak", "url": "https://myanimelist.net/people/49668/Sung-rak_Jang"}, {"mal_id": 63820, "type": "people", "name": "Disciples", "url": "https://myanimelist.net/people/63820/Disciples"}], "serializations": [{"mal_id": 1439, "type": "manga", "name": "KakaoPage", "url": "https://myanimelist.net/manga/magazine/1439/KakaoPage"}], "genres": [{"mal_id": 1, "type": "manga", "name": "Action", "url": "https://myanimelist.net/manga/genre/1/Action"}, {"mal_id": 2, "type": "manga", "name": "Adventure", "url": "https://myanimelist.net/manga/genre/2/Adventure"}, {"mal_id": 10, "type": "manga", "name": "Fantasy", "url": "https://myanimelist.net/manga/genre/10/Fantasy"}], "explicit_genres": [], "themes": [{"mal_id": 50, "type": "manga", "name": "Adult Cast", "url": "https://myanimelist.net/manga/genre/50/Adult_Cast"}, {"mal_id": 83, "type": "manga", "name": "Urban Fantasy", "url": "https://myanimelist.net/manga/genre/83/Urban_Fantasy"}], "demographics": [], "relations": [{"relation": "Sequel", "entry": [{"mal_id": 172429, "type": "manga", "name": "Solo Leveling: Ragnarok", "url": "https://myanimelist.net/manga/172429/Solo_Leveling__Ragnarok"}]}, {"relation": "Adaptation", "entry": [{"mal_id": 119184, "type": "manga", "name": "Solo Leveling", "url": "https://myanimelist.net/manga/119184/Solo_Leveling"}, {"mal_id": 51321, "type": "anime", "name": "Echo", "url": "https://myanimelist.net/anime/51321/Echo"}, {"mal_id": 52299, "type": "anime", "name": "Ore dake Level Up na Ken", "url": "https://myanimelist.net/anime/52299/Ore_dake_Level_Up_na_Ken"}, {"mal_id": 59841, "type": "anime", "name": "Ore dake Level Up na Ken: ReAwakening", "url": "https:/Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"comix": [{"title": "Chapter 6", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874900", "chapter_number": "6", "is_external": false}, {"title": "Chapter 5", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874755", "chapter_number": "5", "is_external": false}, {"title": "Chapter 4", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874561", "chapter_number": "4", "is_external": false}, {"title": "Chapter 3", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874447", "chapter_number": "3", "is_external": false}, {"title": "Chapter 2", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874343", "chapter_number": "2", "is_external": false}, {"title": "Chapter 1", "url": "1mql9:honki-de-shitemo-ii-desu-ka:3874222", "chapter_number": "1", "is_external": false}]}, "_timestamp": 1775087084.836826}
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"mal_id": 113138, "url": "https://myanimelist.net/manga/113138/Jujutsu_Kaisen", "images": {"jpg": {"image_url": "https://myanimelist.net/images/manga/3/210341.jpg", "small_image_url": "https://myanimelist.net/images/manga/3/210341t.jpg", "large_image_url": "https://myanimelist.net/images/manga/3/210341l.jpg"}, "webp": {"image_url": "https://myanimelist.net/images/manga/3/210341.webp", "small_image_url": "https://myanimelist.net/images/manga/3/210341t.webp", "large_image_url": "https://myanimelist.net/images/manga/3/210341l.webp"}}, "approved": true, "titles": [{"type": "Default", "title": "Jujutsu Kaisen"}, {"type": "Synonym", "title": "Sorcery Fight"}, {"type": "Japanese", "title": "\u546a\u8853\u5efb\u6226"}, {"type": "English", "title": "Jujutsu Kaisen"}], "title": "Jujutsu Kaisen", "title_english": "Jujutsu Kaisen", "title_japanese": "\u546a\u8853\u5efb\u6226", "title_synonyms": ["Sorcery Fight"], "type": "Manga", "chapters": 272, "volumes": 30, "status": "Finished", "publishing": false, "published": {"from": "2018-03-05T00:00:00+00:00", "to": "2024-09-30T00:00:00+00:00", "prop": {"from": {"day": 5, "month": 3, "year": 2018}, "to": {"day": 30, "month": 9, "year": 2024}}, "string": "Mar 5, 2018 to Sep 30, 2024"}, "score": 8.19, "scored": 8.19, "scored_by": 260022, "rank": 522, "popularity": 9, "members": 505601, "favorites": 34102, "synopsis": "Hidden in plain sight, an age-old conflict rages on. Supernatural monsters known as Curses terrorize humanity from the shadows, and powerful humans known as Jujutsu sorcerers use mystical arts to exterminate them. When high school student Yuuji Itadori finds a dried-up finger of the legendary Curse Sukuna Ryoumen, he suddenly finds himself joining this bloody conflict.\n\nAttacked by a Curse attracted to the finger's power, Yuuji makes a reckless decision to protect himself, gaining the power to combat Curses in the process but also unwittingly unleashing the malicious Sukuna into the world once more. Though Yuuji can control and confine Sukuna to his own body, the Jujutsu world classifies Yuuji as a dangerous, high-level Curse who must be exterminated.\n\nDetained and sentenced to death, Yuuji meets Satoru Gojou\u2014a teacher at Jujutsu High School\u2014who explains that despite his imminent execution, there is an alternative for him. Being a rare vessel to Sukuna, if Yuuji were to die, then Sukuna would perish too. Therefore, if Yuuji were to consume the many other remnants of Sukuna, then Yuuji's subsequent execution would truly eradicate the malicious demon. Taking up this chance to make the world safer and live his life for a little longer, Yuuji enrolls in Tokyo Prefectural Jujutsu High School, jumping headfirst into a harsh and unforgiving battlefield.\n\n[Written by MAL Rewrite]", "background": "As a part of the JUMP START initiative, the first three chapters of Jujutsu Kaisen were published in English in VIZ Media's digital Weekly Shonen Jump on the same day as the Japanese release. After, the series was added to the MANGA Plus simulpub service, and has been released in print by the same publisher since December 3, 2019. It has also been released in Brazilian Portuguese by Panini Comics since August 21, 2020; and in Polish by Waneko since May 5, 2021.", "authors": [{"mal_id": 47924, "type": "people", "name": "Akutami, Gege", "url": "https://myanimelist.net/people/47924/Gege_Akutami"}], "serializations": [{"mal_id": 83, "type": "manga", "name": "Shounen Jump (Weekly)", "url": "https://myanimelist.net/manga/magazine/83/Shounen_Jump_Weekly"}], "genres": [{"mal_id": 1, "type": "manga", "name": "Action", "url": "https://myanimelist.net/manga/genre/1/Action"}, {"mal_id": 37, "type": "manga", "name": "Supernatural", "url": "https://myanimelist.net/manga/genre/37/Supernatural"}], "explicit_genres": [], "themes": [{"mal_id": 23, "type": "manga", "name": "School", "url": "https://myanimelist.net/manga/genre/23/School"}], "demographics": [{"mal_id": 27, "type": "manga", "name": "Shounen", "url": "https://myanimelist.net/manga/genre/27/Shounen"}], "relations": [{"relation": "Prequel", "entry": [{"mal_id": 115710, "type": "manga", "name": "Jujutsu Kaisen 0: Tokyo Toritsu Jujutsu Koutou Senmon Gakkou", "url": "https://myanimelist.net/manga/115710/Jujutsu_Kaisen_0__Tokyo_Toritsu_Jujutsu_Koutou_Senmon_Gakkou"}]}, {"relation": "Adaptation", "entry": [{"mal_id": 38777, "type": "anime", "name": "Jujutsu Kaisen Official PVs", "url": "https://myanimelist.net/anime/38777/Jujutsu_Kaisen_Official_PVs"}, {"mal_id": 40748, "type": "anime", "name": "Jujutsu Kaisen", "url": "https://myanimelist.net/anime/40748/Jujutsu_Kaisen"}, {"mal_id": 51009, "type": "anime", "name": "Jujutsu Kaisen 2nd Season", "url": "https://myanimelist.net/anime/51009/Jujutsu_Kaisen_2nd_Season"}, {"mal_id": 59654, "type": "anime", "name": "Jujutsu Kaisen: Kaigyoku/Gyokusetsu", "url": "https://myanimelist.net/anime/59654/Jujutsu_Kaisen__Kaigyoku_Gyokusetsu"}, {"mal_id": 62392, "type": "anime", "Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"comix": [{"title": "Final Chapter: From Here on Out", "url": "7nzg:jujutsu-kaisen:5658860", "chapter_number": "271", "is_external": false}, {"title": "A Dream's End", "url": "7nzg:jujutsu-kaisen:5658815", "chapter_number": "270", "is_external": false}, {"title": "Reflection", "url": "7nzg:jujutsu-kaisen:5658773", "chapter_number": "269", "is_external": false}, {"title": "Finale", "url": "7nzg:jujutsu-kaisen:5658740", "chapter_number": "268", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u32b3", "url": "7nzg:jujutsu-kaisen:5658708", "chapter_number": "267", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u32b2", "url": "7nzg:jujutsu-kaisen:5658672", "chapter_number": "266", "is_external": false}, {"title": "That Day", "url": "7nzg:jujutsu-kaisen:5658655", "chapter_number": "265", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u32b1", "url": "7nzg:jujutsu-kaisen:5658612", "chapter_number": "264", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325f", "url": "7nzg:jujutsu-kaisen:5658576", "chapter_number": "263", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325e", "url": "7nzg:jujutsu-kaisen:5658544", "chapter_number": "262.5", "is_external": false}, {"title": "Inhuman Makyo Shinjuku Showdown, Part 34-2", "url": "7nzg:jujutsu-kaisen:6603751", "chapter_number": "262.2", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325e", "url": "7nzg:jujutsu-kaisen:5658508", "chapter_number": "262", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325d", "url": "7nzg:jujutsu-kaisen:5658487", "chapter_number": "261", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325c", "url": "7nzg:jujutsu-kaisen:5658451", "chapter_number": "260", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325b", "url": "7nzg:jujutsu-kaisen:5658406", "chapter_number": "259", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u325a", "url": "7nzg:jujutsu-kaisen:5658352", "chapter_number": "258", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3259", "url": "7nzg:jujutsu-kaisen:5658311", "chapter_number": "257", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3258", "url": "7nzg:jujutsu-kaisen:5658259", "chapter_number": "256", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3257", "url": "7nzg:jujutsu-kaisen:5658234", "chapter_number": "255", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3256", "url": "7nzg:jujutsu-kaisen:5658211", "chapter_number": "254", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3255", "url": "7nzg:jujutsu-kaisen:5658176", "chapter_number": "253", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3254", "url": "7nzg:jujutsu-kaisen:5658144", "chapter_number": "252", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3253", "url": "7nzg:jujutsu-kaisen:5658110", "chapter_number": "251", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3252", "url": "7nzg:jujutsu-kaisen:5658086", "chapter_number": "250", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u3251", "url": "7nzg:jujutsu-kaisen:5658067", "chapter_number": "249", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u2473", "url": "7nzg:jujutsu-kaisen:5658031", "chapter_number": "248", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u2472", "url": "7nzg:jujutsu-kaisen:5657999", "chapter_number": "247", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u2471", "url": "7nzg:jujutsu-kaisen:5657949", "chapter_number": "246", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u2470", "url": "7nzg:jujutsu-kaisen:5657918", "chapter_number": "245", "is_external": false}, {"title": "The Decisive Battle in the Uninhabited, Demon-Infested Shinjuku \u246f", "url": "7nzg:jujutsu-kaisen:5657886", "chapter_number": "244", "is_external": false}, {"title": "Idiot Survivor!! ~Bounce Off the Walls~", "url": "7nzg:jujutsu-kaisen:5657868", "chapter_number": "243", "is_external": false}, {"title": "Idiot Survivor!! ~Soar Ever HighLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"entries": [{"anilist_id": 176496, "mal_id": 58567, "title_romaji": "Ore dake Level Up na Ken: Season 2 - Arise from the Shadow", "title_english": "Solo Leveling Season 2 -Arise from the Shadow-", "title_native": "\u4ffa\u3060\u3051\u30ec\u30d9\u30eb\u30a2\u30c3\u30d7\u306a\u4ef6 Season 2 -Arise from the Shadow-", "format": "TV", "start_date": {"year": 2025, "month": 1, "day": 5}, "season": "WINTER", "season_year": 2025, "episodes": 13, "relation_type_from_parent": null, "inferred_part": 2, "is_season": true, "is_final_from_title": false, "title_display": "Solo Leveling Season 2 -Arise from the Shadow-", "_start_tuple": [2025, 1, 5], "is_final_season": false}, {"anilist_id": 184694, "mal_id": 59841, "title_romaji": "Ore dake Level Up na Ken: ReAwakening", "title_english": "Solo Leveling -ReAwakening-", "title_native": "\u4ffa\u3060\u3051\u30ec\u30d9\u30eb\u30a2\u30c3\u30d7\u306a\u4ef6 -ReAwakening-", "format": "MOVIE", "start_date": {"year": 2024, "month": 11, "day": 29}, "season": "FALL", "season_year": 2024, "episodes": 1, "relation_type_from_parent": null, "inferred_part": null, "is_season": false, "is_final_from_title": false, "title_display": "Solo Leveling -ReAwakening-", "_start_tuple": [2024, 11, 29], "is_final_season": false}, {"anilist_id": 151807, "mal_id": 52299, "title_romaji": "Ore dake Level Up na Ken", "title_english": "Solo Leveling", "title_native": "\u4ffa\u3060\u3051\u30ec\u30d9\u30eb\u30a2\u30c3\u30d7\u306a\u4ef6", "format": "TV", "start_date": {"year": 2024, "month": 1, "day": 7}, "season": "WINTER", "season_year": 2024, "episodes": 12, "relation_type_from_parent": null, "inferred_part": null, "is_season": true, "is_final_from_title": false, "title_display": "Solo Leveling", "_start_tuple": [2024, 1, 7], "is_final_season": false}], "season_groups": [{"season_index": 1, "group_label": "Season 1", "parts": [{"short_label": "S1", "title": "Solo Leveling", "mal_id": 52299, "anilist_id": 151807, "start_date": {"year": 2024, "month": 1, "day": 7}, "format": "TV", "is_final": false}]}, {"season_index": 2, "group_label": "Season 2", "parts": [{"short_label": "S2", "title": "Solo Leveling Season 2 -Arise from the Shadow-", "mal_id": 58567, "anilist_id": 176496, "start_date": {"year": 2025, "month": 1, "day": 5}, "format": "TV", "is_final": false}]}], "extras": [{"title": "Solo Leveling -ReAwakening-", "mal_id": 59841, "anilist_id": 184694, "format": "MOVIE", "start_date": {"year": 2024, "month": 11, "day": 29}}]}, "_timestamp": 1775086915.503556}
|
||||
@@ -0,0 +1 @@
|
||||
{"payload": {"mal_id": 121948, "url": "https://myanimelist.net/manga/121948/Dokusen_shitemo_Ii_desu_ka", "images": {"jpg": {"image_url": "https://myanimelist.net/images/manga/2/235219.jpg", "small_image_url": "https://myanimelist.net/images/manga/2/235219t.jpg", "large_image_url": "https://myanimelist.net/images/manga/2/235219l.jpg"}, "webp": {"image_url": "https://myanimelist.net/images/manga/2/235219.webp", "small_image_url": "https://myanimelist.net/images/manga/2/235219t.webp", "large_image_url": "https://myanimelist.net/images/manga/2/235219l.webp"}}, "approved": true, "titles": [{"type": "Default", "title": "Dokusen shitemo Ii desu ka"}, {"type": "Synonym", "title": "Will You Be Mine?"}, {"type": "Japanese", "title": "\u72ec\u5360\u3057\u3066\u3082\u3044\u3044\u3067\u3059\u304b"}, {"type": "English", "title": "Can I Have You All to Myself?"}], "title": "Dokusen shitemo Ii desu ka", "title_english": "Can I Have You All to Myself?", "title_japanese": "\u72ec\u5360\u3057\u3066\u3082\u3044\u3044\u3067\u3059\u304b", "title_synonyms": ["Will You Be Mine?"], "type": "Manga", "chapters": 7, "volumes": 1, "status": "Finished", "publishing": false, "published": {"from": "2017-04-28T00:00:00+00:00", "to": "2017-10-31T00:00:00+00:00", "prop": {"from": {"day": 28, "month": 4, "year": 2017}, "to": {"day": 31, "month": 10, "year": 2017}}, "string": "Apr 28, 2017 to Oct 31, 2017"}, "score": 6.74, "scored": 6.74, "scored_by": 136, "rank": null, "popularity": 32965, "members": 333, "favorites": 0, "synopsis": "Yuu and Ryou have been best friends since they were kids. Yuu is not the most approachable guy, unlike Ryou, who is very popular. It doesn't really bother Yuu that he's the outcast of the class, and he even admits that Ryou is the only person he feels comfortable talking to. But then, Ryou is asked to substitute for a player on the basketball team, meaning that he is not able to spend as much time with Yuu... Yuu is unhappy about this, and he cannot help but lash out at Ryou. Could Yuu's extremely possessive feelings be something more? Is their relationship really just about friendship?\n\n(Source: Renta!)", "background": "Dokusen shitemo Ii desu ka was published digitally in English as Can I Have You All to Myself? by Renta!", "authors": [{"mal_id": 52232, "type": "people", "name": "Kogamo", "url": "https://myanimelist.net/people/52232/Kogamo"}], "serializations": [], "genres": [{"mal_id": 28, "type": "manga", "name": "Boys Love", "url": "https://myanimelist.net/manga/genre/28/Boys_Love"}, {"mal_id": 49, "type": "manga", "name": "Erotica", "url": "https://myanimelist.net/manga/genre/49/Erotica"}], "explicit_genres": [], "themes": [{"mal_id": 23, "type": "manga", "name": "School", "url": "https://myanimelist.net/manga/genre/23/School"}], "demographics": [], "relations": [], "external": []}, "_timestamp": 1775087082.701801}
|
||||
Reference in new issue
Block a user