mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 01:08:56 +00:00
Merge branch 'master' of https://github.com/NNTmux/newznab-tmux
This commit is contained in:
@@ -84,21 +84,39 @@ class BrowseController extends BasePageController
|
||||
$catname = 'All';
|
||||
} elseif ($category !== -1 && $grp === -1) {
|
||||
$catname = $id;
|
||||
|
||||
// Determine the root category ID - either from the category's root_categories_id
|
||||
// or the category itself if it IS a root category
|
||||
$rootCategoryId = null;
|
||||
$cdata = Category::find($category);
|
||||
if ($cdata !== null) {
|
||||
if ($cdata->root_categories_id === Category::GAME_ROOT) {
|
||||
$covgroup = 'console';
|
||||
} elseif ($cdata->root_categories_id === Category::MOVIE_ROOT) {
|
||||
$covgroup = 'movies';
|
||||
} elseif ($cdata->root_categories_id === Category::PC_ROOT) {
|
||||
$covgroup = 'games';
|
||||
} elseif ($cdata->root_categories_id === Category::MUSIC_ROOT) {
|
||||
$covgroup = 'music';
|
||||
} elseif ($cdata->root_categories_id === Category::BOOKS_ROOT) {
|
||||
$covgroup = 'books';
|
||||
} elseif ($cdata->root_categories_id === Category::TV_ROOT) {
|
||||
$shows = true;
|
||||
}
|
||||
$rootCategoryId = $cdata->root_categories_id ?? $category;
|
||||
} else {
|
||||
// Category not found in categories table, might be a root category
|
||||
// Check if it matches a known root category ID
|
||||
$rootCategoryId = $category;
|
||||
}
|
||||
|
||||
// Also check RootCategory table for parent categories (when $id is 'All')
|
||||
if ($id === 'All' && $parentId !== null) {
|
||||
$rootCategoryId = $parentId;
|
||||
}
|
||||
|
||||
// Set covgroup based on root category
|
||||
if ($rootCategoryId === Category::GAME_ROOT) {
|
||||
$covgroup = 'console';
|
||||
} elseif ($rootCategoryId === Category::MOVIE_ROOT) {
|
||||
$covgroup = 'movies';
|
||||
} elseif ($rootCategoryId === Category::PC_ROOT) {
|
||||
$covgroup = 'games';
|
||||
} elseif ($rootCategoryId === Category::MUSIC_ROOT) {
|
||||
$covgroup = 'music';
|
||||
} elseif ($rootCategoryId === Category::BOOKS_ROOT) {
|
||||
$covgroup = 'books';
|
||||
} elseif ($rootCategoryId === Category::XXX_ROOT) {
|
||||
$covgroup = 'xxx';
|
||||
} elseif ($rootCategoryId === Category::TV_ROOT) {
|
||||
$shows = true;
|
||||
}
|
||||
} else {
|
||||
$catname = $grp;
|
||||
|
||||
@@ -168,18 +168,34 @@ class ConsoleService
|
||||
Cache::put(md5($calcSql.$page), $consoles, $expiresAt);
|
||||
}
|
||||
|
||||
$consoleIDs = $releaseIDs = false;
|
||||
$consoleIDs = $releaseIDs = [];
|
||||
if (\is_array($consoles['result'])) {
|
||||
foreach ($consoles['result'] as $console => $id) {
|
||||
$consoleIDs = [$id->id];
|
||||
$releaseIDs = [$id->grp_release_id];
|
||||
$consoleIDs[] = $id->id;
|
||||
$releaseIDs[] = $id->grp_release_id;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = sprintf(
|
||||
'
|
||||
"
|
||||
SELECT
|
||||
r.id, r.rarinnerfilecount, r.grabs, r.comments, r.totalpart, r.size, r.postdate, r.searchname, r.haspreview, r.passwordstatus, r.guid, rn.releases_id, g.name AS group_name, df.failed AS failed,
|
||||
GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id,
|
||||
GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') AS grp_rarinnerfilecount,
|
||||
GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview,
|
||||
GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password,
|
||||
GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid,
|
||||
GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid,
|
||||
GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname,
|
||||
GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name,
|
||||
GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate,
|
||||
GROUP_CONCAT(r.adddate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_adddate,
|
||||
GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size,
|
||||
GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts,
|
||||
GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments,
|
||||
GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs,
|
||||
GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed,
|
||||
GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_catname,
|
||||
GROUP_CONCAT(r.fromname ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_fromname,
|
||||
con.*,
|
||||
r.consoleinfo_id,
|
||||
g.name AS group_name,
|
||||
@@ -189,15 +205,17 @@ class ConsoleService
|
||||
LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id
|
||||
LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
|
||||
LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
|
||||
LEFT OUTER JOIN categories c ON c.id = r.categories_id
|
||||
LEFT OUTER JOIN root_categories cp ON cp.id = c.root_categories_id
|
||||
INNER JOIN consoleinfo con ON con.id = r.consoleinfo_id
|
||||
INNER JOIN genres ON con.genres_id = genres.id
|
||||
WHERE con.id IN (%s)
|
||||
AND r.id IN (%s)
|
||||
%s
|
||||
GROUP BY con.id
|
||||
ORDER BY %s %s',
|
||||
(\is_array($consoleIDs) ? implode(',', $consoleIDs) : -1),
|
||||
(\is_array($releaseIDs) ? implode(',', $releaseIDs) : -1),
|
||||
ORDER BY %s %s",
|
||||
(! empty($consoleIDs) ? implode(',', $consoleIDs) : -1),
|
||||
(! empty($releaseIDs) ? implode(',', $releaseIDs) : -1),
|
||||
$catsrch,
|
||||
$order[0],
|
||||
$order[1]
|
||||
|
||||
@@ -216,16 +216,51 @@ class GamesService
|
||||
Cache::put(md5($gamesSql.$page), $games, $expiresAt);
|
||||
}
|
||||
|
||||
$gameIDs = $releaseIDs = false;
|
||||
$gameIDs = $releaseIDs = [];
|
||||
if (is_array($games['result'])) {
|
||||
foreach ($games['result'] as $game => $id) {
|
||||
$gameIDs = [$id->id];
|
||||
$releaseIDs = [$id->grp_release_id];
|
||||
$gameIDs[] = $id->id;
|
||||
$releaseIDs[] = $id->grp_release_id;
|
||||
}
|
||||
}
|
||||
|
||||
$returnSql =
|
||||
'SELECT r.id, r.rarinnerfilecount, r.grabs, r.comments, r.totalpart, r.size, r.postdate, r.searchname, r.haspreview, r.passwordstatus, r.guid, g.name AS group_name, df.failed AS failed, gi.*, YEAR (gi.releasedate) as year, r.gamesinfo_id, rn.releases_id AS nfoid FROM releases r LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id INNER JOIN gamesinfo gi ON gi.id = r.gamesinfo_id WHERE gi.id IN ('.(is_array($gameIDs) ? implode(',', $gameIDs) : -1).') AND r.id IN ('.(is_array($releaseIDs) ? implode(',', $releaseIDs) : -1).')'.$catsrch.' GROUP BY gi.id ORDER BY '.($order[0]).' '.($order[1]);
|
||||
$returnSql = sprintf(
|
||||
"SELECT
|
||||
GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id,
|
||||
GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') AS grp_rarinnerfilecount,
|
||||
GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview,
|
||||
GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password,
|
||||
GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid,
|
||||
GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid,
|
||||
GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname,
|
||||
GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name,
|
||||
GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate,
|
||||
GROUP_CONCAT(r.adddate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_adddate,
|
||||
GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size,
|
||||
GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts,
|
||||
GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments,
|
||||
GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs,
|
||||
GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed,
|
||||
GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_catname,
|
||||
gi.*, YEAR(gi.releasedate) as year, r.gamesinfo_id, rn.releases_id AS nfoid, g.name AS group_name
|
||||
FROM releases r
|
||||
LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id
|
||||
LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
|
||||
LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
|
||||
LEFT OUTER JOIN categories c ON c.id = r.categories_id
|
||||
LEFT OUTER JOIN root_categories cp ON cp.id = c.root_categories_id
|
||||
INNER JOIN gamesinfo gi ON gi.id = r.gamesinfo_id
|
||||
WHERE gi.id IN (%s)
|
||||
AND r.id IN (%s)
|
||||
%s
|
||||
GROUP BY gi.id
|
||||
ORDER BY %s %s",
|
||||
(! empty($gameIDs) ? implode(',', $gameIDs) : -1),
|
||||
(! empty($releaseIDs) ? implode(',', $releaseIDs) : -1),
|
||||
$catsrch,
|
||||
$order[0],
|
||||
$order[1]
|
||||
);
|
||||
|
||||
$return = Cache::get(md5($returnSql.$page));
|
||||
if ($return !== null) {
|
||||
|
||||
@@ -152,21 +152,37 @@ class MusicService
|
||||
}
|
||||
|
||||
$sql = sprintf(
|
||||
'
|
||||
"
|
||||
SELECT
|
||||
r.id, r.rarinnerfilecount, r.grabs, r.comments, r.totalpart, r.size, r.postdate, r.searchname, r.haspreview, r.passwordstatus, r.guid, df.failed AS failed,
|
||||
GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id,
|
||||
GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') AS grp_rarinnerfilecount,
|
||||
GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview,
|
||||
GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password,
|
||||
GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid,
|
||||
GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid,
|
||||
GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname,
|
||||
GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name,
|
||||
GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate,
|
||||
GROUP_CONCAT(r.adddate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_adddate,
|
||||
GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size,
|
||||
GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts,
|
||||
GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments,
|
||||
GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs,
|
||||
GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed,
|
||||
GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_catname,
|
||||
m.*,
|
||||
r.musicinfo_id, r.haspreview,
|
||||
g.name AS group_name,
|
||||
rn.releases_id AS nfoid
|
||||
FROM releases r
|
||||
LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id
|
||||
LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
|
||||
LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
|
||||
LEFT OUTER JOIN categories c ON c.id = r.categories_id
|
||||
LEFT OUTER JOIN root_categories cp ON cp.id = c.root_categories_id
|
||||
INNER JOIN musicinfo m ON m.id = r.musicinfo_id
|
||||
%s %s %s
|
||||
GROUP BY m.id
|
||||
ORDER BY %s %s',
|
||||
ORDER BY %s %s",
|
||||
! empty($musicIDs) ? 'WHERE m.id IN ('.implode(',', $musicIDs).')' : 'AND 1=1',
|
||||
(! empty($releaseIDs)) ? 'AND r.id in ('.implode(',', $releaseIDs).')' : '',
|
||||
$catsrch,
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* This migration fixes the invitations table by:
|
||||
* 1. Dropping the old FK_users_inv foreign key constraint
|
||||
* 2. Renaming users_id to invited_by if needed
|
||||
* 3. Adding missing columns for the new invitation system
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// First, drop the old foreign key constraint if it exists
|
||||
$this->dropForeignKeySafely('invitations', 'FK_users_inv');
|
||||
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
// Rename users_id to invited_by if needed
|
||||
if (Schema::hasColumn('invitations', 'users_id') && ! Schema::hasColumn('invitations', 'invited_by')) {
|
||||
$table->renameColumn('users_id', 'invited_by');
|
||||
}
|
||||
});
|
||||
|
||||
// Now add missing columns in a separate Schema call (after rename)
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
// Drop the old guid column if it exists (replaced by token)
|
||||
if (Schema::hasColumn('invitations', 'guid') && Schema::hasColumn('invitations', 'token')) {
|
||||
$table->dropColumn('guid');
|
||||
}
|
||||
|
||||
// Add token if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'token')) {
|
||||
$table->string('token', 64)->unique()->after('id');
|
||||
}
|
||||
|
||||
// Add email if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'email')) {
|
||||
$table->string('email')->after('token');
|
||||
}
|
||||
|
||||
// Add expires_at if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'expires_at')) {
|
||||
if (Schema::hasColumn('invitations', 'invited_by')) {
|
||||
$table->timestamp('expires_at')->after('invited_by');
|
||||
} else {
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
}
|
||||
}
|
||||
|
||||
// Add used_at if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'used_at')) {
|
||||
$table->timestamp('used_at')->nullable();
|
||||
}
|
||||
|
||||
// Add used_by if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'used_by')) {
|
||||
$table->unsignedBigInteger('used_by')->nullable();
|
||||
}
|
||||
|
||||
// Add is_active if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'is_active')) {
|
||||
$table->boolean('is_active')->default(true);
|
||||
}
|
||||
|
||||
// Add metadata if it doesn't exist
|
||||
if (! Schema::hasColumn('invitations', 'metadata')) {
|
||||
$table->json('metadata')->nullable();
|
||||
}
|
||||
});
|
||||
|
||||
// Migrate data from guid to token if guid still exists and has data
|
||||
if (Schema::hasColumn('invitations', 'guid') && Schema::hasColumn('invitations', 'token')) {
|
||||
DB::table('invitations')
|
||||
->whereNull('token')
|
||||
->orWhere('token', '')
|
||||
->update(['token' => DB::raw('guid')]);
|
||||
|
||||
// Now drop guid
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
$table->dropColumn('guid');
|
||||
});
|
||||
}
|
||||
|
||||
// Add indexes safely
|
||||
$this->addIndexSafely('invitations', ['invited_by'], 'invitations_invited_by_index');
|
||||
$this->addIndexSafely('invitations', ['used_by'], 'invitations_used_by_index');
|
||||
$this->addIndexSafely('invitations', ['token', 'is_active'], 'invitations_token_is_active_index');
|
||||
$this->addIndexSafely('invitations', ['email', 'is_active'], 'invitations_email_is_active_index');
|
||||
$this->addIndexSafely('invitations', ['expires_at'], 'invitations_expires_at_index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Drop indexes first
|
||||
$this->dropIndexSafely('invitations', 'invitations_invited_by_index');
|
||||
$this->dropIndexSafely('invitations', 'invitations_used_by_index');
|
||||
$this->dropIndexSafely('invitations', 'invitations_token_is_active_index');
|
||||
$this->dropIndexSafely('invitations', 'invitations_email_is_active_index');
|
||||
$this->dropIndexSafely('invitations', 'invitations_expires_at_index');
|
||||
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
// Rename back to original column name
|
||||
if (Schema::hasColumn('invitations', 'invited_by') && ! Schema::hasColumn('invitations', 'users_id')) {
|
||||
$table->renameColumn('invited_by', 'users_id');
|
||||
}
|
||||
});
|
||||
|
||||
// Re-add the foreign key constraint
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('invitations', 'users_id')) {
|
||||
$table->foreign('users_id', 'FK_users_inv')
|
||||
->references('id')
|
||||
->on('users')
|
||||
->onDelete('cascade')
|
||||
->onUpdate('cascade');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely drop a foreign key if it exists
|
||||
*/
|
||||
private function dropForeignKeySafely(string $table, string $foreignKeyName): void
|
||||
{
|
||||
try {
|
||||
$foreignKeys = DB::select(
|
||||
"SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
|
||||
AND TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND CONSTRAINT_NAME = ?",
|
||||
[$table, $foreignKeyName]
|
||||
);
|
||||
|
||||
if (! empty($foreignKeys)) {
|
||||
Schema::table($table, function (Blueprint $table) use ($foreignKeyName) {
|
||||
$table->dropForeign($foreignKeyName);
|
||||
});
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Foreign key might not exist, continue
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely add an index if it doesn't exist
|
||||
*/
|
||||
private function addIndexSafely(string $table, array $columns, string $indexName): void
|
||||
{
|
||||
try {
|
||||
$indexes = DB::select("SHOW INDEX FROM `{$table}` WHERE Key_name = ?", [$indexName]);
|
||||
if (empty($indexes)) {
|
||||
Schema::table($table, function (Blueprint $table) use ($columns, $indexName) {
|
||||
$table->index($columns, $indexName);
|
||||
});
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Index creation failed, but continue
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely drop an index if it exists
|
||||
*/
|
||||
private function dropIndexSafely(string $table, string $indexName): void
|
||||
{
|
||||
try {
|
||||
$indexes = DB::select("SHOW INDEX FROM `{$table}` WHERE Key_name = ?", [$indexName]);
|
||||
if (! empty($indexes)) {
|
||||
Schema::table($table, function (Blueprint $table) use ($indexName) {
|
||||
$table->dropIndex($indexName);
|
||||
});
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Index drop failed, but continue
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* Remove the legacy users_id column since we now use invited_by
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
// Drop the old users_id column if it exists and invited_by exists
|
||||
if (Schema::hasColumn('invitations', 'users_id') && Schema::hasColumn('invitations', 'invited_by')) {
|
||||
$table->dropColumn('users_id');
|
||||
}
|
||||
|
||||
// Drop guid column if it still exists (we use token now)
|
||||
if (Schema::hasColumn('invitations', 'guid')) {
|
||||
$table->dropColumn('guid');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('invitations', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('invitations', 'users_id')) {
|
||||
$table->unsignedInteger('users_id')->nullable()->after('id');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -74,11 +74,20 @@
|
||||
<!-- Results -->
|
||||
@if(count($results) > 0)
|
||||
<div class="mb-4 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-800">
|
||||
<i class="fa fa-book mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} Books
|
||||
</h2>
|
||||
<span class="text-sm text-gray-600">
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-book mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} Books
|
||||
</h2>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="books"
|
||||
:category="$categorytitle ?? 'All'"
|
||||
parentcat="Books"
|
||||
:shows="false"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $results->total() }} results found
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -56,13 +56,14 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(isset($covgroup) && $covgroup != '')
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400 dark:text-gray-400">View:</span>
|
||||
<a href="{{ url('/' . $covgroup . '/' . $category) }}" class="text-blue-600 dark:text-blue-400 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 dark:hover:text-blue-300">Covers</a>
|
||||
<span class="text-gray-400 dark:text-gray-500">|</span>
|
||||
<span class="font-semibold text-gray-800 dark:text-gray-200 dark:text-gray-200">List</span>
|
||||
</div>
|
||||
@if(isset($covgroup) && $covgroup != '' || isset($shows) && $shows)
|
||||
<x-view-toggle
|
||||
current-view="list"
|
||||
:covgroup="$covgroup ?? null"
|
||||
:category="$category ?? null"
|
||||
:parentcat="$parentcat ?? null"
|
||||
:shows="$shows ?? false"
|
||||
/>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
@@ -136,8 +137,15 @@
|
||||
</td>
|
||||
<td class="px-3 py-4">
|
||||
<div class="flex items-start">
|
||||
@if($result->cover ?? false)
|
||||
<img src="{{ $result->cover }}" class="w-12 h-16 object-cover rounded mr-3" alt="Cover">
|
||||
@php
|
||||
$showThumbnails = request()->query('thumbs', '0') === '1';
|
||||
$coverUrl = ($result->cover ?? false) ? $result->cover : ($showThumbnails ? getReleaseCover($result) : null);
|
||||
$hasValidCover = $coverUrl && !str_contains($coverUrl, 'no-cover.png');
|
||||
@endphp
|
||||
@if($hasValidCover)
|
||||
<a href="{{ url('/details/' . $result->guid) }}" class="flex-shrink-0">
|
||||
<img src="{{ $coverUrl }}" class="w-12 h-16 object-cover rounded mr-3 shadow-sm hover:shadow-md transition" alt="Cover" loading="lazy">
|
||||
</a>
|
||||
@endif
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
@props([
|
||||
'currentView' => 'list',
|
||||
'covgroup' => null,
|
||||
'category' => null,
|
||||
'parentcat' => null,
|
||||
'shows' => false
|
||||
])
|
||||
|
||||
@php
|
||||
// Build URLs for toggling views while preserving current query parameters
|
||||
$currentParams = request()->query();
|
||||
|
||||
// Map covgroup to correct cover view route
|
||||
$coverRouteMap = [
|
||||
'movies' => 'Movies',
|
||||
'console' => 'Console',
|
||||
'games' => 'Games',
|
||||
'music' => 'Audio',
|
||||
'books' => 'Books',
|
||||
'xxx' => 'XXX',
|
||||
];
|
||||
|
||||
// Map covgroup to correct list browse parent category
|
||||
$listParentMap = [
|
||||
'movies' => 'Movies',
|
||||
'console' => 'Console',
|
||||
'games' => 'PC',
|
||||
'music' => 'Audio',
|
||||
'books' => 'Books',
|
||||
'xxx' => 'XXX',
|
||||
];
|
||||
|
||||
// Parent category IDs - these should not be appended to URLs
|
||||
$parentCategoryIds = [
|
||||
1000, // Console/Game
|
||||
2000, // Movies
|
||||
3000, // Audio/Music
|
||||
4000, // PC
|
||||
5000, // TV
|
||||
6000, // XXX
|
||||
7000, // Books
|
||||
8000, // Other
|
||||
];
|
||||
|
||||
// Check if category is a parent category ID (should not be in URL path)
|
||||
$isParentCategory = is_numeric($category) && in_array((int)$category, $parentCategoryIds);
|
||||
|
||||
// Build cover view URL
|
||||
if ($covgroup && isset($coverRouteMap[$covgroup])) {
|
||||
$coverRoute = $coverRouteMap[$covgroup];
|
||||
// Only append category if it's not a parent category ID and not 'All' or -1
|
||||
$catParam = ($category && $category !== -1 && $category !== 'All' && !$isParentCategory) ? $category : '';
|
||||
$coverUrl = url('/' . $coverRoute . ($catParam ? '/' . $catParam : ''));
|
||||
} elseif ($shows) {
|
||||
$coverUrl = route('series');
|
||||
} else {
|
||||
$coverUrl = '#';
|
||||
}
|
||||
|
||||
// Build list view URL - preserve query params except view and thumbs for clean URL
|
||||
$listParams = $currentParams;
|
||||
unset($listParams['view']);
|
||||
|
||||
// Determine the correct parent category for list view
|
||||
$listParent = $parentcat;
|
||||
if ($covgroup && isset($listParentMap[$covgroup])) {
|
||||
$listParent = $listParentMap[$covgroup];
|
||||
}
|
||||
|
||||
// Only append category to list URL if it's not a parent category ID
|
||||
if ($listParent && $category && $category !== -1 && $category !== 'All' && !$isParentCategory) {
|
||||
$listUrl = url('/browse/' . $listParent . '/' . $category);
|
||||
} elseif ($listParent) {
|
||||
$listUrl = url('/browse/' . $listParent);
|
||||
} else {
|
||||
$listUrl = request()->url();
|
||||
}
|
||||
|
||||
// Add query string if there are params
|
||||
if (!empty($listParams)) {
|
||||
$listUrl .= '?' . http_build_query($listParams);
|
||||
}
|
||||
|
||||
// Build thumbnail toggle URL for list view
|
||||
$thumbParams = $currentParams;
|
||||
$showThumbnails = request()->query('thumbs', '0') === '1';
|
||||
$thumbParams['thumbs'] = $showThumbnails ? '0' : '1';
|
||||
$thumbUrl = request()->url() . '?' . http_build_query($thumbParams);
|
||||
@endphp
|
||||
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">View:</span>
|
||||
|
||||
@if($currentView === 'covers')
|
||||
{{-- Currently in cover view --}}
|
||||
<span class="font-semibold text-gray-800 dark:text-gray-200">Covers</span>
|
||||
<span class="text-gray-400 dark:text-gray-500">|</span>
|
||||
<a href="{{ $listUrl }}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">List</a>
|
||||
@else
|
||||
{{-- Currently in list view --}}
|
||||
@if($covgroup || $shows)
|
||||
<a href="{{ $coverUrl }}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">Covers</a>
|
||||
<span class="text-gray-400 dark:text-gray-500">|</span>
|
||||
@endif
|
||||
<span class="font-semibold text-gray-800 dark:text-gray-200">List</span>
|
||||
|
||||
{{-- Thumbnail toggle in list view --}}
|
||||
@if($covgroup || $shows)
|
||||
<span class="text-gray-400 dark:text-gray-500 ml-2">|</span>
|
||||
<a href="{{ $thumbUrl }}"
|
||||
class="inline-flex items-center gap-1 {{ $showThumbnails ? 'text-green-600 dark:text-green-400' : 'text-blue-600 dark:text-blue-400' }} hover:text-blue-800 dark:hover:text-blue-300"
|
||||
title="{{ $showThumbnails ? 'Hide thumbnails' : 'Show thumbnails' }}">
|
||||
<i class="fas fa-image text-xs"></i>
|
||||
<span>{{ $showThumbnails ? 'Hide Thumbs' : 'Show Thumbs' }}</span>
|
||||
</a>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@@ -42,13 +42,16 @@
|
||||
<div class="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4">
|
||||
<!-- Left Section -->
|
||||
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||
<div class="text-sm">
|
||||
<span class="text-gray-600">View: <strong>Covers</strong> |
|
||||
<a href="{{ url('/browse/Console/' . ($categorytitle ?? '')) }}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800">List</a></span>
|
||||
</div>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="console"
|
||||
:category="$categorytitle ?? 'All'"
|
||||
parentcat="Console"
|
||||
:shows="false"
|
||||
/>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<small class="text-gray-600">With Selected:</small>
|
||||
<small class="text-gray-600 dark:text-gray-400">With Selected:</small>
|
||||
<div class="flex gap-1">
|
||||
<button type="button" class="nzb_multi_operations_download px-3 py-1 bg-green-600 dark:bg-green-700 text-white rounded hover:bg-green-700 dark:hover:bg-green-800 transition text-sm" title="Download NZBs">
|
||||
<i class="fa fa-cloud-download"></i>
|
||||
@@ -73,170 +76,192 @@
|
||||
|
||||
<!-- Results Grid -->
|
||||
<div class="px-6 py-4">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
@foreach($resultsadd as $result)
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
||||
<div class="p-4">
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<!-- Console Cover Column -->
|
||||
<div class="col-span-12 sm:col-span-4">
|
||||
<div class="relative mb-3">
|
||||
<a href="{{ url('/details/' . $result->guid) }}">
|
||||
<img class="w-full rounded shadow"
|
||||
src="{{ getReleaseCover($result) }}"
|
||||
alt="{{ $result->title }}"/>
|
||||
@if(!empty($result->failed))
|
||||
<div class="absolute top-2 right-2">
|
||||
<span class="px-2 py-1 bg-red-600 dark:bg-red-700 text-white text-xs rounded-full">
|
||||
<i class="fa fa-exclamation-circle mr-1"></i>Failed
|
||||
</span>
|
||||
</div>
|
||||
@php
|
||||
// Extract grouped release data
|
||||
$releaseGuids = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid) : [];
|
||||
$releaseNames = isset($result->grp_release_name) ? explode('#', $result->grp_release_name) : [];
|
||||
$releaseSizes = isset($result->grp_release_size) ? explode(',', $result->grp_release_size) : [];
|
||||
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
|
||||
$releaseAddDates = isset($result->grp_release_adddate) ? explode(',', $result->grp_release_adddate) : [];
|
||||
$releaseGrabs = isset($result->grp_release_grabs) ? explode(',', $result->grp_release_grabs) : [];
|
||||
$releaseComments = isset($result->grp_release_comments) ? explode(',', $result->grp_release_comments) : [];
|
||||
$releaseNfoIds = isset($result->grp_release_nfoid) ? explode(',', $result->grp_release_nfoid) : [];
|
||||
$releaseHasPreview = isset($result->grp_haspreview) ? explode(',', $result->grp_haspreview) : [];
|
||||
$releaseCategories = isset($result->grp_release_catname) ? explode(',', $result->grp_release_catname) : [];
|
||||
$releaseFromNames = isset($result->grp_release_fromname) ? explode(',', $result->grp_release_fromname) : [];
|
||||
$failedCounts = isset($result->grp_release_failed) ? array_filter(explode(',', $result->grp_release_failed)) : [];
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
|
||||
// Limit to maximum 2 releases displayed
|
||||
$maxReleases = 2;
|
||||
$totalReleases = count($releaseGuids);
|
||||
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
|
||||
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
|
||||
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
|
||||
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
|
||||
$releaseAddDates = array_slice($releaseAddDates, 0, $maxReleases);
|
||||
$releaseGrabs = array_slice($releaseGrabs, 0, $maxReleases);
|
||||
$releaseComments = array_slice($releaseComments, 0, $maxReleases);
|
||||
$releaseNfoIds = array_slice($releaseNfoIds, 0, $maxReleases);
|
||||
$releaseHasPreview = array_slice($releaseHasPreview, 0, $maxReleases);
|
||||
$releaseCategories = array_slice($releaseCategories, 0, $maxReleases);
|
||||
$releaseFromNames = array_slice($releaseFromNames, 0, $maxReleases);
|
||||
|
||||
$guid = $releaseGuids[0] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow">
|
||||
<div class="flex flex-row">
|
||||
<!-- Console Cover -->
|
||||
<div class="flex-shrink-0">
|
||||
@if($guid)
|
||||
<a href="{{ url('/details/' . $guid) }}" class="block relative">
|
||||
<img class="w-32 h-48 object-cover"
|
||||
src="{{ getReleaseCover($result) }}"
|
||||
alt="{{ $result->title }}"
|
||||
onerror="this.onerror=null;this.src='{{ url('/images/no-cover.png') }}';">
|
||||
@if($totalFailed > 0)
|
||||
<div class="absolute top-2 right-2">
|
||||
<span class="px-2 py-1 bg-red-600 dark:bg-red-700 text-white text-xs rounded-full">
|
||||
<i class="fa fa-exclamation-circle mr-1"></i>{{ $totalFailed }} Failed
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-gamepad text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Console Details -->
|
||||
<div class="flex-1 p-4">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ $result->title }}</h3>
|
||||
|
||||
<div class="flex items-center gap-4 mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
@if(isset($result->releasedate) && $result->releasedate != "")
|
||||
<span><i class="fas fa-calendar mr-1"></i> {{ \Carbon\Carbon::parse($result->releasedate)->format('Y') }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
@if(isset($result->platform) && $result->platform != "")
|
||||
<span><i class="fas fa-gamepad mr-1"></i> {{ $result->platform }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- External Links -->
|
||||
<div class="flex flex-wrap gap-1 mb-2">
|
||||
@if(!empty($result->url))
|
||||
<a target="_blank" href="{{ $site['dereferrer_link'] }}{{ $result->url }}"
|
||||
title="View Game page" class="px-2 py-1 bg-gray-600 text-white text-xs rounded hover:bg-gray-700">
|
||||
<i class="fa fa-shopping-cart mr-1"></i>Amazon
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if($result->nfoid > 0)
|
||||
<a href="{{ url('/nfo/' . $result->guid) }}" data-guid="{{ $result->guid }}"
|
||||
title="View NFO" class="modal_nfo px-2 py-1 bg-gray-600 text-white text-xs rounded hover:bg-gray-700">
|
||||
<i class="fa fa-file-text mr-1"></i>NFO
|
||||
</a>
|
||||
@endif
|
||||
|
||||
<a class="px-2 py-1 bg-gray-600 text-white text-xs rounded hover:bg-gray-700"
|
||||
href="{{ url('/browse/group?g=' . $result->group_name) }}"
|
||||
title="Browse releases in {{ str_replace('alt.binaries', 'a.b', $result->group_name) }}">
|
||||
<i class="fa fa-users mr-1"></i>Group
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Console Info Column -->
|
||||
<div class="col-span-12 sm:col-span-8">
|
||||
<!-- Console Title -->
|
||||
<h5 class="text-lg font-semibold mb-2">
|
||||
<a class="text-gray-800 dark:text-gray-200 hover:text-blue-600" href="{{ url('/details/' . $result->guid) }}">
|
||||
{{ $result->title }}
|
||||
</a>
|
||||
</h5>
|
||||
|
||||
<!-- Console Details -->
|
||||
<div class="mb-3 text-sm space-y-1">
|
||||
@if(isset($result->genre) && $result->genre != "")
|
||||
<div class="flex items-start">
|
||||
<i class="fa fa-tags text-gray-400 mr-2 mt-1"></i>
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 mt-2 space-y-1">
|
||||
@if(isset($result->genre) && $result->genre != "")
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<strong>Genre:</strong>
|
||||
@foreach(explode(', ', $result->genre) as $genre)
|
||||
<span class="px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded text-xs">{{ $genre }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(isset($result->esrb) && $result->esrb != "")
|
||||
<div class="flex items-center text-gray-600">
|
||||
<i class="fa fa-shield text-gray-400 mr-2"></i>
|
||||
<span><strong>Rating:</strong> {{ $result->esrb }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(isset($result->publisher) && $result->publisher != "")
|
||||
<div class="flex items-center text-gray-600">
|
||||
<i class="fa fa-building text-gray-400 mr-2"></i>
|
||||
<span><strong>Publisher:</strong> {{ $result->publisher }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(isset($result->releasedate) && $result->releasedate != "")
|
||||
<div class="flex items-center text-gray-600">
|
||||
<i class="fa fa-calendar text-gray-400 mr-2"></i>
|
||||
<span><strong>Released:</strong> {{ \Carbon\Carbon::parse($result->releasedate)->format('M d, Y') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(isset($result->review) && $result->review != "")
|
||||
<div class="text-gray-600 dark:text-gray-400 line-clamp-3">
|
||||
<i class="fa fa-quote-left text-gray-400 mr-2"></i>{{ $result->review }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Release Info Card -->
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-3 border border-gray-200">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<label class="inline-flex items-center">
|
||||
<input type="checkbox" class="form-checkbox h-4 w-4 text-blue-600" value="{{ $result->guid }}" id="chksingle"/>
|
||||
</label>
|
||||
|
||||
<div class="flex items-center text-sm">
|
||||
<i class="fa fa-hdd-o text-gray-400 mr-2"></i>
|
||||
<span class="px-2 py-1 bg-gray-600 text-white text-xs rounded">{{ formatBytes($result->size) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(!empty($result->adddate))
|
||||
<div class="flex items-center text-gray-500 text-sm mb-3">
|
||||
<i class="fa fa-clock-o mr-2"></i>
|
||||
<span>Added {{ userDateDiffForHumans($result->adddate) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-wrap gap-2 text-xs mb-3">
|
||||
@if(!empty($result->group_name))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-users mr-1"></i> {{ $result->group_name }}
|
||||
</span>
|
||||
@endif
|
||||
@if(!empty($result->postdate))
|
||||
<span>
|
||||
<i class="fas fa-calendar mr-1"></i> Posted: {{ userDate($result->postdate, 'M d, Y H:i') }}
|
||||
</span>
|
||||
@if(isset($result->publisher) && $result->publisher != "")
|
||||
<div><strong>Publisher:</strong> {{ $result->publisher }}</div>
|
||||
@endif
|
||||
@if(!empty($result->fromname))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200 font-mono">
|
||||
<i class="fas fa-user mr-1"></i> {{ $result->fromname }}
|
||||
</span>
|
||||
@if(isset($result->esrb) && $result->esrb != "")
|
||||
<div><strong>Rating:</strong> {{ $result->esrb }}</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-wrap gap-2" id="guid{{ $result->guid }}">
|
||||
<a class="px-3 py-1.5 bg-blue-600 dark:bg-blue-700 text-white rounded hover:bg-blue-700 dark:hover:bg-blue-800 text-sm inline-flex items-center"
|
||||
title="Download NZB"
|
||||
href="{{ url('/getnzb?id=' . $result->guid) }}">
|
||||
<i class="fa fa-cloud-download mr-1"></i>
|
||||
<span class="px-1.5 py-0.5 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-xs rounded ml-1">{{ $result->grabs }}</span>
|
||||
</a>
|
||||
|
||||
<a class="px-3 py-1.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 text-sm inline-flex items-center"
|
||||
href="{{ url('/details/' . $result->guid . '#comments') }}">
|
||||
<i class="fa fa-comment-o mr-1"></i>
|
||||
<span class="px-1.5 py-0.5 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-xs rounded ml-1">{{ $result->comments }}</span>
|
||||
</a>
|
||||
|
||||
<a href="#" class="add-to-cart px-3 py-1.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded hover:bg-gray-300 text-sm"
|
||||
data-guid="{{ $result->guid }}"
|
||||
title="Send to my download basket">
|
||||
<i class="icon_cart fa fa-shopping-basket"></i>
|
||||
</a>
|
||||
|
||||
@if(!empty($result->failed))
|
||||
<span class="px-3 py-1.5 bg-red-100 text-red-700 rounded text-sm">
|
||||
<i class="fa fa-exclamation-triangle mr-1"></i>
|
||||
{{ $result->failed }} Failed
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<!-- External Links -->
|
||||
@if(!empty($result->url))
|
||||
<div class="mt-2">
|
||||
<a target="_blank" href="{{ $site['dereferrer_link'] }}{{ $result->url }}"
|
||||
title="View Game page" class="inline-flex items-center px-2 py-1 bg-gray-600 text-white text-xs rounded hover:bg-gray-700">
|
||||
<i class="fa fa-shopping-cart mr-1"></i>Amazon
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Release Information -->
|
||||
@if(!empty($releaseGuids[0]))
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
|
||||
Available Releases
|
||||
@if($totalReleases > $maxReleases)
|
||||
<span class="text-xs font-normal text-gray-500">(Showing {{ $maxReleases }} of {{ $totalReleases }})</span>
|
||||
@endif
|
||||
</h4>
|
||||
<div class="space-y-2">
|
||||
@foreach($releaseNames as $index => $releaseName)
|
||||
@if($releaseName && isset($releaseGuids[$index]))
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-2 border border-gray-200 dark:border-gray-700">
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<!-- Release Name -->
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="text-sm text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 font-medium block break-all flex-1" title="{{ $releaseName }}">
|
||||
{{ $releaseName }}
|
||||
</a>
|
||||
<label class="inline-flex items-center flex-shrink-0">
|
||||
<input type="checkbox" class="form-checkbox h-4 w-4 text-blue-600" value="{{ $releaseGuids[$index] }}" id="chksingle"/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Info Badges -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
@if(isset($releaseSizes[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSizes[$index] / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releasePostDates[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ date('M d, Y H:i', strtotime($releasePostDates[$index])) }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseAddDates[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-plus-circle mr-1"></i>{{ userDateDiffForHumans($releaseAddDates[$index]) }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseNfoIds[$index]) && !empty($releaseNfoIds[$index]))
|
||||
<button type="button"
|
||||
class="nfo-badge inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 hover:bg-yellow-200 dark:hover:bg-yellow-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuids[$index] }}"
|
||||
title="View NFO file">
|
||||
<i class="fas fa-file-alt mr-1"></i> NFO
|
||||
</button>
|
||||
@endif
|
||||
@if(isset($releaseFromNames[$index]) && !empty($releaseFromNames[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200" title="Poster/Uploader">
|
||||
<i class="fas fa-user mr-1"></i> {{ $releaseFromNames[$index] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<a href="{{ url('/getnzb/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-600 dark:bg-green-700 text-white hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-1"></i> Download
|
||||
@if(isset($releaseGrabs[$index]) && $releaseGrabs[$index] > 0)
|
||||
<span class="ml-1 px-1 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-xs rounded">{{ $releaseGrabs[$index] }}</span>
|
||||
@endif
|
||||
</a>
|
||||
<button class="add-to-cart inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-600 dark:bg-blue-700 text-white hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $releaseGuids[$index] }}">
|
||||
<i class="fas fa-shopping-cart mr-1"></i> Cart
|
||||
</button>
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-800 transition">
|
||||
<i class="fas fa-info-circle mr-1"></i> Details
|
||||
@if(isset($releaseComments[$index]) && $releaseComments[$index] > 0)
|
||||
<span class="ml-1 px-1 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-xs rounded">{{ $releaseComments[$index] }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -245,17 +270,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-200">
|
||||
<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 flex-col lg:flex-row justify-between items-start lg:items-center gap-4">
|
||||
<!-- Left Section -->
|
||||
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||
<div class="text-sm">
|
||||
<span class="text-gray-600">View: <strong>Covers</strong> |
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">
|
||||
<span>View: <strong>Covers</strong> |
|
||||
<a href="{{ url('/browse/Console/' . ($categorytitle ?? '')) }}" class="text-blue-600 dark:text-blue-400 hover:text-blue-800">List</a></span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<small class="text-gray-600">With Selected:</small>
|
||||
<small class="text-gray-600 dark:text-gray-400">With Selected:</small>
|
||||
<div class="flex gap-1">
|
||||
<button type="button" class="nzb_multi_operations_download px-3 py-1 bg-green-600 dark:bg-green-700 text-white rounded hover:bg-green-700 dark:hover:bg-green-800 transition text-sm" title="Download NZBs">
|
||||
<i class="fa fa-cloud-download"></i>
|
||||
@@ -280,16 +305,18 @@
|
||||
</form>
|
||||
@else
|
||||
<div class="px-6 py-8">
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4 text-blue-800">
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-700 rounded-lg p-4 text-blue-800 dark:text-blue-200">
|
||||
<i class="fa fa-info-circle mr-2"></i>
|
||||
No console releases with covers available!
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- NFO Modal -->
|
||||
@include('partials.nfo-modal')
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
@include('partials.cart-script')
|
||||
@endpush
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<label for="category" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Category</label>
|
||||
<select id="category"
|
||||
name="t"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500">
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
|
||||
<option value="">All Categories</option>
|
||||
@foreach($catlist ?? [] as $cat)
|
||||
<option value="{{ $cat['id'] }}" {{ ($category ?? '') == $cat['id'] ? 'selected' : '' }}>
|
||||
@@ -45,7 +45,7 @@
|
||||
name="title"
|
||||
value="{{ $title ?? '' }}"
|
||||
placeholder="Search by title"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500">
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
|
||||
</div>
|
||||
|
||||
<!-- Genre Filter -->
|
||||
@@ -53,7 +53,7 @@
|
||||
<label for="genre" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Genre</label>
|
||||
<select id="genre"
|
||||
name="genre"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500">
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
|
||||
<option value="">All Genres</option>
|
||||
@foreach($genres ?? [] as $g)
|
||||
<option value="{{ $g->id }}" {{ ($genre ?? '') == $g->id ? 'selected' : '' }}>
|
||||
@@ -68,7 +68,7 @@
|
||||
<label for="year" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Year</label>
|
||||
<select id="year"
|
||||
name="year"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500">
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
|
||||
<option value="">All Years</option>
|
||||
@foreach($years ?? [] as $y)
|
||||
<option value="{{ $y }}" {{ ($year ?? '') == $y ? 'selected' : '' }}>
|
||||
@@ -93,67 +93,182 @@
|
||||
<!-- Results -->
|
||||
@if(count($results) > 0)
|
||||
<div class="mb-4 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-800">
|
||||
<i class="fa fa-gamepad mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} Games
|
||||
</h2>
|
||||
<span class="text-sm text-gray-600">
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-gamepad mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} Games
|
||||
</h2>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="games"
|
||||
:category="$catname ?? 'All'"
|
||||
parentcat="PC"
|
||||
:shows="false"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $results->total() }} results found
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Games Grid -->
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4 mb-6">
|
||||
<!-- Games Grid - Card Layout with Multiple Releases -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
|
||||
@foreach($results as $result)
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow duration-200">
|
||||
<a href="{{ url('/details/' . $result->guid) }}" class="block relative">
|
||||
@if(!empty($result->cover))
|
||||
<img src="{{ url('/covers/games/' . $result->cover) }}"
|
||||
alt="{{ $result->title ?? $result->searchname }}"
|
||||
class="w-full h-48 object-cover"
|
||||
data-fallback-src="{{ url('/images/no-cover.png') }}">
|
||||
@else
|
||||
<div class="w-full h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fa fa-gamepad text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($result->failed) && $result->failed > 0)
|
||||
<div class="absolute top-2 right-2">
|
||||
<span class="px-2 py-1 bg-red-600 dark:bg-red-700 text-white text-xs rounded-full shadow-lg" title="{{ $result->failed }} user(s) reported download failure">
|
||||
<i class="fa fa-exclamation-triangle mr-1"></i>Failed
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="p-3">
|
||||
<h3 class="font-semibold text-sm text-gray-800 dark:text-gray-200 break-words break-all" title="{{ $result->title ?? $result->searchname }}">
|
||||
{{ $result->title ?? $result->searchname }}
|
||||
</h3>
|
||||
@if(!empty($result->publisher))
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 truncate" title="{{ $result->publisher }}">
|
||||
{{ $result->publisher }}
|
||||
</p>
|
||||
@endif
|
||||
@if(!empty($result->releasedate))
|
||||
<p class="text-xs text-gray-500 mt-1">{{ date('Y', strtotime($result->releasedate)) }}</p>
|
||||
@elseif(!empty($result->year))
|
||||
<p class="text-xs text-gray-500 mt-1">{{ $result->year }}</p>
|
||||
@endif
|
||||
@if(!empty($result->platform))
|
||||
<p class="text-xs text-blue-600 dark:text-blue-400 mt-1 truncate">{{ $result->platform }}</p>
|
||||
@php
|
||||
// Extract grouped release data
|
||||
$releaseGuids = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid) : [];
|
||||
$releaseNames = isset($result->grp_release_name) ? explode('#', $result->grp_release_name) : [];
|
||||
$releaseSizes = isset($result->grp_release_size) ? explode(',', $result->grp_release_size) : [];
|
||||
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
|
||||
$releaseAddDates = isset($result->grp_release_adddate) ? explode(',', $result->grp_release_adddate) : [];
|
||||
$releaseGrabs = isset($result->grp_release_grabs) ? explode(',', $result->grp_release_grabs) : [];
|
||||
$releaseNfoIds = isset($result->grp_release_nfoid) ? explode(',', $result->grp_release_nfoid) : [];
|
||||
$releaseHasPreview = isset($result->grp_haspreview) ? explode(',', $result->grp_haspreview) : [];
|
||||
$releaseCategories = isset($result->grp_release_catname) ? explode(',', $result->grp_release_catname) : [];
|
||||
$failedCounts = isset($result->grp_release_failed) ? array_filter(explode(',', $result->grp_release_failed)) : [];
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
|
||||
// Limit to maximum 2 releases displayed
|
||||
$maxReleases = 2;
|
||||
$totalReleases = count($releaseGuids);
|
||||
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
|
||||
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
|
||||
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
|
||||
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
|
||||
$releaseAddDates = array_slice($releaseAddDates, 0, $maxReleases);
|
||||
$releaseGrabs = array_slice($releaseGrabs, 0, $maxReleases);
|
||||
$releaseNfoIds = array_slice($releaseNfoIds, 0, $maxReleases);
|
||||
$releaseHasPreview = array_slice($releaseHasPreview, 0, $maxReleases);
|
||||
$releaseCategories = array_slice($releaseCategories, 0, $maxReleases);
|
||||
|
||||
$guid = $releaseGuids[0] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow">
|
||||
<div class="flex flex-row">
|
||||
<!-- Game Cover -->
|
||||
<div class="flex-shrink-0">
|
||||
@if($guid)
|
||||
<a href="{{ url('/details/' . $guid) }}" class="block">
|
||||
@if(!empty($result->cover))
|
||||
<img src="{{ url('/covers/games/' . $result->cover) }}"
|
||||
alt="{{ $result->title ?? $result->searchname }}"
|
||||
class="w-32 h-48 object-cover"
|
||||
onerror="this.onerror=null;this.src='{{ url('/images/no-cover.png') }}';">
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-gamepad text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-gamepad text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Game Details -->
|
||||
<div class="flex-1 p-4">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ $result->title ?? $result->searchname }}</h3>
|
||||
|
||||
@if($totalFailed > 0)
|
||||
<div class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-red-100 text-red-800 border border-red-200 mt-1">
|
||||
<i class="fas fa-exclamation-triangle mr-1"></i>
|
||||
<span>{{ $totalFailed }} failed report{{ $totalFailed > 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center gap-4 mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
@if(!empty($result->releasedate))
|
||||
<span><i class="fas fa-calendar mr-1"></i> {{ date('Y', strtotime($result->releasedate)) }}</span>
|
||||
@elseif(!empty($result->year))
|
||||
<span><i class="fas fa-calendar mr-1"></i> {{ $result->year }}</span>
|
||||
@endif
|
||||
@if(!empty($result->platform))
|
||||
<span><i class="fas fa-desktop mr-1"></i> {{ $result->platform }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 mt-2 space-y-1">
|
||||
@if(!empty($result->publisher))
|
||||
<div><strong>Publisher:</strong> {{ $result->publisher }}</div>
|
||||
@endif
|
||||
@if(!empty($result->genre))
|
||||
<div><strong>Genre:</strong> {{ $result->genre }}</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Release Information -->
|
||||
@if(!empty($releaseGuids[0]))
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
|
||||
Available Releases
|
||||
@if($totalReleases > $maxReleases)
|
||||
<span class="text-xs font-normal text-gray-500">(Showing {{ $maxReleases }} of {{ $totalReleases }})</span>
|
||||
@endif
|
||||
</h4>
|
||||
<div class="space-y-2">
|
||||
@foreach($releaseNames as $index => $releaseName)
|
||||
@if($releaseName && isset($releaseGuids[$index]))
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-2 border border-gray-200 dark:border-gray-700">
|
||||
<div class="space-y-2">
|
||||
<!-- Release Name -->
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="text-sm text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 font-medium block break-all" title="{{ $releaseName }}">
|
||||
{{ $releaseName }}
|
||||
</a>
|
||||
|
||||
<!-- Info Badges -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
@if(isset($releaseSizes[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSizes[$index] / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releasePostDates[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ date('M d, Y H:i', strtotime($releasePostDates[$index])) }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseCategories[$index]) && !empty($releaseCategories[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-folder mr-1"></i>{{ $releaseCategories[$index] }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseNfoIds[$index]) && !empty($releaseNfoIds[$index]))
|
||||
<button type="button"
|
||||
class="nfo-badge inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 hover:bg-yellow-200 dark:hover:bg-yellow-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuids[$index] }}"
|
||||
title="View NFO file">
|
||||
<i class="fas fa-file-alt mr-1"></i> NFO
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<a href="{{ url('/getnzb/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-600 dark:bg-green-700 text-white hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-1"></i> Download
|
||||
</a>
|
||||
<button class="add-to-cart inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-600 dark:bg-blue-700 text-white hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $releaseGuids[$index] }}">
|
||||
<i class="fas fa-shopping-cart mr-1"></i> Cart
|
||||
</button>
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-800 transition">
|
||||
<i class="fas fa-info-circle mr-1"></i> Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
<div class="px-3 pb-3 flex gap-1">
|
||||
<a href="{{ url('/getnzb?id=' . $result->guid) }}"
|
||||
class="flex-1 px-2 py-1 bg-green-600 dark:bg-green-700 text-white text-xs rounded hover:bg-green-700 dark:hover:bg-green-800 text-center"
|
||||
title="Download NZB">
|
||||
<i class="fa fa-download"></i>
|
||||
</a>
|
||||
<a href="{{ url('/details/' . $result->guid) }}"
|
||||
class="flex-1 px-2 py-1 bg-blue-600 dark:bg-blue-700 text-white text-xs rounded hover:bg-blue-700 dark:hover:bg-blue-800 text-center"
|
||||
title="View Details">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@@ -165,8 +280,8 @@
|
||||
</div>
|
||||
@else
|
||||
<!-- No Results -->
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-8 text-center">
|
||||
<i class="fa fa-gamepad text-yellow-600 text-5xl mb-4"></i>
|
||||
<div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-700 rounded-lg p-8 text-center">
|
||||
<i class="fa fa-gamepad text-yellow-600 dark:text-yellow-500 text-5xl mb-4"></i>
|
||||
<h3 class="text-xl font-semibold text-gray-800 dark:text-gray-200 mb-2">No games found</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4">Try adjusting your search filters or browse all games.</p>
|
||||
<a href="{{ url('/Games') }}" class="inline-flex items-center px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700">
|
||||
@@ -176,5 +291,8 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NFO Modal -->
|
||||
@include('partials.nfo-modal')
|
||||
@endsection
|
||||
|
||||
|
||||
@@ -24,7 +24,16 @@
|
||||
<!-- Movies Filter Section -->
|
||||
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-b border-gray-200">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Filter Movies</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Filter Movies</h2>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="movies"
|
||||
category="All"
|
||||
parentcat="Movies"
|
||||
:shows="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<!-- Layout Toggle Button -->
|
||||
<button id="layoutToggle" class="inline-flex items-center px-4 py-2 bg-gray-600 dark:bg-gray-700 text-white rounded-lg hover:bg-gray-700 dark:hover:bg-gray-800 transition shadow-md" title="Toggle layout">
|
||||
|
||||
@@ -90,63 +90,178 @@
|
||||
<!-- Results -->
|
||||
@if(count($results) > 0)
|
||||
<div class="mb-4 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-music mr-2 text-blue-600 dark:text-blue-400"></i>
|
||||
{{ $catname ?? 'All' }} Albums
|
||||
</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-music mr-2 text-blue-600 dark:text-blue-400"></i>
|
||||
{{ $catname ?? 'All' }} Albums
|
||||
</h2>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="music"
|
||||
:category="$categorytitle ?? 'All'"
|
||||
parentcat="Audio"
|
||||
:shows="false"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $results->total() }} results found
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Album Grid -->
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4 mb-6">
|
||||
<!-- Album Grid - Card Layout with Multiple Releases -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
|
||||
@foreach($resultsadd as $result)
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow duration-200">
|
||||
<a href="{{ url('/details/' . $result->guid) }}" class="block relative">
|
||||
@if(!empty($result->cover))
|
||||
<img src="{{ url('/covers/music/' . $result->cover) }}"
|
||||
alt="{{ $result->artist ?? '' }} - {{ $result->title ?? '' }}"
|
||||
class="w-full h-48 object-cover"
|
||||
data-fallback-src="{{ url('/images/no-cover.png') }}">
|
||||
@else
|
||||
<div class="w-full h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fa fa-music text-4xl text-gray-400"></i>
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($result->failed) && $result->failed > 0)
|
||||
<div class="absolute top-2 right-2">
|
||||
<span class="px-2 py-1 bg-red-600 dark:bg-red-700 text-white text-xs rounded-full shadow-lg" title="{{ $result->failed }} user(s) reported download failure">
|
||||
<i class="fa fa-exclamation-triangle mr-1"></i>Failed
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="p-3">
|
||||
<h3 class="font-semibold text-sm text-gray-800 dark:text-gray-200 break-words break-all" title="{{ $result->title ?? $result->searchname }}">
|
||||
{{ $result->title ?? $result->searchname }}
|
||||
</h3>
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 truncate" title="{{ $result->artist ?? '' }}">
|
||||
{{ $result->artist ?? 'Unknown Artist' }}
|
||||
</p>
|
||||
@if(!empty($result->year))
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ $result->year }}</p>
|
||||
@endif
|
||||
@if(!empty($result->genre))
|
||||
<p class="text-xs text-blue-600 dark:text-blue-400 mt-1 truncate">{{ $result->genre }}</p>
|
||||
@php
|
||||
// Extract grouped release data
|
||||
$releaseGuids = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid) : [];
|
||||
$releaseNames = isset($result->grp_release_name) ? explode('#', $result->grp_release_name) : [];
|
||||
$releaseSizes = isset($result->grp_release_size) ? explode(',', $result->grp_release_size) : [];
|
||||
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
|
||||
$releaseAddDates = isset($result->grp_release_adddate) ? explode(',', $result->grp_release_adddate) : [];
|
||||
$releaseGrabs = isset($result->grp_release_grabs) ? explode(',', $result->grp_release_grabs) : [];
|
||||
$releaseNfoIds = isset($result->grp_release_nfoid) ? explode(',', $result->grp_release_nfoid) : [];
|
||||
$releaseHasPreview = isset($result->grp_haspreview) ? explode(',', $result->grp_haspreview) : [];
|
||||
$releaseCategories = isset($result->grp_release_catname) ? explode(',', $result->grp_release_catname) : [];
|
||||
$failedCounts = isset($result->grp_release_failed) ? array_filter(explode(',', $result->grp_release_failed)) : [];
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
|
||||
// Limit to maximum 2 releases displayed
|
||||
$maxReleases = 2;
|
||||
$totalReleases = count($releaseGuids);
|
||||
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
|
||||
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
|
||||
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
|
||||
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
|
||||
$releaseAddDates = array_slice($releaseAddDates, 0, $maxReleases);
|
||||
$releaseGrabs = array_slice($releaseGrabs, 0, $maxReleases);
|
||||
$releaseNfoIds = array_slice($releaseNfoIds, 0, $maxReleases);
|
||||
$releaseHasPreview = array_slice($releaseHasPreview, 0, $maxReleases);
|
||||
$releaseCategories = array_slice($releaseCategories, 0, $maxReleases);
|
||||
|
||||
$guid = $releaseGuids[0] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow">
|
||||
<div class="flex flex-row">
|
||||
<!-- Album Cover -->
|
||||
<div class="flex-shrink-0">
|
||||
@if($guid)
|
||||
<a href="{{ url('/details/' . $guid) }}" class="block">
|
||||
@if(!empty($result->cover))
|
||||
<img src="{{ url('/covers/music/' . $result->cover) }}"
|
||||
alt="{{ $result->artist ?? '' }} - {{ $result->title ?? '' }}"
|
||||
class="w-32 h-48 object-cover"
|
||||
onerror="this.onerror=null;this.src='{{ url('/images/no-cover.png') }}';">
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-music text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-music text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Album Details -->
|
||||
<div class="flex-1 p-4">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ $result->title ?? 'Unknown Album' }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ $result->artist ?? 'Unknown Artist' }}</p>
|
||||
|
||||
@if($totalFailed > 0)
|
||||
<div class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-red-100 text-red-800 border border-red-200 mt-1">
|
||||
<i class="fas fa-exclamation-triangle mr-1"></i>
|
||||
<span>{{ $totalFailed }} failed report{{ $totalFailed > 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center gap-4 mt-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
@if(!empty($result->year))
|
||||
<span><i class="fas fa-calendar mr-1"></i> {{ $result->year }}</span>
|
||||
@endif
|
||||
@if(!empty($result->genre))
|
||||
<span><i class="fas fa-tag mr-1"></i> {{ $result->genre }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if(!empty($result->label))
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||
<strong>Label:</strong> {{ $result->label }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Release Information -->
|
||||
@if(!empty($releaseGuids[0]))
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
|
||||
Available Releases
|
||||
@if($totalReleases > $maxReleases)
|
||||
<span class="text-xs font-normal text-gray-500">(Showing {{ $maxReleases }} of {{ $totalReleases }})</span>
|
||||
@endif
|
||||
</h4>
|
||||
<div class="space-y-2">
|
||||
@foreach($releaseNames as $index => $releaseName)
|
||||
@if($releaseName && isset($releaseGuids[$index]))
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-2 border border-gray-200 dark:border-gray-700">
|
||||
<div class="space-y-2">
|
||||
<!-- Release Name -->
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="text-sm text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 font-medium block break-all" title="{{ $releaseName }}">
|
||||
{{ $releaseName }}
|
||||
</a>
|
||||
|
||||
<!-- Info Badges -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
@if(isset($releaseSizes[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSizes[$index] / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releasePostDates[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ date('M d, Y H:i', strtotime($releasePostDates[$index])) }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseCategories[$index]) && !empty($releaseCategories[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-folder mr-1"></i>{{ $releaseCategories[$index] }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseNfoIds[$index]) && !empty($releaseNfoIds[$index]))
|
||||
<button type="button"
|
||||
class="nfo-badge inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 hover:bg-yellow-200 dark:hover:bg-yellow-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuids[$index] }}"
|
||||
title="View NFO file">
|
||||
<i class="fas fa-file-alt mr-1"></i> NFO
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<a href="{{ url('/getnzb/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-600 dark:bg-green-700 text-white hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-1"></i> Download
|
||||
</a>
|
||||
<button class="add-to-cart inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-600 dark:bg-blue-700 text-white hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $releaseGuids[$index] }}">
|
||||
<i class="fas fa-shopping-cart mr-1"></i> Cart
|
||||
</button>
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-800 transition">
|
||||
<i class="fas fa-info-circle mr-1"></i> Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
<div class="px-3 pb-3 flex gap-1">
|
||||
<a href="{{ url('/getnzb?id=' . $result->guid) }}"
|
||||
class="flex-1 px-2 py-1 bg-green-600 dark:bg-green-700 text-white text-xs rounded hover:bg-green-700 dark:hover:bg-green-800 text-center"
|
||||
title="Download NZB">
|
||||
<i class="fa fa-download"></i>
|
||||
</a>
|
||||
<a href="{{ url('/details/' . $result->guid) }}"
|
||||
class="flex-1 px-2 py-1 bg-blue-600 dark:bg-blue-700 text-white text-xs rounded hover:bg-blue-700 dark:hover:bg-blue-800 text-center"
|
||||
title="View Details">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@@ -169,5 +284,8 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NFO Modal -->
|
||||
@include('partials.nfo-modal')
|
||||
@endsection
|
||||
|
||||
|
||||
@@ -85,110 +85,200 @@
|
||||
<!-- Results -->
|
||||
@if(count($results) > 0)
|
||||
<div class="mb-4 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-film mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} XXX
|
||||
</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
|
||||
<i class="fa fa-film mr-2 text-blue-600"></i>
|
||||
{{ $catname ?? 'All' }} XXX
|
||||
</h2>
|
||||
<x-view-toggle
|
||||
current-view="covers"
|
||||
covgroup="xxx"
|
||||
:category="$categorytitle ?? 'All'"
|
||||
parentcat="XXX"
|
||||
:shows="false"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $results->total() }} results found
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- XXX List Table -->
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gray-100 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">Name</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider hidden md:table-cell">Category</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider hidden lg:table-cell">Posted</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider hidden xl:table-cell">Size</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
@foreach($results as $result)
|
||||
@php
|
||||
// Extract first values from comma-separated grouped fields
|
||||
$guid = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid)[0] : null;
|
||||
$searchname = isset($result->grp_release_name) ? explode('#', $result->grp_release_name)[0] : ($result->title ?? '');
|
||||
$postdate = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate)[0] : null;
|
||||
$size = isset($result->grp_release_size) ? explode(',', $result->grp_release_size)[0] : 0;
|
||||
$failedCounts = isset($result->grp_release_failed) ? array_filter(explode(',', $result->grp_release_failed)) : [];
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
@endphp
|
||||
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-1 min-w-0">
|
||||
<a href="{{ url('/details/' . $guid) }}"
|
||||
class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 font-medium break-words">
|
||||
{{ $searchname }}
|
||||
</a>
|
||||
@if($totalFailed > 0)
|
||||
<span class="ml-2 px-2 py-1 bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 text-xs rounded"
|
||||
title="{{ $totalFailed }} user(s) reported download failure">
|
||||
<i class="fa fa-exclamation-triangle mr-1"></i>Failed
|
||||
</span>
|
||||
@endif
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
@if(!empty($result->genre))
|
||||
<span class="mr-3">
|
||||
<i class="fa fa-tag mr-1"></i>
|
||||
{!! makeFieldLinks((array) $result, 'genre', 'xxx') !!}
|
||||
</span>
|
||||
@endif
|
||||
@if(!empty($result->actors))
|
||||
<span class="mr-3">
|
||||
<i class="fa fa-users mr-1"></i>
|
||||
{!! makeFieldLinks((array) $result, 'actors', 'xxx') !!}
|
||||
</span>
|
||||
@endif
|
||||
@if(!empty($result->director))
|
||||
<span>
|
||||
<i class="fa fa-user-circle mr-1"></i>
|
||||
{!! makeFieldLinks((array) $result, 'director', 'xxx') !!}
|
||||
</span>
|
||||
@endif
|
||||
<!-- XXX Grid - Card Layout with Multiple Releases -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
@foreach($results as $result)
|
||||
@php
|
||||
// Extract grouped release data
|
||||
$releaseGuids = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid) : [];
|
||||
$releaseNames = isset($result->grp_release_name) ? explode('#', $result->grp_release_name) : [];
|
||||
$releaseSizes = isset($result->grp_release_size) ? explode(',', $result->grp_release_size) : [];
|
||||
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
|
||||
$releaseGrabs = isset($result->grp_release_grabs) ? explode(',', $result->grp_release_grabs) : [];
|
||||
$releaseComments = isset($result->grp_release_comments) ? explode(',', $result->grp_release_comments) : [];
|
||||
$releaseNfoIds = isset($result->grp_release_nfoid) ? explode(',', $result->grp_release_nfoid) : [];
|
||||
$releaseHasPreview = isset($result->grp_haspreview) ? explode(',', $result->grp_haspreview) : [];
|
||||
$releaseCategories = isset($result->grp_release_catname) ? explode(',', $result->grp_release_catname) : [];
|
||||
$failedCounts = isset($result->grp_release_failed) ? array_filter(explode(',', $result->grp_release_failed)) : [];
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
|
||||
// Limit to maximum 2 releases displayed
|
||||
$maxReleases = 2;
|
||||
$totalReleases = count($releaseGuids);
|
||||
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
|
||||
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
|
||||
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
|
||||
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
|
||||
$releaseGrabs = array_slice($releaseGrabs, 0, $maxReleases);
|
||||
$releaseComments = array_slice($releaseComments, 0, $maxReleases);
|
||||
$releaseNfoIds = array_slice($releaseNfoIds, 0, $maxReleases);
|
||||
$releaseHasPreview = array_slice($releaseHasPreview, 0, $maxReleases);
|
||||
$releaseCategories = array_slice($releaseCategories, 0, $maxReleases);
|
||||
|
||||
$guid = $releaseGuids[0] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden hover:shadow-lg transition-shadow">
|
||||
<div class="flex flex-row">
|
||||
<!-- Cover Image -->
|
||||
<div class="flex-shrink-0">
|
||||
@if($guid)
|
||||
<a href="{{ url('/details/' . $guid) }}" class="block">
|
||||
@if(isset($result->cover) && $result->cover == 1)
|
||||
<img src="{{ url('/covers/xxx/' . $result->id . '-cover.jpg') }}"
|
||||
alt="{{ $result->title }}"
|
||||
class="w-32 h-48 object-cover"
|
||||
onerror="this.onerror=null;this.src='{{ url('/images/no-cover.png') }}';">
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-film text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<div class="w-32 h-48 bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
|
||||
<i class="fas fa-film text-gray-400 text-2xl"></i>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Content Details -->
|
||||
<div class="flex-1 p-4">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ $result->title }}</h3>
|
||||
|
||||
@if($totalFailed > 0)
|
||||
<div class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-red-100 text-red-800 border border-red-200 mt-1">
|
||||
<i class="fas fa-exclamation-triangle mr-1"></i>
|
||||
<span>{{ $totalFailed }} failed report{{ $totalFailed > 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="text-xs text-gray-600 dark:text-gray-400 mt-2 space-y-1">
|
||||
@if(!empty($result->genre))
|
||||
<div>
|
||||
<strong>Genre:</strong> {!! makeFieldLinks((array) $result, 'genre', 'xxx') !!}
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($result->actors))
|
||||
<div>
|
||||
<strong>Actors:</strong> {!! makeFieldLinks((array) $result, 'actors', 'xxx') !!}
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($result->director))
|
||||
<div>
|
||||
<strong>Director:</strong> {!! makeFieldLinks((array) $result, 'director', 'xxx') !!}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if(isset($result->plot) && $result->plot)
|
||||
<p class="text-gray-700 dark:text-gray-300 text-sm mt-2 line-clamp-2">{{ $result->plot }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Release Information -->
|
||||
@if(!empty($releaseGuids[0]))
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
|
||||
Available Releases
|
||||
@if($totalReleases > $maxReleases)
|
||||
<span class="text-xs font-normal text-gray-500">(Showing {{ $maxReleases }} of {{ $totalReleases }})</span>
|
||||
@endif
|
||||
</h4>
|
||||
<div class="space-y-2">
|
||||
@foreach($releaseNames as $index => $releaseName)
|
||||
@if($releaseName && isset($releaseGuids[$index]))
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-2 border border-gray-200 dark:border-gray-700">
|
||||
<div class="space-y-2">
|
||||
<!-- Release Name -->
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="text-sm text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 font-medium block break-all" title="{{ $releaseName }}">
|
||||
{{ $releaseName }}
|
||||
</a>
|
||||
|
||||
<!-- Info Badges -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
@if(isset($releaseSizes[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSizes[$index] / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releasePostDates[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ date('M d, Y H:i', strtotime($releasePostDates[$index])) }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseCategories[$index]) && !empty($releaseCategories[$index]))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-folder mr-1"></i>{{ $releaseCategories[$index] }}
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseGrabs[$index]) && $releaseGrabs[$index] > 0)
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200">
|
||||
<i class="fas fa-download mr-1"></i>{{ $releaseGrabs[$index] }} grabs
|
||||
</span>
|
||||
@endif
|
||||
@if(isset($releaseNfoIds[$index]) && !empty($releaseNfoIds[$index]))
|
||||
<button type="button"
|
||||
class="nfo-badge inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 hover:bg-yellow-200 dark:hover:bg-yellow-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuids[$index] }}"
|
||||
title="View NFO file">
|
||||
<i class="fas fa-file-alt mr-1"></i> NFO
|
||||
</button>
|
||||
@endif
|
||||
@if(isset($releaseHasPreview[$index]) && $releaseHasPreview[$index] == 1)
|
||||
<button type="button"
|
||||
class="preview-badge inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 hover:bg-purple-200 dark:hover:bg-purple-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuids[$index] }}"
|
||||
title="View preview image">
|
||||
<i class="fas fa-image mr-1"></i> Preview
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<a href="{{ url('/getnzb/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-600 dark:bg-green-700 text-white hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-1"></i> Download
|
||||
</a>
|
||||
<button class="add-to-cart inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-600 dark:bg-blue-700 text-white hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $releaseGuids[$index] }}">
|
||||
<i class="fas fa-shopping-cart mr-1"></i> Cart
|
||||
</button>
|
||||
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-800 transition">
|
||||
<i class="fas fa-info-circle mr-1"></i> Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-gray-600 dark:text-gray-400 hidden md:table-cell">
|
||||
@php
|
||||
$categoryName = isset($result->grp_release_catname) ? explode(',', $result->grp_release_catname)[0] : 'XXX';
|
||||
@endphp
|
||||
{{ $categoryName }}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-gray-600 dark:text-gray-400 hidden lg:table-cell whitespace-nowrap">
|
||||
@if($postdate)
|
||||
{{ date('M d, Y', strtotime($postdate)) }}
|
||||
<div class="text-xs text-gray-500">{{ date('H:i', strtotime($postdate)) }}</div>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-gray-600 dark:text-gray-400 hidden xl:table-cell whitespace-nowrap">
|
||||
{{ number_format($size / 1073741824, 2) }} GB
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<a href="{{ url('/getnzb?id=' . $guid) }}"
|
||||
class="inline-flex items-center px-3 py-1.5 bg-green-600 dark:bg-green-700 text-white text-xs rounded hover:bg-green-700 dark:hover:bg-green-800"
|
||||
title="Download NZB">
|
||||
<i class="fa fa-download mr-1"></i>
|
||||
<span class="hidden sm:inline">Download</span>
|
||||
</a>
|
||||
<a href="{{ url('/details/' . $guid) }}"
|
||||
class="inline-flex items-center px-3 py-1.5 bg-blue-600 dark:bg-blue-700 text-white text-xs rounded hover:bg-blue-700 dark:hover:bg-blue-800"
|
||||
title="View Details">
|
||||
<i class="fa fa-info-circle mr-1"></i>
|
||||
<span class="hidden sm:inline">Details</span>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
@@ -208,5 +298,24 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NFO Modal -->
|
||||
@include('partials.nfo-modal')
|
||||
|
||||
<!-- Preview Modal -->
|
||||
<div id="previewModal" class="hidden fixed inset-0 bg-black bg-opacity-75 items-center justify-center p-4 z-50">
|
||||
<div class="relative max-w-4xl w-full">
|
||||
<button type="button" data-close-preview-modal class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<div class="text-center mb-2">
|
||||
<h3 id="previewTitle" class="text-white text-lg font-semibold"></h3>
|
||||
</div>
|
||||
<img id="previewImage" src="" alt="Preview" class="max-w-full max-h-[90vh] mx-auto rounded-lg shadow-2xl">
|
||||
<div class="text-center mt-4">
|
||||
<p id="previewError" class="text-red-400 hidden"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
Reference in New Issue
Block a user