Init
This commit is contained in:
50
app/Http/Controllers/Admin/AlertController.php
Normal file
50
app/Http/Controllers/Admin/AlertController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Alert;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AlertController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display alert index page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('admin.alert.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Alert.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'message' => 'required|string|max:255',
|
||||
'type' => 'required|integer|min:0|digits_between:0,1',
|
||||
]);
|
||||
|
||||
Alert::create([
|
||||
'text' => $request->input('message'),
|
||||
'type' => $request->input('type'),
|
||||
]);
|
||||
|
||||
cache()->forget('alerts');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Alert.
|
||||
*/
|
||||
public function delete(int $alert_id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
Alert::where('id', $alert_id)->forceDelete();
|
||||
|
||||
cache()->forget('alerts');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
31
app/Http/Controllers/Admin/ContactController.php
Normal file
31
app/Http/Controllers/Admin/ContactController.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Contact Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
$contacts = Contact::orderBy('created_at', 'DESC')->get();
|
||||
|
||||
return view('admin.contact.index', [
|
||||
'contacts' => $contacts
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Contact.
|
||||
*/
|
||||
public function delete(int $contact_id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
Contact::where('id', $contact_id)->delete();
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
85
app/Http/Controllers/Admin/EpisodeController.php
Normal file
85
app/Http/Controllers/Admin/EpisodeController.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Episode;
|
||||
|
||||
use App\Jobs\DiscordReleaseNotification;
|
||||
use App\Services\DownloadService;
|
||||
use App\Services\EpisodeService;
|
||||
use App\Services\GalleryService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EpisodeController extends Controller
|
||||
{
|
||||
protected EpisodeService $episodeService;
|
||||
protected GalleryService $galleryService;
|
||||
protected DownloadService $downloadService;
|
||||
|
||||
public function __construct(
|
||||
EpisodeService $episodeService,
|
||||
GalleryService $galleryService,
|
||||
DownloadService $downloadService
|
||||
) {
|
||||
$this->episodeService = $episodeService;
|
||||
$this->galleryService = $galleryService;
|
||||
$this->downloadService = $downloadService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Episode to existing series
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$referenceEpisode = Episode::with('hentai')->where('id', $request->input('episode_id'))->firstOrFail();
|
||||
$episodeNumber = $referenceEpisode->hentai->episodes()->count() + 1;
|
||||
|
||||
// Create Episode
|
||||
$episode = $this->episodeService->createEpisode($request, $referenceEpisode->hentai, $episodeNumber, null, $referenceEpisode);
|
||||
$this->episodeService->createOrUpdateCover($request, $episode, $referenceEpisode->hentai->slug, 1);
|
||||
$this->downloadService->createOrUpdateDownloads($request, $episode, 1);
|
||||
$this->galleryService->createOrUpdateGallery($request, $referenceEpisode->hentai, $episode, $episodeNumber, true);
|
||||
|
||||
// Discord Alert
|
||||
DiscordReleaseNotification::dispatch($episode->slug, 'release');
|
||||
|
||||
cache()->flush();
|
||||
|
||||
return to_route('hentai.index', [
|
||||
'title' => $episode->slug
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit Episode
|
||||
*/
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$episode = Episode::with('hentai')->where('id', $request->input('episode_id'))->firstOrFail();
|
||||
$studio = $this->episodeService->getOrCreateStudio(json_decode($request->input('studio'))[0]->value);
|
||||
|
||||
$oldinterpolated = $episode->interpolated;
|
||||
$oldInterpolatedUHD = $episode->interpolated_uhd;
|
||||
|
||||
$episode = $this->episodeService->updateEpisode($request, $studio, $episode->id);
|
||||
$this->episodeService->createOrUpdateCover($request, $episode, $episode->hentai->slug, 1);
|
||||
$this->downloadService->createOrUpdateDownloads($request, $episode, 1);
|
||||
$this->galleryService->createOrUpdateGallery($request, $episode->hentai, $episode, $episode->episode, true);
|
||||
|
||||
// Discord Alert
|
||||
if ($oldinterpolated !== (int) $episode->interpolated) {
|
||||
DiscordReleaseNotification::dispatch($episode->slug, 'update');
|
||||
}
|
||||
|
||||
if ($oldInterpolatedUHD !== (int) $episode->interpolated_uhd) {
|
||||
DiscordReleaseNotification::dispatch($episode->slug, 'updateUHD');
|
||||
}
|
||||
|
||||
cache()->flush();
|
||||
|
||||
return to_route('hentai.index', [
|
||||
'title' => $episode->slug
|
||||
]);
|
||||
}
|
||||
}
|
84
app/Http/Controllers/Admin/ReleaseController.php
Normal file
84
app/Http/Controllers/Admin/ReleaseController.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Hentai;
|
||||
|
||||
use App\Jobs\DiscordReleaseNotification;
|
||||
use App\Services\DownloadService;
|
||||
use App\Services\EpisodeService;
|
||||
use App\Services\GalleryService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ReleaseController extends Controller
|
||||
{
|
||||
protected EpisodeService $episodeService;
|
||||
protected GalleryService $galleryService;
|
||||
protected DownloadService $downloadService;
|
||||
|
||||
public function __construct(
|
||||
EpisodeService $episodeService,
|
||||
GalleryService $galleryService,
|
||||
DownloadService $downloadService
|
||||
) {
|
||||
$this->episodeService = $episodeService;
|
||||
$this->galleryService = $galleryService;
|
||||
$this->downloadService = $downloadService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display release page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('admin.release.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload New Hentai with One or Multipe Episodes
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
// Create new Hentai or find existing one
|
||||
$slug = $this->episodeService->generateSlug($request->input('title'));
|
||||
|
||||
$hentai = Hentai::where('slug', $slug)->first();
|
||||
|
||||
// If hentai exists and was created today, return to home
|
||||
if ($hentai?->created_at->isToday()) {
|
||||
return to_route('home.index');
|
||||
}
|
||||
|
||||
// If hentai does not exist, create a new instance
|
||||
$hentai = Hentai::firstOrCreate(
|
||||
['slug' => $slug],
|
||||
['description' => $request->input('description1')]
|
||||
);
|
||||
|
||||
// Studio
|
||||
$studio = $this->episodeService->getOrCreateStudio(json_decode($request->input('studio'))[0]->value);
|
||||
|
||||
// Create Episode(s)
|
||||
$releasedEpisodes = [];
|
||||
for ($i = 1; $i <= $request->input('episodes'); $i++) {
|
||||
|
||||
$episode = $this->episodeService->createEpisode($request, $hentai, $i, $studio);
|
||||
|
||||
$this->episodeService->createOrUpdateCover($request, $episode, $slug, $i);
|
||||
$this->downloadService->createOrUpdateDownloads($request, $episode, $i);
|
||||
$this->galleryService->createOrUpdateGallery($request, $hentai, $episode, $i);
|
||||
|
||||
$releasedEpisodes[] = $episode->slug;
|
||||
}
|
||||
|
||||
foreach ($releasedEpisodes as $slug) {
|
||||
// Dispatch Discord Alert
|
||||
DiscordReleaseNotification::dispatch($slug, 'release');
|
||||
}
|
||||
|
||||
cache()->flush();
|
||||
|
||||
return to_route('home.index');
|
||||
}
|
||||
}
|
129
app/Http/Controllers/Admin/SiteBackgroundController.php
Normal file
129
app/Http/Controllers/Admin/SiteBackgroundController.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use App\Models\SiteBackground;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Intervention\Image\Encoders\WebpEncoder;
|
||||
|
||||
class SiteBackgroundController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display admin index page
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('admin.background.index', [
|
||||
'images' => SiteBackground::all(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new site backgrounds
|
||||
*/
|
||||
public function create(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'images' => 'required',
|
||||
'date_start' => 'required',
|
||||
'date_end' => 'required',
|
||||
]);
|
||||
|
||||
foreach($request->file('images') as $file) {
|
||||
// Initiating a database transaction in case something goes wrong.
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$bg = SiteBackground::create(array_merge(
|
||||
$request->only(['date_start', 'date_end']),
|
||||
[
|
||||
'default' => (bool) $request->input('default', false)
|
||||
]
|
||||
));
|
||||
|
||||
$resolutions = [1440, 1080, 720, 640];
|
||||
foreach($resolutions as $resolution) {
|
||||
// /images/background/1-2560p.webp
|
||||
$targetPath = "/images/background/{$bg->id}-{$resolution}p.webp";
|
||||
|
||||
Image::read($file->getRealPath())
|
||||
->scaleDown(height: $resolution)
|
||||
->encode(new WebpEncoder())
|
||||
->save(public_path($targetPath));
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
Log::error($e->getMessage());
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// Committing the database transaction.
|
||||
DB::commit();
|
||||
}
|
||||
|
||||
cache()->forget('background');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'id' => 'required|exists:site_backgrounds,id',
|
||||
'date_start' => 'required',
|
||||
'date_end' => 'required',
|
||||
]);
|
||||
|
||||
SiteBackground::where('id', $request->input('id'))->update(array_merge(
|
||||
$request->only(['date_start', 'date_end']),
|
||||
[
|
||||
'default' => (bool) $request->input('default', false)
|
||||
]
|
||||
));
|
||||
|
||||
cache()->forget('background');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete backround
|
||||
*/
|
||||
public function delete(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$id = $request->input('id');
|
||||
|
||||
// Initiating a database transaction in case something goes wrong.
|
||||
DB::beginTransaction();
|
||||
|
||||
$bg = SiteBackground::where('id', $id)->firstOrFail();
|
||||
$bg->forceDelete();
|
||||
|
||||
$resolutions = [1440, 1080, 720, 640];
|
||||
try {
|
||||
foreach($resolutions as $resolution) {
|
||||
$targetPath = "/images/background/{$id}-{$resolution}p.webp";
|
||||
File::delete(public_path($targetPath));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
Log::error($e->getMessage());
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// Committing the database transaction.
|
||||
DB::commit();
|
||||
|
||||
cache()->forget('background');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
61
app/Http/Controllers/Admin/SubtitleController.php
Normal file
61
app/Http/Controllers/Admin/SubtitleController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Models\EpisodeSubtitle;
|
||||
use App\Models\Subtitle;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SubtitleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Add new Subtitle.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$subtitle = Subtitle::create([
|
||||
'name' => $request->name,
|
||||
'slug' => $request->slug,
|
||||
]);
|
||||
|
||||
// Add to Episode
|
||||
EpisodeSubtitle::create([
|
||||
'episode_id' => $request->episode_id,
|
||||
'subtitle_id' => $subtitle->id,
|
||||
]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Episode Subtitles.
|
||||
*/
|
||||
public function update(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
// Clear everything
|
||||
foreach($episode->subtitles as $sub) {
|
||||
$sub->forceDelete();
|
||||
}
|
||||
|
||||
if (! $request->input('subtitles')) {
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// Re-Add
|
||||
foreach (json_decode($request->input('subtitles')) as $sub) {
|
||||
$subtitle = Subtitle::where('name', $sub->value)->firstOrFail();
|
||||
|
||||
// Add to Episode
|
||||
EpisodeSubtitle::create([
|
||||
'episode_id' => $episode->id,
|
||||
'subtitle_id' => $subtitle->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
40
app/Http/Controllers/Admin/TorrentController.php
Normal file
40
app/Http/Controllers/Admin/TorrentController.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
47
app/Http/Controllers/Admin/UserController.php
Normal file
47
app/Http/Controllers/Admin/UserController.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Users Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('admin.users.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user (ban/unban).
|
||||
*/
|
||||
public function update(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'id' => 'required|exists:users,id',
|
||||
'action' => 'required',
|
||||
]);
|
||||
|
||||
|
||||
$user = User::findOrFail($validated['id']);
|
||||
|
||||
switch ($validated['action']) {
|
||||
case 'ban':
|
||||
$user->update(['is_banned' => 1]);
|
||||
alert()->success('Banned', 'User has been banned.');
|
||||
break;
|
||||
case 'unban':
|
||||
$user->update(['is_banned' => 0]);
|
||||
alert()->success('Unbanned', 'User has been unbanned.');
|
||||
break;
|
||||
default:
|
||||
alert()->error('Error','Invalid action provided');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
102
app/Http/Controllers/Api/AdminApiController.php
Normal file
102
app/Http/Controllers/Api/AdminApiController.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Studios;
|
||||
use App\Models\Subtitle;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AdminApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get Tags (API).
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
$tags = CacheHelper::getAllTags();
|
||||
|
||||
$tagWhiteList = [];
|
||||
foreach ($tags as $tag) {
|
||||
$tagWhiteList[] = $tag->name;
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'success', 'tags' => $tagWhiteList], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Studios (API).
|
||||
*/
|
||||
public function getStudios()
|
||||
{
|
||||
$studios = Studios::orderBy('name', 'ASC')->get();
|
||||
|
||||
$studioList = [];
|
||||
foreach ($studios as $studio) {
|
||||
$studioList[] = $studio->name;
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'success', 'studios' => $studioList], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Subtitles (API).
|
||||
*/
|
||||
public function getSubtitles(int $episode_id)
|
||||
{
|
||||
$subs = Subtitle::all();
|
||||
|
||||
$subsWhiteList = [];
|
||||
foreach ($subs as $sub) {
|
||||
$subsWhiteList[] = $sub->name;
|
||||
}
|
||||
|
||||
$episode = Episode::where('id', $episode_id)->firstOrFail();
|
||||
$episodetags = [];
|
||||
foreach ($episode->subtitles as $tag) {
|
||||
|
||||
$episodetags[] = $tag->subtitle->name;
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'success', 'subs' => $subsWhiteList, 'episodesubs' => $episodetags], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Episode Tags (API).
|
||||
*/
|
||||
public function getEpisodeTags(int $episode_id)
|
||||
{
|
||||
$tags = CacheHelper::getAllTags();
|
||||
$tagWhiteList = [];
|
||||
foreach ($tags as $tag) {
|
||||
$tagWhiteList[] = $tag->name;
|
||||
}
|
||||
|
||||
$episode = Episode::where('id', $episode_id)->firstOrFail();
|
||||
$episodetags = [];
|
||||
foreach ($episode->tags as $tag) {
|
||||
$episodetags[] = $tag->name;
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'success', 'tags' => $tagWhiteList, 'episodetags' => $episodetags], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Episode Studio (API).
|
||||
*/
|
||||
public function getEpisodeStudio(int $episode_id)
|
||||
{
|
||||
$studios = Studios::orderBy('name', 'ASC')->get();
|
||||
|
||||
$studioList = [];
|
||||
foreach ($studios as $studio) {
|
||||
$studioList[] = $studio->name;
|
||||
}
|
||||
|
||||
$episode = Episode::where('id', $episode_id)->firstOrFail();
|
||||
$episodestudio = [$episode->studio->name];
|
||||
|
||||
return response()->json(['message' => 'success', 'studios' => $studioList, 'episodestudios' => $episodestudio], 200);
|
||||
}
|
||||
}
|
38
app/Http/Controllers/Api/DownloadApiController.php
Normal file
38
app/Http/Controllers/Api/DownloadApiController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Downloads;
|
||||
use App\Models\Episode;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class DownloadApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get Download URL for users who are not logged in.
|
||||
*/
|
||||
public function getDownload(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'episode_id' => 'required',
|
||||
'captcha' => 'required|captcha'
|
||||
]);
|
||||
|
||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
// Increase download count, as we assume the user
|
||||
// downloads after submitting the captcha
|
||||
$download = Downloads::find($episode->getDownloadByType('FHD')->id);
|
||||
$oldCount = $download->count;
|
||||
$download->count++;
|
||||
$download->save();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'download_url' => $download->url,
|
||||
'download_count' => $oldCount,
|
||||
], 200);
|
||||
}
|
||||
}
|
39
app/Http/Controllers/Api/StreamApiController.php
Normal file
39
app/Http/Controllers/Api/StreamApiController.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
use App\Models\Episode;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StreamApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get Data used by the Video Player.
|
||||
*/
|
||||
public function getStream(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'episode_id' => 'required',
|
||||
]);
|
||||
|
||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
$subtitles = $episode->subtitles
|
||||
->mapWithKeys(fn($sub) => [$sub->subtitle->slug => $sub->subtitle->name])
|
||||
->toArray();
|
||||
|
||||
return response()->json([
|
||||
'title' => $episode->title.' - '.$episode->episode,
|
||||
'poster' => $episode->gallery()->first()->image_url,
|
||||
'interpolated' => $episode->interpolated,
|
||||
'interpolated_uhd' => $episode->interpolated_uhd,
|
||||
'stream_url' => $episode->url,
|
||||
'stream_domains' => config('hstream.stream_domain'),
|
||||
'asia_stream_domains' => config('hstream.asia_stream_domain'),
|
||||
'extra_subtitles' => $subtitles
|
||||
], 200);
|
||||
}
|
||||
}
|
43
app/Http/Controllers/Api/UserApiController.php
Normal file
43
app/Http/Controllers/Api/UserApiController.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\CacheHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use Conner\Tagging\Model\Tag;
|
||||
|
||||
class UserApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get Tags (API).
|
||||
*/
|
||||
public function getBlacklist(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$tagWhiteList = [];
|
||||
$tagBlackList = [];
|
||||
|
||||
// All Tags
|
||||
foreach (CacheHelper::getAllTags() as $tag) {
|
||||
$tagWhiteList[] = $tag->name;
|
||||
}
|
||||
|
||||
// User Tags
|
||||
if ($user->tag_blacklist) {
|
||||
foreach ($user->tag_blacklist as $tag) {
|
||||
$t = Tag::where('slug', $tag)->first();
|
||||
$tagBlackList[] = $t->name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'tags' => $tagWhiteList,
|
||||
'usertags' => $tagBlackList
|
||||
], 200);
|
||||
}
|
||||
}
|
48
app/Http/Controllers/Auth/AuthenticatedSessionController.php
Normal file
48
app/Http/Controllers/Auth/AuthenticatedSessionController.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginRequest;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class AuthenticatedSessionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the login view.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming authentication request.
|
||||
*/
|
||||
public function store(LoginRequest $request): RedirectResponse
|
||||
{
|
||||
$request->authenticate();
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an authenticated session.
|
||||
*/
|
||||
public function destroy(Request $request): RedirectResponse
|
||||
{
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect('/');
|
||||
}
|
||||
}
|
41
app/Http/Controllers/Auth/ConfirmablePasswordController.php
Normal file
41
app/Http/Controllers/Auth/ConfirmablePasswordController.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ConfirmablePasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the confirm password view.
|
||||
*/
|
||||
public function show(): View
|
||||
{
|
||||
return view('auth.confirm-password');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm the user's password.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
if (! Auth::guard('web')->validate([
|
||||
'email' => $request->user()->email,
|
||||
'password' => $request->password,
|
||||
])) {
|
||||
throw ValidationException::withMessages([
|
||||
'password' => __('auth.password'),
|
||||
]);
|
||||
}
|
||||
|
||||
$request->session()->put('auth.password_confirmed_at', time());
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EmailVerificationNotificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Send a new email verification notification.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
$request->user()->sendEmailVerificationNotification();
|
||||
|
||||
return back()->with('status', 'verification-link-sent');
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class EmailVerificationPromptController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the email verification prompt.
|
||||
*/
|
||||
public function __invoke(Request $request): RedirectResponse|View
|
||||
{
|
||||
return $request->user()->hasVerifiedEmail()
|
||||
? redirect()->intended(RouteServiceProvider::HOME)
|
||||
: view('auth.verify-email');
|
||||
}
|
||||
}
|
61
app/Http/Controllers/Auth/NewPasswordController.php
Normal file
61
app/Http/Controllers/Auth/NewPasswordController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class NewPasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the password reset view.
|
||||
*/
|
||||
public function create(Request $request): View
|
||||
{
|
||||
return view('auth.reset-password', ['request' => $request]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming new password request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'token' => ['required'],
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
// Here we will attempt to reset the user's password. If it is successful we
|
||||
// will update the password on an actual user model and persist it to the
|
||||
// database. Otherwise we will parse the error and return the response.
|
||||
$status = Password::reset(
|
||||
$request->only('email', 'password', 'password_confirmation', 'token'),
|
||||
function ($user) use ($request) {
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($request->password),
|
||||
'remember_token' => Str::random(60),
|
||||
])->save();
|
||||
|
||||
event(new PasswordReset($user));
|
||||
}
|
||||
);
|
||||
|
||||
// If the password was successfully reset, we will redirect the user back to
|
||||
// the application's home authenticated view. If there is an error we can
|
||||
// redirect them back to where they came from with their error message.
|
||||
return $status == Password::PASSWORD_RESET
|
||||
? redirect()->route('login')->with('status', __($status))
|
||||
: back()->withInput($request->only('email'))
|
||||
->withErrors(['email' => __($status)]);
|
||||
}
|
||||
}
|
29
app/Http/Controllers/Auth/PasswordController.php
Normal file
29
app/Http/Controllers/Auth/PasswordController.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
class PasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Update the user's password.
|
||||
*/
|
||||
public function update(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validateWithBag('updatePassword', [
|
||||
'current_password' => ['required', 'current_password'],
|
||||
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||
]);
|
||||
|
||||
$request->user()->update([
|
||||
'password' => Hash::make($validated['password']),
|
||||
]);
|
||||
|
||||
return back()->with('status', 'password-updated');
|
||||
}
|
||||
}
|
44
app/Http/Controllers/Auth/PasswordResetLinkController.php
Normal file
44
app/Http/Controllers/Auth/PasswordResetLinkController.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class PasswordResetLinkController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the password reset link request view.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('auth.forgot-password');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming password reset link request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'email' => ['required', 'email'],
|
||||
]);
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
// to send the link, we will examine the response then see the message we
|
||||
// need to show to the user. Finally, we'll send out a proper response.
|
||||
$status = Password::sendResetLink(
|
||||
$request->only('email')
|
||||
);
|
||||
|
||||
return $status == Password::RESET_LINK_SENT
|
||||
? back()->with('status', __($status))
|
||||
: back()->withInput($request->only('email'))
|
||||
->withErrors(['email' => __($status)]);
|
||||
}
|
||||
}
|
51
app/Http/Controllers/Auth/RegisteredUserController.php
Normal file
51
app/Http/Controllers/Auth/RegisteredUserController.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class RegisteredUserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the registration view.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('auth.register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming registration request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
event(new Registered($user));
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
28
app/Http/Controllers/Auth/VerifyEmailController.php
Normal file
28
app/Http/Controllers/Auth/VerifyEmailController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Foundation\Auth\EmailVerificationRequest;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
class VerifyEmailController extends Controller
|
||||
{
|
||||
/**
|
||||
* Mark the authenticated user's email address as verified.
|
||||
*/
|
||||
public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
|
||||
}
|
||||
|
||||
if ($request->user()->markEmailAsVerified()) {
|
||||
event(new Verified($request->user()));
|
||||
}
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
|
||||
}
|
||||
}
|
45
app/Http/Controllers/ContactController.php
Normal file
45
app/Http/Controllers/ContactController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Contact Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('contact.form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store Contact Submission.
|
||||
*/
|
||||
public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
'email' => 'required|max:50',
|
||||
'message' => 'required|max:1000',
|
||||
'subject' => 'required|max:50',
|
||||
'captcha' => 'required|captcha',
|
||||
]);
|
||||
|
||||
$contact = new Contact();
|
||||
$contact->name = $request->input('name');
|
||||
$contact->email = $request->input('email');
|
||||
$contact->message = $request->input('message');
|
||||
$contact->subject = $request->input('subject');
|
||||
$contact->save();
|
||||
|
||||
return back()->with('status', 'contact-submitted');
|
||||
}
|
||||
|
||||
public function reloadCaptcha(): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
return response()->json(['captcha'=> captcha_img()]);
|
||||
}
|
||||
}
|
12
app/Http/Controllers/Controller.php
Normal file
12
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
}
|
107
app/Http/Controllers/HomeController.php
Normal file
107
app/Http/Controllers/HomeController.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Helpers\CacheHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Home Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
$guest = Auth::guest();
|
||||
|
||||
$guestString = $guest ? 'guest' : 'authed';
|
||||
|
||||
$mostLikes = \cache()->remember('mostLikes'.$guestString, 300, fn () =>
|
||||
Episode::with('gallery')
|
||||
->when($guest, fn ($query) => $query->withoutTags(['loli', 'shota']))
|
||||
->whereIn('id', function($query) {
|
||||
$mostLikesIds = CacheHelper::getMostLikes()->pluck('markable_id')->toArray();
|
||||
$query->selectRaw('id')
|
||||
->from('episodes')
|
||||
->whereIn('id', $mostLikesIds)
|
||||
->orderByRaw("FIELD(id, " . implode(',', $mostLikesIds) . ")");
|
||||
})
|
||||
->get()
|
||||
);
|
||||
|
||||
return view('home.index', [
|
||||
'recentlyReleased' => CacheHelper::getRecentlyReleased($guest),
|
||||
'recentlyUploaded' => CacheHelper::getRecentlyUploaded($guest),
|
||||
'popularAllTime' => CacheHelper::getPopularAllTime($guest),
|
||||
'popularMonthly' => CacheHelper::getPopularMonthly(),
|
||||
'popularWeekly' => CacheHelper::getPopularWeekly(),
|
||||
'popularDaily' => CacheHelper::getPopularDaily(),
|
||||
'mostLikes' => $mostLikes,
|
||||
'latestComments' => CacheHelper::getLatestComments(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Banned Page.
|
||||
*/
|
||||
public function banned(): \Illuminate\View\View
|
||||
{
|
||||
return view('auth.banned');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Search Page.
|
||||
*/
|
||||
public function search(): \Illuminate\View\View
|
||||
{
|
||||
return view('search.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Download Search Page.
|
||||
*/
|
||||
public function downloadSearch(): \Illuminate\View\View
|
||||
{
|
||||
return view('search.download');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect POST Data to GET with Query String.
|
||||
*/
|
||||
public function searchRedirect(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return redirect()->route('hentai.search', [
|
||||
'search' => $request->input('live-search'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Stats Page.
|
||||
*/
|
||||
public function stats(): \Illuminate\View\View
|
||||
{
|
||||
return view('home.stats', [
|
||||
'viewCount' => CacheHelper::getTotalViewCount(),
|
||||
'episodeCount' => CacheHelper::getTotalEpisodeCount(),
|
||||
'hentaiCount' => CacheHelper::getTotalHentaiCount(),
|
||||
'monthlyCount' => CacheHelper::getTotalMonthlyViews()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually set website language
|
||||
*/
|
||||
public function updateLanguage(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if(! in_array($request->language, config('lang-detector.languages'))) {
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
Cookie::queue(Cookie::forever('locale', $request->language));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
39
app/Http/Controllers/NotificationController.php
Normal file
39
app/Http/Controllers/NotificationController.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class NotificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the user's notification page.
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
return view('profile.notifications', [
|
||||
'user' => $request->user(),
|
||||
'notifications' => $request->user()->unreadNotifications,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Notifcation
|
||||
*/
|
||||
public function delete(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'id' => 'required|exists:notifications,id',
|
||||
]);
|
||||
|
||||
$notification = $request->user()
|
||||
->notifications()
|
||||
->where('id', $request->input('id'))
|
||||
->firstOrFail();
|
||||
|
||||
$notification->forceDelete();
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
198
app/Http/Controllers/PlaylistController.php
Normal file
198
app/Http/Controllers/PlaylistController.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Services\PlaylistService;
|
||||
use Illuminate\Http\Request;
|
||||
use RealRashid\SweetAlert\Facades\Alert;
|
||||
|
||||
class PlaylistController extends Controller
|
||||
{
|
||||
protected PlaylistService $playlistService;
|
||||
|
||||
public function __construct(PlaylistService $playlistService)
|
||||
{
|
||||
$this->playlistService = $playlistService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the public playlists page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('playlist.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display public playlist.
|
||||
*/
|
||||
public function show($playlist_id): \Illuminate\View\View
|
||||
{
|
||||
if (!is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$playlist = Playlist::where('is_private', 0)->where('id', $playlist_id)->firstOrFail();
|
||||
|
||||
return view('playlist.list', [
|
||||
'playlist' => $playlist,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the user's playlists page.
|
||||
*/
|
||||
public function playlists(Request $request): \Illuminate\View\View
|
||||
{
|
||||
$title = 'Delete Playlist!';
|
||||
$text = "Are you sure you want to delete?";
|
||||
confirmDelete($title, $text);
|
||||
|
||||
return view('profile.playlists', [
|
||||
'user' => $request->user(),
|
||||
'playlists' => $request->user()->playlists,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display user's playlist.
|
||||
*/
|
||||
public function showPlaylist(Request $request, $playlist_id): \Illuminate\View\View
|
||||
{
|
||||
if (!is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$playlist = Playlist::where('user_id', $user->id)->where('id', $playlist_id)->firstOrFail();
|
||||
|
||||
return view('playlist.list', [
|
||||
'playlist' => $playlist,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user playlist (Form).
|
||||
*/
|
||||
public function createPlaylist(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
]);
|
||||
|
||||
$playlist = new Playlist();
|
||||
$playlist->user_id = $request->user()->id;
|
||||
$playlist->name = $request->input('name');
|
||||
$playlist->is_private = $request->input('visiblity') === 'private';
|
||||
$playlist->save();
|
||||
|
||||
return to_route('profile.playlists');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user playlist.
|
||||
*/
|
||||
public function deletePlaylist(Request $request, $playlist_id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if (!is_numeric($playlist_id)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$playlist = Playlist::where('user_id', $user->id)->where('id', $playlist_id)->firstOrFail();
|
||||
|
||||
// Delete Playlist Episodes
|
||||
PlaylistEpisode::where('playlist_id', $playlist->id)->forceDelete();
|
||||
|
||||
// Delete Playlist
|
||||
$playlist->forceDelete();
|
||||
|
||||
return to_route('profile.playlists');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete episode from playlist.
|
||||
*/
|
||||
public function deleteEpisodeFromPlaylist(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
if (!is_numeric($request->input('playlist')) || !is_numeric($request->input('episode'))) {
|
||||
return response()->json([
|
||||
'message' => 'not-numeric',
|
||||
'user' => $request->user(),
|
||||
], 404);
|
||||
}
|
||||
|
||||
$playlist = Playlist::where('user_id', $request->user()->id)->where('id', (int) $request->input('playlist'))->firstOrFail();
|
||||
PlaylistEpisode::where('playlist_id', $playlist->id)->where('episode_id', (int) $request->input('episode'))->forceDelete();
|
||||
$this->playlistService->reorderPositions($playlist);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'user' => $request->user(),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to user playlist (API).
|
||||
*/
|
||||
public function addPlaylistApi(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$validated = $request->validate([
|
||||
'playlist' => 'required|max:30',
|
||||
'episode_id' => 'required'
|
||||
]);
|
||||
|
||||
$playlist = Playlist::where('user_id', $user->id)->where('id', $request->input('playlist'))->firstOrFail();
|
||||
$episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();
|
||||
|
||||
// Check if already in playlist
|
||||
$exists = PlaylistEpisode::where('playlist_id', $playlist->id)->where('episode_id', $episode->id)->exists();
|
||||
if ($exists) {
|
||||
return response()->json([
|
||||
'message' => 'already-added'
|
||||
], 200);
|
||||
}
|
||||
|
||||
// Position of entry
|
||||
$position = $playlist->episodes->count() + 1;
|
||||
|
||||
PlaylistEpisode::create([
|
||||
'playlist_id' => $playlist->id,
|
||||
'episode_id' => $episode->id,
|
||||
'position' => $position,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success'
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user playlist (API).
|
||||
*/
|
||||
public function createPlaylistApi(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|max:30',
|
||||
]);
|
||||
|
||||
$playlist = new Playlist();
|
||||
$playlist->user_id = $request->user()->id;
|
||||
$playlist->name = $request->input('name');
|
||||
$playlist->is_private = $request->input('visiblity') === 'private';
|
||||
$playlist->save();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'success',
|
||||
'playlist_id' => $playlist->id
|
||||
], 200);
|
||||
}
|
||||
}
|
130
app/Http/Controllers/ProfileController.php
Normal file
130
app/Http/Controllers/ProfileController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Http\Requests\ProfileUpdateRequest;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
|
||||
use Conner\Tagging\Model\Tag;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the user page.
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
return view('profile.index', [
|
||||
'user' => $request->user(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the user's settings form.
|
||||
*/
|
||||
public function settings(Request $request): \Illuminate\View\View
|
||||
{
|
||||
$example = Episode::where('title', 'Succubus Yondara Gibo ga Kita!?')->first();
|
||||
|
||||
return view('profile.settings', [
|
||||
'user' => $request->user(),
|
||||
'example' => $example,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the user's watched page.
|
||||
*/
|
||||
public function watched(Request $request): \Illuminate\View\View
|
||||
{
|
||||
return view('profile.watched', [
|
||||
'user' => $request->user(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the user's comments page.
|
||||
*/
|
||||
public function comments(Request $request): \Illuminate\View\View
|
||||
{
|
||||
return view('profile.comments', [
|
||||
'user' => $request->user(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the user's likes page.
|
||||
*/
|
||||
public function likes(Request $request): \Illuminate\View\View
|
||||
{
|
||||
return view('profile.likes', [
|
||||
'user' => $request->user(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user settings.
|
||||
*/
|
||||
public function saveSettings(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$user->search_design = $request->input('searchDesign') == 'thumbnail';
|
||||
$user->home_top_design = $request->input('topDesign') == 'thumbnail';
|
||||
$user->home_middle_design = $request->input('middleDesign') == 'thumbnail';
|
||||
$user->save();
|
||||
|
||||
return Redirect::route('profile.settings')->with('status', 'design-updated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user tag blacklist.
|
||||
*/
|
||||
public function saveBlacklist(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$tags = json_decode($request->input('tags'));
|
||||
|
||||
if (!$tags) {
|
||||
$user->tag_blacklist = null;
|
||||
$user->save();
|
||||
return Redirect::route('profile.settings')->with('status', 'blacklist-updated');
|
||||
}
|
||||
|
||||
$blacklist = [];
|
||||
foreach ($tags as $tag) {
|
||||
$t = Tag::where('slug', Str::slug($tag->value))->firstOrFail();
|
||||
$blacklist[] = $t->slug;
|
||||
}
|
||||
|
||||
$user->tag_blacklist = $blacklist;
|
||||
$user->save();
|
||||
|
||||
return Redirect::route('profile.settings')->with('status', 'blacklist-updated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user's account.
|
||||
*/
|
||||
public function destroy(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$request->validateWithBag('userDeletion', [
|
||||
'password' => ['required', 'current_password'],
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
Auth::logout();
|
||||
|
||||
$user->delete();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return Redirect::to('/');
|
||||
}
|
||||
}
|
109
app/Http/Controllers/StreamController.php
Normal file
109
app/Http/Controllers/StreamController.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Hentai;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Models\Watched;
|
||||
use App\Helpers\CacheHelper;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use hisorange\BrowserDetect\Facade as Browser;
|
||||
|
||||
class StreamController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Stream Page.
|
||||
*/
|
||||
public function index(Request $request, string $title): \Illuminate\View\View
|
||||
{
|
||||
$titleParts = explode('-', $title);
|
||||
if (! is_numeric($titleParts[array_key_last($titleParts)])) {
|
||||
$hentai = Hentai::with('episodes')->where('slug', $title)->firstOrFail();
|
||||
|
||||
if (Auth::guest() && $hentai->isLoliOrShota()) {
|
||||
return view('auth.please-login');
|
||||
}
|
||||
|
||||
return view('series.index', [
|
||||
'hentai' => $hentai,
|
||||
'popularWeekly' => CacheHelper::getPopularWeekly(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$episode = Episode::where('slug', $title)->firstOrFail();
|
||||
$gallery = Gallery::where('episode_id', $episode->id)->get();
|
||||
$moreEpisodes = Episode::with(['gallery', 'studio'])->where('hentai_id', $episode->hentai_id)->whereNot('id', $episode->id)->get();
|
||||
$studioEpisodes = Episode::with(['gallery', 'studio'])->inRandomOrder()->where('studios_id', $episode->studios_id)->whereNot('id', $episode->id)->limit(6)->get();
|
||||
|
||||
// Only allow access to problematic stuff when logged in
|
||||
if (Auth::guest() && $episode->isLoliOrShota()) {
|
||||
return view('auth.please-login');
|
||||
}
|
||||
|
||||
// Increment View Count
|
||||
$episode->incrementViewCount();
|
||||
|
||||
// Increment Popular Count
|
||||
$episode->incrementPopularCount();
|
||||
|
||||
if (!Auth::guest()) {
|
||||
$user = Auth::user();
|
||||
|
||||
// Add to user watched list
|
||||
$time = Carbon::now()->subHour(1);
|
||||
$alreadyWatched = Watched::where('user_id', $user->id)->where('episode_id', $episode->id)->where('created_at', '>=', $time)->exists();
|
||||
if (!$alreadyWatched) {
|
||||
Watched::create(['user_id' => $user->id, 'episode_id' => $episode->id]);
|
||||
cache()->forget('user' . $user->id . 'watched' . $episode->id);
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile Detection
|
||||
$isMobile = Browser::isMobile();
|
||||
|
||||
// Playlist
|
||||
if ($request->has('playlist')) {
|
||||
// Get and check if playlist exists
|
||||
$playlist = Playlist::where('id', $request->input('playlist'))->firstOrFail();
|
||||
|
||||
// Check if episode is in playlist
|
||||
$inPlaylist = PlaylistEpisode::where('playlist_id', $playlist->id)->where('episode_id', $episode->id)->firstOrFail();
|
||||
|
||||
// Get Playlist Episodes and order them
|
||||
$playlistEpisodes = $playlist->episodes()->orderBy('position')->get();
|
||||
|
||||
// Check if authorized
|
||||
if ($playlist->is_private && (Auth::guest() || (!Auth::guest() && Auth::user()->id != $playlist->user_id))) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return view('stream.index', [
|
||||
'episode' => $episode,
|
||||
'moreEpisodes' => $moreEpisodes,
|
||||
'studioEpisodes' => $studioEpisodes,
|
||||
'gallery' => $gallery,
|
||||
'playlist' => $playlist,
|
||||
'playlistEpisodes' => $playlistEpisodes,
|
||||
'popularWeekly' => CacheHelper::getPopularWeekly(),
|
||||
'isMobile' => $isMobile,
|
||||
]);
|
||||
}
|
||||
|
||||
return view('stream.index', [
|
||||
'episode' => $episode,
|
||||
'moreEpisodes' => $moreEpisodes,
|
||||
'studioEpisodes' => $studioEpisodes,
|
||||
'gallery' => $gallery,
|
||||
'popularWeekly' => CacheHelper::getPopularWeekly(),
|
||||
'isMobile' => $isMobile,
|
||||
]);
|
||||
}
|
||||
}
|
58
app/Http/Controllers/UserController.php
Normal file
58
app/Http/Controllers/UserController.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Playlist;
|
||||
use App\Models\PlaylistEpisode;
|
||||
use App\Models\Watched;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display User Page.
|
||||
*/
|
||||
public function index(string $username): \Illuminate\View\View
|
||||
{
|
||||
$user = User::where('username', $username)
|
||||
->select('id', 'username', 'global_name', 'avatar', 'created_at', 'is_patreon')
|
||||
->firstOrFail();
|
||||
|
||||
return view('user.index', [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete User.
|
||||
*/
|
||||
public function delete(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$user = User::where('id', $request->user()->id)->firstOrFail();
|
||||
|
||||
// Delete Playlist
|
||||
$playlists = Playlist::where('user_id', $user->id)->get();
|
||||
foreach($playlists as $playlist) {
|
||||
PlaylistEpisode::where('playlist_id', $playlist->id)->forceDelete();
|
||||
$playlist->forceDelete();
|
||||
}
|
||||
|
||||
// Update comments to deleted user
|
||||
DB::table('comments')->where('commenter_id', '=', $user->id)->update(['commenter_id' => 1]);
|
||||
|
||||
$user->forceDelete();
|
||||
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
cache()->flush();
|
||||
|
||||
return redirect('/');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user