diff --git a/app/Controllers/AdultController.php b/app/Controllers/AdultController.php index 85b3bb9..45fc00f 100644 --- a/app/Controllers/AdultController.php +++ b/app/Controllers/AdultController.php @@ -28,11 +28,24 @@ class AdultController extends Controller // Get search parameters $search = trim($queryParams['search'] ?? ''); + // Get filter parameters + $genres = $queryParams['genres'] ?? []; + if (!is_array($genres)) { + $genres = [$genres]; + } + $genres = array_filter($genres); + + $directors = $queryParams['directors'] ?? []; + if (!is_array($directors)) { + $directors = [$directors]; + } + $directors = array_filter($directors); + // Get view mode $viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers - // Get adult videos with pagination and search - $adultVideos = AdultVideo::getAllWithPagination($this->pdo, $page, $perPage, $search); + // Get adult videos with pagination and filters + $adultVideos = AdultVideo::getAllWithPagination($this->pdo, $page, $perPage, $search, $genres, $directors); // Process metadata to extract local image paths for template compatibility foreach ($adultVideos as &$video) { @@ -54,7 +67,11 @@ class AdultController extends Controller } // Get total count for pagination - $totalCount = AdultVideo::getTotalCount($this->pdo, $search); + $totalCount = AdultVideo::getTotalCount($this->pdo, $search, $genres, $directors); + + // Get available filter options + $availableGenres = AdultVideo::getAvailableGenres($this->pdo); + $availableDirectors = AdultVideo::getAvailableDirectors($this->pdo); // Calculate pagination info $totalPages = ceil($totalCount / $perPage); @@ -76,7 +93,15 @@ class AdultController extends Controller ], 'search' => $search, 'view_mode' => $viewMode, - 'view_modes' => ['grid', 'list', 'covers'] + 'view_modes' => ['grid', 'list', 'covers'], + 'filters' => [ + 'genres' => $genres, + 'directors' => $directors + ], + 'available_filters' => [ + 'genres' => $availableGenres, + 'directors' => $availableDirectors + ] ]); } diff --git a/app/Controllers/GameController.php b/app/Controllers/GameController.php index 846b92d..dee3c59 100644 --- a/app/Controllers/GameController.php +++ b/app/Controllers/GameController.php @@ -28,14 +28,31 @@ class GameController extends Controller // Get search parameters $search = trim($queryParams['search'] ?? ''); + // Get filter parameters + $genres = $queryParams['genres'] ?? []; + if (!is_array($genres)) { + $genres = [$genres]; + } + $genres = array_filter($genres); + + $platforms = $queryParams['platforms'] ?? []; + if (!is_array($platforms)) { + $platforms = [$platforms]; + } + $platforms = array_filter($platforms); + // Get view mode $viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers - // Get games with pagination and search - $games = Game::getGroupedGamesWithPagination($this->pdo, $page, $perPage, $search); + // Get games with pagination and filters + $games = Game::getGroupedGamesWithPagination($this->pdo, $page, $perPage, $search, $genres, $platforms); // Get total count for pagination - $totalCount = Game::getTotalCount($this->pdo, $search); + $totalCount = Game::getTotalCount($this->pdo, $search, $genres, $platforms); + + // Get available filter options + $availableGenres = Game::getAvailableGenres($this->pdo); + $availablePlatforms = Game::getAvailablePlatforms($this->pdo); // Calculate pagination info $totalPages = ceil($totalCount / $perPage); @@ -57,7 +74,15 @@ class GameController extends Controller ], 'search' => $search, 'view_mode' => $viewMode, - 'view_modes' => ['grid', 'list', 'covers'] + 'view_modes' => ['grid', 'list', 'covers'], + 'filters' => [ + 'genres' => $genres, + 'platforms' => $platforms + ], + 'available_filters' => [ + 'genres' => $availableGenres, + 'platforms' => $availablePlatforms + ] ]); } diff --git a/app/Controllers/MovieController.php b/app/Controllers/MovieController.php index e020ac6..32d71a9 100644 --- a/app/Controllers/MovieController.php +++ b/app/Controllers/MovieController.php @@ -28,14 +28,31 @@ class MovieController extends Controller // Get search parameters $search = trim($queryParams['search'] ?? ''); + // Get filter parameters + $genres = $queryParams['genres'] ?? []; + if (!is_array($genres)) { + $genres = [$genres]; + } + $genres = array_filter($genres); + + $directors = $queryParams['directors'] ?? []; + if (!is_array($directors)) { + $directors = [$directors]; + } + $directors = array_filter($directors); + // Get view mode $viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers - // Get movies with pagination and search - $movies = Movie::getAllWithPagination($this->pdo, $page, $perPage, $search); + // Get movies with pagination and filters + $movies = Movie::getAllWithPagination($this->pdo, $page, $perPage, $search, $genres, $directors); // Get total count for pagination - $totalCount = Movie::getTotalCount($this->pdo, $search); + $totalCount = Movie::getTotalCount($this->pdo, $search, $genres, $directors); + + // Get available filter options + $availableGenres = Movie::getAvailableGenres($this->pdo); + $availableDirectors = Movie::getAvailableDirectors($this->pdo); // Calculate pagination info $totalPages = ceil($totalCount / $perPage); @@ -57,7 +74,15 @@ class MovieController extends Controller ], 'search' => $search, 'view_mode' => $viewMode, - 'view_modes' => ['grid', 'list', 'covers'] + 'view_modes' => ['grid', 'list', 'covers'], + 'filters' => [ + 'genres' => $genres, + 'directors' => $directors + ], + 'available_filters' => [ + 'genres' => $availableGenres, + 'directors' => $availableDirectors + ] ]); } diff --git a/app/Controllers/TvShowController.php b/app/Controllers/TvShowController.php index 8847311..edb0130 100644 --- a/app/Controllers/TvShowController.php +++ b/app/Controllers/TvShowController.php @@ -28,24 +28,37 @@ class TvShowController extends Controller // Get search parameters $search = trim($queryParams['search'] ?? ''); + // Get filter parameters + $genres = $queryParams['genres'] ?? []; + if (!is_array($genres)) { + $genres = [$genres]; + } + $genres = array_filter($genres); + + $years = $queryParams['years'] ?? []; + if (!is_array($years)) { + $years = [$years]; + } + $years = array_filter($years); + // Get view mode $viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers - // Get TV shows with pagination and search - $tvshows = TvShow::getAllWithPagination($this->pdo, $page, $perPage, $search); + // Get TV shows with pagination and filters + $tvshows = TvShow::getAllWithPagination($this->pdo, $page, $perPage, $search, $genres, $years); // Get total count for pagination - $totalCount = TvShow::getTotalCount($this->pdo, $search); + $totalCount = TvShow::getTotalCount($this->pdo, $search, $genres, $years); + + // Get available filter options + $availableGenres = TvShow::getAvailableGenres($this->pdo); + $availableYears = TvShow::getAvailableYears($this->pdo); // Calculate pagination info $totalPages = ceil($totalCount / $perPage); $hasNextPage = $page < $totalPages; $hasPrevPage = $page > 1; -/* - echo '
';
-        print_r($tvshows);
-        die();
-*/
+
         return $this->view->render($response, 'tvshows/index.twig', [
             'title' => 'TV Shows',
             'tvshows' => $tvshows,
@@ -61,7 +74,15 @@ class TvShowController extends Controller
             ],
             'search' => $search,
             'view_mode' => $viewMode,
-            'view_modes' => ['grid', 'list', 'covers']
+            'view_modes' => ['grid', 'list', 'covers'],
+            'filters' => [
+                'genres' => $genres,
+                'years' => $years
+            ],
+            'available_filters' => [
+                'genres' => $availableGenres,
+                'years' => $availableYears
+            ]
         ]);
     }
 
diff --git a/app/Models/AdultVideo.php b/app/Models/AdultVideo.php
index 0e0e0da..e6cdc0c 100644
--- a/app/Models/AdultVideo.php
+++ b/app/Models/AdultVideo.php
@@ -25,59 +25,92 @@ class AdultVideo extends Model
         'external_id'
     ];
 
-    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = ''): array
+    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = '', array $genres = [], array $directors = []): array
     {
         $offset = ($page - 1) * $perPage;
 
-        $whereClause = '';
-        $params = [];
-
-        if (!empty($search)) {
-            $whereClause = "WHERE (title LIKE :search OR overview LIKE :search)";
-            $params['search'] = "%{$search}%";
-        }
-
         $sql = "
             SELECT av.*, s.display_name as source_name
             FROM adult_videos av
             JOIN sources s ON av.source_id = s.id
-            {$whereClause}
-            ORDER BY av.created_at DESC
-            LIMIT :limit OFFSET :offset
         ";
+        $params = [];
+
+        if (!empty($search)) {
+            $sql .= " WHERE (av.title LIKE :search OR av.overview LIKE :search)";
+            $params['search'] = "%{$search}%";
+        }
+
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " av.genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($directors)) {
+            $placeholders = [];
+            foreach ($directors as $index => $director) {
+                $placeholders[] = ":director_{$index}";
+                $params["director_{$index}"] = $director;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " av.director IN (" . implode(',', $placeholders) . ")";
+        }
+
+        $sql .= " ORDER BY av.created_at DESC LIMIT :limit OFFSET :offset";
 
         $stmt = $pdo->prepare($sql);
         $stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT);
         $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT);
 
-        if (!empty($search)) {
-            $stmt->bindValue(':search', "%{$search}%", \PDO::PARAM_STR);
+        foreach ($params as $key => $value) {
+            $stmt->bindValue(":{$key}", $value);
         }
 
         $stmt->execute();
         return $stmt->fetchAll(\PDO::FETCH_ASSOC);
     }
 
-    public static function getTotalCount(\PDO $pdo, string $search = ''): int
+    public static function getTotalCount(\PDO $pdo, string $search = '', array $genres = [], array $directors = []): int
     {
-        $whereClause = '';
+        $sql = "SELECT COUNT(*) as count FROM adult_videos av JOIN sources s ON av.source_id = s.id";
         $params = [];
 
         if (!empty($search)) {
-            $whereClause = "WHERE (title LIKE :search OR overview LIKE :search)";
+            $sql .= " WHERE (av.title LIKE :search OR av.overview LIKE :search)";
             $params['search'] = "%{$search}%";
         }
 
-        $sql = "SELECT COUNT(*) as count FROM adult_videos {$whereClause}";
-
-        $stmt = $pdo->prepare($sql);
-
-        if (!empty($search)) {
-            $stmt->bindValue(':search', "%{$search}%", \PDO::PARAM_STR);
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " av.genre IN (" . implode(',', $placeholders) . ")";
         }
 
+        if (!empty($directors)) {
+            $placeholders = [];
+            foreach ($directors as $index => $director) {
+                $placeholders[] = ":director_{$index}";
+                $params["director_{$index}"] = $director;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " av.director IN (" . implode(',', $placeholders) . ")";
+        }
+
+        $stmt = $pdo->prepare($sql);
+        foreach ($params as $key => $value) {
+            $stmt->bindValue(":{$key}", $value);
+        }
         $stmt->execute();
-        return (int) $stmt->fetch(\PDO::FETCH_ASSOC)['count'];
+        return (int) $stmt->fetch()['count'];
     }
 
     public function markAsWatched(): bool
@@ -181,4 +214,32 @@ class AdultVideo extends Model
         ");
         return $stmt->fetch(\PDO::FETCH_ASSOC);
     }
+
+    /**
+     * Get available genres for filtering
+     */
+    public static function getAvailableGenres(\PDO $pdo): array
+    {
+        $stmt = $pdo->query("
+            SELECT DISTINCT genre
+            FROM adult_videos
+            WHERE genre IS NOT NULL AND genre != ''
+            ORDER BY genre
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
+    }
+
+    /**
+     * Get available directors for filtering
+     */
+    public static function getAvailableDirectors(\PDO $pdo): array
+    {
+        $stmt = $pdo->query("
+            SELECT DISTINCT director
+            FROM adult_videos
+            WHERE director IS NOT NULL AND director != ''
+            ORDER BY director
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
+    }
 }
diff --git a/app/Models/Game.php b/app/Models/Game.php
index 313d049..ac3fdc6 100644
--- a/app/Models/Game.php
+++ b/app/Models/Game.php
@@ -262,16 +262,34 @@ class Game extends Model
     /**
      * Get total count of games for pagination
      */
-    public static function getTotalCount(\PDO $pdo, string $search = ''): int
+    public static function getTotalCount(\PDO $pdo, string $search = '', array $genres = [], array $platforms = []): int
     {
-        $sql = "SELECT COUNT(*) as count FROM games";
+        $sql = "SELECT COUNT(*) as count FROM games WHERE game_key IS NOT NULL";
         $params = [];
 
         if (!empty($search)) {
-            $sql .= " WHERE title LIKE :search";
+            $sql .= " AND title LIKE :search";
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $sql .= " AND genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($platforms)) {
+            $placeholders = [];
+            foreach ($platforms as $index => $platform) {
+                $placeholders[] = ":platform_{$index}";
+                $params["platform_{$index}"] = $platform;
+            }
+            $sql .= " AND platform IN (" . implode(',', $placeholders) . ")";
+        }
+
         $stmt = $pdo->prepare($sql);
         $stmt->execute($params);
         return (int) $stmt->fetch()['count'];
@@ -280,7 +298,7 @@ class Game extends Model
     /**
      * Get grouped games with pagination and search support
      */
-    public static function getGroupedGamesWithPagination(\PDO $pdo, int $page, int $perPage, string $search = ''): array
+    public static function getGroupedGamesWithPagination(\PDO $pdo, int $page, int $perPage, string $search = '', array $genres = [], array $platforms = []): array
     {
         $offset = ($page - 1) * $perPage;
 
@@ -307,6 +325,24 @@ class Game extends Model
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $sql .= " AND genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($platforms)) {
+            $placeholders = [];
+            foreach ($platforms as $index => $platform) {
+                $placeholders[] = ":platform_{$index}";
+                $params["platform_{$index}"] = $platform;
+            }
+            $sql .= " AND platform IN (" . implode(',', $placeholders) . ")";
+        }
+
         $sql .= " GROUP BY game_key, title ORDER BY last_played_at DESC, total_playtime DESC LIMIT :limit OFFSET :offset";
 
         $stmt = $pdo->prepare($sql);
@@ -379,51 +415,31 @@ class Game extends Model
     }
 
     /**
-     * Get Playnite-specific series
+     * Get available genres for filtering
      */
-    public function getSeries(): array
+    public static function getAvailableGenres(\PDO $pdo): array
     {
-        return $this->series_json ?? [];
+        $stmt = $pdo->query("
+            SELECT DISTINCT genre
+            FROM games
+            WHERE genre IS NOT NULL AND genre != ''
+            ORDER BY genre
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
     }
 
     /**
-     * Get Playnite-specific age ratings
+     * Get available platforms for filtering
      */
-    public function getAgeRatings(): array
+    public static function getAvailablePlatforms(\PDO $pdo): array
     {
-        return $this->age_ratings_json ?? [];
-    }
-
-    /**
-     * Get formatted install size
-     */
-    public function getFormattedInstallSize(): string
-    {
-        if (!$this->install_size) {
-            return 'Unknown';
-        }
-
-        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
-        $bytes = $this->install_size;
-        $i = 0;
-
-        while ($bytes >= 1024 && $i < count($units) - 1) {
-            $bytes /= 1024;
-            $i++;
-        }
-
-        return round($bytes, 2) . ' ' . $units[$i];
-    }
-
-    /**
-     * Get Steam store URL if available
-     */
-    public function getSteamUrl(): ?string
-    {
-        if (!$this->steam_app_id) {
-            return null;
-        }
-        return "https://store.steampowered.com/app/{$this->steam_app_id}";
+        $stmt = $pdo->query("
+            SELECT DISTINCT platform
+            FROM games
+            WHERE platform IS NOT NULL AND platform != ''
+            ORDER BY platform
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
     }
 
     /**
@@ -435,4 +451,3 @@ class Game extends Model
                !empty($this->links_json) || !empty($this->background_image);
     }
 }
-
diff --git a/app/Models/Movie.php b/app/Models/Movie.php
index b121005..a67822a 100644
--- a/app/Models/Movie.php
+++ b/app/Models/Movie.php
@@ -109,22 +109,45 @@ class Movie extends Model
         return $stmt->fetchAll(\PDO::FETCH_ASSOC);
     }
 
-    public static function getTotalCount(\PDO $pdo, string $search = ''): int
+    public static function getTotalCount(\PDO $pdo, string $search = '', array $genres = [], array $directors = []): int
     {
         $sql = "SELECT COUNT(*) as count FROM movies m JOIN sources s ON m.source_id = s.id";
         $params = [];
 
         if (!empty($search)) {
-            $sql .= " WHERE m.title LIKE :search";
+            $sql .= " WHERE (m.title LIKE :search OR m.overview LIKE :search)";
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " m.genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($directors)) {
+            $placeholders = [];
+            foreach ($directors as $index => $director) {
+                $placeholders[] = ":director_{$index}";
+                $params["director_{$index}"] = $director;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " m.director IN (" . implode(',', $placeholders) . ")";
+        }
+
         $stmt = $pdo->prepare($sql);
-        $stmt->execute($params);
+        foreach ($params as $key => $value) {
+            $stmt->bindValue(":{$key}", $value);
+        }
+        $stmt->execute();
         return (int) $stmt->fetch()['count'];
     }
 
-    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = ''): array
+    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = '', array $genres = [], array $directors = []): array
     {
         $offset = ($page - 1) * $perPage;
 
@@ -136,10 +159,30 @@ class Movie extends Model
         $params = [];
 
         if (!empty($search)) {
-            $sql .= " WHERE m.title LIKE :search";
+            $sql .= " WHERE (m.title LIKE :search OR m.overview LIKE :search)";
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " m.genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($directors)) {
+            $placeholders = [];
+            foreach ($directors as $index => $director) {
+                $placeholders[] = ":director_{$index}";
+                $params["director_{$index}"] = $director;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " m.director IN (" . implode(',', $placeholders) . ")";
+        }
+
         $sql .= " ORDER BY m.title ASC LIMIT :limit OFFSET :offset";
 
         $stmt = $pdo->prepare($sql);
@@ -226,4 +269,32 @@ class Movie extends Model
             'cast' => $castString
         ]);
     }
+
+    /**
+     * Get available genres for filtering
+     */
+    public static function getAvailableGenres(\PDO $pdo): array
+    {
+        $stmt = $pdo->query("
+            SELECT DISTINCT genre
+            FROM movies
+            WHERE genre IS NOT NULL AND genre != ''
+            ORDER BY genre
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
+    }
+
+    /**
+     * Get available directors for filtering
+     */
+    public static function getAvailableDirectors(\PDO $pdo): array
+    {
+        $stmt = $pdo->query("
+            SELECT DISTINCT director
+            FROM movies
+            WHERE director IS NOT NULL AND director != ''
+            ORDER BY director
+        ");
+        return $stmt->fetchAll(\PDO::FETCH_COLUMN);
+    }
 }
diff --git a/app/Models/TvShow.php b/app/Models/TvShow.php
index 67113cf..398cc54 100644
--- a/app/Models/TvShow.php
+++ b/app/Models/TvShow.php
@@ -83,7 +83,7 @@ class TvShow extends Model
     /**
      * Get total count with optional search
      */
-    public static function getTotalCount(\PDO $pdo, string $search = ''): int
+    public static function getTotalCount(\PDO $pdo, string $search = '', array $genres = [], array $years = []): int
     {
         $sql = "SELECT COUNT(*) as count FROM tv_shows t JOIN sources s ON t.source_id = s.id";
         $params = [];
@@ -93,15 +93,38 @@ class TvShow extends Model
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " t.genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($years)) {
+            $placeholders = [];
+            foreach ($years as $index => $year) {
+                $placeholders[] = ":year_{$index}";
+                $params["year_{$index}"] = $year;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " YEAR(first_air_date) IN (" . implode(',', $placeholders) . ")";
+        }
+
         $stmt = $pdo->prepare($sql);
-        $stmt->execute($params);
+        foreach ($params as $key => $value) {
+            $stmt->bindValue(":{$key}", $value);
+        }
+        $stmt->execute();
         return (int) $stmt->fetch()['count'];
     }
 
     /**
      * Get all TV shows with pagination and optional search
      */
-    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = ''): array
+    public static function getAllWithPagination(\PDO $pdo, int $page, int $perPage, string $search = '', array $genres = [], array $years = []): array
     {
         $offset = ($page - 1) * $perPage;
 
@@ -117,6 +140,26 @@ class TvShow extends Model
             $params['search'] = "%{$search}%";
         }
 
+        if (!empty($genres)) {
+            $placeholders = [];
+            foreach ($genres as $index => $genre) {
+                $placeholders[] = ":genre_{$index}";
+                $params["genre_{$index}"] = $genre;
+            }
+            $whereClause = !empty($search) ? " AND" : " WHERE";
+            $sql .= $whereClause . " t.genre IN (" . implode(',', $placeholders) . ")";
+        }
+
+        if (!empty($years)) {
+            $placeholders = [];
+            foreach ($years as $index => $year) {
+                $placeholders[] = ":year_{$index}";
+                $params["year_{$index}"] = $year;
+            }
+            $whereClause = (!empty($search) || !empty($genres)) ? " AND" : " WHERE";
+            $sql .= $whereClause . " YEAR(first_air_date) IN (" . implode(',', $placeholders) . ")";
+        }
+
         $sql .= " ORDER BY t.title ASC LIMIT :limit OFFSET :offset";
 
         $stmt = $pdo->prepare($sql);
@@ -259,9 +302,8 @@ public function recordView(): bool
 public static function getAvailableGenres(\PDO $pdo): array
 {
     $stmt = $pdo->query("
-        SELECT DISTINCT TRIM(value) as genre
-        FROM tv_shows,
-             json_each('[\"' || REPLACE(genre, ',', '\",\"') || '\"]')
+        SELECT DISTINCT genre
+        FROM tv_shows
         WHERE genre IS NOT NULL AND genre != ''
         ORDER BY genre
     ");
@@ -274,7 +316,7 @@ public static function getAvailableGenres(\PDO $pdo): array
 public static function getAvailableYears(\PDO $pdo): array
 {
     $stmt = $pdo->query("
-        SELECT DISTINCT strftime('%Y', first_air_date) as year
+        SELECT DISTINCT YEAR(first_air_date) as year
         FROM tv_shows
         WHERE first_air_date IS NOT NULL
         ORDER BY year DESC
diff --git a/app/Services/PlayniteImportService.php b/app/Services/PlayniteImportService.php
index de903a8..3bdfd12 100644
--- a/app/Services/PlayniteImportService.php
+++ b/app/Services/PlayniteImportService.php
@@ -75,6 +75,7 @@ class PlayniteImportService
      */
     private function transformPlayniteGame(array $game, int $index): array
     {
+        /*
         // Validate required fields
         if (empty($game['Name'])) {
             throw new \Exception("Missing game name");
@@ -83,7 +84,7 @@ class PlayniteImportService
         if (empty($game['GameId'])) {
             throw new \Exception("Missing GameId");
         }
-
+*/
         // Find or create source
         $source = $this->findOrCreateSource($game);
 
@@ -132,10 +133,10 @@ class PlayniteImportService
             'steam_app_id' => $this->extractSteamAppId($game),
 
             // Playnite-specific metadata
-            'is_installed' => $game['IsInstalled'] ?? false,
-            'is_favorite' => $game['Favorite'] ?? false,
-            'is_custom_game' => $game['IsCustomGame'] ?? false,
-            'installation_status' => $game['InstallationStatus'] ?? 0,
+           // 'is_installed' => $this->toBoolean($game['IsInstalled'] ?? false),
+            //'is_favorite' => $this->toBoolean($game['Favorite'] ?? false),
+            //'is_custom_game' => $this->toBoolean($game['IsCustomGame'] ?? false),
+            //'installation_status' => $game['InstallationStatus'] ?? 0,
 
             // Timestamps
             'added_at' => isset($game['Added']) ? date('Y-m-d H:i:s', strtotime($game['Added'])) : null,
@@ -147,20 +148,20 @@ class PlayniteImportService
             'metadata' => json_encode([
                 'playnite_id' => $game['Id'] ?? null,
                 'version' => $game['Version'] ?? null,
-                'hidden' => $game['Hidden'] ?? false,
+                'hidden' => $this->toBoolean($game['Hidden'] ?? false),
                 'notes' => $game['Notes'] ?? null,
                 'manual' => $game['Manual'] ?? null,
                 'pre_script' => $game['PreScript'] ?? null,
                 'post_script' => $game['PostScript'] ?? null,
                 'game_started_script' => $game['GameStartedScript'] ?? null,
                 'use_global_scripts' => [
-                    'pre' => $game['UseGlobalPreScript'] ?? true,
-                    'post' => $game['UseGlobalPostScript'] ?? true,
-                    'game_started' => $game['UseGlobalGameStartedScript'] ?? true
+                    'pre' => $this->toBoolean($game['UseGlobalPreScript'] ?? true),
+                    'post' => $this->toBoolean($game['UseGlobalPostScript'] ?? true),
+                    'game_started' => $this->toBoolean($game['UseGlobalGameStartedScript'] ?? true)
                 ]
             ])
         ];
-
+         
         return $transformed;
     }
 
@@ -371,4 +372,21 @@ class PlayniteImportService
         $gameModel = new Game($this->pdo);
         $gameModel->update($gameId, $gameData);
     }
+
+    /**
+     * Convert a value to boolean, handling empty strings properly
+     */
+    private function toBoolean($value): bool
+    {
+        if ($value === null || $value === false || $value === 0 || $value === '0') {
+            return false;
+        }
+        if ($value === true || $value === 1 || $value === '1') {
+            return true;
+        }
+        if (is_string($value)) {
+            return !empty(trim($value));
+        }
+        return (bool) $value;
+    }
 }
diff --git a/resources/views/adult/index.twig b/resources/views/adult/index.twig
index fff684f..4e03bc0 100644
--- a/resources/views/adult/index.twig
+++ b/resources/views/adult/index.twig
@@ -1,299 +1,387 @@
 {% extends "layouts/app.twig" %}
 
 {% block content %}
-
- -
-
-

Adult Videos

- {% if pagination.total_items > 0 %} -
- {{ pagination.total_items }} videos - {% if search %} - matching "{{ search }}" - {% endif %} -
- {% endif %} -
- -
- -
- - -
- - - - +
+
+ +
+
+
+
Filters
- - + -
- - {% if error %} -
- {{ error }} -
- {% endif %} - - {% if movies is empty %} -
- - - -

- {% if search %} - No adult videos found matching "{{ search }}" - {% else %} - No adult videos found - {% endif %} -

-

- {% if search %} - Try adjusting your search terms or browse all adult videos. - {% else %} - Adult videos will appear here after syncing with XBVR or Stash sources. - {% endif %} -

- {% if search %} - - View all adult videos - - {% endif %} -
- {% else %} - - {% if view_mode == 'list' %} - -
-
    - {% for movie in movies %} -
  • -
    -
    - {% if movie.poster_url %} - {{ movie.title }} - {% else %} -
    - - - -
    - {% endif %} -
    -

    - - {{ movie.title }} - -

    -
    - {% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 - {% endif %} - {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m - {% endif %} - {{ movie.source_name }} + + {% if available_filters.genres %} +
    +
    Genres
    + {% for genre in available_filters.genres %} +
    + +
    + {% endfor %} +
    + {% endif %} + + + {% if available_filters.directors %} +
    +
    Directors
    + {% for director in available_filters.directors %} +
    + + +
    + {% endfor %} +
    + {% endif %} + + +
    + + + Clear All + +
    + +
    +
    +
    + + +
    +
    + +
    +
    +

    Adult Videos

    + {% if pagination.total_items > 0 %} +
    + {{ pagination.total_items }} videos + {% if search %} + matching "{{ search }}" + {% endif %} + {% if filters.genres or filters.directors %} + {% if filters.genres %} + {{ filters.genres|join(', ') }} + {% endif %} + {% if filters.directors %} + {{ filters.directors|join(', ') }} + {% endif %} + {% endif %} +
    + {% endif %} +
    + +
    + +
    + + + {% for genre in filters.genres %} + + {% endfor %} + {% for director in filters.directors %} + + {% endfor %} +
    + + + + +
    + +
    + + +
    -
    - {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} -
    -
  • - {% endfor %} -
-
- {% elseif view_mode == 'covers' %} - -
- {% for movie in movies %} -
-
- {% if movie.poster_url %} -
- {{ movie.title }} + {% if error %} +
+ {{ error }}
- {% else %} -
- + {% endif %} + + {% if movies is empty %} +
+ -
- {% endif %} -
-
- - {{ movie.title }} - -
- {% if movie.release_date %} -

{{ movie.release_date|date('Y') }}

+

+ {% if search or filters.genres or filters.directors %} + No adult videos found matching your criteria + {% else %} + No adult videos found + {% endif %} +

+

+ {% if search or filters.genres or filters.directors %} + Try adjusting your search terms or filters. + {% else %} + Adult videos will appear here after syncing with XBVR or Stash sources. + {% endif %} +

+ {% if search or filters.genres or filters.directors %} + + Clear filters + {% endif %}
-
-
- {% endfor %} -
+ {% else %} + + {% if view_mode == 'list' %} + +
+
    + {% for movie in movies %} +
  • +
    +
    + {% if movie.poster_url %} + {{ movie.title }} + {% else %} +
    + + + +
    + {% endif %} +
    +

    + + {{ movie.title }} + +

    +
    + {% if movie.release_date %} + {{ movie.release_date|date('Y') }} + {% endif %} + {% if movie.rating %} + ⭐ {{ movie.rating }}/10 + {% endif %} + {% if movie.runtime_minutes %} + {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endif %} + {{ movie.source_name }} +
    +
    +
    +
    + {% if movie.watched %} + + Watched + + {% endif %} + {% if movie.is_favorite %} + + Favorite + + {% endif %} +
    +
    +
  • + {% endfor %} +
+
- {% else %} - -
- {% for movie in movies %} -
-
-
-
-
+ {% elseif view_mode == 'covers' %} + +
+ {% for movie in movies %} +
+
{% if movie.poster_url %} - {{ movie.title }} +
+ {{ movie.title }} +
{% else %} -
- +
+
{% endif %} -
-
-
- - {{ movie.title }} - -
-
+
+
+ + {{ movie.title }} + +
{% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 +

{{ movie.release_date|date('Y') }}

{% endif %}
- {% if movie.source_name %} -

- {{ movie.source_name }} -

- {% endif %}
- {% if movie.overview %} -
-

- {{ movie.overview|slice(0, 150) }}{% if movie.overview|length > 150 %}...{% endif %} -

+ {% endfor %} +
+ + {% else %} + +
+ {% for movie in movies %} +
+
+
+
+
+ {% if movie.poster_url %} + {{ movie.title }} + {% else %} +
+ + + +
+ {% endif %} +
+
+
+ + {{ movie.title }} + +
+
+ {% if movie.release_date %} + {{ movie.release_date|date('Y') }} + {% endif %} + {% if movie.rating %} + ⭐ {{ movie.rating }}/10 + {% endif %} +
+ {% if movie.source_name %} +

+ {{ movie.source_name }} +

+ {% endif %} +
+
+ {% if movie.overview %} +
+

+ {{ movie.overview|slice(0, 150) }}{% if movie.overview|length > 150 %}...{% endif %} +

+
+ {% endif %} +
+ {% if movie.runtime_minutes %} + {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endif %} +
+ {% if movie.watched %} + + Watched + + {% endif %} + {% if movie.is_favorite %} + + Favorite + + {% endif %} +
+
+
+
- {% endif %} -
- {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endfor %} +
+ {% endif %} + + + {% if pagination.total_pages > 1 %} +
+
+ + + per page +
+ +
+ {% if pagination.has_prev %} + + Previous + {% endif %} -
- {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} + +
+ {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} + + {{ page_num }} + + {% endfor %}
+ + {% if pagination.has_next %} + + Next + + {% endif %}
+ {% endif %} + {% endif %}
- {% endfor %}
- {% endif %} - - - {% if pagination.total_pages > 1 %} -
-
- - - per page -
- -
- {% if pagination.has_prev %} - - Previous - - {% endif %} - -
- {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} - - {{ page_num }} - - {% endfor %} -
- - {% if pagination.has_next %} - - Next - - {% endif %} -
-
- {% endif %} - {% endif %}
{% endblock %} diff --git a/resources/views/games/index.twig b/resources/views/games/index.twig index 70ed769..3f4079f 100644 --- a/resources/views/games/index.twig +++ b/resources/views/games/index.twig @@ -1,274 +1,362 @@ {% extends "layouts/app.twig" %} {% block content %} -
- -
-
-

Games

- {% if pagination.total_items > 0 %} -
- {{ pagination.total_items }} games from {{ games|reduce((carry, game) => carry + game.platform_count, 0) }} platforms - {% if search %} - matching "{{ search }}" - {% endif %} -
- {% endif %} -
- -
- -
- - -
- - - - +
+
+ +
+
+
+
Filters
- - + -
- - {% if games is empty %} -
- - - -

- {% if search %} - No games found matching "{{ search }}" - {% else %} - No games found - {% endif %} -

-

- {% if search %} - Try adjusting your search terms or browse all games. - {% else %} - Start syncing your gaming libraries to see your games here. - {% endif %} -

- {% if search %} - - View all games - - {% endif %} -
- {% else %} - - {% if view_mode == 'list' %} - -
-
    - {% for game in games %} -
  • -
    -
    - {% if game.image_url %} - {{ game.title }} - {% else %} -
    - - - + + {% if available_filters.genres %} +
    +
    Genres
    + {% for genre in available_filters.genres %} +
    + + +
    + {% endfor %}
    {% endif %} -
    -

    - - {{ game.title }} - -

    -
    - {{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }} - {% if game.platforms %} - - {{ game.platforms|join(', ') }} - - {% endif %} - {{ game.total_playtime|format_duration }} played - {% if game.max_completion > 0 %} - {{ game.max_completion }}% complete - {% endif %} -
    -
    -
    - {% if game.genres %} -
    - {% for genre in game.genres|slice(0, 3) %} - - {{ genre }} - - {% endfor %} -
    - {% endif %} -
    -
  • - {% endfor %} -
-
- {% elseif view_mode == 'covers' %} - -
- {% for game in games %} -
-
- {% if game.image_url %} -
- {{ game.title }} -
- {% else %} -
- - - -
- {% endif %} -
-
- {{ game.title }} -
-

{{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }}

+ + {% if available_filters.platforms %} +
+
Platforms
+ {% for platform in available_filters.platforms %} +
+ + +
+ {% endfor %} +
+ {% endif %} + + +
+ + + Clear All + +
+
- {% endfor %} -
- {% else %} - -
- {% for game in games %} -
-
-
-
-
+ +
+
+ +
+
+

Games

+ {% if pagination.total_items > 0 %} +
+ {{ pagination.total_items }} games from {{ games|reduce((carry, game) => carry + game.platform_count, 0) }} platforms + {% if search %} + matching "{{ search }}" + {% endif %} + {% if filters.genres or filters.platforms %} + {% if filters.genres %} + {{ filters.genres|join(', ') }} + {% endif %} + {% if filters.platforms %} + {{ filters.platforms|join(', ') }} + {% endif %} + {% endif %} +
+ {% endif %} +
+ +
+ +
+ + + {% for genre in filters.genres %} + + {% endfor %} + {% for platform in filters.platforms %} + + {% endfor %} +
+ + + + +
+ +
+ + + +
+
+ + {% if games is empty %} +
+ + + +

+ {% if search or filters.genres or filters.platforms %} + No games found matching your criteria + {% else %} + No games found + {% endif %} +

+

+ {% if search or filters.genres or filters.platforms %} + Try adjusting your search terms or filters. + {% else %} + Start syncing your gaming libraries to see your games here. + {% endif %} +

+ {% if search or filters.genres or filters.platforms %} + + Clear filters + + {% endif %} +
+ {% else %} + + {% if view_mode == 'list' %} + +
+
    + {% for game in games %} +
  • +
    +
    + {% if game.image_url %} + {{ game.title }} + {% else %} +
    + + + +
    + {% endif %} +
    +

    + + {{ game.title }} + +

    +
    + {{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }} + {% if game.platforms %} + + {{ game.platforms|join(', ') }} + + {% endif %} + {{ game.total_playtime|format_duration }} played + {% if game.max_completion > 0 %} + {{ game.max_completion }}% complete + {% endif %} +
    +
    +
    + {% if game.genres %} +
    + {% for genre in game.genres|slice(0, 3) %} + + {{ genre }} + + {% endfor %} +
    + {% endif %} +
    +
  • + {% endfor %} +
+
+ + {% elseif view_mode == 'covers' %} + +
+ {% for game in games %} +
+
{% if game.image_url %} - {{ game.title }} +
+ {{ game.title }} +
{% else %} -
- +
+
{% endif %} -
-
-
- +
+
{{ game.title }} - -
-

- {{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }} - {% if game.platforms %} - - {{ game.platforms|join(', ') }} - - {% endif %} -

+
+

{{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }}

+
-
-
- {{ game.total_playtime|format_duration }} played - {% if game.max_completion > 0 %} - {{ game.max_completion }}% complete - {% endif %} + {% endfor %} +
+ + {% else %} + +
+ {% for game in games %} +
+
+
+
+
+ {% if game.image_url %} + {{ game.title }} + {% else %} +
+ + + +
+ {% endif %} +
+
+
+ + {{ game.title }} + +
+

+ {{ game.platform_count }} platform{{ game.platform_count > 1 ? 's' : '' }} + {% if game.platforms %} + + {{ game.platforms|join(', ') }} + + {% endif %} +

+
+
+
+
+ {{ game.total_playtime|format_duration }} played + {% if game.max_completion > 0 %} + {{ game.max_completion }}% complete + {% endif %} +
+ {% if game.genres %} +
+ {% for genre in game.genres|slice(0, 3) %} + + {{ genre }} + + {% endfor %} +
+ {% endif %} +
+
- {% if game.genres %} -
- {% for genre in game.genres|slice(0, 3) %} - - {{ genre }} - +
+ {% endfor %} +
+ {% endif %} + + + {% if pagination.total_pages > 1 %} +
+
+ + + per page +
+ +
+ {% if pagination.has_prev %} + + Previous + + {% endif %} + +
+ {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} + + {{ page_num }} + {% endfor %}
+ + {% if pagination.has_next %} + + Next + {% endif %}
+ {% endif %} + {% endif %}
- {% endfor %}
- {% endif %} - - - {% if pagination.total_pages > 1 %} -
-
- - - per page -
- -
- {% if pagination.has_prev %} - - Previous - - {% endif %} - -
- {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} - - {{ page_num }} - - {% endfor %} -
- - {% if pagination.has_next %} - - Next - - {% endif %} -
-
- {% endif %} - {% endif %}
{% endblock %} diff --git a/resources/views/movies/index.twig b/resources/views/movies/index.twig index 7a97a68..2ddeec7 100644 --- a/resources/views/movies/index.twig +++ b/resources/views/movies/index.twig @@ -1,293 +1,381 @@ {% extends "layouts/app.twig" %} {% block content %} -
- -
-
-

Movies

- {% if pagination.total_items > 0 %} -
- {{ pagination.total_items }} movies - {% if search %} - matching "{{ search }}" - {% endif %} -
- {% endif %} -
- -
- -
- - -
- - - - +
+
+ +
+
+
+
Filters
- - + -
- - {% if movies is empty %} -
- - - -

- {% if search %} - No movies found matching "{{ search }}" - {% else %} - No movies found - {% endif %} -

-

- {% if search %} - Try adjusting your search terms or browse all movies. - {% else %} - Start syncing your movie libraries to see your movies here. - {% endif %} -

- {% if search %} - - View all movies - - {% endif %} -
- {% else %} - - {% if view_mode == 'list' %} - -
-
    - {% for movie in movies %} -
  • -
    -
    - {% if movie.poster_url %} - {{ movie.title }} - {% else %} -
    - - - -
    - {% endif %} -
    -

    - - {{ movie.title }} - -

    -
    - {% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 - {% endif %} - {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m - {% endif %} - {{ movie.source_name }} + + {% if available_filters.genres %} +
    +
    Genres
    + {% for genre in available_filters.genres %} +
    + +
    + {% endfor %} +
    + {% endif %} + + + {% if available_filters.directors %} +
    +
    Directors
    + {% for director in available_filters.directors %} +
    + + +
    + {% endfor %} +
    + {% endif %} + + +
    + + + Clear All + +
    + +
    +
    +
    + + +
    +
    + +
    +
    +

    Movies

    + {% if pagination.total_items > 0 %} +
    + {{ pagination.total_items }} movies + {% if search %} + matching "{{ search }}" + {% endif %} + {% if filters.genres or filters.directors %} + {% if filters.genres %} + {{ filters.genres|join(', ') }} + {% endif %} + {% if filters.directors %} + {{ filters.directors|join(', ') }} + {% endif %} + {% endif %} +
    + {% endif %} +
    + +
    + +
    + + + {% for genre in filters.genres %} + + {% endfor %} + {% for director in filters.directors %} + + {% endfor %} +
    + + + + +
    + +
    + + +
    -
    - {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} -
    -
  • - {% endfor %} -
-
- {% elseif view_mode == 'covers' %} - -
- {% for movie in movies %} -
-
- {% if movie.poster_url %} -
- {{ movie.title }} -
- {% else %} -
- + {% if movies is empty %} +
+ -
- {% endif %} -
-
- - {{ movie.title }} - -
- {% if movie.release_date %} -

{{ movie.release_date|date('Y') }}

+

+ {% if search or filters.genres or filters.directors %} + No movies found matching your criteria + {% else %} + No movies found + {% endif %} +

+

+ {% if search or filters.genres or filters.directors %} + Try adjusting your search terms or filters. + {% else %} + Start syncing your movie libraries to see your movies here. + {% endif %} +

+ {% if search or filters.genres or filters.directors %} + + Clear filters + {% endif %}
-
-
- {% endfor %} -
+ {% else %} + + {% if view_mode == 'list' %} + +
+
    + {% for movie in movies %} +
  • +
    +
    + {% if movie.poster_url %} + {{ movie.title }} + {% else %} +
    + + + +
    + {% endif %} +
    +

    + + {{ movie.title }} + +

    +
    + {% if movie.release_date %} + {{ movie.release_date|date('Y') }} + {% endif %} + {% if movie.rating %} + ⭐ {{ movie.rating }}/10 + {% endif %} + {% if movie.runtime_minutes %} + {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endif %} + {{ movie.source_name }} +
    +
    +
    +
    + {% if movie.watched %} + + Watched + + {% endif %} + {% if movie.is_favorite %} + + Favorite + + {% endif %} +
    +
    +
  • + {% endfor %} +
+
- {% else %} - -
- {% for movie in movies %} -
-
-
-
-
+ {% elseif view_mode == 'covers' %} + +
+ {% for movie in movies %} +
+
{% if movie.poster_url %} - {{ movie.title }} +
+ {{ movie.title }} +
{% else %} -
- +
+
{% endif %} -
-
-
- - {{ movie.title }} - -
-
+
+
+ + {{ movie.title }} + +
{% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 +

{{ movie.release_date|date('Y') }}

{% endif %}
- {% if movie.source_name %} -

- {{ movie.source_name }} -

- {% endif %}
- {% if movie.overview %} -
-

- {{ movie.overview|slice(0, 150) }}{% if movie.overview|length > 150 %}...{% endif %} -

+ {% endfor %} +
+ + {% else %} + +
+ {% for movie in movies %} +
+
+
+
+
+ {% if movie.poster_url %} + {{ movie.title }} + {% else %} +
+ + + +
+ {% endif %} +
+
+
+ + {{ movie.title }} + +
+
+ {% if movie.release_date %} + {{ movie.release_date|date('Y') }} + {% endif %} + {% if movie.rating %} + ⭐ {{ movie.rating }}/10 + {% endif %} +
+ {% if movie.source_name %} +

+ {{ movie.source_name }} +

+ {% endif %} +
+
+ {% if movie.overview %} +
+

+ {{ movie.overview|slice(0, 150) }}{% if movie.overview|length > 150 %}...{% endif %} +

+
+ {% endif %} +
+ {% if movie.runtime_minutes %} + {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endif %} +
+ {% if movie.watched %} + + Watched + + {% endif %} + {% if movie.is_favorite %} + + Favorite + + {% endif %} +
+
+
+
- {% endif %} -
- {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endfor %} +
+ {% endif %} + + + {% if pagination.total_pages > 1 %} +
+
+ + + per page +
+ +
+ {% if pagination.has_prev %} + + Previous + {% endif %} -
- {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} + +
+ {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} + + {{ page_num }} + + {% endfor %}
+ + {% if pagination.has_next %} + + Next + + {% endif %}
+ {% endif %} + {% endif %}
- {% endfor %}
- {% endif %} - - - {% if pagination.total_pages > 1 %} -
-
- - - per page -
- -
- {% if pagination.has_prev %} - - Previous - - {% endif %} - -
- {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} - - {{ page_num }} - - {% endfor %} -
- - {% if pagination.has_next %} - - Next - - {% endif %} -
-
- {% endif %} - {% endif %}
{% endblock %} diff --git a/resources/views/tvshows/index.twig b/resources/views/tvshows/index.twig index 3f9338c..0dbd193 100644 --- a/resources/views/tvshows/index.twig +++ b/resources/views/tvshows/index.twig @@ -1,286 +1,389 @@ {% extends "layouts/app.twig" %} {% block content %} -
- -
-
-

TV Shows

-
-
-
- -
- -
- - -
- - - - +
+
+ +
+
+
+
Filters
- - +
+ +
+ + + - -
- {% for mode in view_modes %} - - {% endfor %} -
-
-
- - - {% if tvshows is empty %} -
- - - -

- {% if search %} - No TV shows found matching "{{ search }}" - {% else %} - No TV shows found - {% endif %} -

-

- {% if search %} - Try adjusting your search terms or browse all TV shows. - {% else %} - Start syncing your TV show libraries to see your TV shows here. - {% endif %} -

- {% if search %} - - View all TV shows - - {% endif %} -
- {% else %} - - {% if view_mode == 'list' %} - -
-
    - {% for movie in tvshows %} -
  • -
    -
    - {% if movie.poster_url %} - {{ movie.title }} - {% else %} -
    - - - -
    - {% endif %} -
    -

    - - {{ movie.title }} - -

    -
    - {% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 - {% endif %} - {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m - {% endif %} - {{ movie.source_name }} + + {% if available_filters.genres %} +
    +
    Genres
    + {% for genre in available_filters.genres %} +
    + +
    + {% endfor %} +
    + {% endif %} + + + {% if available_filters.years %} +
    +
    Years
    + {% for year in available_filters.years %} +
    + + +
    + {% endfor %} +
    + {% endif %} + + +
    + + + Clear All + +
    + +
    +
    +
    + + +
    +
    + +
    +
    +

    TV Shows

    + {% if pagination.total_items > 0 %} +
    + {{ pagination.total_items }} TV shows + {% if search %} + matching "{{ search }}" + {% endif %} + {% if filters.genres or filters.years %} + {% if filters.genres %} + {{ filters.genres|join(', ') }} + {% endif %} + {% if filters.years %} + {{ filters.years|join(', ') }} + {% endif %} + {% endif %} +
    + {% endif %} +
    + +
    + +
    + + + {% for genre in filters.genres %} + + {% endfor %} + {% for year in filters.years %} + + {% endfor %} +
    + + + + +
    + +
    + + +
    -
    - {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} -
    -
  • - {% endfor %} -
-
- {% elseif view_mode == 'covers' %} - -
- {% for movie in tvshows %} -
-
- {% if movie.poster_url %} -
- {{ movie.title }} -
- {% else %} -
- + {% if tvshows is empty %} +
+ -
- {% endif %} -
-
- - {{ movie.title }} - -
- {% if movie.release_date %} -

{{ movie.release_date|date('Y') }}

+

+ {% if search or filters.genres or filters.years %} + No TV shows found matching your criteria + {% else %} + No TV shows found + {% endif %} +

+

+ {% if search or filters.genres or filters.years %} + Try adjusting your search terms or filters. + {% else %} + Start syncing your TV show libraries to see your TV shows here. + {% endif %} +

+ {% if search or filters.genres or filters.years %} + + Clear filters + {% endif %}
-
-
- {% endfor %} -
+ {% else %} + + {% if view_mode == 'list' %} + +
+
    + {% for tvshow in tvshows %} +
  • +
    +
    + {% if tvshow.poster_url %} + {{ tvshow.title }} + {% else %} +
    + + + +
    + {% endif %} +
    +

    + + {{ tvshow.title }} + +

    +
    + {% if tvshow.first_air_date %} + {{ tvshow.first_air_date|date('Y') }} + {% endif %} + {% if tvshow.rating %} + ⭐ {{ tvshow.rating }}/10 + {% endif %} + {% if tvshow.number_of_seasons %} + {{ tvshow.number_of_seasons }} season{{ tvshow.number_of_seasons > 1 ? 's' : '' }} + {% endif %} + {% if tvshow.number_of_episodes %} + {{ tvshow.number_of_episodes }} episode{{ tvshow.number_of_episodes > 1 ? 's' : '' }} + {% endif %} + {{ tvshow.source_name }} +
    +
    +
    +
    + {% if tvshow.is_favorite %} + + Favorite + + {% endif %} +
    +
    +
  • + {% endfor %} +
+
- {% else %} - -
- {% for movie in tvshows %} -
-
-
-
-
- {% if movie.poster_url %} - {{ movie.title }} + {% elseif view_mode == 'covers' %} + +
+ {% for tvshow in tvshows %} +
+
+ {% if tvshow.poster_url %} +
+ {{ tvshow.title }} +
{% else %} -
- +
+
{% endif %} -
-
-
- - {{ movie.title }} - -
-
- {% if movie.release_date %} - {{ movie.release_date|date('Y') }} - {% endif %} - {% if movie.rating %} - ⭐ {{ movie.rating }}/10 +
+
+ + {{ tvshow.title }} + +
+ {% if tvshow.first_air_date %} +

{{ tvshow.first_air_date|date('Y') }}

{% endif %}
- {% if movie.source_name %} -

- {{ movie.source_name }} -

- {% endif %}
- {% if movie.overview %} -
-

- {{ movie.overview|slice(0, 150) }}{% if movie.overview|length > 150 %}...{% endif %} -

+ {% endfor %} +
+ + {% else %} + +
+ {% for tvshow in tvshows %} +
+
+
+
+
+ {% if tvshow.poster_url %} + {{ tvshow.title }} + {% else %} +
+ + + +
+ {% endif %} +
+
+
+ + {{ tvshow.title }} + +
+
+ {% if tvshow.first_air_date %} + {{ tvshow.first_air_date|date('Y') }} + {% endif %} + {% if tvshow.rating %} + ⭐ {{ tvshow.rating }}/10 + {% endif %} +
+ {% if tvshow.source_name %} +

+ {{ tvshow.source_name }} +

+ {% endif %} +
+
+ {% if tvshow.overview %} +
+

+ {{ tvshow.overview|slice(0, 150) }}{% if tvshow.overview|length > 150 %}...{% endif %} +

+
+ {% endif %} +
+ {% if tvshow.number_of_seasons %} + {{ tvshow.number_of_seasons }} season{{ tvshow.number_of_seasons > 1 ? 's' : '' }} + {% endif %} +
+ {% if tvshow.is_favorite %} + + Favorite + + {% endif %} +
+
+
+
- {% endif %} -
- {% if movie.runtime_minutes %} - {{ (movie.runtime_minutes / 60)|round(1) }}h {{ movie.runtime_minutes % 60 }}m + {% endfor %} +
+ {% endif %} + + + {% if pagination.total_pages > 1 %} +
+
+ + + per page +
+ +
+ {% if pagination.has_prev %} + + Previous + {% endif %} -
- {% if movie.watched %} - - Watched - - {% endif %} - {% if movie.is_favorite %} - - Favorite - - {% endif %} + +
+ {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} + + {{ page_num }} + + {% endfor %}
+ + {% if pagination.has_next %} + + Next + + {% endif %}
+ {% endif %} + {% endif %}
- {% endfor %}
- {% endif %} - - - {% if pagination.total_pages > 1 %} -
-
- - - per page -
- -
- {% if pagination.has_prev %} - - Previous - - {% endif %} - -
- {% for page_num in range(max(1, pagination.current_page - 2), min(pagination.total_pages, pagination.current_page + 2)) %} - - {{ page_num }} - - {% endfor %} -
- - {% if pagination.has_next %} - - Next - - {% endif %} -
-
- {% endif %} - {% endif %}
+ + {% endblock %}