From f92dd65d35bfeed22af408727d3c5177e3987b52 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 14:08:27 +0200 Subject: [PATCH 01/11] tests.fappi,.parse - check user folders in submissions --- tests/test_faapi.py | 13 +++++++++++-- tests/test_parse.py | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/test_faapi.py b/tests/test_faapi.py index 23c411c..c1f3d71 100644 --- a/tests/test_faapi.py +++ b/tests/test_faapi.py @@ -47,9 +47,11 @@ def submission_test_data() -> dict: def journal_test_data() -> dict: return load((__root__ / "test_journal.json").open()) + def compare_dates(a: datetime, b: datetime, max_variance: int) -> bool: return (b - timedelta(hours=max_variance)) <= a <= (b + timedelta(hours=max_variance)) + def remove_user_icons(html: str) -> str: return sub(r"a\.furaffinity\.net/\d{8}/[^. ]+.gif", "", html) @@ -139,7 +141,8 @@ def test_submission(cookies: RequestsCookieJar, submission_test_data: dict): assert submission.id == submission_dict["id"] == submission_test_data["id"] assert submission.title == submission_dict["title"] == submission_test_data["title"] - assert submission.author.name.lower() == submission_dict["author"]["name"].lower() == submission_test_data["author"]["name"].lower() + assert submission.author.name.lower() == submission_dict["author"]["name"].lower() == \ + submission_test_data["author"]["name"].lower() assert submission.author.avatar_url == submission_dict["author"]["avatar_url"] != "" assert compare_dates(submission.date, submission_dict["date"], 1) assert compare_dates(submission.date, datetime.fromisoformat(submission_test_data["date"]), 1) @@ -156,6 +159,11 @@ def test_submission(cookies: RequestsCookieJar, submission_test_data: dict): assert submission.type == submission_dict["type"] == submission_test_data["type"] assert submission.mentions == submission_dict["mentions"] == submission_test_data["mentions"] assert submission.folder == submission_dict["folder"] == submission_test_data["folder"] + assert ( + [f._asdict() for f in submission.user_folders] == + submission_dict["user_folders"] == + submission_test_data["user_folders"] + ) assert submission.file_url == submission_dict["file_url"] != "" assert submission.thumbnail_url == submission_dict["thumbnail_url"] != "" assert submission.prev == submission_dict["prev"] == submission_test_data["prev"] @@ -199,7 +207,8 @@ def test_journal(cookies: RequestsCookieJar, journal_test_data: dict): assert journal.id == journal_dict["id"] == journal_test_data["id"] assert journal.title == journal_dict["title"] == journal_test_data["title"] - assert journal.author.name.lower() == journal_dict["author"]["name"].lower() == journal_test_data["author"]["name"].lower() + assert journal.author.name.lower() == journal_dict["author"]["name"].lower() == journal_test_data["author"][ + "name"].lower() assert compare_dates(journal.author.join_date, journal_dict["author"]["join_date"], 1) assert compare_dates(journal.author.join_date, datetime.fromisoformat(journal_test_data["author"]["join_date"]), 1) assert journal.author.avatar_url == journal_dict["author"]["avatar_url"] != "" diff --git a/tests/test_parse.py b/tests/test_parse.py index 441727f..2dfa424 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -138,6 +138,7 @@ def test_parse_submission_page(session: Session, submission_test_data: dict): assert result["type"] == submission_test_data["type"] assert result["mentions"] == submission_test_data["mentions"] assert result["folder"] == submission_test_data["folder"] + assert result["user_folders"] == {tuple(f.values()) for f in submission_test_data["user_folders"]} assert [list(f) for f in result["user_folders"]] == submission_test_data["user_folders_tuples"] assert result["file_url"] != "" assert result["thumbnail_url"] != "" From 880f9421afd650a3888dd37bd5f45a0c32bdfb39 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 18:25:41 +0200 Subject: [PATCH 02/11] parse:parse_submission_page - use more precise selector for folder tag --- faapi/parse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/faapi/parse.py b/faapi/parse.py index 6a41653..76f8f24 100644 --- a/faapi/parse.py +++ b/faapi/parse.py @@ -524,7 +524,7 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: tag_category2: Optional[Tag] = tag_info.select_one("span.type-name") tag_species: Optional[Tag] = tag_info.select("span")[bool(tag_category1) + bool(tag_category2)] tag_description: Optional[Tag] = sub_page.select_one("div.submission-description") - tag_folder: Optional[Tag] = sub_page.select_one("a.button[href^='/scraps/'],a.button[href^='/gallery/']") + tag_folder: Optional[Tag] = sub_page.select_one("div.favorite-nav a.button[href^='/scraps/'],a.button[href^='/gallery/']") tag_file_url: Optional[Tag] = sub_page.select_one("div.download a") tag_thumbnail_url: Optional[Tag] = sub_page.select_one("img#submissionImg") tag_prev: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:nth-child(1)") From 06a1772a789eeaac59ebb903cc521609f504b6f0 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 18:35:21 +0200 Subject: [PATCH 03/11] tests.parse:test_parse_submission_page - fix comparison of user folders --- tests/test_parse.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_parse.py b/tests/test_parse.py index 2dfa424..6b933b4 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -138,8 +138,7 @@ def test_parse_submission_page(session: Session, submission_test_data: dict): assert result["type"] == submission_test_data["type"] assert result["mentions"] == submission_test_data["mentions"] assert result["folder"] == submission_test_data["folder"] - assert result["user_folders"] == {tuple(f.values()) for f in submission_test_data["user_folders"]} - assert [list(f) for f in result["user_folders"]] == submission_test_data["user_folders_tuples"] + assert result["user_folders"] == [tuple(f.values()) for f in submission_test_data["user_folders"]] assert result["file_url"] != "" assert result["thumbnail_url"] != "" assert result["prev"] == submission_test_data["prev"] From e02c386e791559eba74d20728b31ec32d72f7ec9 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 18:45:37 +0200 Subject: [PATCH 04/11] parse - fix line too long --- faapi/parse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/faapi/parse.py b/faapi/parse.py index 76f8f24..e0454d2 100644 --- a/faapi/parse.py +++ b/faapi/parse.py @@ -524,7 +524,9 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: tag_category2: Optional[Tag] = tag_info.select_one("span.type-name") tag_species: Optional[Tag] = tag_info.select("span")[bool(tag_category1) + bool(tag_category2)] tag_description: Optional[Tag] = sub_page.select_one("div.submission-description") - tag_folder: Optional[Tag] = sub_page.select_one("div.favorite-nav a.button[href^='/scraps/'],a.button[href^='/gallery/']") + tag_folder: Optional[Tag] = ( + sub_page.select_one("div.favorite-nav a.button[href^='/scraps/'],a.button[href^='/gallery/']") + ) tag_file_url: Optional[Tag] = sub_page.select_one("div.download a") tag_thumbnail_url: Optional[Tag] = sub_page.select_one("img#submissionImg") tag_prev: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:nth-child(1)") From d942acb004be45f1aa1c7dda17ba6ed21d70a504 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 18:50:13 +0200 Subject: [PATCH 05/11] changelog:3.12.2 - add fixes --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aea9ac..c9f2acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v3.12.2 + +### Fixes + +* Fix imprecise selector for submission folder (gallery/scraps) + ## v3.12.1 ### Fixes From 0ff3bae7e8bee2a5efae5ad639040808bcf1cc8a Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 18:50:51 +0200 Subject: [PATCH 06/11] version - patch 3.12.1 > 3.12.2 --- faapi/__version__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/faapi/__version__.py b/faapi/__version__.py index 555cdb2..e2257b3 100644 --- a/faapi/__version__.py +++ b/faapi/__version__.py @@ -1 +1 @@ -__version__ = "3.12.1" +__version__ = "3.12.2" diff --git a/pyproject.toml b/pyproject.toml index 0cbefd4..b36e43d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "faapi" -version = "3.12.1" +version = "3.12.2" description = "Python module to implement API-like functionality for the FurAffinity.net website." authors = ["Matteo Campinoti "] license = "EUPL-1.2" From 1f15f148c2f993383d88170d155b56c250d54c77 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 22:28:45 +0200 Subject: [PATCH 07/11] Revert "parse:parse_submission_page - use more precise selector for folder tag" This reverts commit 880f9421 --- faapi/parse.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/faapi/parse.py b/faapi/parse.py index e0454d2..6a41653 100644 --- a/faapi/parse.py +++ b/faapi/parse.py @@ -524,9 +524,7 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: tag_category2: Optional[Tag] = tag_info.select_one("span.type-name") tag_species: Optional[Tag] = tag_info.select("span")[bool(tag_category1) + bool(tag_category2)] tag_description: Optional[Tag] = sub_page.select_one("div.submission-description") - tag_folder: Optional[Tag] = ( - sub_page.select_one("div.favorite-nav a.button[href^='/scraps/'],a.button[href^='/gallery/']") - ) + tag_folder: Optional[Tag] = sub_page.select_one("a.button[href^='/scraps/'],a.button[href^='/gallery/']") tag_file_url: Optional[Tag] = sub_page.select_one("div.download a") tag_thumbnail_url: Optional[Tag] = sub_page.select_one("img#submissionImg") tag_prev: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:nth-child(1)") From dc91923a1c1ec6017921e73fd9061abdb1a9fa88 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 22:31:12 +0200 Subject: [PATCH 08/11] parse:parse_submission_page - use more precise selector for folder tag Fix #27 --- faapi/parse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/faapi/parse.py b/faapi/parse.py index 6a41653..749cf64 100644 --- a/faapi/parse.py +++ b/faapi/parse.py @@ -524,7 +524,9 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: tag_category2: Optional[Tag] = tag_info.select_one("span.type-name") tag_species: Optional[Tag] = tag_info.select("span")[bool(tag_category1) + bool(tag_category2)] tag_description: Optional[Tag] = sub_page.select_one("div.submission-description") - tag_folder: Optional[Tag] = sub_page.select_one("a.button[href^='/scraps/'],a.button[href^='/gallery/']") + tag_folder: Optional[Tag] = ( + sub_page.select_one(".favorite-nav a[href^='/scraps/'], .favorite-nav a[href^='/gallery/']") + ) tag_file_url: Optional[Tag] = sub_page.select_one("div.download a") tag_thumbnail_url: Optional[Tag] = sub_page.select_one("img#submissionImg") tag_prev: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:nth-child(1)") From ccf204e7c87c945c3fb1277b381939cd37578d43 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 22:31:36 +0200 Subject: [PATCH 09/11] changelog:3.12.2 - update fixes --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f2acb..6dd3475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Fixes -* Fix imprecise selector for submission folder (gallery/scraps) +* Fix selector for submission folder (gallery/scraps) in submission pages that did not work with the "minigallery" + navigation turned on ## v3.12.1 From 707f82f77c80be576f5e01fad7c62dea0846c743 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 22:50:31 +0200 Subject: [PATCH 10/11] parse:parse_submission_page - adapt selectors for folder, next, and previous to work with the minigallery setting Fix #27 --- faapi/parse.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/faapi/parse.py b/faapi/parse.py index 749cf64..f644bb4 100644 --- a/faapi/parse.py +++ b/faapi/parse.py @@ -525,12 +525,19 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: tag_species: Optional[Tag] = tag_info.select("span")[bool(tag_category1) + bool(tag_category2)] tag_description: Optional[Tag] = sub_page.select_one("div.submission-description") tag_folder: Optional[Tag] = ( - sub_page.select_one(".favorite-nav a[href^='/scraps/'], .favorite-nav a[href^='/gallery/']") + sub_page.select_one('.favorite-nav a[href^="/scraps/"], .favorite-nav a[href^="/gallery/"]') + or sub_page.select_one('#minigallery a[href^="/scraps/"], #minigallery a[href^="/gallery/"]') ) tag_file_url: Optional[Tag] = sub_page.select_one("div.download a") tag_thumbnail_url: Optional[Tag] = sub_page.select_one("img#submissionImg") - tag_prev: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:nth-child(1)") - tag_next: Optional[Tag] = sub_page.select_one("div.submission-content div.favorite-nav a:last-child") + tag_prev: Optional[Tag] = ( + sub_page.select_one('div.submission-content div.favorite-nav a:nth-child(1)[href^="/view/"]') + or sub_page.select_one(".minigallery-container > div:nth-child(1) figure:last-child a") + ) + tag_next: Optional[Tag] = ( + sub_page.select_one('div.submission-content div.favorite-nav a:last-child[href^="/view/"]') + or sub_page.select_one(".minigallery-container > div:last-child figure:nth-child(1) a") + ) assert tag_id is not None, _raise_exception(ParsingError("Missing id tag")) assert tag_title is not None, _raise_exception(ParsingError("Missing title tag")) @@ -583,10 +590,10 @@ def parse_submission_page(sub_page: BeautifulSoup) -> dict[str, Any]: if thumbnail_url else "" prev_sub: Optional[int] = int( get_attr(tag_prev, "href").strip("/").split("/")[-1] - ) if tag_prev and tag_prev.text.lower() == "newer" else None + ) if tag_prev else None next_sub: Optional[int] = int( get_attr(tag_next, "href").strip("/").split("/")[-1] - ) if tag_next and tag_next.text.lower() == "older" else None + ) if tag_next else None fav_link: Optional[str] = f"{root}{href}" if (href := get_attr(tag_fav, "href")).startswith("/fav/") else None unfav_link: Optional[str] = f"{root}{href}" if (href := get_attr(tag_fav, "href")).startswith("/unfav/") else None user_folders: list[tuple[str, str, str]] = [] From e1b2a280750e0a2d2e2e6c038bf735ecddcb45b9 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Sat, 4 Apr 2026 22:53:06 +0200 Subject: [PATCH 11/11] changelog:3.12.2 - update fixes --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dd3475..b9e2480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,9 @@ ### Fixes -* Fix selector for submission folder (gallery/scraps) in submission pages that did not work with the "minigallery" - navigation turned on +* Fix selectors for submission folder (gallery/scraps), next submission, and previous submission in submission pages + that did not work with the "minigallery" navigation turned on + * Fix issue [#27](https://github.com/FurryCoders/FAAPI/issues/27) ## v3.12.1