├── LICENSE ├── README.md ├── components.json ├── env.zip ├── next-env.d.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── prettier.config.mjs ├── public ├── images │ ├── grey-thumbnail.jpg │ ├── hero.jpg │ ├── logo.png │ └── no-image.png ├── next.svg └── vercel.svg ├── src ├── app │ ├── (front) │ │ ├── home │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── movies │ │ │ ├── [slug] │ │ │ │ └── page.tsx │ │ │ └── page.tsx │ │ ├── new-and-popular │ │ │ └── page.tsx │ │ ├── page.tsx │ │ ├── search │ │ │ └── page.tsx │ │ └── tv-shows │ │ │ ├── [slug] │ │ │ └── page.tsx │ │ │ └── page.tsx │ ├── api │ │ └── trpc │ │ │ └── [trpc] │ │ │ └── route.ts │ ├── favicon.ico │ ├── layout.tsx │ └── watch │ │ ├── movie │ │ └── [slug] │ │ │ └── page.tsx │ │ └── tv │ │ └── [slug] │ │ └── page.tsx ├── assets │ └── fonts │ │ ├── CalSans-SemiBold.ttf │ │ ├── CalSans-SemiBold.woff │ │ ├── CalSans-SemiBold.woff2 │ │ ├── Inter-Bold.ttf │ │ └── Inter-Regular.ttf ├── client │ ├── trpc-provider.tsx │ └── trpc.ts ├── components │ ├── analytics.tsx │ ├── debounced-input.tsx │ ├── dynamic-tooltip.tsx │ ├── hero.tsx │ ├── icons.tsx │ ├── main │ │ ├── site-footer.tsx │ │ └── site-header.tsx │ ├── max-width-wrapper.tsx │ ├── navigation │ │ ├── main-nav.tsx │ │ └── mobile-nav.tsx │ ├── search-container.tsx │ ├── search-input.tsx │ ├── shows-carousel.tsx │ ├── shows-container.tsx │ ├── shows-grid.tsx │ ├── shows-modal.tsx │ ├── shows-skeleton.tsx │ ├── tailwind-indicator.tsx │ ├── theme-provider.tsx │ ├── theme-toggle.tsx │ ├── tmdb-image.tsx │ ├── ui │ │ ├── accordion.tsx │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── input.tsx │ │ ├── navigation-menu.tsx │ │ ├── skeleton.tsx │ │ └── tooltip.tsx │ └── watch │ │ └── embed-player.tsx ├── configs │ └── site.ts ├── enums │ ├── genre.ts │ └── request-type.ts ├── env.mjs ├── hooks │ ├── use-lock-body.ts │ ├── use-mounted.ts │ └── use-on-click-outside.ts ├── lib │ ├── apiClient.ts │ ├── constants.ts │ ├── stack.ts │ └── utils.ts ├── server │ ├── index.ts │ ├── routers │ │ └── hello.ts │ └── trpc.ts ├── services │ ├── BaseService │ │ ├── BaseService.ts │ │ └── index.ts │ └── MovieService │ │ ├── MovieService.ts │ │ ├── index.ts │ │ └── tmdbService.ts ├── stores │ ├── modal.ts │ └── search.ts ├── styles │ └── globals.css └── types │ └── index.ts ├── tailwind.config.ts └── tsconfig.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Bitfree 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CineGeek 2.0 Beta 2 | 3 | ![Next.js](https://img.shields.io/badge/Framework-Next.js-black) 4 | ![TypeScript](https://img.shields.io/badge/Language-TypeScript-blue) 5 | ![TailwindCSS](https://img.shields.io/badge/CSS-Tailwind-38bdf8) 6 | ![Vercel](https://img.shields.io/badge/Deploy-Vercel-black) 7 | ![TMDb](https://img.shields.io/badge/Data-TMDb-01b4e4) 8 | ![Vidsrc.to](https://img.shields.io/badge/Streaming-Vidsrc.to-purple) 9 | 10 | > **Developed by Alan Cyril Sunny** 11 | > If you find this project helpful, please consider ⭐ [starring the repository](https://github.com/dragonpilee/cinegeek)! 12 | 13 | --- 14 | 15 | ## 🎬 CineGeek 2.0 Beta 16 | 17 | A movie and series streaming website. 18 | 19 | --- 20 | 21 | ## ✨ Features 22 | 23 | - **Browse Movies**: Explore a vast collection of movies sorted by genre, release date, or popularity. 24 | - **Search Functionality**: Easily find movies by title, director, or cast. 25 | - **Recommendation Engine**: Get personalized movie recommendations based on your preferences and viewing history. 26 | - **Responsive Design**: Enjoy a seamless experience across devices with our responsive web design. 27 | 28 | --- 29 | 30 | ## 🛠️ Tech Stack 31 | 32 | - [Next.js](https://nextjs.org/) – framework 33 | - [TypeScript](https://www.typescriptlang.org/) – language 34 | - [Tailwind](https://tailwindcss.com/) – CSS 35 | - [Vercel](https://vercel.com/) – deployments 36 | - [TMDb](https://www.themoviedb.org/) – movie database 37 | - [Vidsrc.to](https://vidsrc.to/) – streaming links 38 | 39 | --- 40 | 41 | ## 💻 Local Development 42 | 43 | 1. **Clone the repository** 44 | ```bash 45 | git clone https://github.com/dragonpilee/cinegeek.git 46 | cd cinegeek 47 | ``` 48 | 2. **Install dependencies** 49 | ```bash 50 | npm install 51 | ``` 52 | 3. **Create `.env` file** 53 | ```bash 54 | cp .env.example .env 55 | ``` 56 | 4. **Start the development server** 57 | ```bash 58 | npm run dev 59 | ``` 60 | 61 | --- 62 | 63 | ## 🤝 Contributing 64 | 65 | Contributions are welcome! If you'd like to contribute to this project, please follow these steps: 66 | 67 | 1. **Fork the repository** 68 | 2. Create a new branch 69 | ```bash 70 | git checkout -b feature/improvement 71 | ``` 72 | 3. Make your changes. 73 | 4. Commit your changes 74 | ```bash 75 | git commit -am 'Add new feature' 76 | ``` 77 | 5. Push to the branch 78 | ```bash 79 | git push origin feature/improvement 80 | ``` 81 | 6. Create a new Pull Request. 82 | 83 | --- 84 | 85 | ## 📄 License 86 | 87 | This project is licensed under the [MIT License](LICENSE). 88 | 89 | --- 90 | 91 | ## 🙏 Acknowledgements 92 | 93 | - The Movie Database (TMDb) for providing the movie data through their API. 94 | - Vidsrc.to for providing the movie streaming links. 95 | 96 | --- 97 | 98 | For more information, updates, and documentation, visit the 99 | 👉 [GitHub Repository](https://github.com/dragonpilee/cinegeek) 100 | 101 | Feel free to fork, star ⭐, and contribute! 102 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /env.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/env.zip -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful 3 | * for Docker builds. 4 | */ 5 | await import("./src/env.mjs"); 6 | 7 | /** @type {import("next").NextConfig} */ 8 | const config = { 9 | reactStrictMode: true, 10 | 11 | /** 12 | * If you are using `appDir` then you must comment the below `i18n` config out. 13 | * 14 | * @see https://github.com/vercel/next.js/issues/41980 15 | */ 16 | i18n: { 17 | locales: ["en"], 18 | defaultLocale: "en", 19 | }, 20 | images: { 21 | unoptimized: true, 22 | domains: ["image.tmdb.org"], 23 | }, 24 | typescript: { 25 | ignoreBuildErrors: true, 26 | }, 27 | eslint: { 28 | ignoreDuringBuilds: true, 29 | }, 30 | swcMinify: true, 31 | }; 32 | 33 | export default config; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CineGeek", 3 | "version": "2.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint --cache", 10 | "format": "prettier --write .", 11 | "typecheck": "tsc --noEmit", 12 | "prepare": "husky install" 13 | }, 14 | "dependencies": { 15 | "@next/third-parties": "^14.1.0", 16 | "@radix-ui/react-accordion": "^1.1.2", 17 | "@radix-ui/react-dialog": "^1.0.5", 18 | "@radix-ui/react-dropdown-menu": "^2.0.6", 19 | "@radix-ui/react-navigation-menu": "^1.1.4", 20 | "@radix-ui/react-tooltip": "^1.0.7", 21 | "@t3-oss/env-nextjs": "^0.7.0", 22 | "@tanstack/react-query": "^4.35.7", 23 | "@tanstack/react-query-devtools": "^4.35.7", 24 | "@trpc/client": "^10.38.5", 25 | "@trpc/next": "^10.38.5", 26 | "@trpc/react-query": "^10.38.5", 27 | "@trpc/server": "^10.38.5", 28 | "@vercel/analytics": "^1.1.0", 29 | "@vercel/speed-insights": "^1.0.9", 30 | "axios": "^1.6.5", 31 | "class-variance-authority": "^0.7.0", 32 | "clsx": "^2.0.0", 33 | "framer-motion": "^10.12.4", 34 | "lucide-react": "^0.279.0", 35 | "next": "^14.1.0", 36 | "next-themes": "^0.2.1", 37 | "react": "^18.2.0", 38 | "react-dom": "^18.2.0", 39 | "react-youtube": "^10.1.0", 40 | "superjson": "^1.13.3", 41 | "tailwind-merge": "^1.14.0", 42 | "tailwindcss-animate": "^1.0.7", 43 | "zod": "^3.22.3", 44 | "zustand": "^4.4.6" 45 | }, 46 | "devDependencies": { 47 | "@types/eslint": "^8.44.2", 48 | "@types/node": "^20.6.2", 49 | "@types/react": "^18.2.21", 50 | "@types/react-dom": "^18.2.7", 51 | "@typescript-eslint/eslint-plugin": "^6.7.0", 52 | "@typescript-eslint/parser": "^6.7.0", 53 | "autoprefixer": "^10.4.15", 54 | "eslint": "^8.49.0", 55 | "eslint-config-next": "^14.1.0", 56 | "husky": "^8.0.0", 57 | "lint-staged": "^15.2.0", 58 | "postcss": "^8.4.29", 59 | "prettier": "^3.0.3", 60 | "prettier-plugin-tailwindcss": "^0.5.4", 61 | "tailwindcss": "^3.3.3", 62 | "typescript": "^5.2.2" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | 8 | module.exports = config; 9 | -------------------------------------------------------------------------------- /prettier.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').options} */ 2 | const config = { 3 | plugins: ['prettier-plugin-tailwindcss'], 4 | trailingComma: 'all', 5 | singleQuote: true, 6 | printWidth: 80, 7 | tabWidth: 2, 8 | bracketSameLine: true, 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /public/images/grey-thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/public/images/grey-thumbnail.jpg -------------------------------------------------------------------------------- /public/images/hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/public/images/hero.jpg -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/public/images/logo.png -------------------------------------------------------------------------------- /public/images/no-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/public/images/no-image.png -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/(front)/home/page.tsx: -------------------------------------------------------------------------------- 1 | import Hero from '@/components/hero'; 2 | import ShowsContainer from '@/components/shows-container'; 3 | import { MediaType } from '@/types'; 4 | import { siteConfig } from '@/configs/site'; 5 | import { RequestType, type ShowRequest } from '@/enums/request-type'; 6 | import MovieService from '@/services/MovieService'; 7 | import { Genre } from '@/enums/genre'; 8 | 9 | export const revalidate = 3600; 10 | 11 | export default async function Home() { 12 | const h1 = `${siteConfig.name} Home`; 13 | const requests: ShowRequest[] = [ 14 | { 15 | title: 'Trending Now', 16 | req: { requestType: RequestType.TRENDING, mediaType: MediaType.ALL }, 17 | visible: true, 18 | }, 19 | { 20 | title: 'Netflix TV Shows', 21 | req: { requestType: RequestType.NETFLIX, mediaType: MediaType.TV }, 22 | visible: true, 23 | }, 24 | { 25 | title: 'Popular TV Shows', 26 | req: { 27 | requestType: RequestType.TOP_RATED, 28 | mediaType: MediaType.TV, 29 | genre: Genre.TV_MOVIE, 30 | }, 31 | visible: true, 32 | }, 33 | { 34 | title: 'Korean Movies', 35 | req: { 36 | requestType: RequestType.KOREAN, 37 | mediaType: MediaType.MOVIE, 38 | genre: Genre.THRILLER, 39 | }, 40 | visible: true, 41 | }, 42 | { 43 | title: 'Comedy Movies', 44 | req: { 45 | requestType: RequestType.GENRE, 46 | mediaType: MediaType.MOVIE, 47 | genre: Genre.COMEDY, 48 | }, 49 | visible: true, 50 | }, 51 | { 52 | title: 'Action Movies', 53 | req: { 54 | requestType: RequestType.GENRE, 55 | mediaType: MediaType.MOVIE, 56 | genre: Genre.ACTION, 57 | }, 58 | visible: true, 59 | }, 60 | { 61 | title: 'Romance Movies', 62 | req: { 63 | requestType: RequestType.GENRE, 64 | mediaType: MediaType.MOVIE, 65 | genre: Genre.ROMANCE, 66 | }, 67 | visible: true, 68 | }, 69 | { 70 | title: 'Scary Movies', 71 | req: { 72 | requestType: RequestType.GENRE, 73 | mediaType: MediaType.MOVIE, 74 | genre: Genre.THRILLER, 75 | }, 76 | visible: true, 77 | }, 78 | ]; 79 | const allShows = await MovieService.getShows(requests); 80 | 81 | return ( 82 | <> 83 |

{h1}

84 | 85 | 86 | 87 | ); 88 | } 89 | -------------------------------------------------------------------------------- /src/app/(front)/layout.tsx: -------------------------------------------------------------------------------- 1 | import SiteFooter from '@/components/main/site-footer'; 2 | import SiteHeader from '@/components/main/site-header'; 3 | 4 | const FrontLayout = ({ children }: { children: React.ReactNode }) => { 5 | return ( 6 |
7 | 8 |
{children}
9 | 10 |
11 | ); 12 | }; 13 | 14 | export default FrontLayout; 15 | -------------------------------------------------------------------------------- /src/app/(front)/movies/[slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { type Metadata } from 'next'; 2 | import { handleMetadata } from '@/lib/utils'; 3 | import MoviePage from '../page'; 4 | 5 | type Props = { 6 | params: { slug: string }; 7 | searchParams: Record; 8 | }; 9 | 10 | export const revalidate = 3600; 11 | 12 | export async function generateMetadata({ params }: Props): Promise { 13 | return handleMetadata(params.slug, 'movies', 'movie'); 14 | } 15 | 16 | export default async function Home() { 17 | return MoviePage(); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/(front)/movies/page.tsx: -------------------------------------------------------------------------------- 1 | import Hero from '@/components/hero'; 2 | import ShowsContainer from '@/components/shows-container'; 3 | import { siteConfig } from '@/configs/site'; 4 | import { Genre } from '@/enums/genre'; 5 | import { RequestType, type ShowRequest } from '@/enums/request-type'; 6 | import MovieService from '@/services/MovieService'; 7 | import { MediaType } from '@/types'; 8 | 9 | export const revalidate = 3600; 10 | 11 | export default async function MoviePage() { 12 | const h1 = `${siteConfig.name} Movie`; 13 | const requests: ShowRequest[] = [ 14 | { 15 | title: 'Trending Now', 16 | req: { requestType: RequestType.TRENDING, mediaType: MediaType.MOVIE }, 17 | visible: true, 18 | }, 19 | { 20 | title: 'Netflix Movies', 21 | req: { requestType: RequestType.NETFLIX, mediaType: MediaType.MOVIE }, 22 | visible: true, 23 | }, 24 | { 25 | title: 'Popular', 26 | req: { requestType: RequestType.POPULAR, mediaType: MediaType.MOVIE }, 27 | visible: true, 28 | }, 29 | { 30 | title: 'Comedy Movies', 31 | req: { 32 | requestType: RequestType.GENRE, 33 | mediaType: MediaType.MOVIE, 34 | genre: Genre.COMEDY, 35 | }, 36 | visible: true, 37 | }, 38 | { 39 | title: 'Action Movies', 40 | req: { 41 | requestType: RequestType.GENRE, 42 | mediaType: MediaType.MOVIE, 43 | genre: Genre.ACTION, 44 | }, 45 | visible: true, 46 | }, 47 | { 48 | title: 'Romance Movies', 49 | req: { 50 | requestType: RequestType.GENRE, 51 | mediaType: MediaType.MOVIE, 52 | genre: Genre.ROMANCE, 53 | }, 54 | visible: true, 55 | }, 56 | { 57 | title: 'Scary Movies', 58 | req: { 59 | requestType: RequestType.GENRE, 60 | mediaType: MediaType.MOVIE, 61 | genre: Genre.THRILLER, 62 | }, 63 | visible: true, 64 | }, 65 | ]; 66 | const allShows = await MovieService.getShows(requests); 67 | 68 | return ( 69 | <> 70 |

{h1}

71 | 72 | 73 | 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /src/app/(front)/new-and-popular/page.tsx: -------------------------------------------------------------------------------- 1 | import Hero from '@/components/hero'; 2 | import ShowsContainer from '@/components/shows-container'; 3 | import { siteConfig } from '@/configs/site'; 4 | import { RequestType, type ShowRequest } from '@/enums/request-type'; 5 | import MovieService from '@/services/MovieService'; 6 | import { MediaType } from '@/types'; 7 | 8 | export const revalidate = 3600; 9 | 10 | export default async function NewAndPopularPage() { 11 | const h1 = `${siteConfig.name} New And Popular`; 12 | const requests: ShowRequest[] = [ 13 | { 14 | title: 'Netflix', 15 | req: { requestType: RequestType.NETFLIX, mediaType: MediaType.TV }, 16 | visible: false, 17 | }, 18 | { 19 | title: 'Trending TV Shows', 20 | req: { requestType: RequestType.TRENDING, mediaType: MediaType.TV }, 21 | visible: true, 22 | }, 23 | { 24 | title: 'Trending Movies', 25 | req: { requestType: RequestType.TRENDING, mediaType: MediaType.MOVIE }, 26 | visible: true, 27 | }, 28 | { 29 | title: 'Top Rated TV Shows', 30 | req: { requestType: RequestType.TOP_RATED, mediaType: MediaType.TV }, 31 | visible: true, 32 | }, 33 | { 34 | title: 'Top Rated Movies', 35 | req: { requestType: RequestType.TOP_RATED, mediaType: MediaType.MOVIE }, 36 | visible: true, 37 | }, 38 | ]; 39 | const allShows = await MovieService.getShows(requests); 40 | 41 | return ( 42 | <> 43 |

{h1}

44 | 45 | 46 | 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /src/app/(front)/page.tsx: -------------------------------------------------------------------------------- 1 | import { Icons } from "@/components/icons"; 2 | import { Badge } from "@/components/ui/badge"; 3 | import { buttonVariants } from "@/components/ui/button"; 4 | import { siteConfig } from "@/configs/site"; 5 | import { ArrowRight } from "lucide-react"; 6 | import Link from "next/link"; 7 | 8 | export default function Index() { 9 | return ( 10 | <> 11 |
16 | 17 | 25 | Twitter 26 | 27 |

28 | {siteConfig.name} - {siteConfig.slogan} 29 | {/* {siteConfig.name} - watch tv shows online, watch movies online. */} 30 | {/* An e-commerce skateshop built with everything new in Next.js 13 */} 31 |

32 |

33 | Step into a world where entertainment knows no boundaries, where your 34 | screens come alive with an endless array of captivating stories. 35 |

36 |
37 | 38 | Watch Now 39 | 40 | {/* GitHub */} 42 |
43 |
44 |
48 |
49 |

50 | Features 51 |

52 |

53 | {siteConfig.name} offers a host of powerful features designed to 54 | enhance your movie-watching experience. 55 |

56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 |
64 |

Vast Movie Library

65 |

66 | Thousands of movies, spanning diverse genres, languages, and 67 | decades. 68 |

69 |
70 |
71 |
72 |
73 |
74 | 75 | 76 | 77 |
78 |

Personalized Recommendations

79 |

80 | Suggesting movies and shows tailored to your taste. 81 |

82 |
83 |
84 |
85 |
86 |
87 | 88 | 89 | 90 |
91 |

Multiple Device Support

92 |

93 | Including smart TVs, smartphones, tablets, laptops, and gaming 94 | consoles. 95 |

96 |
97 |
98 |
99 |
100 |
101 | 102 | 103 | 104 |
105 |

Privacy First

106 |

107 | No Login , No Signup = No Data Collection 108 | 109 |

110 |
111 |
112 |
113 |
114 |
115 | 122 | 123 | 124 |
125 |

High-Definition Streaming

126 |

127 | Stunning visuals with content available in 4K, Ultra HD and 128 | HDR. 129 |

130 |
131 |
132 |
133 |
134 |
135 | 136 | 137 | 138 |
139 |

Free

140 |

141 | Everything is free, no subscription or credit card required. 142 |

143 |
144 |
145 |
146 |
147 | {/*
*/} 148 | {/*

*/} 149 | {/* Taxonomy also includes a blog and a full-featured documentation site */} 150 | {/*

*/} 151 | {/*
*/} 152 |
153 | 154 | ); 155 | } 156 | -------------------------------------------------------------------------------- /src/app/(front)/search/page.tsx: -------------------------------------------------------------------------------- 1 | import SearchContainer from '@/components/search-container'; 2 | import MovieService from '@/services/MovieService'; 3 | import { redirect } from 'next/navigation'; 4 | 5 | interface SearchProps { 6 | searchParams: { 7 | q?: string; 8 | }; 9 | } 10 | 11 | export const revalidate = 3600; 12 | 13 | export default async function SearchPage({ searchParams }: SearchProps) { 14 | if (!searchParams?.q?.trim()?.length) { 15 | redirect('/home'); 16 | } 17 | 18 | const shows = await MovieService.searchMovies(searchParams.q); 19 | return ; 20 | } 21 | -------------------------------------------------------------------------------- /src/app/(front)/tv-shows/[slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { type Metadata } from 'next'; 2 | import { handleMetadata } from '@/lib/utils'; 3 | import TvShowPage from '../page'; 4 | 5 | type Props = { 6 | params: { slug: string }; 7 | searchParams: Record; 8 | }; 9 | 10 | export const revalidate = 3600; 11 | 12 | export async function generateMetadata({ params }: Props): Promise { 13 | return handleMetadata(params.slug, 'tv-shows', 'tv'); 14 | } 15 | 16 | export default async function Home() { 17 | return TvShowPage(); 18 | } 19 | -------------------------------------------------------------------------------- /src/app/(front)/tv-shows/page.tsx: -------------------------------------------------------------------------------- 1 | import Hero from '@/components/hero'; 2 | import ShowsContainer from '@/components/shows-container'; 3 | import { siteConfig } from '@/configs/site'; 4 | import { Genre } from '@/enums/genre'; 5 | import { RequestType, type ShowRequest } from '@/enums/request-type'; 6 | import MovieService from '@/services/MovieService'; 7 | import { MediaType } from '@/types'; 8 | 9 | export const revalidate = 3600; 10 | 11 | export default async function TvShowPage() { 12 | const h1 = `${siteConfig.name} TV Shows`; 13 | const requests: ShowRequest[] = [ 14 | { 15 | title: 'Trending Now', 16 | req: { requestType: RequestType.TRENDING, mediaType: MediaType.TV }, 17 | visible: true, 18 | }, 19 | { 20 | title: 'Netflix TV Shows', 21 | req: { requestType: RequestType.NETFLIX, mediaType: MediaType.TV }, 22 | visible: true, 23 | }, 24 | { 25 | title: 'Popular', 26 | req: { 27 | requestType: RequestType.TOP_RATED, 28 | mediaType: MediaType.TV, 29 | genre: Genre.FAMILY, 30 | }, 31 | visible: true, 32 | }, 33 | { 34 | title: 'Comedy TV Shows', 35 | req: { 36 | requestType: RequestType.GENRE, 37 | mediaType: MediaType.TV, 38 | genre: Genre.COMEDY, 39 | }, 40 | visible: true, 41 | }, 42 | { 43 | title: 'Action TV Shows', 44 | req: { 45 | requestType: RequestType.GENRE, 46 | mediaType: MediaType.TV, 47 | genre: Genre.ACTION_ADVENTURE, 48 | }, 49 | visible: true, 50 | }, 51 | { 52 | title: 'Drama TV Shows', 53 | req: { 54 | requestType: RequestType.GENRE, 55 | mediaType: MediaType.TV, 56 | genre: Genre.DRAMA, 57 | }, 58 | visible: true, 59 | }, 60 | { 61 | title: 'Scary TV Shows', 62 | req: { 63 | requestType: RequestType.GENRE, 64 | mediaType: MediaType.TV, 65 | genre: Genre.THRILLER, 66 | }, 67 | visible: true, 68 | }, 69 | ]; 70 | const allShows = await MovieService.getShows(requests); 71 | 72 | return ( 73 | <> 74 |

{h1}

75 | 76 | 77 | 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /src/app/api/trpc/[trpc]/route.ts: -------------------------------------------------------------------------------- 1 | import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; 2 | import { appRouter } from "@/server/index"; 3 | 4 | const handler = (req: Request) => 5 | fetchRequestHandler({ 6 | endpoint: "/api/trpc", 7 | req, 8 | router: appRouter, 9 | createContext: () => ({}), 10 | }); 11 | 12 | export { handler as GET, handler as POST }; 13 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonpilee/cinegeek-beta/6b96b94408651f903695d418556a2f7e6568fc72/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { TailwindIndicator } from '@/components/tailwind-indicator'; 2 | import { ThemeProvider } from '@/components/theme-provider'; 3 | import { cn } from '@/lib/utils'; 4 | import '@/styles/globals.css'; 5 | // import { TrpcProvider } from '@/client/trpc-provider'; 6 | import type { Metadata, Viewport } from 'next'; 7 | import { Inter as FontSans } from 'next/font/google'; 8 | import localFont from 'next/font/local'; 9 | import { Analytics } from '@/components/analytics'; 10 | import { siteConfig } from '@/configs/site'; 11 | import { env } from '@/env.mjs'; 12 | import { SpeedInsights } from '@vercel/speed-insights/next'; 13 | import { GoogleAnalytics } from '@next/third-parties/google'; 14 | import Script from 'next/script'; 15 | 16 | const fontSans = FontSans({ 17 | subsets: ['latin'], 18 | variable: '--font-sans', 19 | display: 'swap', 20 | }); 21 | 22 | // Font files can be colocated inside of `pages` 23 | const fontHeading = localFont({ 24 | src: '../assets/fonts/CalSans-SemiBold.woff2', 25 | variable: '--font-heading', 26 | }); 27 | 28 | export const viewport: Viewport = { 29 | themeColor: [ 30 | { media: '(prefers-color-scheme: light)', color: 'white' }, 31 | { media: '(prefers-color-scheme: dark)', color: 'black' }, 32 | ], 33 | }; 34 | 35 | export const metadata: Metadata = { 36 | metadataBase: new URL(env.NEXT_PUBLIC_APP_URL), 37 | title: { 38 | default: siteConfig.name, 39 | template: `%s - ${siteConfig.name}`, 40 | }, 41 | description: siteConfig.description, 42 | keywords: siteConfig.keywords, 43 | authors: [ 44 | { 45 | name: siteConfig.author, 46 | url: siteConfig.url, 47 | }, 48 | ], 49 | creator: siteConfig.author, 50 | openGraph: { 51 | type: 'website', 52 | locale: 'en_US', 53 | url: siteConfig.url, 54 | title: siteConfig.name, 55 | images: siteConfig.ogImage, 56 | description: siteConfig.description, 57 | siteName: siteConfig.name, 58 | }, 59 | twitter: { 60 | card: 'summary_large_image', 61 | title: siteConfig.name, 62 | description: siteConfig.description, 63 | images: [siteConfig.ogImage], 64 | creator: siteConfig.author, 65 | }, 66 | icons: { 67 | icon: '/favicon.ico', 68 | }, 69 | other: { referrer: 'no-referrer-when-downgrade' }, 70 | }; 71 | 72 | export default function RootLayout({ 73 | children, 74 | }: { 75 | children: React.ReactNode; 76 | }) { 77 | return ( 78 | 79 | 85 | 90 | {/* */} 91 | {children} 92 | 93 | 94 | 95 | {/* */} 96 | {env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID && ( 97 | <> 98 |