Compare commits

...

2 Commits

Author SHA1 Message Date
74753d94be Added another group regex 2026-03-20 13:21:07 -04:00
02741c1e77 Fixed imports and refactored some attributes 2026-03-20 13:05:45 -04:00
21 changed files with 68 additions and 72 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/test.xml
/uv.lock
/main.py

View File

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

View File

@@ -3,8 +3,9 @@ from pathlib import Path
from pkgutil import iter_modules
from typing import Optional, Type
from parsers.generic.parsers import DataParser
from parsers.generic.watfag import WATFAG, SeedStatus
from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.generic.watfag import *
from watfag.parsers.generic.watfag import WATFAG
class Release:
@@ -23,6 +24,18 @@ class Release:
self.seed_status: Optional[SeedStatus] = None
self.parser_results: dict[str, bool] = {} # Stores which parsers have been run and their results.
self.group: Optional[Group] = None
self.group_name: Optional[str] = None
self.quality: Optional[Resolution] = None
self.source: Optional[Source] = None
self.streaming: Optional[StreamingService] = None
self.video_codec: Optional[VideoCodec] = None
self.audio_codec: Optional[AudioCodec] = None
self.audio_layout: Optional[AudioLayout] = None
self.dynamic_range: Optional[DynamicRange] = None
self.repack: Optional[Repack] = None
self.multi: Optional[Multi] = None
def __lt__(self, other):
return self.watfag < other.watfag
@@ -63,6 +76,7 @@ class GenericParser:
class ParserManager:
"""Manages and runs parsers on releases."""
def __init__(self):
self.parsers: list[Type[DataParser]] = []
self.collect_parsers()

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import DataParser
from parsers.generic.watfag import AudioCodec, AudioLayout
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.generic.watfag import AudioCodec, AudioLayout
patterns = [
re.compile(

View File

@@ -1,11 +1,12 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.watfag import Group
from parsers.generic.parsers import DataParser
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.watfag import Group
from watfag.parsers.generic.parsers import DataParser
patterns = [
re.compile(r"(?:-| - )(?P<group>[a-zA-Z0-9 &]*)\)?$", re.UNICODE),
re.compile(r"\[(?P<group>[a-zA-Z0-9 &]*)\]?$", re.UNICODE),
re.compile(r"(?: )\[?(?P<group>[a-zA-Z0-9]*?)]?\)?$", re.UNICODE)
]

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import DynamicRange
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import DynamicRange
checks = {
re.compile(r"hybrid|do?vi? ?hdr(?:10)?[\+p]?", re.IGNORECASE): DynamicRange.HYBRID,

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import Multi
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import Multi
checks = {
re.compile(r"multi", re.IGNORECASE): Multi.MULTI

View File

@@ -3,7 +3,7 @@ from typing import Optional, TYPE_CHECKING
from regex import Pattern
if TYPE_CHECKING:
from parsers.generic import WATFAG, Release
from watfag.parsers.generic import WATFAG, Release
class DataParser:

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import Repack
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import Repack
checks = {
re.compile(r"repack", re.IGNORECASE): Repack.REPACK,

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import Resolution
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import Resolution
checks = {
re.compile(r"2160p", re.IGNORECASE): Resolution.UHD,

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import SeedStatus
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import SeedStatus
class SeederParser(CheckParser, GenericParser):
def parse(self) -> bool:

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import Source
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import Source
checks = {
re.compile(r"remux", re.IGNORECASE): Source.REMUX,

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import StreamingService
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import StreamingService
checks = {
re.compile(r"ATVP"): StreamingService.ATVP,

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic import GenericParser
from parsers.generic.parsers import CheckParser
from parsers.generic.watfag import VideoCodec
from watfag.parsers.generic import GenericParser
from watfag.parsers.generic.parsers import CheckParser
from watfag.parsers.generic.watfag import VideoCodec
checks = {
re.compile(r"avc|[hx][\. -]?264", re.IGNORECASE): VideoCodec.AVC,

View File

@@ -189,6 +189,7 @@ class Group(WATFAG):
"""
FLUX = "FLUX", 10 # Very good WEB-DL releases and fast
HONE = "HONE", 10 # High quality re-encodes
TAOE = "TAoE", 10 # High quality re-encodes
PHOCIS = "PHOCiS", 8 # Same as FLUX
LEGION = "LEGi0N", 8 # Same as FLUX
AOC = "AOC", 1 # Often low quality CAM releases. While fast, not worth it for most movies.

View File

@@ -3,32 +3,22 @@ from pathlib import Path
from pkgutil import iter_modules
from typing import Optional
from parsers.generic import Release, ParserManager
from parsers.generic.watfag import *
from watfag.parsers.generic import Release, ParserManager
class MovieRelease(Release):
"""Holds info representing a release of a movie."""
def __init__(self, unparsed_text, dl_link, **kwargs):
super().__init__(unparsed_text, dl_link, **kwargs)
self.title: str = ""
self.year: int = 0
self.edition: Optional[str] = None
self.group: Optional[Group] = None
self.group_name: Optional[str] = None
self.quality: Optional[Resolution] = None
self.source: Optional[Source] = None
self.streaming: Optional[StreamingService] = None
self.video_codec: Optional[VideoCodec] = None
self.audio_codec: Optional[AudioCodec] = None
self.audio_layout: Optional[AudioLayout] = None
self.dynamic_range: Optional[DynamicRange] = None
self.repack: Optional[Repack] = None
self.multi: Optional[Multi] = None
def __str__(self):
parts = [f"{self.title} ({self.year})" + (f" [{self.edition}]" if self.edition else "")]
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)
parts.append(f"{attr.capitalize()}: {value if value else 'Unknown'}")
if self.streaming:
@@ -39,12 +29,14 @@ class MovieRelease(Release):
parts.append(f"WATFAG: {self.watfag:.2f}")
return " | ".join(parts)
class MovieParser:
"""
This class can be inherited by any parser that is specific to movies.
It allows dynamic importing of parser classes and provides a method to run all parsers on a given movie release.
"""
class MovieParserManager(ParserManager):
"""Parses movie releases."""

View File

@@ -1,8 +1,8 @@
import regex as re
from parsers.generic.parsers import DataParser
from parsers.movie import MovieParser, MovieRelease
from parsers.movie.title_year import edition_regex
from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.movie import MovieParser, MovieRelease
from watfag.parsers.movie.title_year import edition_regex
class EditionParser(DataParser, MovieParser):

View File

@@ -1,7 +1,7 @@
import regex as re
from parsers.generic.parsers import DataParser
from parsers.movie import MovieParser, MovieRelease
from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.movie import MovieParser, MovieRelease
# Shamelessly stolen from Radarr: https://github.com/Radarr/Radarr/blob/develop/src/NzbDrone.Core/Parser/Parser.cs
edition_regex = r"\(?\b(?P<edition>(((Recut.|Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Extended|Despecialized|(Special|Rouge|Final|Assembly|Imperial|Diamond|Signature|Hunter|Rekall)(?=(.(Cut|Edition|Version)))|\d{2,3}(th)?.Anniversary)(?:.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|Open.?Matte|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|Open?.Matte|IMAX|Fan.?Edit|Restored|((2|3|4)in1))))))\b\)?"

View File

@@ -3,8 +3,7 @@ from pathlib import Path
from pkgutil import iter_modules
from typing import Optional
from parsers.generic import Release, ParserManager
from parsers.generic.watfag import *
from watfag.parsers.generic import Release, ParserManager
class TVBoxSetRelease(Release):
@@ -13,17 +12,6 @@ class TVBoxSetRelease(Release):
super().__init__(unparsed_text, dl_link, **kwargs)
self.show_title: str = ""
self.seasons: Optional[str] = None
self.group: Optional[Group] = None
self.group_name: Optional[str] = None
self.quality: Optional[Resolution] = None
self.source: Optional[Source] = None
self.streaming: Optional[StreamingService] = None
self.video_codec: Optional[VideoCodec] = None
self.audio_codec: Optional[AudioCodec] = None
self.audio_layout: Optional[AudioLayout] = None
self.dynamic_range: Optional[DynamicRange] = None
self.repack: Optional[Repack] = None
self.multi: Optional[Multi] = None
def __str__(self):
parts = [f"{self.show_title} (Seasons: {self.seasons})"]
@@ -46,7 +34,6 @@ class TVBoxSetParser:
class TVBoxSetParserManager(ParserManager):
"""Parses TV box set releases."""
def collect_parsers(self):
"""Dynamically imports all TV box set parsers."""
super().collect_parsers()

View File

@@ -1,7 +1,7 @@
import regex as re
from parsers.generic.parsers import DataParser
from parsers.tvboxset import TVBoxSetParser, TVBoxSetRelease
from watfag.parsers.generic.parsers import DataParser
from watfag.parsers.tvboxset import TVBoxSetParser, TVBoxSetRelease
patterns = [
re.compile( # Show Name S01-S02 (year)

View File

@@ -2,9 +2,9 @@ from xml.etree import ElementTree
from httpx import AsyncClient
from parsers.generic import Release
from parsers.movie import MovieRelease, MovieParserManager
from parsers.tvboxset import TVBoxSetRelease, TVBoxSetParserManager
from watfag.parsers.generic import Release
from watfag.parsers.movie import MovieRelease, MovieParserManager
from watfag.parsers.tvboxset import TVBoxSetRelease, TVBoxSetParserManager
class Jackett: