pysaka 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. pysaka-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +72 -0
  2. pysaka-0.3.0/.github/workflows/publish.yml +62 -0
  3. pysaka-0.3.0/.github/workflows/test-publish.yml +146 -0
  4. pysaka-0.3.0/.github/workflows/test.yml +33 -0
  5. pysaka-0.3.0/.gitignore +63 -0
  6. pysaka-0.3.0/CHANGELOG.md +109 -0
  7. pysaka-0.3.0/CONTRIBUTING.md +265 -0
  8. pysaka-0.3.0/PKG-INFO +228 -0
  9. pysaka-0.3.0/README.md +194 -0
  10. pysaka-0.3.0/docs/API.md +354 -0
  11. pysaka-0.3.0/docs/RELEASE_GUIDE.md +65 -0
  12. pysaka-0.3.0/examples/auth_flow.py +25 -0
  13. pysaka-0.3.0/examples/download_content.py +35 -0
  14. pysaka-0.3.0/examples/fetch_profile.py +36 -0
  15. pysaka-0.3.0/pyproject.toml +124 -0
  16. pysaka-0.3.0/scripts/login.py +70 -0
  17. pysaka-0.3.0/src/pysaka/__init__.py +42 -0
  18. pysaka-0.3.0/src/pysaka/auth.py +344 -0
  19. pysaka-0.3.0/src/pysaka/blog/__init__.py +90 -0
  20. pysaka-0.3.0/src/pysaka/blog/base.py +224 -0
  21. pysaka-0.3.0/src/pysaka/blog/config.py +79 -0
  22. pysaka-0.3.0/src/pysaka/blog/hinatazaka.py +506 -0
  23. pysaka-0.3.0/src/pysaka/blog/nogizaka.py +433 -0
  24. pysaka-0.3.0/src/pysaka/blog/sakurazaka.py +550 -0
  25. pysaka-0.3.0/src/pysaka/client.py +994 -0
  26. pysaka-0.3.0/src/pysaka/config.py +23 -0
  27. pysaka-0.3.0/src/pysaka/credentials.py +209 -0
  28. pysaka-0.3.0/src/pysaka/exceptions.py +41 -0
  29. pysaka-0.3.0/src/pysaka/logging.py +171 -0
  30. pysaka-0.3.0/src/pysaka/manager.py +470 -0
  31. pysaka-0.3.0/src/pysaka/media.py +110 -0
  32. pysaka-0.3.0/src/pysaka/utils.py +166 -0
  33. pysaka-0.3.0/tests/conftest.py +20 -0
  34. pysaka-0.3.0/tests/test_auth.py +88 -0
  35. pysaka-0.3.0/tests/test_auth_extended.py +276 -0
  36. pysaka-0.3.0/tests/test_bench.py +32 -0
  37. pysaka-0.3.0/tests/test_blog.py +198 -0
  38. pysaka-0.3.0/tests/test_blog_scrapers.py +521 -0
  39. pysaka-0.3.0/tests/test_client.py +196 -0
  40. pysaka-0.3.0/tests/test_client_extended.py +448 -0
  41. pysaka-0.3.0/tests/test_client_new_apis.py +383 -0
  42. pysaka-0.3.0/tests/test_client_refresh.py +152 -0
  43. pysaka-0.3.0/tests/test_client_storage.py +72 -0
  44. pysaka-0.3.0/tests/test_coverage_boost.py +225 -0
  45. pysaka-0.3.0/tests/test_credentials.py +62 -0
  46. pysaka-0.3.0/tests/test_credentials_extended.py +277 -0
  47. pysaka-0.3.0/tests/test_integration.py +154 -0
  48. pysaka-0.3.0/tests/test_logging.py +176 -0
  49. pysaka-0.3.0/tests/test_manager.py +196 -0
  50. pysaka-0.3.0/tests/test_media.py +213 -0
  51. pysaka-0.3.0/tests/test_properties.py +41 -0
  52. pysaka-0.3.0/tests/test_utils.py +128 -0
  53. pysaka-0.3.0/uv.lock +2882 -0
@@ -0,0 +1,72 @@
1
+ ## Description
2
+
3
+ <!-- Provide a clear and concise description of what this PR does. -->
4
+
5
+
6
+
7
+ ## Type of Change
8
+
9
+ <!-- Mark the appropriate option with an [x] -->
10
+
11
+ - [ ] `feat` - New feature
12
+ - [ ] `fix` - Bug fix
13
+ - [ ] `docs` - Documentation only
14
+ - [ ] `refactor` - Code refactoring (no behavior change)
15
+ - [ ] `test` - Adding or updating tests
16
+ - [ ] `build` - Build system or CI changes
17
+ - [ ] `chore` - Maintenance tasks
18
+
19
+ ## Related Issues
20
+
21
+ <!-- Link any related issues. Use "Closes #123" to auto-close. -->
22
+
23
+ Closes #
24
+
25
+ ## Changes Made
26
+
27
+ <!-- List the specific changes in bullet points -->
28
+
29
+ -
30
+ -
31
+ -
32
+
33
+ ## Testing Performed
34
+
35
+ <!-- Describe how you tested these changes -->
36
+
37
+ - [ ] Unit tests pass (`uv run pytest`)
38
+ - [ ] Type checking passes (`uv run mypy .`)
39
+ - [ ] Linting passes (`uv run ruff check .`)
40
+ - [ ] Integration tests pass (if applicable)
41
+
42
+ **Test Details:**
43
+ <!-- Describe specific testing performed -->
44
+
45
+
46
+
47
+ ## Checklist
48
+
49
+ <!-- Ensure all items are checked before requesting review -->
50
+
51
+ - [ ] My code follows the project's style guidelines
52
+ - [ ] I have performed a self-review of my code
53
+ - [ ] I have added docstrings to new public functions/classes
54
+ - [ ] I have added tests that prove my fix/feature works
55
+ - [ ] New and existing tests pass locally
56
+ - [ ] Type hints are complete for all new public APIs
57
+ - [ ] **I have updated `CHANGELOG.md` under the `[Unreleased]` section**
58
+
59
+ ## Changelog Entry
60
+
61
+ <!-- Copy your CHANGELOG.md addition here for easy review -->
62
+
63
+ ```markdown
64
+ ### Added/Changed/Fixed
65
+ - Your changelog entry here (#PR-number)
66
+ ```
67
+
68
+ ## Additional Notes
69
+
70
+ <!-- Any additional context for reviewers -->
71
+
72
+
@@ -0,0 +1,62 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*.*.*' # Trigger on version tags like v0.1.1, v1.0.0
7
+ release:
8
+ types: [published] # Also trigger on GitHub Release (creates tag if needed)
9
+
10
+ permissions:
11
+ id-token: write # Required for trusted publishing
12
+
13
+ jobs:
14
+ build:
15
+ name: Build distribution
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v5
22
+
23
+ - name: Set up Python
24
+ run: uv python install 3.12
25
+
26
+ - name: Verify version matches tag
27
+ if: startsWith(github.ref, 'refs/tags/v')
28
+ run: |
29
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
30
+ PKG_VERSION=$(grep -Po '(?<=^version = ")[^"]*' pyproject.toml)
31
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
32
+ echo "Error: Tag version ($TAG_VERSION) does not match package version ($PKG_VERSION)"
33
+ exit 1
34
+ fi
35
+ echo "Version verified: $PKG_VERSION"
36
+
37
+ - name: Build package
38
+ run: uv build
39
+
40
+ - name: Upload distribution artifacts
41
+ uses: actions/upload-artifact@v4
42
+ with:
43
+ name: python-package-distributions
44
+ path: dist/
45
+
46
+ publish-pypi:
47
+ name: Publish to PyPI
48
+ needs: build
49
+ runs-on: ubuntu-latest
50
+ environment:
51
+ name: pypi
52
+ url: https://pypi.org/p/pysaka
53
+ steps:
54
+ - name: Download distribution artifacts
55
+ uses: actions/download-artifact@v4
56
+ with:
57
+ name: python-package-distributions
58
+ path: dist/
59
+
60
+ - name: Publish to PyPI
61
+ uses: pypa/gh-action-pypi-publish@release/v1
62
+ # No API token needed - uses trusted publishing via OIDC
@@ -0,0 +1,146 @@
1
+ name: Test Publish to TestPyPI
2
+
3
+ on:
4
+ # Manual trigger for dry-run testing
5
+ workflow_dispatch:
6
+ inputs:
7
+ version_suffix:
8
+ description: 'Version suffix (e.g., dev1, rc1). Leave empty for timestamp-based suffix.'
9
+ required: false
10
+ default: ''
11
+ # Automatically run on PRs to main for validation
12
+ pull_request:
13
+ branches: [main]
14
+ paths:
15
+ - 'pyproject.toml'
16
+ - 'src/**'
17
+ - '.github/workflows/publish.yml'
18
+ - '.github/workflows/test-publish.yml'
19
+
20
+ permissions:
21
+ id-token: write # Required for trusted publishing
22
+
23
+ jobs:
24
+ test-build:
25
+ name: Build and Test Publish
26
+ runs-on: ubuntu-latest
27
+ outputs:
28
+ test_version: ${{ steps.test_version.outputs.test_version }}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@v5
34
+
35
+ - name: Set up Python
36
+ run: uv python install 3.12
37
+
38
+ - name: Get base version
39
+ id: version
40
+ run: |
41
+ BASE_VERSION=$(grep -Po '(?<=^version = ")[^"]*' pyproject.toml)
42
+ echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
43
+ echo "Base version: $BASE_VERSION"
44
+
45
+ - name: Generate test version
46
+ id: test_version
47
+ env:
48
+ INPUT_SUFFIX: ${{ github.event.inputs.version_suffix }}
49
+ run: |
50
+ BASE="${{ steps.version.outputs.base_version }}"
51
+
52
+ # Use provided suffix or generate timestamp-based one
53
+ if [ -n "$INPUT_SUFFIX" ]; then
54
+ SUFFIX="$INPUT_SUFFIX"
55
+ else
56
+ # Use timestamp for unique version
57
+ TIMESTAMP=$(date +%Y%m%d%H%M%S)
58
+ SUFFIX="dev${TIMESTAMP}"
59
+ fi
60
+
61
+ TEST_VERSION="${BASE}.${SUFFIX}"
62
+ echo "test_version=$TEST_VERSION" >> $GITHUB_OUTPUT
63
+ echo "Test version: $TEST_VERSION"
64
+
65
+ - name: Update version for TestPyPI
66
+ env:
67
+ TEST_VERSION: ${{ steps.test_version.outputs.test_version }}
68
+ run: |
69
+ # Create a temporary version for TestPyPI
70
+ sed -i "s/^version = \".*\"/version = \"$TEST_VERSION\"/" pyproject.toml
71
+ echo "Updated pyproject.toml version:"
72
+ grep '^version' pyproject.toml
73
+
74
+ - name: Build package
75
+ run: uv build
76
+
77
+ - name: List built artifacts
78
+ run: ls -la dist/
79
+
80
+ - name: Upload distribution artifacts
81
+ uses: actions/upload-artifact@v4
82
+ with:
83
+ name: test-python-package-distributions
84
+ path: dist/
85
+
86
+ publish-testpypi:
87
+ name: Publish to TestPyPI
88
+ needs: test-build
89
+ runs-on: ubuntu-latest
90
+ # Only publish on manual trigger, not on PR (to save TestPyPI quota)
91
+ if: github.event_name == 'workflow_dispatch'
92
+ environment:
93
+ name: testpypi
94
+ url: https://test.pypi.org/p/pysaka
95
+ steps:
96
+ - name: Download distribution artifacts
97
+ uses: actions/download-artifact@v4
98
+ with:
99
+ name: test-python-package-distributions
100
+ path: dist/
101
+
102
+ - name: Publish to TestPyPI
103
+ uses: pypa/gh-action-pypi-publish@release/v1
104
+ with:
105
+ repository-url: https://test.pypi.org/legacy/
106
+ # Uses trusted publishing via OIDC - no API token needed
107
+ # Requires TestPyPI trusted publisher to be configured
108
+
109
+ verify-install:
110
+ name: Verify Installation from TestPyPI
111
+ needs: [test-build, publish-testpypi]
112
+ runs-on: ubuntu-latest
113
+ if: github.event_name == 'workflow_dispatch'
114
+ strategy:
115
+ matrix:
116
+ python-version: ["3.9", "3.12"]
117
+ steps:
118
+ - name: Install uv
119
+ uses: astral-sh/setup-uv@v5
120
+
121
+ - name: Set up Python ${{ matrix.python-version }}
122
+ run: uv python install ${{ matrix.python-version }}
123
+
124
+ - name: Wait for TestPyPI index to update
125
+ run: sleep 30
126
+
127
+ - name: Install from TestPyPI
128
+ env:
129
+ TEST_VERSION: ${{ needs.test-build.outputs.test_version }}
130
+ run: |
131
+ # Install from TestPyPI, falling back to PyPI for dependencies
132
+ uv pip install --index-url https://test.pypi.org/simple/ \
133
+ --extra-index-url https://pypi.org/simple/ \
134
+ "pysaka==$TEST_VERSION"
135
+
136
+ - name: Verify import
137
+ run: |
138
+ uv run python -c "from importlib.metadata import version; print(f'pysaka version: {version(\"pysaka\")}')"
139
+
140
+ - name: Run basic smoke test
141
+ run: |
142
+ uv run python -c "
143
+ from pysaka import Group
144
+ print('Available groups:', [g.value for g in Group])
145
+ print('Smoke test passed!')
146
+ "
@@ -0,0 +1,33 @@
1
+
2
+ name: Test
3
+
4
+ on:
5
+ push:
6
+ branches: [main, dev]
7
+ pull_request:
8
+ branches: [main, dev]
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v5
22
+
23
+ - name: Set up Python ${{ matrix.python-version }}
24
+ run: uv python install ${{ matrix.python-version }}
25
+
26
+ - name: Install dependencies
27
+ run: uv sync --all-extras --dev
28
+
29
+ - name: Run Tests
30
+ run: uv run pytest
31
+
32
+ - name: Run Benchmarks (Check)
33
+ run: uv run pytest --benchmark-only
@@ -0,0 +1,63 @@
1
+
2
+ # Python
3
+ __pycache__/
4
+ *.pyc
5
+ *.pyo
6
+ *.pyd
7
+ .Python
8
+ env/
9
+ venv/
10
+ .venv/
11
+ pip-log.txt
12
+
13
+ # pysaka local state
14
+ sync_state.json
15
+ tokens.json
16
+ *_data/
17
+
18
+ # Environment Variables
19
+ .env
20
+ .env.*
21
+
22
+ # Tooling
23
+ .ruff_cache/
24
+ .mypy_cache/
25
+
26
+ # Distribution
27
+ build/
28
+ dist/
29
+ *.egg-info/
30
+
31
+ # Testing
32
+ .pytest_cache/
33
+ .coverage
34
+ htmlcov/
35
+ .hypothesis/
36
+ .benchmarks/
37
+
38
+ # Editor
39
+ .vscode/
40
+ .idea/
41
+ *.swp
42
+ *.swo
43
+ *~
44
+
45
+ # macOS
46
+ .DS_Store
47
+ .AppleDouble
48
+ .LSOverride
49
+ ._*
50
+
51
+ # Windows
52
+ Thumbs.db
53
+ ehthumbs.db
54
+ Desktop.ini
55
+
56
+ # Logs
57
+ *.log
58
+ logs/
59
+
60
+ # Temporary files
61
+ *.tmp
62
+ *.temp
63
+ .cache/
@@ -0,0 +1,109 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-03-21
11
+
12
+ ### Changed
13
+ - **Breaking:** Package renamed from `pyhako`/`pyzaka` to `pysaka`
14
+ - Incremental sync now uses timestamp-based cursor instead of message ID
15
+ - `get_messages()` accepts `since_ts` parameter for cursor-based fetching
16
+ - `sync_member()` accepts `prefetched_messages` for group-level batching
17
+ - Integrity check resets on any message count drop (stricter)
18
+
19
+ ### Added
20
+ - Log rotation with separate `error.log` file
21
+ - Thread name included in structlog output
22
+
23
+ ### Fixed
24
+ - Message loss prevented during force-close with atomic temp file writes
25
+ - Overly aggressive low-ID message warning removed
26
+
27
+ ## [0.2.0] - 2026-03-15
28
+
29
+ ### Added
30
+ - Yodel service with multi-organization support
31
+ - `RefreshFailedError` exception and `is_active` single source of truth
32
+ - OAuth cookie preservation for Google, Apple, and LINE providers
33
+ - `get_token_manager()` singleton factory for credential management
34
+ - File handler support and configurable log levels
35
+ - API methods for official app feature parity (media duration, is_muted)
36
+ - Lazy token refresh to reduce unnecessary API calls
37
+ - JWT parsing shared utilities
38
+ - `BlogGoneError` for permanently removed blogs (404/410)
39
+ - Blog URL normalization and Sakurazaka thumbnail support
40
+ - `keyrings.alt` declared as optional dependency for headless environments
41
+
42
+ ### Changed
43
+ - Client now uses `get_token_manager()` singleton instead of creating new instances
44
+ - Blog `MemberInfo` moved to `base.py` for shared access
45
+ - `get_blog_thumbnail` renamed to `get_blog_detail_metadata`
46
+ - Removed internal semaphore from `process_media_queue`
47
+
48
+ ### Fixed
49
+ - TLS certificate verification enabled on all API calls (removed `ssl=False`)
50
+ - Session cookie value no longer logged in plaintext
51
+ - Token prefix removed from debug logs to prevent leakage
52
+ - Incremental sync correctly handles non-sequential message IDs
53
+ - Nogizaka blog content truncation and path issues resolved
54
+ - Sakurazaka blog timestamp parsing uses correct `.blog-foot .date` selector
55
+ - Sakurazaka `og:title` site suffix stripped during parsing
56
+ - Group official accounts excluded from member lists
57
+ - Group rename detection prevents duplicate directories
58
+ - Dead `max_id is not None` guard removed from sync manager
59
+
60
+ ### Security
61
+ - Removed `ssl=False` from all 9 aiohttp API calls — TLS verification now active
62
+ - Session cookie values redacted from debug logs
63
+ - mypy overrides documented with rationale for remaining suppressions
64
+
65
+ ## [0.1.1] - 2026-01-11
66
+
67
+ ### Added
68
+ - Blog backup support with parallel downloading for all three groups
69
+ - Media dimension extraction (width/height) for images and videos
70
+ - `SessionExpiredError` exception for proper session handling
71
+ - `display_name` configuration option
72
+ - Git Flow workflow documentation (CONTRIBUTING.md, PR template)
73
+
74
+ ### Changed
75
+ - Improved browser mimicry with proper headers (Accept, Accept-Language, Origin, Platform)
76
+ - Optimized headless refresh wait condition
77
+
78
+ ### Fixed
79
+ - Token refresh now sends `refresh_token: null` to match browser behavior
80
+ - Added `x-talk-app-platform` header for correct web token refresh
81
+ - Removed Authorization header that caused refresh failures
82
+
83
+ ### Documentation
84
+ - Added official Terms of Service links and warnings
85
+ - Added blog scraper documentation
86
+
87
+ ## [0.1.0] - 2026-01-11
88
+
89
+ ### Added
90
+ - Initial pysaka core library release
91
+ - Multi-group support: Hinatazaka46, Nogizaka46, Sakurazaka46
92
+ - OAuth browser authentication flow
93
+ - Message synchronization with incremental updates
94
+ - Media downloading with progress tracking
95
+ - Member information and avatar management
96
+ - SQLite database for sync state persistence
97
+ - Async/await API design
98
+ - Comprehensive type hints
99
+ - Property-based testing with Hypothesis
100
+
101
+ ### Security
102
+ - Secure credential storage via system keyring
103
+ - Token refresh without storing plaintext credentials
104
+
105
+ [Unreleased]: https://github.com/xebjhm/pysaka/compare/v0.3.0...HEAD
106
+ [0.3.0]: https://github.com/xebjhm/pysaka/compare/v0.2.0...v0.3.0
107
+ [0.2.0]: https://github.com/xebjhm/pysaka/compare/v0.1.1...v0.2.0
108
+ [0.1.1]: https://github.com/xebjhm/pysaka/compare/v0.1.0...v0.1.1
109
+ [0.1.0]: https://github.com/xebjhm/pysaka/releases/tag/v0.1.0