from bbss.lists import BaseListFile, ListFileEntry, parse_listfile import bbss.site as site from bbss import DEFAULT_PATHS from dataclasses import dataclass from typing import cast, Optional from collections.abc import Sequence import requests import re FRIEND_REGEX = re.compile(r"""^ (?:(?P[a-z]+)://)? # match the URL scheme, e.x. `https://` (?P(?:[a-z0-9\-]+\.)*(?:[a-z])+) # match the actual domain (?: | # match no path (?P(?:/[^/\s#?]+)*/?) # match a path ) $""", re.X) @dataclass(frozen=True) class FriendListFileEntry(ListFileEntry): url: str domain: str scheme: str path: str def __init__(self, entry: str, comment: Optional[str]): super().__init__(entry, comment) m = FRIEND_REGEX.match(entry) if m is None: return self.__setattr__('scheme', m.group('scheme') or None) self.__setattr__('domain', m.group('domain')) self.__setattr__('path', m.group('path').removesuffix('/')) self.__setattr__('url', (self.scheme if self.scheme else 'https') + '://' + self.domain + (self.path if self.path is not None else "")) def exists(self) -> bool: if self.path is not None: return requests.head(self.url + "/sizes.txt").ok or requests.head(self.url + "/88x31/list.txt").ok else: for default in DEFAULT_PATHS: if requests.head(default + "sizes.txt").ok or requests.head(default + "/88x31/list.txt").ok: return True return False def get(self) -> "site.Site": return site.Site(self.domain, self.path, scheme = self.scheme) class FriendListFile(BaseListFile[FriendListFileEntry]): def __init__(self, contents: str): super().__init__(contents) self._entries = parse_listfile(contents, FriendListFileEntry) __all__ = ["FriendListFileEntry", "FriendListFile"]