Skip to content

Commit 3403e5f

Browse files
authored
feat: integrate movierulz indexer (#13)
1 parent 77eb30d commit 3403e5f

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "torrra"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
description = "A Python tool that lets you find and download torrents without leaving your CLI."
55
readme = "README.md"
66
authors = [{ name = "stabldev" }]

src/torrra/indexers/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
INDEXERS = {
2-
"yts (movies)": "torrra.indexers.yts",
2+
"yts": "torrra.indexers.yts",
33
"magnetdl": "torrra.indexers.magnetdl",
4+
"movierulz": "torrra.indexers.movierulz"
45
}

src/torrra/indexers/movierulz.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import re
2+
import asyncio
3+
from typing import List, Tuple
4+
from urllib.parse import quote_plus
5+
6+
import httpx
7+
from selectolax.parser import HTMLParser
8+
9+
from torrra.indexers.base import BaseIndexer
10+
from torrra.types import Torrent
11+
12+
13+
class Indexer(BaseIndexer):
14+
BASE_URL = ""
15+
def search(self, query: str) -> List[Torrent]:
16+
normalized_query = quote_plus(query)
17+
url = f"https://www.5movierulz.voto/search_movies?s={normalized_query}"
18+
parser = self._get_parser(url)
19+
20+
results = []
21+
22+
has_no_results = parser.css_first("div.content ul h1")
23+
if has_no_results:
24+
return results
25+
26+
titles_links: List[Tuple[str, str]] = []
27+
28+
nodes = parser.css("div.content ul li")
29+
for node in nodes:
30+
title_node = node.css_first("p b")
31+
link_node = node.css_first("a")
32+
title = title_node.text() if title_node else ""
33+
link = link_node.attributes.get("href") if link_node else ""
34+
35+
if query.lower() not in title.lower() or not link:
36+
continue
37+
38+
titles_links.append((title, link))
39+
40+
magnets_list = asyncio.run(self._fetch_magnet_uris(titles_links))
41+
42+
for title, magnets in zip([t[0] for t in titles_links], magnets_list):
43+
for magnet in magnets:
44+
results.append(
45+
Torrent(
46+
title=f"{title} {magnet.title}",
47+
magnet_uri=magnet.magnet_uri
48+
)
49+
)
50+
51+
return results
52+
53+
async def _fetch_magnet_uris(self, items: List[Tuple[str, str]]) -> List[List[Torrent]]:
54+
async def fetch(client: httpx.AsyncClient, url: str):
55+
res = await client.get(url, timeout=10)
56+
parser = HTMLParser(res.text)
57+
58+
results = []
59+
60+
a_nodes = parser.css("div.entry-content p a")
61+
nodes = [node for node in a_nodes if "GET THIS TORRENT" in node.text(strip=True)]
62+
63+
for node in nodes:
64+
magnet_uri = node.attributes.get("href")
65+
if not magnet_uri:
66+
continue
67+
68+
title_node = node.css_first("small")
69+
title = title_node.text(strip=True) if title_node else ""
70+
formatted_title = re.sub(r'\b(\d+(\.\d+)?)\s*(gb|mb|kb)\b', lambda m: f"{m.group(1)} {m.group(3).upper()}", title)
71+
72+
results.append(Torrent(title=formatted_title, magnet_uri=magnet_uri))
73+
74+
return results
75+
76+
async with httpx.AsyncClient() as client:
77+
tasks = [fetch(client, url) for (_, url) in items]
78+
return await asyncio.gather(*tasks)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)