diff --git a/api/main.py b/api/main.py index f2a7398..f82b14c 100644 --- a/api/main.py +++ b/api/main.py @@ -10,6 +10,7 @@ from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from db import database, crud, schemas +from db.config import settings from utils import scrap logging.basicConfig(format="%(levelname)s::%(asctime)s - %(message)s", datefmt="%d-%b-%y %H:%M:%S", level=logging.INFO) @@ -54,7 +55,7 @@ async def get_home(request: Request): { "request": request, "name": manifest.get("name"), - "version": manifest.get("version"), + "version": f"{manifest.get('version')}-{settings.git_rev[:7]}", "description": manifest.get("description"), "gives": [ "Tamil Movies & Series", @@ -87,6 +88,14 @@ async def get_catalog(response: Response, catalog_id: str, skip: int = 0): return movies +@app.get("/catalog/{content_type}/tamil_blasters/search={search_query}.json", response_model=schemas.Movie) +async def search_movie(response: Response, content_type: Literal["movie", "series"], search_query: str): + response.headers.update({"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "*"}) + logging.info(f"Searching for {search_query}") + + return await crud.process_search_query(search_query, content_type) + + @app.get("/meta/movie/{meta_id}.json") async def get_meta(meta_id: str, response: Response): response.headers.update({"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "*"}) diff --git a/beamup.json b/beamup.json index b964948..10ff491 100644 --- a/beamup.json +++ b/beamup.json @@ -1,4 +1,4 @@ { "projectName": "stremio-tamilblasters", - "lastCommit": "b98ac2d" + "lastCommit": "898b1f4" } \ No newline at end of file diff --git a/db/config.py b/db/config.py index 63c109e..7f2c448 100644 --- a/db/config.py +++ b/db/config.py @@ -3,9 +3,11 @@ from pydantic_settings import BaseSettings class Settings(BaseSettings): mongo_uri: str + git_rev: str = "beta" class Config: env_file = ".env" + extra = "ignore" settings = Settings() diff --git a/db/crud.py b/db/crud.py index bc2bc74..f4b59f0 100644 --- a/db/crud.py +++ b/db/crud.py @@ -12,7 +12,7 @@ from utils.parser import extract_stream_details ia = Cinemagoer() -async def get_movies_meta(catalog: str, skip: int = 0, limit: int = 100): +async def get_movies_meta(catalog: str, skip: int = 0, limit: int = 100) -> list[schemas.Meta]: movies_meta = [] movies = ( await TamilBlasterMovie.find(TamilBlasterMovie.catalog == catalog) @@ -149,7 +149,7 @@ async def save_movie_metadata(metadata: dict): movie_data.created_at = metadata["created_at"] logging.info(f"update video qualities for {metadata['name']}") else: - movie_data = TamilBlasterMovie.parse_obj(metadata) + movie_data = TamilBlasterMovie.model_validate(metadata) movie_data.video_qualities = metadata["video_qualities"] series_data = await TamilBlasterMovie.find_one( @@ -175,3 +175,21 @@ async def save_movie_metadata(metadata: dict): logging.info(f"new movie '{metadata['name']}' added.") await movie_data.save() + + +async def process_search_query(search_query: str, content_type: str) -> dict: + query = {"$text": {"$search": search_query}, "type": content_type} + search_results = await TamilBlasterMovie.find(query).to_list() + logging.info(f"Found {len(search_results)} results for {search_query} in {content_type}") + + movies_meta = [] + unique_names = [] + + for movie in search_results: + meta_data = schemas.Meta.model_validate(movie.model_dump()) + meta_data.id = movie.imdb_id or movie.tamilblaster_id + if movie.name not in unique_names: + movies_meta.append(meta_data) + unique_names.append(movie.name) + + return {"metas": movies_meta} diff --git a/db/models.py b/db/models.py index 86b5966..794ff4f 100644 --- a/db/models.py +++ b/db/models.py @@ -11,11 +11,11 @@ class TamilBlasterMovie(Document): name: str catalog: str type: str - season: Optional[int] - episode: Optional[str] + season: Optional[int] = None + episode: Optional[str] = None poster: str - imdb_id: Optional[str] - tamilblaster_id: Optional[str] + imdb_id: Optional[str] = None + tamilblaster_id: Optional[str] = None created_at: datetime = Field(default_factory=datetime.now) video_qualities: dict @@ -29,5 +29,6 @@ class TamilBlasterMovie(Document): ("episode", pymongo.ASCENDING), ], unique=True, - ) + ), + IndexModel([("name", pymongo.TEXT)]), ] diff --git a/db/schemas.py b/db/schemas.py index 71cd329..86e4dee 100644 --- a/db/schemas.py +++ b/db/schemas.py @@ -17,7 +17,7 @@ class Meta(BaseModel): class Movie(BaseModel): - metas: Optional[List[Meta]] = [] + metas: list[Meta] = [] class Stream(BaseModel): diff --git a/resources/manifest.json b/resources/manifest.json index 243f950..28a199a 100644 --- a/resources/manifest.json +++ b/resources/manifest.json @@ -35,6 +35,28 @@ "series" ], "catalogs": [ + { + "id": "tamil_blasters", + "type": "movie", + "name": "Movies", + "extra": [ + { + "name": "search", + "isRequired": true + } + ] + }, + { + "id": "tamil_blasters", + "type": "series", + "name": "Series", + "extra": [ + { + "name": "search", + "isRequired": true + } + ] + }, { "id": "any_any", "type": "movie", diff --git a/utils/scrap.py b/utils/scrap.py index 8482fc0..c0be67b 100755 --- a/utils/scrap.py +++ b/utils/scrap.py @@ -225,22 +225,23 @@ async def run_scraper( except KeyError: logging.error(f"Unsupported language or video type: {language}_{video_type}") return - for page in range(start_page, pages + 1): + for page in range(start_page, pages + start_page): scrap_link = f"{scrap_link}/page/{page}/" logging.info(f"Scrap page: {page}") await scrap_page(scrap_link, language, video_type) logging.info(f"Scrap completed for : {language}_{video_type}") -async def run_schedule_scrape(): +async def run_schedule_scrape(pages: int = 1, start_page: int = 1): for language in tamil_blaster_links: for video_type in tamil_blaster_links[language]: - await run_scraper(language, video_type, pages=1, start_page=1, is_scrape_home=False) + await run_scraper(language, video_type, pages=pages, start_page=start_page, is_scrape_home=False) await run_scraper(is_scrape_home=True) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Scrap Movie metadata from TamilBlasters") + parser.add_argument("--all", action="store_true", help="scrap all type of movies & series") parser.add_argument("--home", action="store_true", help="scrap home page") parser.add_argument("-l", "--language", help="scrap movie language", default="tamil") parser.add_argument("-t", "--video-type", help="scrap movie video type", default="hdrip") @@ -253,4 +254,7 @@ if __name__ == "__main__": datefmt="%d-%b-%y %H:%M:%S", level=logging.INFO, ) - asyncio.run(run_scraper(args.language, args.video_type, args.pages, args.start_pages, args.home)) + if args.all: + asyncio.run(run_schedule_scrape(args.pages, args.start_pages)) + else: + asyncio.run(run_scraper(args.language, args.video_type, args.pages, args.start_pages, args.home))