Compare commits

..

2 Commits

Author SHA1 Message Date
7cd556bab2 Added tracker info to releases 2026-03-20 22:14:28 -04:00
8f58d8db82 Change title attribute to be standard 2026-03-20 21:34:40 -04:00
7 changed files with 76 additions and 27 deletions

View File

@@ -1 +1 @@
__version__ = "1.0.1" __version__ = "1.0.3"

View File

@@ -2,28 +2,34 @@ import importlib
from pathlib import Path from pathlib import Path
from pkgutil import iter_modules from pkgutil import iter_modules
from typing import Optional, Type from typing import Optional, Type
from xml.etree.ElementTree import Element
from watfag.parsers.generic.parsers import DataParser from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.generic.watfag import * from watfag.parsers.generic.watfag import *
from watfag.parsers.generic.watfag import WATFAG from watfag.parsers.generic.watfag import WATFAG
from watfag.trackers import TrackerInfo
class Release: class Release:
def __init__( def __init__(
self, self,
unparsed_text, xml_result: Element,
dl_link, tracker_info: Optional[TrackerInfo] = None
**kwargs
): ):
self.original_text: str = unparsed_text self.xml: Element = xml_result
self.tracker_info: Optional[TrackerInfo] = tracker_info
self.original_text: str = ''
self.metadata_text: Optional[str] = '' self.metadata_text: Optional[str] = ''
self.dl_link: str = dl_link self.dl_link: str = ''
self.view_link: str = kwargs.get('view_link', dl_link) self.view_link: str = ''
self.size: int = kwargs.get('size', 0) self.size: int = 0
self.seeders: int = kwargs.get('seeders', 0) self.seeders: int = 0
self.tracker: str = ''
self.tracker_abbr: str = ''
self.seed_status: Optional[SeedStatus] = None self.seed_status: Optional[SeedStatus] = None
self.parser_results: dict[str, bool] = {} # Stores which parsers have been run and their results. self.parser_results: dict[str, bool] = {} # Stores which parsers have been run and their results.
self.title: Optional[str] = None
self.group: Optional[Group] = None self.group: Optional[Group] = None
self.group_name: Optional[str] = None self.group_name: Optional[str] = None
self.quality: Optional[Resolution] = None self.quality: Optional[Resolution] = None
@@ -36,6 +42,22 @@ class Release:
self.repack: Optional[Repack] = None self.repack: Optional[Repack] = None
self.multi: Optional[Multi] = None self.multi: Optional[Multi] = None
self._parse_xml()
def _parse_xml(self):
# Get the torznab attributes
attrs: dict[str, list[str]] = {}
for attr in self.xml.findall('torznab:attr', namespaces={'torznab': 'http://torznab.com/schemas/2015/feed'}):
attrs[attr.get('name')] = attrs.get(attr.get('name'), []) + [attr.get('value')]
self.original_text = self.xml.find('title').text
self.dl_link = self.xml.find('link').text
self.size = int(self.xml.find('size').text)
self.seeders = int(attrs.get('seeders')[0])
self.view_link = self.xml.find('comments').text
self.tracker = self.xml.find('jackettindexer').text
self.tracker_abbr = self.tracker_info.get_tracker_info(self.tracker).get('Abbreviation') if self.tracker_info else self.tracker
def __lt__(self, other): def __lt__(self, other):
return self.watfag < other.watfag return self.watfag < other.watfag

View File

@@ -2,16 +2,21 @@ import importlib
from pathlib import Path from pathlib import Path
from pkgutil import iter_modules from pkgutil import iter_modules
from typing import Optional from typing import Optional
from xml.etree.ElementTree import Element
from watfag.parsers.generic import Release, ParserManager from watfag.parsers.generic import Release, ParserManager
from watfag.trackers import TrackerInfo
class MovieRelease(Release): class MovieRelease(Release):
"""Holds info representing a release of a movie.""" """Holds info representing a release of a movie."""
def __init__(self, unparsed_text, dl_link, **kwargs): def __init__(
super().__init__(unparsed_text, dl_link, **kwargs) self,
self.title: str = "" xml_result: Element,
tracker_info: Optional[TrackerInfo] = None
):
super().__init__(xml_result, tracker_info)
self.year: int = 0 self.year: int = 0
self.edition: Optional[str] = None self.edition: Optional[str] = None

View File

@@ -2,19 +2,24 @@ import importlib
from pathlib import Path from pathlib import Path
from pkgutil import iter_modules from pkgutil import iter_modules
from typing import Optional from typing import Optional
from xml.etree.ElementTree import Element
from watfag.parsers.generic import Release, ParserManager from watfag.parsers.generic import Release, ParserManager
from watfag.trackers import TrackerInfo
class TVBoxSetRelease(Release): class TVBoxSetRelease(Release):
"""Holds info representing a release of a TV box set.""" """Holds info representing a release of a TV box set."""
def __init__(self, unparsed_text, dl_link, **kwargs): def __init__(
super().__init__(unparsed_text, dl_link, **kwargs) self,
self.show_title: str = "" xml_result: Element,
tracker_info: Optional[TrackerInfo] = None
):
super().__init__(xml_result, tracker_info)
self.seasons: Optional[str] = None self.seasons: Optional[str] = None
def __str__(self): def __str__(self):
parts = [f"{self.show_title} (Seasons: {self.seasons})"] parts = [f"{self.title} (Seasons: {self.seasons})"]
for attr in ['quality', 'video_codec', 'audio_codec', 'audio_layout', 'dynamic_range', 'repack', 'multi', 'source']: for attr in ['quality', 'video_codec', 'audio_codec', 'audio_layout', 'dynamic_range', 'repack', 'multi', 'source']:
value = getattr(self, attr) value = getattr(self, attr)
parts.append(f"{attr.capitalize()}: {value if value else 'Unknown'}") parts.append(f"{attr.capitalize()}: {value if value else 'Unknown'}")

View File

@@ -45,7 +45,7 @@ class TitleSeasonsParser(DataParser, TVBoxSetParser):
for pattern in patterns: for pattern in patterns:
match = pattern.match(self.release.original_text) match = pattern.match(self.release.original_text)
if match: if match:
self.release.show_title = match.group("title").replace(".", " ").replace("_", " ").strip() if match.group("title") else "" self.release.title = match.group("title").replace(".", " ").replace("_", " ").strip() if match.group("title") else ""
season_start = int(match.group("season_start")) if match.group("season_start") else 0 season_start = int(match.group("season_start")) if match.group("season_start") else 0
season_end = int(match.group("season_end")) if "season_end" in match.groupdict() and match.group("season_end") else season_start season_end = int(match.group("season_end")) if "season_end" in match.groupdict() and match.group("season_end") else season_start
self.release.seasons = f"{season_start}" if season_start == season_end else f"{season_start}-{season_end}" self.release.seasons = f"{season_start}" if season_start == season_end else f"{season_start}-{season_end}"

View File

@@ -5,6 +5,7 @@ from httpx import AsyncClient
from watfag.parsers.generic import Release from watfag.parsers.generic import Release
from watfag.parsers.movie import MovieRelease, MovieParserManager from watfag.parsers.movie import MovieRelease, MovieParserManager
from watfag.parsers.tvboxset import TVBoxSetRelease, TVBoxSetParserManager from watfag.parsers.tvboxset import TVBoxSetRelease, TVBoxSetParserManager
from watfag.trackers import TrackerInfo
class Jackett: class Jackett:
@@ -13,6 +14,9 @@ class Jackett:
self.base_url = base_url self.base_url = base_url
self.movie_parser = MovieParserManager() self.movie_parser = MovieParserManager()
self.tvboxset_parser = TVBoxSetParserManager() self.tvboxset_parser = TVBoxSetParserManager()
self.tracker_info = TrackerInfo(
"https://raw.githubusercontent.com/HDVinnie/Private-Trackers-Spreadsheet/refs/heads/master/trackers.json"
)
async def get_capabilities(self): async def get_capabilities(self):
params = { params = {
@@ -45,21 +49,15 @@ class Jackett:
# Find out from categories what kind of result this is # Find out from categories what kind of result this is
if any(cat.startswith('2') for cat in attrs.get('category')): # This is a movie if any(cat.startswith('2') for cat in attrs.get('category')): # This is a movie
release = MovieRelease( release = MovieRelease(
item.find('title').text, item,
item.find('link').text, self.tracker_info
size=int(item.find('size').text),
seeders=int(attrs.get('seeders')[0]),
view_link=item.find('comments').text
) )
self.movie_parser.run_parsers(release) self.movie_parser.run_parsers(release)
releases.append(release) releases.append(release)
elif any(cat == '100027' for cat in attrs.get('category')): # This is a TV boxset elif any(cat == '100027' for cat in attrs.get('category')): # This is a TV boxset
release = TVBoxSetRelease( release = TVBoxSetRelease(
item.find('title').text, item,
item.find('link').text, self.tracker_info
size=int(item.find('size').text),
seeders=int(attrs.get('seeders')[0]),
view_link=item.find('comments').text
) )
self.tvboxset_parser.run_parsers(release) self.tvboxset_parser.run_parsers(release)
releases.append(release) releases.append(release)

19
src/watfag/trackers.py Normal file
View File

@@ -0,0 +1,19 @@
from typing import Optional
import httpx
class TrackerInfo:
def __init__(self, url):
self.url = url
self.json: Optional[dict] = None
def _refresh(self):
r = httpx.get(self.url)
r.raise_for_status()
self.json = r.json().get('trackers', [])
def get_tracker_info(self, tracker_name):
if self.json is None:
self._refresh()
return next((tracker for tracker in self.json if tracker['Name'] == tracker_name), None)