@home-cinema/app 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ ## Home Cinema
2
+
3
+ A website for browsing movie lists and information. it uses [YTS](https://yts.mx/) API and [Torrent Streamer Api](https://github.com/KHLALA-Gh/torrent-streamer-api), built with [Vite](https://vite.dev/) and [React](https://react.dev/)
4
+
5
+ ![](./imgs/home_page.png)
6
+
7
+ ### Setup
8
+
9
+ #### Docker (Recommended) :
10
+
11
+ You can use Home Cinema Docker images to run the application with Docker Compose.
12
+ First create `docker-compose.yml` file in the location you want and add the content below.
13
+
14
+ ```yml
15
+ services:
16
+ home-cinema-website:
17
+ image: khlala/home-cinema-web:alpha5
18
+ # image: khlala/home-cinema-web:alpha5-arm64 ## use this image if you are running on arm64 arch
19
+ ports:
20
+ - "8000:4173"
21
+ environment:
22
+ - TMDB_KEY=<your_TMDB_api_key> ## Set your TMDB api key here
23
+ restart: always
24
+ ```
25
+
26
+ To get TV Shows information you need to get TMDB api key from [TMDB](https://www.themoviedb.org/).
27
+
28
+ > **Note** : Home cinema is still in alpha versions, you may encounter difficulties when installing it.
29
+
30
+ To run the application execute this command :
31
+
32
+ ```shell
33
+ docker compose up
34
+ ```
35
+
36
+ The website should be accessible from : http://localhost:8000/home_cinema
37
+
38
+ ### Configs
39
+
40
+ Create `./config` directory where you created `docker-compose.yml`. Then create your config file `home_cinema_config.json` inside the new directory.
41
+ If you want to know about configurations go [here](./docs/configurations.md).
42
+
43
+ To pass configs through docker compose add your config file in the container volumes.
44
+
45
+ ```yml
46
+ volumes:
47
+ - ./config/home_cinema_config.json:/app/dist/home_cinema_config.json
48
+ ```
49
+
50
+ ### Issues
51
+
52
+ If you encounter any issues using the website don't hesitate to submit an [issue](https://github.com/KHLALA-Gh/HomeCinemaWebsite/issues)
@@ -0,0 +1,4 @@
1
+ import { router as Config } from "./routes/config.js";
2
+ import { router as tvShows } from "./routes/tv_shows.js";
3
+ import { router as playlist } from "./routes/streamFiles.js";
4
+ export default { Config, tvShows, playlist };
@@ -0,0 +1,6 @@
1
+ import { Router } from "express";
2
+ import data from "../../../home_cinema_config.json" with { type: "json" };
3
+ export const router = Router();
4
+ router.get("/api/config", (_, res) => {
5
+ res.status(200).json(data);
6
+ });
@@ -0,0 +1,42 @@
1
+ import { Router } from "express";
2
+ export const router = Router();
3
+ router.get("/api/playlist", (req, res) => {
4
+ let streams = [];
5
+ if (typeof req.query.streams === "string") {
6
+ streams = [req.query.streams];
7
+ }
8
+ else if (req.query.streams instanceof Array) {
9
+ streams = req.query.streams;
10
+ }
11
+ else {
12
+ res.status(400).json({
13
+ error: "Stream urls are required",
14
+ });
15
+ return;
16
+ }
17
+ let names = [];
18
+ if (typeof req.query.names === "string") {
19
+ names = [req.query.names];
20
+ }
21
+ else if (req.query.names instanceof Array) {
22
+ names = req.query.names;
23
+ }
24
+ else {
25
+ res.status(400).json({
26
+ error: "stream names are required",
27
+ });
28
+ return;
29
+ }
30
+ let fileName = req.query.fileName;
31
+ if (!fileName) {
32
+ fileName = "playlist";
33
+ }
34
+ let playlist = "#EXTM3U\n";
35
+ streams.forEach((url, index) => {
36
+ playlist += `#EXTINF:-1,${names[index]}\n${url}\n`;
37
+ });
38
+ // Set response headers
39
+ res.setHeader("Content-Type", "audio/x-mpegurl");
40
+ res.setHeader("Content-Disposition", `attachment; filename="${fileName}.m3u"`);
41
+ res.send(playlist);
42
+ });
@@ -0,0 +1,98 @@
1
+ import { Router } from "express";
2
+ import { TMDBApi, TMDBError } from "../../lib/tmdb_api.js";
3
+ export const router = Router();
4
+ function HandlerTMDBApiErr(res, err) {
5
+ console.log(TMDBError.format(err));
6
+ res.status(err.statusCode || 500).json({
7
+ error: err.message,
8
+ });
9
+ return;
10
+ }
11
+ router.get("/api/tv_shows", async (req, res) => {
12
+ try {
13
+ const tmApi = new TMDBApi(process.env.TMDB_KEY);
14
+ let page = req.query.page;
15
+ if (page && isNaN(+page)) {
16
+ page = "1";
17
+ }
18
+ const data = await tmApi.getTVShows(page);
19
+ res.status(200).json(data);
20
+ }
21
+ catch (err) {
22
+ if (err instanceof TMDBError) {
23
+ res.status(err.statusCode || 500).json({
24
+ error: err.message,
25
+ });
26
+ console.log(TMDBError.format(err));
27
+ return;
28
+ }
29
+ res.status(500).json({
30
+ error: "internal server error",
31
+ });
32
+ console.log("error when getting TV SHOWS");
33
+ }
34
+ });
35
+ router.get("/api/tv_shows/search", async (req, res) => {
36
+ try {
37
+ const query = req.query.query;
38
+ let page = +req.query.page;
39
+ if (typeof query !== "string") {
40
+ res.status(400).json({
41
+ error: "search query is required",
42
+ });
43
+ return;
44
+ }
45
+ if (!page) {
46
+ page = 1;
47
+ }
48
+ const api = new TMDBApi(process.env.TMDB_KEY);
49
+ const data = await api.searchTvShows(query, page.toString());
50
+ res.status(200).json(data);
51
+ }
52
+ catch (err) {
53
+ if (err instanceof TMDBError) {
54
+ return HandlerTMDBApiErr(res, err);
55
+ }
56
+ res.status(500).json({
57
+ error: "Internal Server Error",
58
+ });
59
+ }
60
+ });
61
+ router.get("/api/tv_shows/:id", async (req, res) => {
62
+ try {
63
+ const id = req.params.id;
64
+ const api = new TMDBApi(process.env.TMDB_KEY);
65
+ const data = await api.getTVShowDetails(id);
66
+ res.status(200).json(data);
67
+ }
68
+ catch (err) {
69
+ if (err instanceof TMDBError) {
70
+ console.log(TMDBError.format(err));
71
+ res.status(err.statusCode || 500).json({
72
+ error: err.message,
73
+ });
74
+ return;
75
+ }
76
+ console.log("Internal Server Error !! : ", err);
77
+ res.status(500).json({
78
+ error: "internal server error",
79
+ });
80
+ }
81
+ });
82
+ router.get("/api/tv_shows/:id/season/:season_number", async (req, res) => {
83
+ try {
84
+ const id = req.params.id;
85
+ const seasonNumber = req.params.season_number;
86
+ const api = new TMDBApi(process.env.TMDB_KEY);
87
+ const data = await api.getSeasonDetails(id, seasonNumber);
88
+ res.status(200).json(data);
89
+ }
90
+ catch (err) {
91
+ if (err instanceof TMDBError) {
92
+ return HandlerTMDBApiErr(res, err);
93
+ }
94
+ res.status(500).json({
95
+ error: "Internal Server Error",
96
+ });
97
+ }
98
+ });
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM48 368l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zm368-16c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zM48 240l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zm368-16c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zM48 112l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16L64 96c-8.8 0-16 7.2-16 16zM416 96c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l0-32c0-8.8-7.2-16-16-16l-32 0zM160 128l0 64c0 17.7 14.3 32 32 32l128 0c17.7 0 32-14.3 32-32l0-64c0-17.7-14.3-32-32-32L192 96c-17.7 0-32 14.3-32 32zm32 160c-17.7 0-32 14.3-32 32l0 64c0 17.7 14.3 32 32 32l128 0c17.7 0 32-14.3 32-32l0-64c0-17.7-14.3-32-32-32l-128 0z"/></svg>