aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/conf.py9
-rw-r--r--docs/index.rst205
-rw-r--r--src/bbss/site.py2
-rw-r--r--src/bbss/sizes.py7
4 files changed, 209 insertions, 14 deletions
diff --git a/docs/conf.py b/docs/conf.py
index 760ad19..0ac5971 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -29,11 +29,18 @@ exclude_patterns = ['*~']
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinxdoc'
+html_theme_options = {
+ 'sidebarwidth': 300
+}
+
html_static_path = ['_static']
python_display_short_literal_types = True
-intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
+intersphinx_mapping = {
+ 'python': ('https://docs.python.org/3', None),
+ 'requests': ('https://requests.readthedocs.io/en/latest/', None)
+}
doctest_global_setup = """
import bbss
diff --git a/docs/index.rst b/docs/index.rst
index 963c702..8e82f55 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -35,6 +35,11 @@ bbss.site
Whether the site was generated from a default directory, or a user-supplied one
+ .. py:attribute:: root
+ :type: str
+
+ The base URL of the BBSS directory
+
.. py:attribute:: has_sizes_txt
:type: bool
@@ -50,6 +55,21 @@ bbss.site
A list of friend sites found at the site
+ .. doctest::
+
+ >>> site = bbss.site.Site('aleteoryx.me')
+ >>> for size in site.sizes:
+ ... print(f"{size.entry} @ {size.url()}")
+ ... if size.exists():
+ ... for button in size.get():
+ ... print(f"===> {button.entry} @ {button.url()}")
+ ... else:
+ ... print("...doesn't seem to exist!")
+ ...
+ 88x31 @ https://aleteoryx.me/BBSS/88x31/list.txt
+ ===> ame.gif @ https://aleteoryx.me/BBSS/88x31/ame.gif
+ ===> amev2.gif @ https://aleteoryx.me/BBSS/88x31/amev2.gif
+
bbss.lists
==========
@@ -81,7 +101,7 @@ bbss.lists
.. py:class:: ListFileEntry(entry, comment)
- The base class for all listfile entries.
+ The base class for all listfile entries
:param str entry: The main content of the entry
:param comment: The comment, if present
@@ -89,7 +109,7 @@ bbss.lists
.. py:class:: BaseListFile(contents)
- The base class for all listfile representations.
+ The base class for all listfile representations
It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
@@ -105,20 +125,12 @@ bbss.lists
.. py:class:: ListFile(contents)
- A representation of an arbitrary listfile.
+ A representation of an arbitrary listfile
It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
:param str contents: The contents of the source listfile
- .. py:classmethod:: from_url(url)
-
- Alternate constructor, which will attempt to download the listfile at ``url``.
-
- :param str url: The URL to download from.
- :return: A representation of the remote file, if available
- :rtype: BaseListFile | None
-
.. doctest::
>>> contents = """
@@ -140,6 +152,177 @@ bbss.lists
``this is a comment on entry two''
> entry 3
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``.
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote file, if available
+ :rtype: BaseListFile | None
+
+bbss.buttons
+============
+
+.. py:module:: bbss.buttons
+
+ .. py:class:: ButtonListFileEntry(entry, comment, root)
+
+ A representation of a button image
+
+ :param str entry: The button's filename
+ :param comment: The comment for this button
+ :type comment: str or None
+ :param str root: The URL that this button is a child of
+
+ .. py:method:: url()
+
+ :return: The URL of the button file
+ :rtype: str
+
+ .. py:method:: exists()
+
+ :return: Whether the button actually exists on the server
+ :rtype: bool
+
+ .. py:method:: get()
+
+ :return: The HTTP response from trying to ``GET`` the button
+ :rtype: requests.Response
+
+ .. py:class:: ButtonListFile(contents)
+
+ A representation of a list of buttons
+
+ It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
+
+ :param str contents: The contents of the source listfile
+
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``.
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote button list, if available
+ :rtype: ButtonListFile | None
+
+ .. doctest::
+
+ >>> buttons = bbss.buttons.ButtonListFile \
+ ... .from_url("https://aleteoryx.me/BBSS/88x31/list.txt")
+ >>> for button in buttons:
+ ... print(button.url())
+ ...
+ https://aleteoryx.me/BBSS/88x31/ame.gif
+ https://aleteoryx.me/BBSS/88x31/amev2.gif
+
+bbss.sizes
+============
+
+.. py:module:: bbss.sizes
+
+ .. py:class:: SizeListFileEntry(entry, comment, root)
+
+ A representation of a given size for buttons
+
+ :param str entry: The actual size
+ :param comment: The comment for this size
+ :type comment: str or None
+ :param str root: The BBSS directory that this size is within
+
+ .. py:method:: url()
+
+ :return: The URL of the size's button list
+ :rtype: str
+
+ .. py:method:: exists()
+
+ :return: Whether the size's button list file exists
+ :rtype: bool
+
+ .. py:method:: get()
+
+ :return: The actual button list, if available
+ :rtype: bbss.buttons.ButtonListFile
+
+ .. py:method:: dims()
+
+ :return: The dimensions of the size, ``(x, y)``, if they can be parsed from the name
+ :rtype: (int, int) or None
+
+ .. py:class:: SizeListFile(contents)
+
+ A representation of a list of button sizes
+
+ It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
+
+ :param str contents: The contents of the source listfile
+
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote size list, if available
+ :rtype: ButtonListFile | None
+
+bbss.friends
+============
+
+.. py:module:: bbss.friends
+
+ .. py:class:: FriendListFileEntry(entry, comment)
+
+ A representation of a friend site
+
+ :param str entry: The actual size
+ :param comment: The comment for this size
+ :type comment: str or None
+
+ .. py:attribute:: url
+ :type: str
+
+ The URL of the size's button list
+
+ .. py:attribute:: domain
+ :type: str
+
+ The domain of the friend site
+
+ .. py:attribute:: scheme
+ :type: str
+
+ The scheme of the friend site
+
+ .. py:attribute:: path
+ :type: str
+
+ The optional path of the remote BBSS directory
+
+ .. py:method:: exists()
+
+ :return: Whether the size's button list file exists
+ :rtype: bool
+
+ .. py:method:: get()
+
+ :return: The remote site
+ :rtype: bbss.site.Size
+
+ .. py:class:: FriendListFile(contents)
+
+ A representation of a list of friend sites
+
+ It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
+
+ :param str contents: The contents of the source listfile
+
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote friend list, if available
+ :rtype: ButtonListFile | None
==================
Indices and tables
diff --git a/src/bbss/site.py b/src/bbss/site.py
index 134ee8b..3829ae9 100644
--- a/src/bbss/site.py
+++ b/src/bbss/site.py
@@ -6,7 +6,7 @@ from collections.abc import Sequence
import requests
class Site:
- def __init__(self, domain: str, path: Optional[str], *, scheme: Optional[str]):
+ def __init__(self, domain: str, path: Optional[str] = None, *, scheme: Optional[str] = None):
base = (scheme if scheme is not None else "https") + "://" + domain
hit_sizefile = False
diff --git a/src/bbss/sizes.py b/src/bbss/sizes.py
index f71a94c..c1d58f5 100644
--- a/src/bbss/sizes.py
+++ b/src/bbss/sizes.py
@@ -1,9 +1,10 @@
from bbss.lists import BaseListFile, ListFileEntry, parse_listfile
from bbss.buttons import ButtonListFile
from dataclasses import dataclass
-from typing import Optional, Self
+from typing import Optional, Self, Tuple
from collections.abc import Sequence
import requests
+import re
@dataclass(frozen=True)
class SizeListFileEntry(ListFileEntry):
@@ -18,6 +19,10 @@ class SizeListFileEntry(ListFileEntry):
def get(self) -> Optional[ButtonListFile]:
return ButtonListFile.from_url(self.url())
+ def dims(self) -> Optional[Tuple[int, int]]:
+ matches = re.match("^([0-9]+)x([0-9]+)$", self.entry)
+ return (matches[1], matches[2]) if matches is not None else None
+
class SizeListFile(BaseListFile[SizeListFileEntry]):
def __init__(self, contents: str, root: str):
super().__init__(contents)