Add tvshows management to admin area

This commit is contained in:
DariusIII
2025-10-10 12:46:26 +02:00
parent 3521c93e20
commit 0d83048c50
6 changed files with 635 additions and 81 deletions
@@ -5,86 +5,76 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BasePageController;
use App\Models\Release;
use App\Models\Video;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class AdminShowsController extends BasePageController
{
/**
* @throws \Exception
* Display a listing of TV shows
*/
public function index(Request $request): void
public function index(Request $request): View
{
$this->setAdminPrefs();
$meta_title = $title = 'TV Shows List';
$tvshowname = ($request->has('showname') && ! empty($request->input('showname')) ? $request->input('showname') : '');
$showname = $request->input('showname', '');
$tvshowlist = Video::getRange($showname);
$this->smarty->assign(
[
'showname' => $tvshowname,
'tvshowlist' => Video::getRange($tvshowname),
]
);
$content = $this->smarty->fetch('show-list.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
return view('admin.shows.index', compact('tvshowlist', 'showname', 'title', 'meta_title'));
}
/**
* @throws \Exception
* Show the form for editing a TV show
*/
public function edit(Request $request): void
public function edit(Request $request): View|RedirectResponse
{
$this->setAdminPrefs();
switch ($request->input('action') ?? 'view') {
case 'submit':
if ($request->has('from') && ! empty($request->input('from'))) {
header('Location:'.$request->input('from'));
exit;
}
$action = $request->input('action', 'view');
header('Location:'.url('admin/show-list'));
break;
if ($action === 'submit') {
if ($request->has('from') && ! empty($request->input('from'))) {
return redirect($request->input('from'));
}
case 'view':
default:
if ($request->has('id')) {
$title = 'TV Show Edit';
$show = Video::getByVideoID($request->input('id'));
}
break;
return redirect()->route('admin.show-list')->with('success', 'TV show updated successfully');
}
$this->smarty->assign('show', $show);
$show = null;
if ($request->has('id')) {
$show = Video::getByVideoID($request->input('id'));
}
if (! $show) {
return redirect()->route('admin.show-list')->with('error', 'TV show not found');
}
$meta_title = $title = 'Edit TV Show Data';
$content = $this->smarty->fetch('show-edit.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
return view('admin.shows.edit', compact('show', 'title', 'meta_title'));
}
/**
* @throws \Exception
* Remove video ID from releases
*/
public function destroy($id): void
public function destroy(Request $request): View
{
$this->setAdminPrefs();
$id = $request->route('id');
$success = false;
$videoid = null;
if ($id) {
$success = Release::removeVideoIdFromReleases($id);
$this->smarty->assign('videoid', $id);
$videoid = $id;
}
$this->smarty->assign('success', $success);
$meta_title = $title = 'Remove Video and Episode IDs from Releases';
$content = $this->smarty->fetch('show-remove.tpl');
$this->smarty->assign(compact('title', 'meta_title', 'content'));
$this->adminrender();
return view('admin.shows.remove', compact('success', 'videoid', 'title', 'meta_title'));
}
}
+229
View File
@@ -0,0 +1,229 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fas fa-edit mr-2"></i>{{ $title }}
</h1>
<a href="{{ route('admin.show-list') }}" class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700">
<i class="fas fa-arrow-left mr-2"></i>Back to List
</a>
</div>
</div>
<!-- Edit Form -->
<div class="p-6">
<form method="POST" action="{{ url('admin/show-edit?id=' . $show['id']) }}">
@csrf
<input type="hidden" name="action" value="submit">
<input type="hidden" name="id" value="{{ $show['id'] }}">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Left Column -->
<div class="space-y-6">
<!-- Title -->
<div>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Title <span class="text-red-500">*</span>
</label>
<input type="text"
id="title"
name="title"
value="{{ $show['title'] ?? '' }}"
readonly
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Title is read-only</p>
</div>
<!-- Type -->
<div>
<label for="type" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Type
</label>
<select id="type"
name="type"
disabled
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">
<option value="0" {{ isset($show['type']) && $show['type'] == 0 ? 'selected' : '' }}>TV Show</option>
<option value="1" {{ isset($show['type']) && $show['type'] == 1 ? 'selected' : '' }}>Film</option>
<option value="2" {{ isset($show['type']) && $show['type'] == 2 ? 'selected' : '' }}>Anime</option>
</select>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Type is read-only</p>
</div>
<!-- Started Date -->
<div>
<label for="started" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Started Date
</label>
<input type="text"
id="started"
name="started"
value="{{ $show['started'] ?? '' }}"
readonly
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">
</div>
<!-- Country -->
<div>
<label for="countries_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Country Code
</label>
<input type="text"
id="countries_id"
name="countries_id"
value="{{ $show['countries_id'] ?? '' }}"
readonly
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">
</div>
<!-- External IDs -->
<div class="bg-gray-50 dark:bg-gray-900 p-4 rounded-lg">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">External IDs</h3>
<div class="space-y-3">
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">TVDB ID</label>
<input type="text"
value="{{ $show['tvdb'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">IMDB ID</label>
<input type="text"
value="{{ $show['imdb'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">TMDB ID</label>
<input type="text"
value="{{ $show['tmdb'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">Trakt ID</label>
<input type="text"
value="{{ $show['trakt'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">TVMaze ID</label>
<input type="text"
value="{{ $show['tvmaze'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
<div>
<label class="block text-xs text-gray-500 dark:text-gray-400 mb-1">AniDB ID</label>
<input type="text"
value="{{ $show['anidb'] ?? '—' }}"
readonly
class="w-full px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 rounded bg-gray-100">
</div>
</div>
</div>
</div>
<!-- Right Column -->
<div class="space-y-6">
<!-- Cover Image -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Cover Image
</label>
<div class="border border-gray-300 dark:border-gray-600 rounded-lg p-4 bg-gray-50 dark:bg-gray-900">
@if(!empty($show['image']))
<img src="{{ $show['image'] }}"
alt="{{ $show['title'] }}"
class="max-w-full h-auto mx-auto rounded shadow-lg"
style="max-height: 400px;"
onerror="this.src='{{ asset('images/no-cover.png') }}'">
@else
<div class="flex flex-col items-center justify-center py-12 text-gray-400 dark:text-gray-500">
<i class="fas fa-tv text-6xl mb-3"></i>
<p>No cover image available</p>
</div>
@endif
</div>
</div>
<!-- Summary -->
<div>
<label for="summary" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Summary
</label>
<textarea id="summary"
name="summary"
rows="8"
readonly
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">{{ $show['summary'] ?? '' }}</textarea>
</div>
<!-- Publisher -->
<div>
<label for="publisher" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Publisher
</label>
<input type="text"
id="publisher"
name="publisher"
value="{{ $show['publisher'] ?? '' }}"
readonly
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md bg-gray-100 dark:bg-gray-900">
</div>
<!-- Show Info -->
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">Show Information</h3>
<dl class="space-y-2 text-sm">
<div class="flex justify-between">
<dt class="text-gray-500 dark:text-gray-400">ID:</dt>
<dd class="text-gray-900 dark:text-gray-200 font-mono">{{ $show['id'] }}</dd>
</div>
<div class="flex justify-between">
<dt class="text-gray-500 dark:text-gray-400">Source:</dt>
<dd class="text-gray-900 dark:text-gray-200">
@if(isset($show['source']))
@if($show['source'] == 0)
TVDB
@elseif($show['source'] == 1)
TMDB
@elseif($show['source'] == 2)
Trakt
@elseif($show['source'] == 3)
TVMaze
@else
Unknown
@endif
@else
@endif
</dd>
</div>
</dl>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="mt-6 flex items-center justify-between border-t border-gray-200 dark:border-gray-700 pt-6">
<a href="{{ route('admin.show-list') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">
<i class="fas fa-arrow-left mr-2"></i>Back to List
</a>
<div class="text-sm text-yellow-600 dark:text-yellow-400">
<i class="fas fa-info-circle mr-1"></i>This is a view-only page. TV show data is automatically fetched from external sources.
</div>
</div>
</form>
</div>
</div>
</div>
@endsection
+205
View File
@@ -0,0 +1,205 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fas fa-tv mr-2"></i>{{ $title }}
</h1>
<div class="text-sm text-gray-600 dark:text-gray-400">
Total: {{ $tvshowlist->total() }} shows
</div>
</div>
</div>
<!-- Search Form -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<form method="GET" action="{{ url('admin/show-list') }}" class="flex items-center space-x-4">
<div class="flex-1">
<label for="showname" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Search TV Shows
</label>
<input type="text"
id="showname"
name="showname"
value="{{ $showname }}"
placeholder="Enter show name..."
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="flex items-end space-x-2">
<button type="submit" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
<i class="fas fa-search mr-2"></i>Search
</button>
@if($showname)
<a href="{{ url('admin/show-list') }}" class="px-6 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700">
<i class="fas fa-times mr-2"></i>Clear
</a>
@endif
</div>
</form>
</div>
<!-- TV Shows Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-900">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Cover</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Title</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Started</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">IDs</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Publisher</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
@forelse($tvshowlist as $show)
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 whitespace-nowrap">
@php
$coverPath = public_path('covers/tvshows/' . $show->id . '.jpg');
$hasCover = file_exists($coverPath);
@endphp
@if($hasCover)
<img src="{{ asset('covers/tvshows/' . $show->id . '.jpg') }}"
alt="{{ $show->title }}"
class="h-16 w-12 object-cover rounded shadow"
loading="lazy">
@else
<div class="h-16 w-12 bg-gray-200 dark:bg-gray-700 rounded flex items-center justify-center">
<i class="fas fa-tv text-gray-400 text-sm"></i>
</div>
@endif
</td>
<td class="px-6 py-4">
<div class="text-sm font-medium text-gray-900 dark:text-gray-200">
{{ $show->title }}
</div>
@if(!empty($show->summary))
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1 max-w-md line-clamp-2">
{{ Str::limit($show->summary, 100) }}
</div>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap">
@if($show->type == 0)
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
<i class="fas fa-tv mr-1"></i>TV
</span>
@elseif($show->type == 1)
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
<i class="fas fa-film mr-1"></i>Film
</span>
@elseif($show->type == 2)
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-200">
<i class="fas fa-dragon mr-1"></i>Anime
</span>
@endif
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
{{ $show->started ?? '—' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-xs">
<div class="space-y-1">
@if($show->tvdb)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">TVDB:</span> {{ $show->tvdb }}
</div>
@endif
@if($show->imdb)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">IMDB:</span> {{ $show->imdb }}
</div>
@endif
@if($show->tmdb)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">TMDB:</span> {{ $show->tmdb }}
</div>
@endif
@if($show->trakt)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">Trakt:</span> {{ $show->trakt }}
</div>
@endif
@if($show->tvmaze)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">TVMaze:</span> {{ $show->tvmaze }}
</div>
@endif
@if($show->anidb)
<div class="text-gray-600 dark:text-gray-400">
<span class="font-semibold">AniDB:</span> {{ $show->anidb }}
</div>
@endif
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-200">
{{ $show->publisher ?? '—' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2">
<a href="{{ url('admin/show-edit?id=' . $show->id) }}"
class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<a href="{{ url('admin/show-remove/' . $show->id) }}"
class="text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300"
title="Remove from Releases">
<i class="fas fa-unlink"></i>
</a>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
@if($showname)
<div class="flex flex-col items-center">
<i class="fas fa-search text-4xl mb-3"></i>
<p class="text-lg">No TV shows found for "{{ $showname }}"</p>
<a href="{{ url('admin/show-list') }}" class="mt-3 text-blue-600 dark:text-blue-400 hover:underline">
Clear search and view all
</a>
</div>
@else
<div class="flex flex-col items-center">
<i class="fas fa-tv text-4xl mb-3"></i>
<p class="text-lg">No TV shows available</p>
</div>
@endif
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<!-- Pagination -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-600 dark:text-gray-400">
Showing {{ $tvshowlist->firstItem() ?? 0 }} to {{ $tvshowlist->lastItem() ?? 0 }} of {{ $tvshowlist->total() }} shows
</div>
<div>
{{ $tvshowlist->appends(['showname' => $showname])->links() }}
</div>
</div>
</div>
</div>
</div>
@push('styles')
<style>
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>
@endpush
@endsection
@@ -0,0 +1,117 @@
@extends('layouts.admin')
@section('content')
<div class="container mx-auto px-4 py-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
<i class="fas fa-unlink mr-2"></i>{{ $title }}
</h1>
<a href="{{ route('admin.show-list') }}" class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700">
<i class="fas fa-arrow-left mr-2"></i>Back to List
</a>
</div>
</div>
<!-- Content -->
<div class="p-6">
@if($success)
<div class="bg-green-50 dark:bg-green-900 border-l-4 border-green-500 dark:border-green-600 p-4 rounded mb-6">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-check-circle text-green-600 dark:text-green-400 text-xl"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-green-800 dark:text-green-200">
Successfully Removed Video IDs
</h3>
<div class="mt-2 text-sm text-green-700 dark:text-green-300">
<p>Video ID <strong class="font-mono">{{ $videoid }}</strong> and its associated episode IDs have been successfully removed from all releases.</p>
</div>
</div>
</div>
</div>
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">
What was removed?
</h3>
<ul class="space-y-2 text-gray-600 dark:text-gray-400">
<li class="flex items-start">
<i class="fas fa-check text-green-600 dark:text-green-400 mt-1 mr-2"></i>
<span>All releases linked to video ID <strong class="font-mono text-gray-900 dark:text-gray-200">{{ $videoid }}</strong> have been unlinked</span>
</li>
<li class="flex items-start">
<i class="fas fa-check text-green-600 dark:text-green-400 mt-1 mr-2"></i>
<span>All episode IDs associated with this video have been removed from releases</span>
</li>
<li class="flex items-start">
<i class="fas fa-info-circle text-blue-600 dark:text-blue-400 mt-1 mr-2"></i>
<span>The TV show data itself remains in the database and can be re-linked if needed</span>
</li>
</ul>
</div>
@else
<div class="bg-red-50 dark:bg-red-900 border-l-4 border-red-500 dark:border-red-600 p-4 rounded mb-6">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-circle text-red-600 dark:text-red-400 text-xl"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-red-800 dark:text-red-200">
Operation Failed
</h3>
<div class="mt-2 text-sm text-red-700 dark:text-red-300">
<p>Failed to remove video IDs from releases. This could be due to:</p>
<ul class="list-disc list-inside mt-2 space-y-1">
<li>Invalid video ID provided</li>
<li>No releases linked to this video ID</li>
<li>Database error</li>
</ul>
</div>
</div>
</div>
</div>
@endif
<!-- Info Box -->
<div class="mt-6 bg-blue-50 dark:bg-blue-900 border-l-4 border-blue-500 dark:border-blue-600 p-4 rounded">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-blue-600 dark:text-blue-400"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">
About This Operation
</h3>
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
<p>This operation removes the association between TV show data and releases in your database. It's useful when:</p>
<ul class="list-disc list-inside mt-2 space-y-1">
<li>Incorrect TV show data has been linked to releases</li>
<li>You want to force releases to be re-processed for TV show matching</li>
<li>You're cleaning up orphaned or incorrect associations</li>
</ul>
<p class="mt-2"><strong>Note:</strong> This does not delete the TV show from the database, only unlinks it from releases.</p>
</div>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="mt-6 flex items-center justify-between border-t border-gray-200 dark:border-gray-700 pt-6">
<a href="{{ route('admin.show-list') }}" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
<i class="fas fa-list mr-2"></i>Return to TV Shows List
</a>
@if($videoid)
<a href="{{ url('admin/show-edit?id=' . $videoid) }}" class="px-6 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700">
<i class="fas fa-eye mr-2"></i>View TV Show Details
</a>
@endif
</div>
</div>
</div>
</div>
@endsection
@@ -79,6 +79,19 @@
</div>
</div>
<!-- TV Shows -->
<div class="mb-4">
<button type="button" class="flex items-center justify-between w-full text-left text-gray-300 dark:text-gray-400 hover:text-white dark:hover:text-white transition" onclick="toggleAdminSubmenu('shows-menu')">
<div class="flex items-center space-x-3">
<i class="fas fa-tv"></i>
<span>TV Shows</span>
</div>
<i class="fas fa-chevron-down text-sm transform transition-transform" id="shows-menu-icon"></i>
</button>
<div id="shows-menu" class="hidden mt-2 ml-6 space-y-1">
<a href="{{ url('/admin/show-list') }}" class="block py-2 px-3 text-gray-400 dark:text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-800 dark:hover:bg-gray-800 rounded transition">TV Shows List</a>
</div>
</div>
<!-- Games -->
<div class="mb-4">
<button type="button" class="flex items-center justify-between w-full text-left text-gray-300 dark:text-gray-400 hover:text-white dark:hover:text-white transition" onclick="toggleAdminSubmenu('games-menu')">
+39 -39
View File
@@ -165,69 +165,69 @@ Route::middleware('isVerified')->group(function () {
});
Route::middleware('role:Admin', '2fa')->prefix('admin')->group(function () {
Route::match(['GET', 'POST'], 'index', [AdminPageController::class, 'index'])->name('admin.index');
Route::match(['GET', 'POST'], 'anidb-delete/{id}', [AdminAnidbController::class, 'destroy'])->name('admin.anidb-delete');
Route::get('index', [AdminPageController::class, 'index'])->name('admin.index');
Route::post('anidb-delete/{id}', [AdminAnidbController::class, 'destroy'])->name('admin.anidb-delete');
Route::match(['GET', 'POST'], 'anidb-edit/{id}', [AdminAnidbController::class, 'edit'])->name('admin.anidb-edit');
Route::match(['GET', 'POST'], 'anidb-list', [AdminAnidbController::class, 'index'])->name('admin.anidb-list');
Route::match(['GET', 'POST'], 'binaryblacklist-list', [AdminBlacklistController::class, 'index'])->name('admin.binaryblacklist-list');
Route::get('anidb-list', [AdminAnidbController::class, 'index'])->name('admin.anidb-list');
Route::get('binaryblacklist-list', [AdminBlacklistController::class, 'index'])->name('admin.binaryblacklist-list');
Route::match(['GET', 'POST'], 'binaryblacklist-edit', [AdminBlacklistController::class, 'edit'])->name('admin.binaryblacklist-edit');
Route::match(['GET', 'POST'], 'book-list', [AdminBookController::class, 'index'])->name('admin.book-list');
Route::get('book-list', [AdminBookController::class, 'index'])->name('admin.book-list');
Route::match(['GET', 'POST'], 'book-edit', [AdminBookController::class, 'edit'])->name('admin.book-edit');
Route::match(['GET', 'POST'], 'category-list', [AdminCategoryController::class, 'index'])->name('admin.category-list');
Route::get('category-list', [AdminCategoryController::class, 'index'])->name('admin.category-list');
Route::match(['GET', 'POST'], 'category-edit', [AdminCategoryController::class, 'edit'])->name('admin.category-edit');
Route::match(['GET', 'POST'], 'user-list', [AdminUserController::class, 'index'])->name('admin.user-list');
Route::get('user-list', [AdminUserController::class, 'index'])->name('admin.user-list');
Route::match(['GET', 'POST'], 'user-edit', [AdminUserController::class, 'edit'])->name('admin.user-edit');
Route::match(['GET', 'POST'], 'user-delete', [AdminUserController::class, 'destroy'])->name('admin.user-delete');
Route::match(['GET', 'POST'], 'verify', [AdminUserController::class, 'verify'])->name('admin.verify');
Route::match(['GET', 'POST'], 'resendverification', [AdminUserController::class, 'resendVerification'])->name('admin.resend-verification');
Route::post('user-delete', [AdminUserController::class, 'destroy'])->name('admin.user-delete');
Route::post('verify', [AdminUserController::class, 'verify'])->name('admin.verify');
Route::post('resendverification', [AdminUserController::class, 'resendVerification'])->name('admin.resend-verification');
Route::match(['GET', 'POST'], 'site-edit', [AdminSiteController::class, 'edit'])->name('admin.site-edit');
Route::match(['GET', 'POST'], 'site-stats', [AdminSiteController::class, 'stats'])->name('admin.site-stats');
Route::match(['GET', 'POST'], 'role-list', [AdminRoleController::class, 'index'])->name('admin.role-list');
Route::get('site-stats', [AdminSiteController::class, 'stats'])->name('admin.site-stats');
Route::get('role-list', [AdminRoleController::class, 'index'])->name('admin.role-list');
Route::match(['GET', 'POST'], 'role-add', [AdminRoleController::class, 'create'])->name('admin.role-add');
Route::match(['GET', 'POST'], 'role-edit', [AdminRoleController::class, 'edit'])->name('admin.role-edit');
Route::match(['GET', 'POST'], 'role-delete', [AdminRoleController::class, 'destroy'])->name('admin.role-delete');
Route::match(['GET', 'POST'], 'content-list', [AdminContentController::class, 'index'])->name('admin.content-list');
Route::post('role-delete', [AdminRoleController::class, 'destroy'])->name('admin.role-delete');
Route::get('content-list', [AdminContentController::class, 'index'])->name('admin.content-list');
Route::match(['GET', 'POST'], 'content-add', [AdminContentController::class, 'create'])->name('admin.content-add');
Route::match(['GET', 'POST'], 'content-delete', [AdminContentController::class, 'destroy'])->name('admin.content-delete');
Route::match(['GET', 'POST'], 'category_regexes-list', [AdminCategoryRegexesController::class, 'index'])->name('admin.category-regexes-list');
Route::post('content-delete', [AdminContentController::class, 'destroy'])->name('admin.content-delete');
Route::get('category_regexes-list', [AdminCategoryRegexesController::class, 'index'])->name('admin.category-regexes-list');
Route::match(['GET', 'POST'], 'category_regexes-edit', [AdminCategoryRegexesController::class, 'edit'])->name('admin.category-regexes-edit');
Route::match(['GET', 'POST'], 'collection_regexes-list', [AdminCollectionRegexesController::class, 'index'])->name('admin.collection-regexes-list');
Route::get('collection_regexes-list', [AdminCollectionRegexesController::class, 'index'])->name('admin.collection-regexes-list');
Route::match(['GET', 'POST'], 'collection_regexes-edit', [AdminCollectionRegexesController::class, 'edit'])->name('admin.collection-regexes-edit');
Route::match(['GET', 'POST'], 'collection_regexes-test', [AdminCollectionRegexesController::class, 'testRegex'])->name('admin.collection-regexes-test');
Route::match(['GET', 'POST'], 'release_naming_regexes-list', [AdminReleaseNamingRegexesController::class, 'index'])->name('admin.release-naming-regexes-list');
Route::post('collection_regexes-test', [AdminCollectionRegexesController::class, 'testRegex'])->name('admin.collection-regexes-test');
Route::get('release_naming_regexes-list', [AdminReleaseNamingRegexesController::class, 'index'])->name('admin.release-naming-regexes-list');
Route::match(['GET', 'POST'], 'release_naming_regexes-edit', [AdminReleaseNamingRegexesController::class, 'edit'])->name('admin.release-naming-regexes-edit');
Route::match(['GET', 'POST'], 'release_naming_regexes-test', [AdminReleaseNamingRegexesController::class, 'testRegex'])->name('admin.release-naming-regexes-test');
Route::match(['GET', 'POST'], 'ajax', [AdminAjaxController::class, 'ajaxAction'])->name('admin.ajax');
Route::post('release_naming_regexes-test', [AdminReleaseNamingRegexesController::class, 'testRegex'])->name('admin.release-naming-regexes-test');
Route::post('ajax', [AdminAjaxController::class, 'ajaxAction'])->name('admin.ajax');
Route::match(['GET', 'POST'], 'tmux-edit', [AdminTmuxController::class, 'edit'])->name('admin.tmux-edit');
Route::match(['GET', 'POST'], 'release-list', [AdminReleasesController::class, 'index'])->name('admin.release-list');
Route::match(['GET', 'POST'], 'release-delete/{id}', [AdminReleasesController::class, 'destroy'])->name('admin.release-delete');
Route::match(['GET', 'POST'], 'show-list', [AdminShowsController::class, 'index'])->name('admin.show-list');
Route::get('release-list', [AdminReleasesController::class, 'index'])->name('admin.release-list');
Route::post('release-delete/{id}', [AdminReleasesController::class, 'destroy'])->name('admin.release-delete');
Route::get('show-list', [AdminShowsController::class, 'index'])->name('admin.show-list');
Route::match(['GET', 'POST'], 'show-edit', [AdminShowsController::class, 'edit'])->name('admin.show-edit');
Route::match(['GET', 'POST'], 'show-remove', [AdminShowsController::class, 'destroy'])->name('admin.show-remove');
Route::match(['GET', 'POST'], 'comments-list', [AdminCommentsController::class, 'index'])->name('admin.comments-list');
Route::match(['GET', 'POST'], 'comments-delete/{id}', [AdminCommentsController::class, 'destroy'])->name('admin.comments-delete');
Route::match(['GET', 'POST'], 'console-list', [AdminConsoleController::class, 'index'])->name('admin.console-list');
Route::get('show-remove/{id}', [AdminShowsController::class, 'destroy'])->name('admin.show-remove');
Route::get('comments-list', [AdminCommentsController::class, 'index'])->name('admin.comments-list');
Route::post('comments-delete/{id}', [AdminCommentsController::class, 'destroy'])->name('admin.comments-delete');
Route::get('console-list', [AdminConsoleController::class, 'index'])->name('admin.console-list');
Route::match(['GET', 'POST'], 'console-edit', [AdminConsoleController::class, 'edit'])->name('admin.console-edit');
Route::match(['GET', 'POST'], 'failrel-list', [AdminFailedReleasesController::class, 'index'])->name('admin.failrel-list');
Route::match(['GET', 'POST'], 'game-list', [AdminGameController::class, 'index'])->name('admin.game-list');
Route::get('failrel-list', [AdminFailedReleasesController::class, 'index'])->name('admin.failrel-list');
Route::get('game-list', [AdminGameController::class, 'index'])->name('admin.game-list');
Route::match(['GET', 'POST'], 'game-edit', [AdminGameController::class, 'edit'])->name('admin.game-edit');
Route::match(['GET', 'POST'], 'movie-list', [AdminMovieController::class, 'index'])->name('admin.movie-list');
Route::get('movie-list', [AdminMovieController::class, 'index'])->name('admin.movie-list');
Route::match(['GET', 'POST'], 'movie-edit', [AdminMovieController::class, 'edit'])->name('admin.movie-edit');
Route::match(['GET', 'POST'], 'movie-add', [AdminMovieController::class, 'create'])->name('admin.movie-add');
Route::match(['GET', 'POST'], 'music-list', [AdminMusicController::class, 'index'])->name('admin.music-list');
Route::get('music-list', [AdminMusicController::class, 'index'])->name('admin.music-list');
Route::match(['GET', 'POST'], 'music-edit', [AdminMusicController::class, 'edit'])->name('admin.music-edit');
Route::match(['GET', 'POST'], 'predb', [AdminPredbController::class, 'index'])->name('admin.predb');
Route::match(['GET', 'POST'], 'group-list', [AdminGroupController::class, 'index'])->name('admin.group-list');
Route::get('predb', [AdminPredbController::class, 'index'])->name('admin.predb');
Route::get('group-list', [AdminGroupController::class, 'index'])->name('admin.group-list');
Route::match(['GET', 'POST'], 'group-edit', [AdminGroupController::class, 'edit'])->name('admin.group-edit');
Route::match(['GET', 'POST'], 'group-bulk', [AdminGroupController::class, 'createBulk'])->name('admin.group-bulk');
Route::match(['GET', 'POST'], 'group-list-active', [AdminGroupController::class, 'active'])->name('admin.group-list-active');
Route::match(['GET', 'POST'], 'group-list-inactive', [AdminGroupController::class, 'inactive'])->name('admin.group-list-inactive');
Route::get('group-list-active', [AdminGroupController::class, 'active'])->name('admin.group-list-active');
Route::get('group-list-inactive', [AdminGroupController::class, 'inactive'])->name('admin.group-list-inactive');
// Deleted Users Management Routes
Route::match(['GET', 'POST'], 'deleted-users', [DeletedUsersController::class, 'index'])->name('admin.deleted.users.index');
Route::get('deleted-users', [DeletedUsersController::class, 'index'])->name('admin.deleted.users.index');
Route::post('deleted-users/bulk', [DeletedUsersController::class, 'bulkAction'])->name('admin.deleted.users.bulk');
Route::match(['GET', 'POST'], 'deleted-users/restore/{id}', [DeletedUsersController::class, 'restore'])->name('admin.deleted.users.restore');
Route::match(['GET', 'POST'], 'deleted-users/permanent-delete/{id}', [DeletedUsersController::class, 'permanentDelete'])->name('admin.deleted.users.permanent-delete');
Route::post('deleted-users/restore/{id}', [DeletedUsersController::class, 'restore'])->name('admin.deleted.users.restore');
Route::post('deleted-users/permanent-delete/{id}', [DeletedUsersController::class, 'permanentDelete'])->name('admin.deleted.users.permanent-delete');
});
Route::middleware('role_or_permission:Admin|Moderator|edit release')->prefix('admin')->group(function () {