From 15beef89631c35e28744c4a9cdeb000c81fa17c4 Mon Sep 17 00:00:00 2001 From: ThaUnknown <6506529+ThaUnknown@users.noreply.github.com> Date: Tue, 5 Dec 2023 00:23:31 +0100 Subject: [PATCH] feat(web): smooth scroll, about section, cards, scroll animations --- pnpm-lock.yaml | 3 + web/package.json | 3 +- web/src/lib/components/Hero.svelte | 14 +- web/src/lib/components/PreviewCard.svelte | 145 +++++++ web/src/lib/components/SmallCard.svelte | 66 ++++ web/src/lib/components/anime.js | 20 + web/src/lib/css.css | 4 + web/src/lib/dummyData.js | 461 ++++++++++++++++++++++ web/src/routes/+layout.js | 1 + web/src/routes/+layout.svelte | 46 ++- web/src/routes/+page.svelte | 59 ++- 11 files changed, 817 insertions(+), 5 deletions(-) create mode 100644 web/src/lib/components/PreviewCard.svelte create mode 100644 web/src/lib/components/SmallCard.svelte create mode 100644 web/src/lib/components/anime.js create mode 100644 web/src/lib/dummyData.js diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 963c7a78..35c5ffdb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,6 +268,9 @@ importers: quartermoon: specifier: ^1.2.3 version: 1.2.3 + simple-store-svelte: + specifier: ^1.0.1 + version: 1.0.1 devDependencies: '@sveltejs/adapter-auto': specifier: ^2.1.1 diff --git a/web/package.json b/web/package.json index fffaa524..961ff527 100644 --- a/web/package.json +++ b/web/package.json @@ -22,7 +22,8 @@ "@fontsource-variable/material-symbols-outlined": "^5.0.16", "@fontsource-variable/nunito": "^5.0.16", "@fontsource/roboto": "^5.0.8", - "quartermoon": "^1.2.3" + "quartermoon": "^1.2.3", + "simple-store-svelte": "^1.0.1" }, "type": "module" } diff --git a/web/src/lib/components/Hero.svelte b/web/src/lib/components/Hero.svelte index 2f3a4dfc..28f7374b 100644 --- a/web/src/lib/components/Hero.svelte +++ b/web/src/lib/components/Hero.svelte @@ -1,4 +1,14 @@ -
+ + +
MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU
@@ -10,7 +20,7 @@ Download - Learn More +
diff --git a/web/src/lib/components/PreviewCard.svelte b/web/src/lib/components/PreviewCard.svelte new file mode 100644 index 00000000..c648166c --- /dev/null +++ b/web/src/lib/components/PreviewCard.svelte @@ -0,0 +1,145 @@ + + +
+ +
+
+ {media.title.userPreferred} +
+
+ + + +
+
+ + {#if media.format} + {formatMap[media.format]} + {/if} + + {#if media.episodes && media.episodes !== 1} + + {#if media.mediaListEntry?.status === 'CURRENT' && media.mediaListEntry?.progress } + {media.mediaListEntry.progress} / {media.episodes} Episodes + {:else} + {media.episodes} Episodes + {/if} + + {:else if media.duration} + + {media.duration + ' Minutes'} + + {/if} + {#if media.season || media.seasonYear} + + {[media.season?.toLowerCase(), media.seasonYear].filter(s => s).join(' ')} + + {/if} +
+
+ {media.description?.replace(/<[^>]*>/g, '')} +
+
+
+ + diff --git a/web/src/lib/components/SmallCard.svelte b/web/src/lib/components/SmallCard.svelte new file mode 100644 index 00000000..649ce133 --- /dev/null +++ b/web/src/lib/components/SmallCard.svelte @@ -0,0 +1,66 @@ + + +
+ {#if preview} + + {/if} +
+ cover +
+ {#if media.mediaListEntry?.status} +
+ {/if} + {media.title.userPreferred} +
+
+
+ calendar_month + {media.seasonYear || 'N/A'} +
+
+ {formatMap[media.format]} + monitor +
+
+
+
+ + diff --git a/web/src/lib/components/anime.js b/web/src/lib/components/anime.js new file mode 100644 index 00000000..50bbd3fc --- /dev/null +++ b/web/src/lib/components/anime.js @@ -0,0 +1,20 @@ +export const formatMap = { + TV: 'TV Series', + TV_SHORT: 'TV Short', + MOVIE: 'Movie', + SPECIAL: 'Special', + OVA: 'OVA', + ONA: 'ONA', + MUSIC: 'Music', + undefined: 'N/A', + null: 'N/A' +} + +export const statusColorMap = { + CURRENT: 'rgb(61,180,242)', + PLANNING: 'rgb(247,154,99)', + COMPLETED: 'rgb(123,213,85)', + PAUSED: 'rgb(250,122,122)', + REPEATING: '#3baeea', + DROPPED: 'rgb(232,93,117)' +} diff --git a/web/src/lib/css.css b/web/src/lib/css.css index 856ddae5..4bbd6a9a 100644 --- a/web/src/lib/css.css +++ b/web/src/lib/css.css @@ -9,4 +9,8 @@ hr { .h-vh-half { height: 50vh; +} + +:root { + --container-xl-max-width: 150rem } \ No newline at end of file diff --git a/web/src/lib/dummyData.js b/web/src/lib/dummyData.js new file mode 100644 index 00000000..6c3cbbab --- /dev/null +++ b/web/src/lib/dummyData.js @@ -0,0 +1,461 @@ +export const cards = [ + { + id: 154587, + idMal: 52991, + title: { + romaji: 'Sousou no Frieren', + english: 'Frieren: Beyond Journey’s End', + native: '葬送のフリーレン', + userPreferred: 'Frieren: Beyond Journey’s End' + }, + description: 'The adventure is over but life goes on for an elf mage just beginning to learn what living is all about. Elf mage Frieren and her courageous fellow adventurers have defeated the Demon King and brought peace to the land. But Frieren will long outlive the rest of her former party. How will she come to understand what life means to the people around her? Decades after their victory, the funeral of one her friends confronts Frieren with her own near immortality. Frieren sets out to fulfill the last wishes of her comrades and finds herself beginning a new adventure…\n

\n(Source: Crunchyroll)', + season: 'FALL', + seasonYear: 2023, + format: 'TV', + status: 'RELEASING', + episodes: 28, + duration: 24, + averageScore: 89, + genres: [ + 'Adventure', + 'Drama', + 'Fantasy' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx154587-n1fmjRv4JQUd.jpg', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx154587-n1fmjRv4JQUd.jpg', + color: '#d6f1c9' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/154587-ivXNJ23SM1xB.jpg', + synonyms: [ + 'Frieren at the Funeral', + '장송의 프리렌', + 'Frieren: Oltre la Fine del Viaggio', + 'คำอธิษฐานในวันที่จากลา Frieren', + 'Frieren e a Jornada para o Além', + 'Frieren – Nach dem Ende der Reise', + '葬送的芙莉蓮', + 'Frieren: Más allá del final del viaje', + 'Frieren en el funeral', + 'Sōsō no Furīren', + 'Frieren. U kresu drogi', + 'Frieren - Pháp sư tiễn táng', + 'Фрирен, провожающая в последний путь' + ], + nextAiringEpisode: { + timeUntilAiring: 317046, + episode: 14 + }, + startDate: { + year: 2023, + month: 9, + day: 29 + }, + trailer: { + id: 'qgQunxD0qCk', + site: 'youtube' + }, + source: 'MANGA', + studios: { + nodes: [ + { + name: 'MADHOUSE' + } + ] + } + }, + { + id: 145064, + idMal: 51009, + title: { + romaji: 'Jujutsu Kaisen 2nd Season', + english: 'JUJUTSU KAISEN Season 2', + native: '呪術廻戦 第2期', + userPreferred: 'JUJUTSU KAISEN Season 2' + }, + description: 'The second season of Jujutsu Kaisen.
\n
\nThe past comes to light when second-year students Satoru Gojou and Suguru Getou are tasked with escorting young Riko Amanai to Master Tengen. But when a non-sorcerer user tries to kill them, their mission to protect the Star Plasma Vessel threatens to turn them into bitter enemies and cement their destinies—one as the world’s strongest sorcerer, and the other its most twisted curse user!
\n
\n(Source: Crunchyroll)', + season: 'SUMMER', + seasonYear: 2023, + format: 'TV', + status: 'RELEASING', + episodes: 23, + duration: 24, + averageScore: 87, + genres: [ + 'Action', + 'Drama', + 'Supernatural' + ], + isFavourite: true, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx145064-5fa4ZBbW4dqA.jpg', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx145064-5fa4ZBbW4dqA.jpg', + color: '#5d86e4' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/145064-S7qAgxf6kMrW.jpg', + synonyms: [ + '呪術廻戦 懐玉・玉折/渋谷事変 ', + 'Jujutsu Kaisen: Kaigyoku Gyokusetsu / Shibuya Jihen', + 'Jujutsu Kaisen: Hidden Inventory / Premature Death', + 'JJK2', + '咒術迴戰 第二季', + 'มหาเวทย์ผนึกมาร ภาค 2 ', + '咒术回战 2', + '2جوجوتسو كايسن ' + ], + nextAiringEpisode: { + timeUntilAiring: 234006, + episode: 20 + }, + startDate: { + year: 2023, + month: 7, + day: 6 + }, + trailer: { + id: 'O6qVieflwqs', + site: 'youtube' + }, + mediaListEntry: { + progress: 19, + repeat: 0, + status: 'CURRENT', + score: 0 + }, + source: 'MANGA', + studios: { + nodes: [ + { + name: 'MAPPA' + } + ] + } + }, + { + id: 145139, + idMal: 51019, + title: { + romaji: 'Kimetsu no Yaiba: Katanakaji no Sato-hen', + english: 'Demon Slayer: Kimetsu no Yaiba Swordsmith Village Arc', + native: '鬼滅の刃 刀鍛冶の里編', + userPreferred: 'Demon Slayer: Kimetsu no Yaiba Swordsmith Village Arc' + }, + description: 'Adaptation of the Swordsmith Village Arc.
\n
\nTanjiro’s journey leads him to the Swordsmith Village, where he reunites with two Hashira, members of the Demon Slayer Corps’ highest-ranking swordsmen - Mist Hashira Muichiro Tokito and Love Hashira Mitsuri Kanroji. With the shadows of demons lurking near, a new battle begins for Tanjiro and his comrades.\n

\nNotes:
\n• The first episode has a runtime of ~49 minutes, and received an early premiere in cinemas worldwide as part of a special screening alongside the final two episodes of Kimetsu no Yaiba: Yuukaku-hen.
\n• The final episode has a runtime of ~52 minutes.
', + season: 'SPRING', + seasonYear: 2023, + format: 'TV', + status: 'FINISHED', + episodes: 11, + duration: 24, + averageScore: 83, + genres: [ + 'Action', + 'Adventure', + 'Drama', + 'Fantasy', + 'Supernatural' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx145139-rRimpHGWLhym.png', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx145139-rRimpHGWLhym.png', + color: '#1aaed6' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/145139-V01Prh6UzfRk.jpg', + synonyms: [ + 'KnY 3', + 'ดาบพิฆาตอสูร ภาค 3 บทหมู่บ้านช่างตีดาบ', + 'Demon Slayer: Kimetsu no Yaiba - Le village des forgerons', + 'Истребитель демонов: Kimetsu no Yaiba. Деревня кузнецов' + ], + nextAiringEpisode: null, + startDate: { + year: 2023, + month: 4, + day: 9 + }, + trailer: { + id: 'a9tq0aS5Zu8', + site: 'youtube' + }, + mediaListEntry: { + progress: 11, + repeat: 0, + status: 'COMPLETED', + score: 0 + }, + source: 'MANGA', + studios: { + nodes: [ + { + name: 'ufotable' + } + ] + } + }, + { + id: 150672, + idMal: 52034, + title: { + romaji: '[Oshi no Ko]', + english: 'Oshi No Ko', + native: '【推しの子】', + userPreferred: 'Oshi No Ko' + }, + description: 'When a pregnant young starlet appears in Gorou Amemiya’s countryside medical clinic, the doctor takes it upon himself to safely (and secretly) deliver Ai Hoshino’s child so she can make a scandal-free return to the stage. But no good deed goes unpunished, and on the eve of her delivery, he finds himself slain at the hands of Ai’s deluded stalker — and subsequently reborn as Ai’s child, Aquamarine Hoshino! The glitz and glamor of showbiz hide the dark underbelly of the entertainment industry, threatening to dull the shine of his favorite star. Can he help his new mother rise to the top of the charts? And what will he do when unthinkable disaster strikes?
\n
\n(Source: HIDIVE)\n

\n\nNote: Episode 1【推しの子】Mother and Children was pre-screened in advance in Japanese theaters on March 17, 2023. The regular TV broadcast began on April 12, 2023. The first episode has an extended runtime of ~82 minutes.', + season: 'SPRING', + seasonYear: 2023, + format: 'TV', + status: 'FINISHED', + episodes: 11, + duration: 24, + averageScore: 86, + genres: [ + 'Drama', + 'Mystery', + 'Psychological', + 'Supernatural' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx150672-2WWJVXIAOG11.png', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx150672-2WWJVXIAOG11.png', + color: '#ff35c9' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/150672-ISwoA0eS722H.jpg', + synonyms: [ + 'Favorite Girl', + "My Idol's Child", + '[Mein*Star]', + 'เกิดใหม่เป็นลูกโอชิ', + 'Anak Idola', + '【OSHI NO KO】', + '【推しの子】Mother and Children', + '[Oshi no Ko] Mother and Children', + '我推的孩子', + '【최애의 아이】' + ], + nextAiringEpisode: null, + startDate: { + year: 2023, + month: 4, + day: 12 + }, + trailer: { + id: 'gKWEUJ4r5do', + site: 'youtube' + }, + streamingEpisodes: [], + mediaListEntry: { + progress: 11, + repeat: 0, + status: 'COMPLETED', + score: 0 + }, + source: 'MANGA', + studios: { + nodes: [ + { + name: 'Doga Kobo' + } + ] + } + }, + { + id: 151807, + idMal: 52299, + title: { + romaji: 'Ore dake Level Up na Ken', + english: 'Solo Leveling', + native: '俺だけレベルアップな件', + userPreferred: 'Solo Leveling' + }, + description: "It's been over a decade since the sudden appearance of the \"gates\"—the paths that connect our world with a different dimension. Since then, certain humans have awakened to supernatural powers. We call these individuals \"hunters.\" Hunters make their living by using their powers to conquer dungeons inside the gates. In this world of tough customers, the low-ranked hunter Shun Mizushino is known as \"the weakest hunter of all mankind.\" One day, Shun gets fatally injured when he runs into high-rank double dungeons hidden within a low-rank dungeon. Just then, a mysterious quest window appears in front of him. On the verge of death, Shun decides to accept the quest and starts leveling up... while the others aren't.
\n
\n(Source: Anime News Network, edited)

\n\n Note: Announced at the Crunchyroll Anime Expo 2022 Industry Panel.", + season: 'WINTER', + seasonYear: 2024, + format: 'TV', + status: 'NOT_YET_RELEASED', + episodes: null, + duration: null, + averageScore: null, + genres: [ + 'Action', + 'Adventure', + 'Fantasy' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx151807-m1gX3iwfIsLu.png', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx151807-m1gX3iwfIsLu.png', + color: '#28aef1' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/151807-37yfQA3ym8PA.jpg', + synonyms: [ + '나 혼자만 레벨업', + 'Na Honjaman Level Up' + ], + nextAiringEpisode: null, + startDate: { + year: 2024, + month: 1, + day: null + }, + trailer: { + id: 'NtssbUbxDDM', + site: 'youtube' + }, + mediaListEntry: { + progress: 0, + repeat: 0, + status: 'PLANNING', + score: 0 + }, + source: 'OTHER', + studios: { + nodes: [ + { + name: 'A-1 Pictures' + } + ] + } + }, + { + id: 101165, + idMal: 37349, + title: { + romaji: 'Goblin Slayer', + english: 'GOBLIN SLAYER', + native: 'ゴブリンスレイヤー', + userPreferred: 'GOBLIN SLAYER' + }, + description: "A young priestess has formed her first adventuring party, but almost immediately they find themselves in distress. It's the Goblin Slayer who comes to their rescue--a man who's dedicated his life to the extermination of all goblins, by any means necessary. And when rumors of his feats begin to circulate, there's no telling who might come calling next...

\n\n(Source: Yen Press)", + season: 'FALL', + seasonYear: 2018, + format: 'TV', + status: 'FINISHED', + episodes: 12, + duration: 24, + averageScore: 71, + genres: [ + 'Action', + 'Adventure', + 'Fantasy' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/nx101165-dVgOyGhEP4mB.jpg', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/nx101165-dVgOyGhEP4mB.jpg', + color: '#5d93e4' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/101165-bXPZrNiQGPHd.jpg', + synonyms: [ + 'ก็อบลิน สเลเยอร์' + ], + nextAiringEpisode: null, + startDate: { + year: 2018, + month: 10, + day: 7 + }, + trailer: { + id: '6sdxN30qNrw', + site: 'youtube' + }, + mediaListEntry: { + id: 122792777, + progress: 12, + repeat: 1, + status: 'COMPLETED', + customLists: [ + { + name: 'Watched using Miru', + enabled: true + } + ], + score: 0 + }, + source: 'LIGHT_NOVEL', + studios: { + nodes: [ + { + name: 'White Fox' + } + ] + } + }, + { + id: 21087, + idMal: 30276, + title: { + romaji: 'One Punch Man', + english: 'One-Punch Man', + native: 'ワンパンマン', + userPreferred: 'One Punch Man' + }, + description: "Saitama has a rather peculiar hobby, being a superhero, but despite his heroic deeds and superhuman abilities, a shadow looms over his life. He's become much too powerful, to the point that every opponent ends up defeated with a single punch.\n

\nThe lack of challenge has driven him into a state of apathy, as he watches his life pass by having lost all enthusiasm, at least until he's unwillingly thrust in the role of being a mentor to the young and revenge-driven Genos. \n\n", + season: 'FALL', + seasonYear: 2015, + format: 'TV', + status: 'FINISHED', + episodes: 12, + duration: 24, + averageScore: 83, + genres: [ + 'Action', + 'Comedy', + 'Sci-Fi', + 'Supernatural' + ], + isFavourite: false, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx21087-UV2tu6exrfXz.jpg', + medium: 'https://s4.anilist.co/file/anilistcdn/media/anime/cover/small/bx21087-UV2tu6exrfXz.jpg', + color: '#e4ae5d' + }, + countryOfOrigin: 'JP', + isAdult: false, + bannerImage: 'https://s4.anilist.co/file/anilistcdn/media/anime/banner/21087-sHb9zUZFsHe1.jpg', + synonyms: [ + 'OPM', + 'Wanpanman', + 'איש האגרוף הבודד', + '一拳超人', + 'วันพันช์แมน', + 'Jagoan Sekali Pukul S1', + 'رجل اللكمة الواحدة', + 'ون بنش مان' + ], + nextAiringEpisode: null, + startDate: { + year: 2015, + month: 10, + day: 5 + }, + trailer: { + id: 'RzmFKUDOUgw', + site: 'youtube' + }, + mediaListEntry: null, + source: 'MANGA', + studios: { + nodes: [ + { + name: 'MADHOUSE' + } + ] + } + } +] diff --git a/web/src/routes/+layout.js b/web/src/routes/+layout.js index 0ceb16fb..7f241458 100644 --- a/web/src/routes/+layout.js +++ b/web/src/routes/+layout.js @@ -7,6 +7,7 @@ import '$lib/css.css' export const prerender = false export const csr = true +export const ssr = false export const trailingSlash = 'always' /** @type {import('./$types').LayoutLoad} */ diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 450345be..60161d8c 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -2,12 +2,56 @@ import Footer from '$lib/components/Footer.svelte' import Loader from '$lib/components/Loader.svelte' import Navbar from '$lib/components/Navbar.svelte' + import { setContext } from 'svelte' + import { writable } from 'simple-store-svelte' + + const scrollPosition = writable(0) + setContext('scroll-position', scrollPosition) + function smoothScroll (t, { speed = 120, smooth = 10 } = {}) { + let moving = false + let pos = 0 + let scrollTop = 0 + let lastTime = null + t.addEventListener('wheel', e => { + e.preventDefault() + // is trackpad + const spd = (e.deltaY !== (e.deltaY | 0) || e.wheelDelta % 10 !== 0) ? speed / 10 : speed + pos = Math.max(0, Math.min(pos - Math.max(-1, Math.min(1, e.deltaY * -1)) * spd, (t.scrollHeight - t.clientHeight) + (smooth * 2))) + if (!moving) { + lastTime = null + update() + } + }, { capture: true, passive: false }) + + function getDeltaTime () { + const now = performance.now() + if (!lastTime) { + lastTime = now + return 1 + } + const deltaTime = now - lastTime + lastTime = now + return deltaTime / 14 + } + + t.addEventListener('pointerup', () => { pos = scrollTop = t.scrollTop }) + + function update () { + const delta = pos - scrollTop === smooth * 2 ? 0 : ((pos - scrollTop) / smooth) * getDeltaTime() + scrollTop += delta + + scrollPosition.value = scrollTop < 1.3 ? 0 : scrollTop + + t.scrollTo(0, scrollTop < 1.3 ? 0 : scrollTop) + moving = Math.abs(delta) > 0.1 && !!requestAnimationFrame(update) + } + }
-
+
diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index d9ed50f2..4d5dd833 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,17 +1,74 @@ -
+
app
+ +
+

+ Torrenting made simple. +

+
+
+
+

Quality meets speed

+

Stream torrents directly for playback, with no time wasted on looking for torrents or waiting for downloads to finish.

+
+
+
+
+

No expertise required

+

You don’t need to be a master of torrenting or have a deep understanding of technology, it simply works.

+
+
+
+
+

Configuration free

+

No need to look for setup guides, no need to worry about the ideal configuration, it’s perfect out of the box.

+
+
+
+
+
+
+
+
+
+

+ Tightly integrated. +

+

Find and download torrents, watch trailers, manage your list, search, browse and discover anime, watch together with friends and more, all in the same interface. No need to open multiple apps, tabs, everything shipped in one package.

+
+
+
+ +
+
+