Compare commits

..

20 Commits

Author SHA1 Message Date
444feac1e0 Use redirect for random button to save database queries 2025-10-09 12:55:24 +02:00
c034c94db5 Add padding to comments on home page 2025-10-09 12:38:54 +02:00
ca52584da9 Cache random hentai row for 5 minutes 2025-10-09 12:38:17 +02:00
dca4924e9a Add v2 re-release discord webhook 2025-10-08 20:01:06 +02:00
9ad7c7afc2 Fix incorrect cache key 2025-10-08 19:50:55 +02:00
6c8d34b030 Fix vite build 2025-10-08 19:38:54 +02:00
35a0d61437 Add censored discord notification 2025-10-08 18:32:08 +02:00
725a441d9e Add discord notification for v2 releases 2025-10-08 17:41:10 +02:00
96a9019eba Temp fix call on null for removed downloads (dmca) 2025-10-08 17:24:14 +02:00
e2497867f0 Display login message 2025-10-08 17:05:31 +02:00
a6c47cf2e6 Remove unused Controller 2025-10-08 16:53:51 +02:00
fffa320c08 Add monthly views chart 2025-10-08 16:52:40 +02:00
2880547f3e Fix mobile offset episode thumbnail / cover 2025-10-08 13:00:16 +02:00
b5dbf24e91 Update node packages 2025-10-08 12:42:35 +02:00
43cf5db6c9 Update composer packages 2025-10-08 12:04:12 +02:00
9e0042b09f Add stats and current git commit to footer 2025-10-08 11:44:40 +02:00
e717b2bd07 Temp fix call on null for removed downloads (dmca) 2025-10-07 23:46:17 +02:00
bbbc4ac329 Add domain 2025-10-07 22:38:20 +02:00
55739a21b5 Add hentai list api endoint 2025-10-02 21:26:09 +02:00
bc193c7141 Remove torrents system 2025-09-22 13:34:52 +02:00
42 changed files with 3164 additions and 1869 deletions

View File

@@ -8,7 +8,7 @@
# Install PHP # Install PHP
sudo add-apt-repository ppa:ondrej/php sudo add-apt-repository ppa:ondrej/php
apt update && apt upgrade apt update && apt upgrade
apt install php8.4 php8.4-xml php8.4-mysql php8.4-gd php8.4-zip php8.4-curl php8.4-mbstring apt install php8.3 php8.3-xml php8.3-mysql php8.3-gd php8.3-zip php8.3-curl php8.3-mbstring
# Install NodeJS # Install NodeJS
curl -sL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup.sh curl -sL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup.sh
@@ -22,7 +22,7 @@ mv composer.phar composer
# Install NGINX (skip for local dev) # Install NGINX (skip for local dev)
apt install nginx apt install nginx
apt install php8.4-fpm apt install php8.3-fpm
# Install MariaDB # Install MariaDB
apt install mariadb-server apt install mariadb-server

View File

@@ -60,13 +60,6 @@ class CacheHelper
}); });
} }
public static function getTotalMonthlyViews()
{
return Cache::remember("total_monthly_view_count", now()->addMinutes(60), function () {
return PopularMonthly::count();
});
}
public static function getPopularAllTime(bool $guest) public static function getPopularAllTime(bool $guest)
{ {
$guestString = $guest ? 'guest' : 'authed'; $guestString = $guest ? 'guest' : 'authed';

19
app/Helpers/GitHelper.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Cache;
class GitHelper
{
public static function shortCommit()
{
return Cache::remember("git_commit", now()->addMinutes(60), function () {
try {
return trim(exec('git rev-parse --short HEAD'));
} catch (\Exception $e) {
return 'unknown';
}
});
}
}

View File

@@ -42,7 +42,11 @@ class EpisodeController extends Controller
$this->galleryService->createOrUpdateGallery($request, $referenceEpisode->hentai, $episode, $episodeNumber, true); $this->galleryService->createOrUpdateGallery($request, $referenceEpisode->hentai, $episode, $episodeNumber, true);
// Discord Alert // Discord Alert
DiscordReleaseNotification::dispatch($episode->slug, 'release'); if ($request->has('censored')) {
DiscordReleaseNotification::dispatch($referenceEpisode->title." - ".$episodeNumber, 'release-censored');
} else {
DiscordReleaseNotification::dispatch($episode->slug, 'release');
}
cache()->flush(); cache()->flush();
@@ -76,6 +80,10 @@ class EpisodeController extends Controller
DiscordReleaseNotification::dispatch($episode->slug, 'updateUHD'); DiscordReleaseNotification::dispatch($episode->slug, 'updateUHD');
} }
if ($request->has('v2')) {
DiscordReleaseNotification::dispatch($episode->slug, 'v2');
}
cache()->flush(); cache()->flush();
return to_route('hentai.index', [ return to_route('hentai.index', [

View File

@@ -72,9 +72,13 @@ class ReleaseController extends Controller
$releasedEpisodes[] = $episode->slug; $releasedEpisodes[] = $episode->slug;
} }
foreach ($releasedEpisodes as $slug) { if ($request->has('censored')) {
// Dispatch Discord Alert DiscordReleaseNotification::dispatch($request->input('title'), 'release-censored');
DiscordReleaseNotification::dispatch($slug, 'release'); } else {
foreach ($releasedEpisodes as $slug) {
// Dispatch Discord Alert
DiscordReleaseNotification::dispatch($slug, 'release');
}
} }
cache()->flush(); cache()->flush();

View File

@@ -1,40 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Torrents;
use Illuminate\Http\Request;
class TorrentController extends Controller
{
/**
* Display Add Torrent Page.
*/
public function index(int $hentai_id): \Illuminate\View\View
{
return view('admin.add-torrent', [
'hentai_id' => $hentai_id
]);
}
/**
* Add Torrent.
*/
public function store(Request $request): \Illuminate\Http\RedirectResponse
{
$validated = $request->validate([
'hentai_id' => 'required|exists:hentais,id',
'torrent_url' => 'required|string|max:256',
'torrent_episodes' => 'required|string|max:8',
]);
Torrents::create([
'hentai_id' => $request->hentai_id,
'torrent_url' => $request->torrent_url,
'episodes' => $request->torrent_episodes,
]);
return to_route('download.search');
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Hentai;
use App\Models\PopularMonthly;
use Illuminate\Support\Facades\Cache;
use App\Http\Controllers\Controller;
class HentaiApiController extends Controller
{
/**
* Get a list of all hentai with it's episodes
*/
public function index()
{
// Cache for 10 minutes
$data = Cache::remember('api_hentai_list', now()->addMinutes(10), function () {
return Hentai::with('episodes')
->orderBy('created_at', 'desc')
->get()
->map(function ($hentai) {
return [
'title' => $hentai->episodes[0]->title,
'title_jpn' => $hentai->episodes[0]->title_jpn,
'slug' => $hentai->slug,
'episodes' => $hentai->episodes->map(function ($ep) {
return [
'episode' => $ep->episode,
'slug' => $ep->slug,
];
}),
];
});
});
return response()->json($data);
}
/**
* Get monthly views by day for stats
*/
public function getMonthlyViews()
{
// Cache for 60 minutes
$data = Cache::remember('api_monthly_views', now()->addMinutes(60), function () {
return PopularMonthly::selectRaw('DATE(created_at) as date, COUNT(*) as count')
->groupBy('date')
->orderBy('date', 'asc')
->get();
});
return response()->json($data);
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DownloadsController extends Controller
{
/**
* Display Downloads Page.
*/
public function index(Request $request): \Illuminate\View\View
{
$user = $request->user();
if (!$user->is_patreon) {
abort(404);
}
return view('search.download-patreon');
}
}

View File

@@ -52,6 +52,22 @@ class HomeController extends Controller
return view('auth.banned'); return view('auth.banned');
} }
/**
* Redirects to a random Hentai episode
* Done due to performance reasons
*/
public function random(): \Illuminate\Http\RedirectResponse
{
$random = Episode::inRandomOrder()
->limit(1)
->pluck('slug')
->first();
return redirect()->route('hentai.index', [
'title' => $random,
]);
}
/** /**
* Display Search Page. * Display Search Page.
*/ */
@@ -87,7 +103,6 @@ class HomeController extends Controller
'viewCount' => CacheHelper::getTotalViewCount(), 'viewCount' => CacheHelper::getTotalViewCount(),
'episodeCount' => CacheHelper::getTotalEpisodeCount(), 'episodeCount' => CacheHelper::getTotalEpisodeCount(),
'hentaiCount' => CacheHelper::getTotalHentaiCount(), 'hentaiCount' => CacheHelper::getTotalHentaiCount(),
'monthlyCount' => CacheHelper::getTotalMonthlyViews()
]); ]);
} }

View File

@@ -32,19 +32,29 @@ class DiscordReleaseNotification implements ShouldQueue
*/ */
public function handle(): void public function handle(): void
{ {
// Wait 2s to avoid Discord API Rate limit switch($this->messageType)
sleep(2); {
case 'release':
if ($this->messageType == 'release') { DiscordAlert::message("<@&868457842250764289> (´• ω •`)ノ New **4k** Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
DiscordAlert::message("<@&868457842250764289> (´• ω •`)ノ New **4k** Release! Check it out here: https://hstream.moe/hentai/".$this->slug); break;
} case 'release-censored':
# Because Discord TOS
if ($this->messageType == 'update') { DiscordAlert::message("<@&868457842250764289> (´• ω •`)ノ New **4k** Release: ".$this->slug." - *No link here because of* :pLoli:");
DiscordAlert::to('update')->message("<@&1283518462584426598> (´• ω •`)ノ Added **48fps** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug); break;
} case 'update':
# 1080p 48fps added
if ($this->messageType == 'updateUHD') { DiscordAlert::to('update')->message("<@&1283518462584426598> (´• ω •`)ノ Added **48fps** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
DiscordAlert::to('update')->message("<@&1326860920902778963> (´• ω •`)ノ Added **48fps 4k** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug); break;
case 'updateUHD':
# 4k 48fps added
DiscordAlert::to('update')->message("<@&1326860920902778963> (´• ω •`)ノ Added **48fps 4k** to Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
break;
case 'v2':
# v2 re-release
DiscordAlert::to('rerelease')->message("<@&1425505303075754035> (´• ω •`)ノ **v2 Re-**Release! Check it out here: https://hstream.moe/hentai/".$this->slug);
break;
default:
break;
} }
} }
} }

View File

@@ -32,11 +32,6 @@ class Hentai extends Model implements Sitemapable
return $this->hasMany(Episode::class, 'hentai_id'); return $this->hasMany(Episode::class, 'hentai_id');
} }
public function torrents()
{
return $this->hasMany(Torrents::class, 'hentai_id');
}
public function title(): String public function title(): String
{ {
return $this->episodes->first()->title; return $this->episodes->first()->title;

View File

@@ -1,22 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Torrents extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [
'hentai_id',
'torrent_url',
'episodes',
];
}

View File

@@ -19,7 +19,7 @@
"laravel/tinker": "^2.10", "laravel/tinker": "^2.10",
"laravelista/comments": "dev-l11-compatibility", "laravelista/comments": "dev-l11-compatibility",
"livewire/livewire": "^3.6.4", "livewire/livewire": "^3.6.4",
"maize-tech/laravel-markable": "2.2.0", "maize-tech/laravel-markable": "^2.3.0",
"mews/captcha": "3.4.4", "mews/captcha": "3.4.4",
"predis/predis": "^2.2", "predis/predis": "^2.2",
"realrashid/sweet-alert": "^7.2", "realrashid/sweet-alert": "^7.2",
@@ -29,7 +29,7 @@
"vluzrmos/language-detector": "^2.3" "vluzrmos/language-detector": "^2.3"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "3.14.7", "barryvdh/laravel-debugbar": "^3.14.7",
"fakerphp/faker": "^1.24.0", "fakerphp/faker": "^1.24.0",
"laravel/pint": "^1.18", "laravel/pint": "^1.18",
"laravel/sail": "^1.38", "laravel/sail": "^1.38",

2567
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ return [
'webhook_urls' => [ 'webhook_urls' => [
'default' => env('DISCORD_ALERT_WEBHOOK'), 'default' => env('DISCORD_ALERT_WEBHOOK'),
'update' => env('DISCORD_ALERT_UPDATE_WEBHOOK'), 'update' => env('DISCORD_ALERT_UPDATE_WEBHOOK'),
'rerelease' => env('DISCORD_ALERT_RERELEASE_WEBHOOK'),
], ],
/* /*

View File

@@ -6,7 +6,8 @@ return [
'https://imoto-ddl.ane-h.xyz', 'https://imoto-ddl.ane-h.xyz',
'https://chibi-ddl.imoto-h.xyz', 'https://chibi-ddl.imoto-h.xyz',
'https://koneko-ddl.musume-h.xyz', 'https://koneko-ddl.musume-h.xyz',
'https://shinobu-ddl.rorikon-h.xyz' 'https://shinobu-ddl.rorikon-h.xyz',
'https://oppai-ddl.shoujo-h.org',
], ],
// 4k Download Domain // 4k Download Domain
@@ -14,7 +15,8 @@ return [
'https://imoto-ddlp.ane-h.xyz', 'https://imoto-ddlp.ane-h.xyz',
'https://chibi-ddlp.imoto-h.xyz', 'https://chibi-ddlp.imoto-h.xyz',
'https://koneko-ddlp.musume-h.xyz', 'https://koneko-ddlp.musume-h.xyz',
'https://shinobu-ddlp.rorikon-h.xyz' 'https://shinobu-ddlp.rorikon-h.xyz',
'https://oppai-ddlp.shoujo-h.org',
], ],
// Stream Domain // Stream Domain
@@ -22,7 +24,8 @@ return [
'https://imoto-str.ane-h.xyz', 'https://imoto-str.ane-h.xyz',
'https://chibi-str.imoto-h.xyz', 'https://chibi-str.imoto-h.xyz',
'https://koneko-str.musume-h.xyz', 'https://koneko-str.musume-h.xyz',
'https://shinobu-str.rorikon-h.xyz' 'https://shinobu-str.rorikon-h.xyz',
'https://oppai-str.shoujo-h.org',
], ],
// Asia Fallback (HTTP) // Asia Fallback (HTTP)

View File

@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::dropIfExists('torrents');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Not reversible
}
};

1824
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,17 +9,18 @@
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"autoprefixer": "^10.4.18", "autoprefixer": "^10.4.18",
"axios": "^1.6.8", "axios": "^1.6.8",
"laravel-vite-plugin": "^1.0.2", "laravel-vite-plugin": "^2.0.0",
"postcss": "^8.4.35", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"vite": "^5.1.6", "vite": "^7.1.6",
"vite-plugin-static-copy": "^1.0.1" "vite-plugin-static-copy": "^3.0.1"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.5.1", "@fortawesome/fontawesome-free": "^6.5.1",
"@jellyfin/libass-wasm": "^4.1.1", "@jellyfin/libass-wasm": "^4.1.1",
"@yaireo/tagify": "^4.21.2", "@yaireo/tagify": "^4.21.2",
"dashjs": "^4.7.4", "chart.js": "^4.5.0",
"dashjs": "^5.0.0",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"plyr": "^3.7.8", "plyr": "^3.7.8",
"tw-elements": "^1.1.0", "tw-elements": "^1.1.0",

View File

@@ -1,5 +1,5 @@
// Plyr Player // Plyr Player
import Plyr from 'plyr/dist/plyr.polyfilled.min.js'; import Plyr from 'plyr';
import 'plyr/dist/plyr.css'; import 'plyr/dist/plyr.css';
// Vidstack Player // Vidstack Player
@@ -8,7 +8,7 @@ import 'vidstack/player/styles/default/layouts/video.css';
import { VidstackPlayer, VidstackPlayerLayout } from 'vidstack/global/player'; import { VidstackPlayer, VidstackPlayerLayout } from 'vidstack/global/player';
// Dash Support // Dash Support
import dashjs from 'dashjs'; import * as dashjs from 'dashjs';
// Subtitle Support // Subtitle Support
import SubtitlesOctopus from '@jellyfin/libass-wasm'; import SubtitlesOctopus from '@jellyfin/libass-wasm';

73
resources/js/stats.js Normal file
View File

@@ -0,0 +1,73 @@
import Chart from 'chart.js/auto';
// Theming
if (localStorage.theme !== 'light') {
Chart.defaults.color = "#ADBABD";
Chart.defaults.borderColor = "rgba(255,255,255,0.1)";
Chart.defaults.backgroundColor = "rgba(255,255,0,0.1)";
Chart.defaults.elements.line.borderColor = "rgba(255,255,0,0.4)";
}
// Get Tags from API
window.axios.get('/v1/monthly-views').then(function (response) {
if (response.status != 200) {
return;
}
const data = {
labels: response.data.map((entry) => { return entry.date }),
datasets: [{
label: 'Views',
fill: false,
backgroundColor: 'rgba(190, 18, 60, 0.3)',
borderColor: 'rgba(190, 18, 60, 1.0)',
cubicInterpolationMode: 'monotone',
data: response.data.map((entry) => { return entry.count }),
}]
}
const config = {
type: 'line',
data: data,
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Views the last 30 days',
font: {
size: 18
}
},
},
interaction: {
intersect: false,
},
scales: {
x: {
display: true,
title: {
display: true
}
},
y: {
display: true,
title: {
display: true,
text: 'Views'
},
suggestedMin: 0,
suggestedMax: 40000
}
}
},
};
const monthlyViewChart = new Chart(
document.getElementById('monthlyChart'),
config
);
}).catch(function (error) {
console.log(error);
});

View File

@@ -1,32 +0,0 @@
<x-app-layout>
<div class="p-5">
<div class="w-[50%] mx-auto sm:px-6 lg:px-8 text-gray-800 dark:text-gray-200 bg-white dark:bg-neutral-950 rounded-lg">
<div class="relative p-4">
<form method="POST" action="{{ route('admin.add.torrent') }}">
@csrf
<div class="p-4">
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Hentai ID:</label>
<input id="hentai_id" name="hentai_id" class="block w-full p-4 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900" value="{{ $hentai_id }}" required>
</div>
<div class="p-4">
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Torrent URL:</label>
<input id="torrent_url" name="torrent_url" class="block w-full p-4 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900" required>
</div>
<div class="p-4">
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Episodes (e.g. "01-02" or "01"):</label>
<input id="torrent_episodes" name="torrent_episodes" class="block w-full p-4 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900" required>
</div>
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
<button type="submit" class="ml-1 inline-block rounded bg-rose-600 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600" data-te-ripple-init data-te-ripple-color="light">
Create
</button>
</div>
</form>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -97,6 +97,13 @@
</div> </div>
<div class="flex flex-wrap flex-shrink-0 justify-end items-center p-4 rounded-b-md"> <div class="flex flex-wrap flex-shrink-0 justify-end items-center p-4 rounded-b-md">
<div class="inline-block mr-2">
<input class="w-4 h-4 text-rose-600 bg-gray-100 border-gray-300 rounded focus:ring-rose-500 dark:focus:ring-rose-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
type="checkbox" value="true" id="v2" name="v2" />
<label class="inline-block hover:cursor-pointer dark:text-white" for="v2">
v2 Re-Release Notification
</label>
</div>
<button type="button" class="inline-block px-6 pt-2.5 pb-2 text-xs font-medium leading-normal uppercase rounded transition duration-150 ease-in-out bg-primary-100 text-primary-700 hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light"> <button type="button" class="inline-block px-6 pt-2.5 pb-2 text-xs font-medium leading-normal uppercase rounded transition duration-150 ease-in-out bg-primary-100 text-primary-700 hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light">
Cancel Cancel
</button> </button>

View File

@@ -56,6 +56,13 @@
</div> </div>
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4"> <div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
<div class="inline-block mr-2">
<input class="w-4 h-4 text-rose-600 bg-gray-100 border-gray-300 rounded focus:ring-rose-500 dark:focus:ring-rose-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
type="checkbox" value="true" id="censored" name="censored" />
<label class="inline-block hover:cursor-pointer dark:text-white" for="censored">
Censored Notification
</label>
</div>
<button type="button" class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light"> <button type="button" class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light">
Cancel Cancel
</button> </button>

View File

@@ -62,13 +62,12 @@
<div class="p-4 pt-0"> <div class="p-4 pt-0">
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="description1">Description 1:</label> <label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="description1">Description 1:</label>
<textarea rows="4" cols="50" id="description1" name="description1" class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm" required> <textarea rows="4" cols="50" id="description1" name="description1" class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-neutral-900 dark:text-gray-300 focus:border-rose-500 dark:focus:border-rose-600 focus:ring-rose-500 dark:focus:ring-rose-600 rounded-md shadow-sm" required></textarea>
</textarea>
</div> </div>
<div class="p-4 pt-0"> <div class="p-4 pt-0">
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl1">Download 1080p 1:</label> <label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl1">Download 1080p 1:</label>
<x-text-input id="episodedlurl1" class="block w-full" type="text" name="episodedlurl1" required /> <x-text-input id="episodedlurl1" class="block w-full" type="text" name="episodedlurl1" />
</div> </div>
<div class="p-4 pt-0"> <div class="p-4 pt-0">
@@ -78,7 +77,7 @@
<div class="p-4 pt-0"> <div class="p-4 pt-0">
<label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl4k1">Download 4k 1:</label> <label class="leading-tight text-gray-800 dark:text-gray-200 w-full" for="episodedlurl4k1">Download 4k 1:</label>
<x-text-input id="episodedlurl4k1" class="block w-full" type="text" name="episodedlurl4k1" required /> <x-text-input id="episodedlurl4k1" class="block w-full" type="text" name="episodedlurl4k1" />
</div> </div>
<div class="p-4 pt-0"> <div class="p-4 pt-0">
@@ -90,6 +89,13 @@
</div> </div>
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4"> <div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
<div class="inline-block mr-2">
<input class="w-4 h-4 text-rose-600 bg-gray-100 border-gray-300 rounded focus:ring-rose-500 dark:focus:ring-rose-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
type="checkbox" value="true" id="censored" name="censored" />
<label class="inline-block hover:cursor-pointer dark:text-white" for="censored">
Censored Notification
</label>
</div>
<button type="button" class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light"> <button type="button" class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light">
Cancel Cancel
</button> </button>

View File

@@ -1,7 +1,11 @@
<x-app-layout> <x-app-layout>
<div class="container my-24 mx-auto md:px-6 z-10 relative"> <div class="container my-24 mx-auto md:px-6 z-10 relative">
<p class="leading-normal font-bold text-lg text-rose-600 text-center"> <p class="leading-normal font-bold text-2xl text-rose-600 text-center">
(╥﹏╥) (╥﹏╥)
</p> </p>
<br>
<p class="leading-normal font-bold text-lg text-rose-600 text-center">
Please login to view this hentai!
</p>
</div> </div>
</x-app-layout> </x-app-layout>

View File

@@ -1,6 +1,6 @@
@props(['episode']) @props(['episode'])
<div class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 hover:-translate-y-1 hover:scale-110"> <div class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 md:hover:-translate-y-1 md:hover:scale-110">
<a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}"> <a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}">
<img alt="{{ $episode->title }} - {{ $episode->episode }}" loading="lazy" width="1000" <img alt="{{ $episode->title }} - {{ $episode->episode }}" loading="lazy" width="1000"
class="block object-cover object-center relative z-20 rounded-lg aspect-video" class="block object-cover object-center relative z-20 rounded-lg aspect-video"
@@ -8,10 +8,10 @@
@guest @guest
<p <p
class="absolute right-2 top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-4 bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-4 bottom-1 md:bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i class="fa-regular fa-heart"></i> <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i class="fa-regular fa-heart"></i>
{{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i>
{{ $episode->commentCount() }} {{ $episode->commentCount() }}
@@ -29,20 +29,20 @@
@auth @auth
@if ($episode->userWatched(auth()->user()->id)) @if ($episode->userWatched(auth()->user()->id))
<p <p
class="absolute right-2 top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i>
{{ $episode->commentCount() }} {{ $episode->commentCount() }}
</p> </p>
@else @else
<p <p
class="absolute right-2 top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i>
{{ $episode->commentCount() }} {{ $episode->commentCount() }}
@@ -50,7 +50,7 @@
@endif @endif
@endauth @endauth
<div class="absolute w-[95%] grid grid-cols-1 text-center"> <div class="absolute w-[95%] grid grid-cols-1 text-center">
<p class="text-sm text-center text-black dark:text-white">{{ $episode->title }} - <p class="text-sm text-center text-black dark:text-white">{{ $episode->title }} -
{{ $episode->episode }}</p> {{ $episode->episode }}</p>
</div> </div>

View File

@@ -24,9 +24,8 @@
@include('home.partials.random') @include('home.partials.random')
</div> </div>
<!-- Comments --> <!-- Comments -->
<div class="mx-auto pt-6 sm:px-6 lg:px-8 space-y-6 max-w-[100%] xl:max-w-[95%] 2xl:max-w-[85%]"> <div class="mx-auto pt-6 sm:px-6 lg:px-8 space-y-6 max-w-[100%] xl:max-w-[95%] 2xl:max-w-[85%] pb-2">
@include('home.partials.comments') @include('home.partials.comments')
</div> </div>
</x-app-layout> </x-app-layout>

View File

@@ -1,8 +1,12 @@
<p class="leading-normal font-bold text-lg text-neutral-800 dark:text-white"> <p class="leading-normal font-bold text-lg text-neutral-800 dark:text-white">
Random Random <span class="font-light text-xs text-neutral-800/60 dark:text-white/40">(Cached for 5 minutes)</span>
</p> </p>
@php $random = \App\Models\Episode::inRandomOrder()->limit(8)->get(); @endphp @php
$random = \cache()->remember('random_home', 300, function () {
return \App\Models\Episode::inRandomOrder()->limit(8)->get(); ;
});
@endphp
<div class="mb-6"> <div class="mb-6">
@include('home.partials.tab.template', ['episodes' => $random, 'showThumbnails' => false]) @include('home.partials.tab.template', ['episodes' => $random, 'showThumbnails' => false])

View File

@@ -4,7 +4,7 @@
<div class="flex justify-center pb-10"> <div class="flex justify-center pb-10">
<img src="/images/cropped-HS-1-270x270.webp" class="max-w-[150px]" alt="hstream.moe Logo" /> <img src="/images/cropped-HS-1-270x270.webp" class="max-w-[150px]" alt="hstream.moe Logo" />
</div> </div>
<div class="grid md:grid-cols-5 lg:gap-x-12"> <div class="grid md:grid-cols-2 lg:grid-cols-4 lg:gap-x-12">
<div class="mb-12 md:mb-0"> <div class="mb-12 md:mb-0">
<div class="mb-6 inline-block rounded-md bg-white dark:bg-neutral-950 p-4 text-sky-500"> <div class="mb-6 inline-block rounded-md bg-white dark:bg-neutral-950 p-4 text-sky-500">
<i class="fa-solid fa-eye text-3xl"> {{ number_format($viewCount) }}</i> <i class="fa-solid fa-eye text-3xl"> {{ number_format($viewCount) }}</i>
@@ -14,15 +14,7 @@
</h5> </h5>
</div> </div>
<div class="mb-12 md:mb-0"> <div class="mb-12 md:mb-0">
<div class="mb-6 inline-block rounded-md bg-white dark:bg-neutral-950 p-4 text-sky-500"> <div class="b-6 inline-block rounded-md bg-white dark:bg-neutral-950 p-4 text-sky-500">
<i class="fa-solid fa-calendar-days text-3xl"> {{ number_format($monthlyCount) }}</i>
</div>
<h5 class="text-lg font-medium dark:text-neutral-300">
views the last 30 days
</h5>
</div>
<div class="mb-12 md:mb-0">
<div class="mb-6 inline-block rounded-md bg-white dark:bg-neutral-950 p-4 text-rose-600">
<i class="fa-solid fa-video text-3xl"> {{ $episodeCount }}</i> <i class="fa-solid fa-video text-3xl"> {{ $episodeCount }}</i>
</div> </div>
<h5 class="text-lg font-medium dark:text-neutral-300"> <h5 class="text-lg font-medium dark:text-neutral-300">
@@ -46,7 +38,10 @@
</h5> </h5>
</div> </div>
</div> </div>
<div class="flex justify-center dark:bg-neutral-950 bg-gray-50 rounded-xl md:m-11 hidden md:block">
<canvas id="monthlyChart"></canvas>
</div>
</section> </section>
<p class="text-center text-black/40 dark:text-white/40">Cached for 60 Minutes</p>
</div> </div>
@vite(['resources/js/stats.js'])
</x-app-layout> </x-app-layout>

View File

@@ -1,4 +1,4 @@
<footer class="mt-auto bg-white z-10 rounded-lg shadow dark:bg-neutral-950 m-4"> <footer class="bg-white z-10 rounded-lg shadow dark:bg-neutral-950 m-4 mb-0 mt-auto">
<div class="w-full xl:max-w-[95%] 2xl:max-w-[84%] mx-auto p-4"> <div class="w-full xl:max-w-[95%] 2xl:max-w-[84%] mx-auto p-4">
<div class="sm:flex sm:items-center sm:justify-between"> <div class="sm:flex sm:items-center sm:justify-between">
<a href="https://hstream.moe/" class="flex items-center mb-4 sm:mb-0"> <a href="https://hstream.moe/" class="flex items-center mb-4 sm:mb-0">
@@ -65,3 +65,9 @@
</div> </div>
</footer> </footer>
@include('modals.language-selector') @include('modals.language-selector')
<div class="m-2 w-full mx-auto">
<div class="text-sm text-gray-500 text-center">
<p>Render time: {{ number_format(microtime(true) - (defined('LARAVEL_START') ? LARAVEL_START : request()->server('REQUEST_TIME_FLOAT')), 3) }} seconds | Memory usage: {{ number_format(memory_get_peak_usage(true) / 1048576, 2) }} MB | Git: <a href="https://gitea.hstream.moe/w33b/hstream/commits/branch/main" target="_blank">{{ \App\Helpers\GitHelper::shortCommit() }}</a></p>
</div>
</div>

View File

@@ -67,8 +67,7 @@
@livewire('nav-live-search') @livewire('nav-live-search')
<div class="hidden lg:block pl-4"> <div class="hidden lg:block pl-4">
<div class="flex flex-col items-center bg-gray-50/20 dark:bg-neutral-900/40 rounded-md"> <div class="flex flex-col items-center bg-gray-50/20 dark:bg-neutral-900/40 rounded-md">
@php $random = App\Models\Episode::inRandomOrder()->limit(1)->pluck('slug')->first(); @endphp <a href="{{ route('hentai.random') }}"
<a href="{{ route('hentai.index', ['title' => $random]) }}"
class="cursor-pointer px-4 py-2 text-sm font-medium dark:hover:text-white text-gray-500 dark:text-white/90 focus:outline-none flex flex-col items-center md:flex-row"> class="cursor-pointer px-4 py-2 text-sm font-medium dark:hover:text-white text-gray-500 dark:text-white/90 focus:outline-none flex flex-col items-center md:flex-row">
<i class="fa-solid fa-shuffle"></i> <i class="fa-solid fa-shuffle"></i>
<p class="md:pl-1 pl-0">Random</p> <p class="md:pl-1 pl-0">Random</p>

View File

@@ -1,10 +1,10 @@
<div wire:key="episode-{{ $episode->id }}"> <div wire:key="episode-{{ $episode->id }}">
@if ($searchIsJpn) @if ($searchIsJpn)
<div class="relative p-1 mb-14 w-full transition duration-300 ease-in-out md:p-2 hover:-translate-y-1 hover:scale-110" <div class="relative p-1 mb-14 w-full transition duration-300 ease-in-out md:p-2 md:hover:-translate-y-1 md:hover:scale-110"
data-thumbs="{{ optional($episode->gallery)->pluck('thumbnail_url') }}"> data-thumbs="{{ optional($episode->gallery)->pluck('thumbnail_url') }}">
@else @else
<div class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 hover:-translate-y-1 hover:scale-110" <div class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 md:hover:-translate-y-1 md:hover:scale-110"
data-thumbs="{{ optional($episode->gallery)->pluck('thumbnail_url') }}"> data-thumbs="{{ optional($episode->gallery)->pluck('thumbnail_url') }}">
@endif @endif
<a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}"> <a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}">
<div class="absolute w-[95%] top-[38%] text-center z-10"> <div class="absolute w-[95%] top-[38%] text-center z-10">
@@ -27,7 +27,7 @@
src="{{ optional($episode->gallery->first())->thumbnail_url }}"> src="{{ optional($episode->gallery->first())->thumbnail_url }}">
@if ($episode->hasAutoTrans()) @if ($episode->hasAutoTrans())
<p <p
class="absolute right-2 bottom-2 bg-blue-600/80 !text-white rounded-tl-lg rounded-br-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 bottom-1 md:bottom-2 bg-blue-600/80 !text-white rounded-tl-lg rounded-br-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-closed-captioning"></i> Multi-Subs <i class="fa-regular fa-closed-captioning"></i> Multi-Subs
</p> </p>
@endif @endif
@@ -44,27 +44,27 @@
@php $problematic = cache()->rememberForever('episodeProblematic'.$episode->id, fn () => $episode->getProblematicTags()); @endphp @php $problematic = cache()->rememberForever('episodeProblematic'.$episode->id, fn () => $episode->getProblematicTags()); @endphp
@if (!empty($problematic)) @if (!empty($problematic))
<p <p
class="absolute left-2 top-2 bg-red-700/70 !text-white rounded-br-lg rounded-tl-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 top-1 md:top-2 bg-red-700/70 !text-white rounded-br-lg rounded-tl-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-solid fa-triangle-exclamation"></i> {{ $problematic }} <i class="fa-solid fa-triangle-exclamation"></i> {{ $problematic }}
</p> </p>
@endif @endif
@if (auth()->check() && $episode->userWatched(auth()->user()->id)) @if (auth()->check() && $episode->userWatched(auth()->user()->id))
<p <p
class="absolute right-2 top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> class="fa-regular fa-heart"></i>
{{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> {{ $episode->commentCount() }} {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> {{ $episode->commentCount() }}
</p> </p>
@else @else
<p <p
class="absolute right-2 top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> <i class="fa-regular fa-eye"></i>
{{ $episode->viewCountFormatted() }} {{ $episode->viewCountFormatted() }}
<i class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> <i class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i>

View File

@@ -1,25 +0,0 @@
@forelse ($hentai->torrents as $torrent)
<a href="{{ $torrent->torrent_url }}" target="_blank">
<button class="group rounded-md shadow bg-primary-600 text-white cursor-pointer flex justify-between items-center overflow-hidden transition-all hover:glow m-1 w-[150px]">
<div class="relative w-12 h-12 bg-white bg-opacity-20 text-white flex justify-center items-center transition-all">
<i id="arrow" class="fa-solid fa-magnet transition-all group-hover:-translate-y-1"></i>
<div id="progress" class="absolute w-full h-0 bg-white bg-opacity-20 top-0 duration-200"></div>
</div>
<div class="w-32 text-center">
<p class="text-sm">Episode {{ $torrent->episodes }}</p>
</div>
</button>
</a>
@empty
<a>
<button class="group rounded-md shadow bg-gray-600 text-white cursor-pointer flex justify-between items-center overflow-hidden transition-all hover:glow m-1 w-[150px]">
<div class="relative w-12 h-12 bg-white bg-opacity-20 text-white flex justify-center items-center transition-all">
<i id="arrow" class="fa-solid fa-magnet transition-all group-hover:-translate-y-1"></i>
<div id="progress" class="absolute w-full h-0 bg-white bg-opacity-20 top-0 duration-200"></div>
</div>
<div class="w-32 text-center">
<p class="text-sm">Torrent not available</p>
</div>
</button>
</a>
@endforelse

View File

@@ -1,4 +1,6 @@
@auth @auth
@php $download = $episode->getDownloadByType('FHD'); @endphp
@isset($download)
<p class="font-bold text-gray-800 dark:text-gray-200"> <p class="font-bold text-gray-800 dark:text-gray-200">
<i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> 1080p <i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> 1080p
</p> </p>
@@ -13,13 +15,21 @@
@foreach ($dlList as $hdl) @foreach ($dlList as $hdl)
@include('modals.partials.download-button') @include('modals.partials.download-button')
@endforeach @endforeach
@include('livewire.partials.torrent-button', ['hentai' => $episode->hentai])
</div> </div>
@include('modals.partials.download-backup') @include('modals.partials.download-backup')
@else
<p class="text-gray-800 dark:text-gray-200 font-bold">
<i class="fa-solid fa-lock pr-[4px] text-red-600"></i> 1080p
</p>
<p class="text-gray-800 dark:text-gray-200">
Unavailable.
</p>
@endisset
@if ($episode->interpolated) @if ($episode->interpolated)
@php $download = $episode->getDownloadByType('FHDi'); @endphp
@isset($download)
<p class="font-bold text-gray-800 dark:text-gray-200"> <p class="font-bold text-gray-800 dark:text-gray-200">
<i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> 1080p 48fps <i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> 1080p 48fps
</p> </p>
@@ -29,10 +39,19 @@
@include('modals.partials.download-button-interpolated') @include('modals.partials.download-button-interpolated')
@endforeach @endforeach
</div> </div>
@else
<p class="text-gray-800 dark:text-gray-200 font-bold">
<i class="fa-solid fa-lock pr-[4px] text-red-600"></i> 1080p 48fps
</p>
<p class="text-gray-800 dark:text-gray-200">
Unavailable.
</p>
@endisset
@endif @endif
<br> <br>
@php $download = $episode->getDownloadByType('UHD'); @endphp
@isset($download)
@if (!Auth::user()->is_patreon) @if (!Auth::user()->is_patreon)
@if (config('hstream.free_downloads')) @if (config('hstream.free_downloads'))
<p class="font-bold text-gray-800 dark:text-gray-200"> <p class="font-bold text-gray-800 dark:text-gray-200">
@@ -61,6 +80,14 @@
@endforeach @endforeach
</div> </div>
@endif @endif
@else
<p class="text-gray-800 dark:text-gray-200 font-bold">
<i class="fa-solid fa-lock pr-[4px] text-red-600"></i> 4k
</p>
<p class="text-gray-800 dark:text-gray-200">
Unavailable.
</p>
@endisset
<br> <br>
@if ($episode->interpolated_uhd) @if ($episode->interpolated_uhd)

View File

@@ -8,6 +8,9 @@
@foreach ($dlList as $hdl) @foreach ($dlList as $hdl)
@php @php
$download = $hdl->getDownloadByType('FHD'); $download = $hdl->getDownloadByType('FHD');
@endphp
@isset($download)
@php
$downloadURL = $dlDomainsBackup[array_rand($dlDomainsBackup)].'/'.$download->url; $downloadURL = $dlDomainsBackup[array_rand($dlDomainsBackup)].'/'.$download->url;
$background = 'bg-green-600'; $background = 'bg-green-600';
@endphp @endphp
@@ -20,6 +23,11 @@
:fill-numbers="$fillNumbers" :fill-numbers="$fillNumbers"
:file-size="$download->getFileSize()" :file-size="$download->getFileSize()"
:background="$background"> :background="$background">
@else
<a class="inline-flex items-center ml-4 px-4 p-4 mt-4 cursor-not-allowed bg-gray-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-rose-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150" id="downloadEpisode" alt="Kekw">
<i class="fa-solid fa-download mr-2"></i> Episode {{ $hdl->episode }} (Unavailable)
</a>
@endisset
@endforeach @endforeach
</div> </div>
</div> </div>

View File

@@ -1,5 +1,9 @@
@php @php
$download = $hdl->getDownloadByType('FHD'); $download = $hdl->getDownloadByType('FHD');
@endphp
@isset($download)
@php
$downloadURL = $dldomains[array_rand($dldomains)].'/'.$download->url; $downloadURL = $dldomains[array_rand($dldomains)].'/'.$download->url;
@endphp @endphp
@@ -10,3 +14,8 @@
:episode-number="$hdl->episode" :episode-number="$hdl->episode"
:fill-numbers="$fillNumbers" :fill-numbers="$fillNumbers"
:file-size="$download->getFileSize()"> :file-size="$download->getFileSize()">
@else
<a class="inline-flex items-center ml-4 px-4 p-4 mt-4 cursor-not-allowed bg-gray-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-rose-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150" id="downloadEpisode" alt="Kekw">
<i class="fa-solid fa-download mr-2"></i> Episode {{ $hdl->episode }} (Unavailable)
</a>
@endisset

View File

@@ -1,5 +1,16 @@
@guest @guest
@php $download = $episode->getDownloadByType('FHD'); @endphp
@isset($download)
@include('modals.partials.download-captcha') @include('modals.partials.download-captcha')
@else
<p class="text-gray-800 dark:text-gray-200 font-bold">
<i class="fa-solid fa-lock pr-[4px] text-red-600"></i> FHD
</p>
<p class="text-gray-800 dark:text-gray-200">
Unavailable.
</p>
@endisset
@if ($episode->interpolated) @if ($episode->interpolated)
<br> <br>

View File

@@ -1,4 +1,6 @@
<br> <br>
@php $download = $episode->getDownloadByType('FHD'); @endphp
@isset($download)
<p class="font-bold text-gray-800 dark:text-gray-200"> <p class="font-bold text-gray-800 dark:text-gray-200">
<i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> Subtitles <i class="fa-solid fa-lock-open pr-[4px] text-green-400"></i> Subtitles
</p> </p>
@@ -32,3 +34,11 @@
@endforeach @endforeach
@endforeach @endforeach
</div> </div>
@else
<p class="text-gray-800 dark:text-gray-200 font-bold">
<i class="fa-solid fa-lock pr-[4px] text-red-600"></i> Subtitles
</p>
<p class="text-gray-800 dark:text-gray-200">
Unavailable.
</p>
@endisset

View File

@@ -12,7 +12,7 @@
@endif @endif
<div <div
class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 hover:-translate-y-1 hover:scale-110"> class="relative p-1 mb-8 w-full transition duration-300 ease-in-out md:p-2 md:hover:-translate-y-1 md:hover:scale-110">
<a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}"> <a class="hover:text-blue-600" href="{{ route('hentai.index', ['title' => $episode->slug]) }}">
<img alt="{{ $episode->title }} - {{ $episode->episode }}" loading="lazy" width="400" <img alt="{{ $episode->title }} - {{ $episode->episode }}" loading="lazy" width="400"
class="block relative rounded-lg object-cover object-center aspect-[11/16] z-20 " class="block relative rounded-lg object-cover object-center aspect-[11/16] z-20 "
@@ -20,10 +20,10 @@
@guest @guest
<p <p
class="absolute right-2 top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i> class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-comment"></i>
{{ $episode->commentCount() }} {{ $episode->commentCount() }}
@@ -33,7 +33,7 @@
@php $problematic = cache()->rememberForever('episodeProblematic'.$episode->id, fn () => $episode->getProblematicTags()); @endphp @php $problematic = cache()->rememberForever('episodeProblematic'.$episode->id, fn () => $episode->getProblematicTags()); @endphp
@if (!empty($problematic)) @if (!empty($problematic))
<p <p
class="absolute left-2 top-2 bg-red-700/70 !text-white rounded-br-lg rounded-tl-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 top-1 md:top-2 bg-red-700/70 !text-white rounded-br-lg rounded-tl-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-solid fa-triangle-exclamation"></i> {{ $problematic }} <i class="fa-solid fa-triangle-exclamation"></i> {{ $problematic }}
</p> </p>
@endif @endif
@@ -41,20 +41,20 @@
@auth @auth
@if ($episode->userWatched(auth()->user()->id)) @if ($episode->userWatched(auth()->user()->id))
<p <p
class="absolute right-2 top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-green-600/80 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i
class="fa-regular fa-comment"></i> {{ $episode->commentCount() }} class="fa-regular fa-comment"></i> {{ $episode->commentCount() }}
</p> </p>
@else @else
<p <p
class="absolute right-2 top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute right-1 md:right-2 top-1 md:top-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
{{ $episode->getResolution() }}</p> {{ $episode->getResolution() }}</p>
<p <p
class="absolute left-2 bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30"> class="absolute left-1 md:left-2 bottom-1 md:bottom-2 bg-rose-700/70 !text-white rounded-bl-lg rounded-tr-lg p-1 pr-2 pl-2 font-semibold text-sm z-30">
<i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i <i class="fa-regular fa-eye"></i> {{ $episode->viewCountFormatted() }} <i
class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i class="fa-regular fa-heart"></i> {{ $episode->likeCount() }} <i
class="fa-regular fa-comment"></i> {{ $episode->commentCount() }} class="fa-regular fa-comment"></i> {{ $episode->commentCount() }}

View File

@@ -1,7 +1,6 @@
<?php <?php
use App\Http\Controllers\ContactController; use App\Http\Controllers\ContactController;
use App\Http\Controllers\DownloadsController;
use App\Http\Controllers\HomeController; use App\Http\Controllers\HomeController;
use App\Http\Controllers\PlaylistController; use App\Http\Controllers\PlaylistController;
use App\Http\Controllers\ProfileController; use App\Http\Controllers\ProfileController;
@@ -9,6 +8,7 @@ use App\Http\Controllers\StreamController;
use App\Http\Controllers\UserController; use App\Http\Controllers\UserController;
use App\Http\Controllers\Api\AdminApiController; use App\Http\Controllers\Api\AdminApiController;
use App\Http\Controllers\Api\DownloadApiController; use App\Http\Controllers\Api\DownloadApiController;
use App\Http\Controllers\Api\HentaiApiController;
use App\Http\Controllers\Api\StreamApiController; use App\Http\Controllers\Api\StreamApiController;
use App\Http\Controllers\Api\UserApiController; use App\Http\Controllers\Api\UserApiController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@@ -22,6 +22,11 @@ use Illuminate\Support\Facades\Route;
Route::get('/', [HomeController::class, 'index'])->name('home.index'); Route::get('/', [HomeController::class, 'index'])->name('home.index');
Route::get('/stats', [HomeController::class, 'stats'])->name('home.stats'); Route::get('/stats', [HomeController::class, 'stats'])->name('home.stats');
Route::get('/banned', [HomeController::class, 'banned'])->name('home.banned'); Route::get('/banned', [HomeController::class, 'banned'])->name('home.banned');
Route::get('/random', [HomeController::class, 'random'])->name('hentai.random');
// API Endpoint
Route::get('/v1/hentai-list', [HentaiApiController::class, 'index'])->name('api.hentai.index');
Route::get('/v1/monthly-views', [HentaiApiController::class, 'getMonthlyViews'])->name('api.hentai.monthly');
// Stream Page // Stream Page
Route::get('/hentai/{title}', [StreamController::class, 'index'])->name('hentai.index'); Route::get('/hentai/{title}', [StreamController::class, 'index'])->name('hentai.index');
@@ -123,10 +128,6 @@ Route::group(['middleware' => ['auth', 'auth.admin']], function () {
Route::get('/admin/tags/{episode_id}', [AdminApiController::class, 'getEpisodeTags'])->name('admin.tags.episode'); Route::get('/admin/tags/{episode_id}', [AdminApiController::class, 'getEpisodeTags'])->name('admin.tags.episode');
Route::get('/admin/studio/{episode_id}', [AdminApiController::class, 'getEpisodeStudio'])->name('admin.studio.episode'); Route::get('/admin/studio/{episode_id}', [AdminApiController::class, 'getEpisodeStudio'])->name('admin.studio.episode');
// Torrents
Route::get('/admin/add-torrent/{hentai_id}', [App\Http\Controllers\Admin\TorrentController::class, 'index'])->name('admin.add.torrentpage');
Route::post('/admin/add-torrent', [App\Http\Controllers\Admin\TorrentController::class, 'store'])->name('admin.add.torrent');
// Subtitles // Subtitles
Route::get('/admin/subtitles/{episode_id}', [AdminApiController::class, 'getSubtitles'])->name('admin.subtitles'); Route::get('/admin/subtitles/{episode_id}', [AdminApiController::class, 'getSubtitles'])->name('admin.subtitles');
Route::post('/admin/add-new-subtitle', [App\Http\Controllers\Admin\SubtitleController::class, 'store'])->name('admin.add.new.subtitle'); Route::post('/admin/add-new-subtitle', [App\Http\Controllers\Admin\SubtitleController::class, 'store'])->name('admin.add.new.subtitle');

View File

@@ -20,7 +20,8 @@ export default defineConfig({
'resources/js/user-blacklist.js', 'resources/js/user-blacklist.js',
'resources/js/admin-edit.js', 'resources/js/admin-edit.js',
'resources/js/admin-subtitles.js', 'resources/js/admin-subtitles.js',
'resources/js/preview.js' 'resources/js/preview.js',
'resources/js/stats.js'
], ],
refresh: true, refresh: true,
}), }),