diff --git a/backend/server/api.py b/backend/server/api.py index d1a2c88..5e2a880 100644 --- a/backend/server/api.py +++ b/backend/server/api.py @@ -1,14 +1,10 @@ import logging -from logging.config import dictConfig import uvicorn -from fastapi import FastAPI +from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import StreamingResponse -from server import config -from server.config import log_config -from server.lib.epg.epg import EPGParser from server.lib.streamer import Streamer from server.lib.xtream import XTream @@ -24,8 +20,6 @@ origins = [ "https://streams.fergl.ie", "http://127.0.0.1:35729", "http://localhost:35729", - "https://bitmovin.com", - "https://players.akamai.com", ] app.add_middleware( @@ -42,34 +36,54 @@ app.add_middleware( # listings = epg.get_listings(channel_id) # return listings -def __get_provider(request): +def __get_provider(request: Request): return XTream( - config.provider['server'], - config.provider['username'], - config.provider['password'] + request.headers.get("x-xtream-server"), + request.headers.get("x-xtream-username"), + request.headers.get("x-xtream-password"), ) +@app.get("/validate") +async def validate_crendentials(request: Request, response: Response): + try: + provider = __get_provider(request) + categories = provider.get_categories().json() + if type(categories) is list: + return {"status": "accepted"} + except ValueError as e: + logger.error(e) + except Exception as e: + logger.error(e) + + response.status_code = 401 + return {"status": "denied"} + + @app.get("/channels") -async def channels(): +async def channels(request: Request): + provider = __get_provider(request) categories = provider.get_categories() return categories.json() @app.get("/streams/{category_id}") -async def read_item(category_id): +async def read_item(category_id, request: Request): + provider = __get_provider(request) streams = provider.get_streams_for_category(category_id) return streams.json() @app.get("/live/stream/{stream_id}") -async def get_live_stream(stream_id: str): +async def get_live_stream(stream_id: str, request: Request): + provider = __get_provider(request) url = provider.get_live_stream_url(stream_id) return StreamingResponse(Streamer.receive_stream(url), media_type="video/mp2t") @app.get("/live/stream/url/{stream_id}") -async def get_live_stream(stream_id: str): +async def get_live_stream(stream_id: str, request: Request): + provider = __get_provider(request) url = provider.get_live_stream_url(stream_id) return { "url": url diff --git a/backend/server/lib/xtream.py b/backend/server/lib/xtream.py index aaeaced..1b18ab5 100644 --- a/backend/server/lib/xtream.py +++ b/backend/server/lib/xtream.py @@ -18,6 +18,9 @@ class XTream: _cache = Cache() def __init__(self, server, username, password): + if not (server and username and password): + raise ValueError("XTream: must specify server, username and password") + self._server = server self._username = username self._password = password diff --git a/frontend/package.json b/frontend/package.json index 7c2e183..0a9b8a5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", "autoprefixer": "^10.4.4", + "axios": "^0.26.1", "classnames": "^2.3.1", "hls.js": "^1.1.5", "postcss": "^8.4.12", @@ -15,6 +16,7 @@ "react-dom": "^17.0.2", "react-focus-lock": "^2.8.1", "react-helmet": "^6.1.0", + "react-hook-form": "^7.29.0", "react-icons": "^4.3.1", "react-router-dom": "6", "react-scripts": "5.0.0", diff --git a/frontend/public/images/unknown-stream.svg b/frontend/public/images/unknown-stream.svg new file mode 100644 index 0000000..1adf606 --- /dev/null +++ b/frontend/public/images/unknown-stream.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index badbdb5..746801e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,14 +1,20 @@ import React from "react"; import { BrowserRouter, Route, Routes } from "react-router-dom"; -import { ToastContainer } from "react-toastify"; import { Layout } from "./containers"; +import { OnboardingPage } from "./pages"; function App() { return ( - - } /> + {localStorage.getItem("server") ? ( + <> + } /> + } /> + + ) : ( + } /> + )} ); diff --git a/frontend/src/assets/images/love-tv.jpg b/frontend/src/assets/images/love-tv.jpg new file mode 100644 index 0000000..dd8ac59 Binary files /dev/null and b/frontend/src/assets/images/love-tv.jpg differ diff --git a/frontend/src/assets/images/tv.png b/frontend/src/assets/images/tv.png new file mode 100644 index 0000000..4a75dc8 Binary files /dev/null and b/frontend/src/assets/images/tv.png differ diff --git a/frontend/src/components/epg.component.tsx b/frontend/src/components/epg.component.tsx index 3249bb0..02316df 100644 --- a/frontend/src/components/epg.component.tsx +++ b/frontend/src/components/epg.component.tsx @@ -1,5 +1,4 @@ import React from "react"; - interface IEPGComponentProps { channelId: string; } diff --git a/frontend/src/components/header.component.tsx b/frontend/src/components/header.component.tsx index 011398d..6923c98 100644 --- a/frontend/src/components/header.component.tsx +++ b/frontend/src/components/header.component.tsx @@ -50,7 +50,7 @@ const Header = () => {