From 96445aca821bd40a6c66a54f01624dd010b308d0 Mon Sep 17 00:00:00 2001 From: psilabs-dev <113860476+psilabs-dev@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:51:21 -0700 Subject: [PATCH 1/5] chore: promote patch version 2.4.5 -> 2.4.6 --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5ea882f..7999bb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ license = { file = "LICENSE" } authors = [ { name = "psilabs-dev" } ] -version = "2.4.5" +version = "2.4.6" dependencies = [ "aiofiles>=25.1.0", "celery>=5.5.3", diff --git a/uv.lock b/uv.lock index 44a01a8..2d32005 100644 --- a/uv.lock +++ b/uv.lock @@ -896,7 +896,7 @@ wheels = [ [[package]] name = "pixivutil-server" -version = "2.4.5" +version = "2.4.6" source = { editable = "." } dependencies = [ { name = "aiofiles" }, From b567b876b5f46a7a5594aa829c42bd8315869590 Mon Sep 17 00:00:00 2001 From: psilabs-dev <113860476+psilabs-dev@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:57:44 -0700 Subject: [PATCH 2/5] chore: update PixivUtil2 submodule to server-mode head (88b5957) --- PixivUtil2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PixivUtil2 b/PixivUtil2 index dd3d9ef..88b5957 160000 --- a/PixivUtil2 +++ b/PixivUtil2 @@ -1 +1 @@ -Subproject commit dd3d9efec27b85a15e73a3788210e28abb36d4f4 +Subproject commit 88b5957761045b544db505bd015357bd7105fb16 From b85a54463c6e9dbf3fd4c8d894189dbfafab1aea Mon Sep 17 00:00:00 2001 From: psilabs-dev <113860476+psilabs-dev@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:42:32 -0700 Subject: [PATCH 3/5] chore: update PixivUtil2 submodule to server-mode/dev head (856cb33) Brings in the artwork engagement stats feature (pixiv_stats table, insertStats/selectStatsByImageId, autoAddStats config) cherry-picked onto server-mode/dev. Co-Authored-By: Claude Opus 4.8 (1M context) --- PixivUtil2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PixivUtil2 b/PixivUtil2 index 88b5957..856cb33 160000 --- a/PixivUtil2 +++ b/PixivUtil2 @@ -1 +1 @@ -Subproject commit 88b5957761045b544db505bd015357bd7105fb16 +Subproject commit 856cb3340e7d8d92e82d95d77e6e4260ac864115 From e7f58c5c0b2f23b8d349e31480d44c4f67ab737a Mon Sep 17 00:00:00 2001 From: psilabs-dev <113860476+psilabs-dev@users.noreply.github.com> Date: Fri, 10 Jul 2026 06:49:20 -0700 Subject: [PATCH 4/5] feat: wire pixiv_stats through server read and delete paths Mirrors the existing pixiv_date_info handling for the new engagement stats table introduced by the PixivUtil2 server-mode/dev engine: - Add PixivStats DTO to shared models and re-export chains (common, server metadata compat module, client). - Expose stats on PixivImageComplete via get_image_data_by_id. - Cascade-delete pixiv_stats rows on artwork deletion when delete_metadata is set. Co-Authored-By: Claude Opus 4.8 (1M context) --- PixivServer/models/pixiv_metadata.py | 2 ++ PixivServer/repository/pixivutil.py | 26 ++++++++++++++++++- PixivServer/routers/download_queue.py | 2 +- PixivServer/service/pixiv.py | 1 + .../pixivutil_server_common/__init__.py | 2 ++ .../pixivutil_server_common/models.py | 12 +++++++++ PixivUtilClient/pixivutil_client/models.py | 2 ++ 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/PixivServer/models/pixiv_metadata.py b/PixivServer/models/pixiv_metadata.py index 001058d..0c17b72 100644 --- a/PixivServer/models/pixiv_metadata.py +++ b/PixivServer/models/pixiv_metadata.py @@ -14,6 +14,7 @@ PixivMasterTag, PixivMemberPortfolio, PixivSeriesInfo, + PixivStats, PixivTagInfo, PixivTagTranslation, ) @@ -30,6 +31,7 @@ "PixivMasterTag", "PixivMemberPortfolio", "PixivSeriesInfo", + "PixivStats", "PixivTagInfo", "PixivTagTranslation", ] diff --git a/PixivServer/repository/pixivutil.py b/PixivServer/repository/pixivutil.py index 144e06a..a922cb7 100644 --- a/PixivServer/repository/pixivutil.py +++ b/PixivServer/repository/pixivutil.py @@ -14,6 +14,7 @@ PixivMasterTag, PixivMemberPortfolio, PixivSeriesInfo, + PixivStats, PixivTagInfo, PixivTagTranslation, ) @@ -531,13 +532,36 @@ def get_image_data_by_id(self, image_id: int) -> PixivImageComplete: last_update_date=date_row[4] ) + # Get server-mode engagement stats + cursor.execute( + """SELECT image_id, view_count, like_count, bookmark_count, + comment_count, response_count, created_date, last_update_date + FROM pixiv_stats + WHERE image_id = ?""", + (image_id,) + ) + stats_row = cursor.fetchone() + stats = None + if stats_row is not None: + stats = PixivStats( + image_id=stats_row[0], + view_count=stats_row[1], + like_count=stats_row[2], + bookmark_count=stats_row[3], + comment_count=stats_row[4], + response_count=stats_row[5], + created_date=stats_row[6], + last_update_date=stats_row[7] + ) + return PixivImageComplete( image=image, member=member, pages=pages, series=series, tags=tags, - dates=dates + dates=dates, + stats=stats ) except Exception as e: logger.error(f"Error getting image data for {image_id}: {e}") diff --git a/PixivServer/routers/download_queue.py b/PixivServer/routers/download_queue.py index e9f20be..b300ea0 100644 --- a/PixivServer/routers/download_queue.py +++ b/PixivServer/routers/download_queue.py @@ -160,7 +160,7 @@ async def queue_delete_artwork_by_id( Args: artwork_id: The Pixiv artwork ID to delete - delete_metadata: If True (default), also deletes metadata (date_info, ai_info, series). + delete_metadata: If True (default), also deletes metadata (date_info, stats, ai_info, series). If False, only deletes artwork files and basic records. This is a queue operation as it operates on a sqlite database. diff --git a/PixivServer/service/pixiv.py b/PixivServer/service/pixiv.py index 5ec0820..38dec2f 100644 --- a/PixivServer/service/pixiv.py +++ b/PixivServer/service/pixiv.py @@ -345,6 +345,7 @@ def delete_artwork_by_id(self, request: DeleteArtworkByIdRequest): if request.delete_metadata: cursor.execute("DELETE FROM pixiv_date_info WHERE image_id = ?", (request.artwork_id,)) + cursor.execute("DELETE FROM pixiv_stats WHERE image_id = ?", (request.artwork_id,)) cursor.execute("DELETE FROM pixiv_ai_info WHERE image_id = ?", (request.artwork_id,)) cursor.execute("DELETE FROM pixiv_image_to_series WHERE image_id = ?", (request.artwork_id,)) PixivHelper.print_and_log("info", f"Deleted artwork and metadata from database: {request.artwork_id}") diff --git a/PixivServerCommon/pixivutil_server_common/__init__.py b/PixivServerCommon/pixivutil_server_common/__init__.py index e2a6c01..59ad30a 100644 --- a/PixivServerCommon/pixivutil_server_common/__init__.py +++ b/PixivServerCommon/pixivutil_server_common/__init__.py @@ -10,6 +10,7 @@ PixivMasterTag, PixivMemberPortfolio, PixivSeriesInfo, + PixivStats, PixivTagInfo, PixivTagTranslation, QueueTaskResponse, @@ -30,6 +31,7 @@ "PixivMasterTag", "PixivMemberPortfolio", "PixivSeriesInfo", + "PixivStats", "PixivTagInfo", "PixivTagTranslation", "QueueTaskResponse", diff --git a/PixivServerCommon/pixivutil_server_common/models.py b/PixivServerCommon/pixivutil_server_common/models.py index c887d54..f71aa4a 100644 --- a/PixivServerCommon/pixivutil_server_common/models.py +++ b/PixivServerCommon/pixivutil_server_common/models.py @@ -90,6 +90,17 @@ class PixivDateInfo(BaseModel): last_update_date: str +class PixivStats(BaseModel): + image_id: int + view_count: int + like_count: int + bookmark_count: int + comment_count: int + response_count: int + created_date: str + last_update_date: str + + class PixivTagTranslation(BaseModel): tag_id: str translation_type: str @@ -134,6 +145,7 @@ class PixivImageComplete(BaseModel): series: tuple[PixivImageToSeries, PixivMasterSeries] | None = Field(None) tags: list[tuple[PixivImageToTag, PixivMasterTag, PixivTagTranslation | None]] dates: PixivDateInfo | None = Field(None) + stats: PixivStats | None = Field(None) class PixivTagInfo(BaseModel): diff --git a/PixivUtilClient/pixivutil_client/models.py b/PixivUtilClient/pixivutil_client/models.py index 14571fc..ccdee50 100644 --- a/PixivUtilClient/pixivutil_client/models.py +++ b/PixivUtilClient/pixivutil_client/models.py @@ -19,6 +19,7 @@ PixivMasterTag, PixivMemberPortfolio, PixivSeriesInfo, + PixivStats, PixivTagInfo, PixivTagTranslation, QueueTaskResponse, @@ -44,6 +45,7 @@ "PixivMasterTag", "PixivMemberPortfolio", "PixivSeriesInfo", + "PixivStats", "PixivTagInfo", "PixivTagTranslation", "QueueTaskResponse", From 12e866da04775b2615e257f87e94b44cac066077 Mon Sep 17 00:00:00 2001 From: psilabs-dev <113860476+psilabs-dev@users.noreply.github.com> Date: Fri, 10 Jul 2026 07:53:15 -0700 Subject: [PATCH 5/5] don't log expected 'not found' KeyError as an error --- PixivServer/repository/pixivutil.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PixivServer/repository/pixivutil.py b/PixivServer/repository/pixivutil.py index a922cb7..9f51462 100644 --- a/PixivServer/repository/pixivutil.py +++ b/PixivServer/repository/pixivutil.py @@ -103,6 +103,9 @@ def get_member_data_by_id(self, member_id: int) -> PixivMemberPortfolio: ] return PixivMemberPortfolio(member=member, images=images) + except KeyError: + # Expected when the member is not yet in the DB; let the caller decide. + raise except Exception as e: logger.error(f"Error getting member data for {member_id}: {e}") raise @@ -563,6 +566,9 @@ def get_image_data_by_id(self, image_id: int) -> PixivImageComplete: dates=dates, stats=stats ) + except KeyError: + # Expected when the image (or its member) is not yet in the DB; let the caller decide. + raise except Exception as e: logger.error(f"Error getting image data for {image_id}: {e}") raise