tbr-deal-finder 0.2.0__tar.gz → 0.3.1__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 (56) hide show
  1. tbr_deal_finder-0.3.1/.github/workflows/build-release-dmg.yml +115 -0
  2. tbr_deal_finder-0.3.1/.github/workflows/build-release-exe.yml +198 -0
  3. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/.gitignore +3 -0
  4. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/CHANGELOG.md +31 -0
  5. tbr_deal_finder-0.3.1/Makefile +143 -0
  6. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/PKG-INFO +19 -88
  7. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/README.md +14 -87
  8. tbr_deal_finder-0.3.1/assets/icon.ico +0 -0
  9. tbr_deal_finder-0.3.1/assets/icon.png +0 -0
  10. tbr_deal_finder-0.3.1/docs/desktop-app.md +251 -0
  11. tbr_deal_finder-0.3.1/docs/development.md +198 -0
  12. tbr_deal_finder-0.3.1/docs/python-cli.md +413 -0
  13. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/pyproject.toml +13 -2
  14. tbr_deal_finder-0.3.1/scripts/packaging/create_dmg.sh +93 -0
  15. tbr_deal_finder-0.3.1/tbr_deal_finder/__init__.py +5 -0
  16. tbr_deal_finder-0.3.1/tbr_deal_finder/__main__.py +7 -0
  17. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/book.py +28 -8
  18. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/cli.py +15 -28
  19. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/config.py +3 -3
  20. tbr_deal_finder-0.3.1/tbr_deal_finder/desktop_updater.py +147 -0
  21. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/__init__.py +0 -0
  22. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/main.py +725 -0
  23. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/__init__.py +1 -0
  24. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/all_books.py +93 -0
  25. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/all_deals.py +63 -0
  26. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/base_book_page.py +291 -0
  27. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/book_details.py +604 -0
  28. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/latest_deals.py +370 -0
  29. tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/settings.py +389 -0
  30. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/migrations.py +26 -0
  31. tbr_deal_finder-0.3.1/tbr_deal_finder/queries/latest_unknown_book_sync.sql +5 -0
  32. tbr_deal_finder-0.3.1/tbr_deal_finder/retailer/amazon.py +136 -0
  33. tbr_deal_finder-0.3.1/tbr_deal_finder/retailer/amazon_custom_auth.py +79 -0
  34. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/audible.py +2 -1
  35. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/chirp.py +55 -11
  36. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/kindle.py +68 -44
  37. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/librofm.py +58 -21
  38. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/models.py +31 -1
  39. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer_deal.py +62 -21
  40. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/tracked_books.py +76 -8
  41. tbr_deal_finder-0.3.1/tbr_deal_finder/utils.py +119 -0
  42. tbr_deal_finder-0.3.1/tbr_deal_finder/version_check.py +40 -0
  43. tbr_deal_finder-0.3.1/tbr_deal_finder.py +7 -0
  44. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/uv.lock +768 -1
  45. tbr_deal_finder-0.2.0/tbr_deal_finder/__init__.py +0 -9
  46. tbr_deal_finder-0.2.0/tbr_deal_finder/retailer/amazon.py +0 -85
  47. tbr_deal_finder-0.2.0/tbr_deal_finder/utils.py +0 -57
  48. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/.github/workflows/publish-to-pypi.yaml +0 -0
  49. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/.python-version +0 -0
  50. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/DESIGN.md +0 -0
  51. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/LICENSE +0 -0
  52. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/owned_books.py +0 -0
  53. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/get_active_deals.sql +0 -0
  54. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/get_deals_found_at.sql +0 -0
  55. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/latest_deal_last_ran_most_recent_success.sql +0 -0
  56. {tbr_deal_finder-0.2.0 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/__init__.py +0 -0
@@ -0,0 +1,115 @@
1
+ name: Build and Attach DMG to Release
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ build-dmg:
12
+ runs-on: macos-latest
13
+ env:
14
+ HAS_MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE != '' }}
15
+ HAS_MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD != '' }}
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: '3.13'
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v5
28
+
29
+ - name: Install project dependencies
30
+ run: |
31
+ uv sync
32
+
33
+ - name: Set up Xcode
34
+ uses: maxim-lobanov/setup-xcode@v1
35
+ with:
36
+ xcode-version: latest-stable
37
+
38
+ - name: Set up CocoaPods
39
+ uses: maxim-lobanov/setup-cocoapods@v1
40
+ with:
41
+ version: latest
42
+
43
+ - name: Import Code Signing Certificate (if available)
44
+ if: ${{ env.HAS_MACOS_CERTIFICATE == 'true' && env.HAS_MACOS_CERTIFICATE_PASSWORD == 'true' }}
45
+ run: |
46
+ # Create temporary keychain
47
+ security create-keychain -p "temp_keychain_password" temp.keychain
48
+ security default-keychain -s temp.keychain
49
+ security unlock-keychain -p "temp_keychain_password" temp.keychain
50
+
51
+ # Import certificate
52
+ echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12
53
+ security import certificate.p12 -k temp.keychain -P "${{ secrets.MACOS_CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign
54
+
55
+ # Allow codesign to access the certificate
56
+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "temp_keychain_password" temp.keychain
57
+
58
+ # Set code signing identity
59
+ if [ -n "${{ secrets.CODESIGN_IDENTITY }}" ]; then
60
+ # Use provided identity name
61
+ echo "CODESIGN_IDENTITY=${{ secrets.CODESIGN_IDENTITY }}" >> $GITHUB_ENV
62
+ echo "✅ Code signing certificate imported: ${{ secrets.CODESIGN_IDENTITY }}"
63
+ else
64
+ # Auto-detect identity from certificate
65
+ CERT_IDENTITY=$(security find-identity -v -p codesigning temp.keychain | head -1 | grep -o '"[^"]*"' | tr -d '"')
66
+ echo "CODESIGN_IDENTITY=$CERT_IDENTITY" >> $GITHUB_ENV
67
+ echo "✅ Code signing certificate imported (auto-detected): $CERT_IDENTITY"
68
+ fi
69
+
70
+ # Clean up certificate file
71
+ rm -f certificate.p12
72
+
73
+ - name: Build DMG
74
+ run: |
75
+ make build-mac
76
+
77
+ - name: Cleanup Code Signing
78
+ if: ${{ env.HAS_MACOS_CERTIFICATE == 'true' && env.HAS_MACOS_CERTIFICATE_PASSWORD == 'true' }}
79
+ run: |
80
+ # Remove temporary keychain
81
+ security delete-keychain temp.keychain || true
82
+ echo "🧹 Cleaned up code signing keychain"
83
+
84
+ - name: Find and verify DMG was created
85
+ id: find-dmg
86
+ run: |
87
+ ls -la gui_dist/
88
+ DMG_FILE=$(find gui_dist/ -name "*.dmg" -type f | head -1)
89
+ if [ -z "$DMG_FILE" ]; then
90
+ echo "❌ DMG file not found!"
91
+ echo "Contents of gui_dist/:"
92
+ ls -la gui_dist/ || echo "gui_dist/ directory not found"
93
+ exit 1
94
+ fi
95
+ echo "✅ DMG file created successfully: $DMG_FILE"
96
+ echo "dmg_path=$DMG_FILE" >> $GITHUB_OUTPUT
97
+ echo "dmg_name=$(basename $DMG_FILE)" >> $GITHUB_OUTPUT
98
+
99
+ - name: Get DMG info
100
+ id: dmg-info
101
+ run: |
102
+ DMG_SIZE=$(ls -lh "${{ steps.find-dmg.outputs.dmg_path }}" | awk '{print $5}')
103
+ echo "size=$DMG_SIZE" >> $GITHUB_OUTPUT
104
+ echo "📦 DMG Size: $DMG_SIZE"
105
+ echo "📦 DMG Name: ${{ steps.find-dmg.outputs.dmg_name }}"
106
+
107
+ - name: Upload DMG to Release
108
+ env:
109
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
110
+ run: |
111
+ gh release upload ${{ github.event.release.tag_name }} \
112
+ "${{ steps.find-dmg.outputs.dmg_path }}" \
113
+ --clobber \
114
+ --repo ${{ github.repository }}
115
+
@@ -0,0 +1,198 @@
1
+ name: Build and Attach Windows EXE to Release
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ permissions:
8
+ contents: write
9
+
10
+ jobs:
11
+ build-exe:
12
+ runs-on: windows-latest
13
+ env:
14
+ HAS_WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE != '' }}
15
+ HAS_WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD != '' }}
16
+ APP_DISPLAY_NAME: "TBR Deal Finder"
17
+ APP_FILENAME_BASE: "TBR-Deal-Finder"
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Flutter
24
+ uses: subosito/flutter-action@v2
25
+ with:
26
+ flutter-version: '3.29.2'
27
+ channel: 'stable'
28
+
29
+ - name: Enable Windows Desktop
30
+ run: flutter config --enable-windows-desktop
31
+
32
+ - name: Set up Python
33
+ uses: actions/setup-python@v5
34
+ with:
35
+ python-version: '3.13'
36
+
37
+ - name: Install uv
38
+ uses: astral-sh/setup-uv@v5
39
+
40
+ - name: Install project dependencies
41
+ run: |
42
+ uv sync
43
+
44
+ - name: Import Code Signing Certificate (if available)
45
+ if: ${{ env.HAS_WINDOWS_CERTIFICATE == 'true' && env.HAS_WINDOWS_CERTIFICATE_PASSWORD == 'true' }}
46
+ run: |
47
+ # Decode and import certificate
48
+ $certBytes = [System.Convert]::FromBase64String("${{ secrets.WINDOWS_CERTIFICATE }}")
49
+ $certPath = "windows-cert.pfx"
50
+ [System.IO.File]::WriteAllBytes($certPath, $certBytes)
51
+
52
+ # Import certificate to certificate store
53
+ $securePassword = ConvertTo-SecureString -String "${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}" -Force -AsPlainText
54
+ Import-PfxCertificate -FilePath $certPath -CertStoreLocation Cert:\CurrentUser\My -Password $securePassword
55
+
56
+ Write-Output "✅ Code signing certificate imported successfully"
57
+
58
+ # Clean up certificate file
59
+ Remove-Item $certPath -Force
60
+
61
+ - name: Build Windows EXE
62
+ env:
63
+ PYTHONIOENCODING: utf-8
64
+ PYTHONLEGACYWINDOWSFSENCODING: utf-8
65
+ # Disable Rich progress bars to avoid Unicode issues
66
+ TERM: dumb
67
+ NO_COLOR: 1
68
+ run: |
69
+ # Set console to UTF-8 to handle Unicode characters
70
+ chcp 65001
71
+
72
+ # Clean any existing build cache to ensure fresh plugin compilation
73
+ Write-Output "🧹 Cleaning build cache..."
74
+ Remove-Item -Path "build" -Recurse -Force -ErrorAction SilentlyContinue
75
+ Remove-Item -Path "gui_dist" -Recurse -Force -ErrorAction SilentlyContinue
76
+
77
+ # Use flet to build Windows executable (Flutter environment now properly set up)
78
+ Write-Output "🪟 Building Windows executable..."
79
+ uv run flet build windows --output gui_dist/ --verbose
80
+
81
+ Write-Output "📁 Build output contents:"
82
+ Get-ChildItem -Path gui_dist -Recurse | Format-Table Name, Length, LastWriteTime
83
+
84
+ - name: Sign Windows EXE (if certificate available)
85
+ if: ${{ env.HAS_WINDOWS_CERTIFICATE == 'true' && env.HAS_WINDOWS_CERTIFICATE_PASSWORD == 'true' }}
86
+ uses: dlemstra/code-sign-action@v1
87
+ with:
88
+ certificate: '${{ secrets.WINDOWS_CERTIFICATE }}'
89
+ password: '${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}'
90
+ folder: 'gui_dist'
91
+ recursive: true
92
+
93
+ - name: Get App Info
94
+ id: app-info
95
+ run: |
96
+ # Find the EXE file
97
+ $exeFile = Get-ChildItem -Path "gui_dist" -Filter "*.exe" | Select-Object -First 1
98
+ if (-not $exeFile) {
99
+ Write-Output "❌ EXE file not found!"
100
+ exit 1
101
+ }
102
+
103
+ $exeName = [System.IO.Path]::GetFileNameWithoutExtension($exeFile.Name)
104
+ $appVersion = "${{ github.event.release.tag_name }}".TrimStart('v')
105
+
106
+ # Default to 1.0.0 if tag isn't semver
107
+ if (-not ($appVersion -match '^\d+\.\d+\.\d+')) {
108
+ $appVersion = "1.0.0"
109
+ }
110
+
111
+ Write-Output "exe_name=$($exeFile.Name)" >> $env:GITHUB_OUTPUT
112
+ Write-Output "exe_base_name=$exeName" >> $env:GITHUB_OUTPUT
113
+ Write-Output "app_version=$appVersion" >> $env:GITHUB_OUTPUT
114
+
115
+ - name: Install Inno Setup
116
+ run: |
117
+ # Download and install Inno Setup silently
118
+ Invoke-WebRequest -Uri "https://jrsoftware.org/download.php/is.exe" -OutFile "innosetup.exe"
119
+ Start-Process -FilePath ".\innosetup.exe" -ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-" -Wait
120
+
121
+ # Add to PATH for current session
122
+ $env:PATH += ";C:\Program Files (x86)\Inno Setup 6"
123
+
124
+ Write-Output "✅ Inno Setup installed successfully"
125
+
126
+ - name: Create InnoSetup Script
127
+ run: |
128
+ @"
129
+ [Setup]
130
+ AppId={{$(New-Guid)}}
131
+ AppName=${{ env.APP_DISPLAY_NAME }}
132
+ AppVersion=${{ steps.app-info.outputs.app_version }}
133
+ AppPublisher=WillNye
134
+ AppPublisherURL=https://github.com/WillNye
135
+ AppSupportURL=https://github.com/WillNye/${{ github.event.repository.name }}/issues
136
+ AppUpdatesURL=https://github.com/WillNye/${{ github.event.repository.name }}/releases
137
+ DefaultDirName={autopf}\${{ env.APP_DISPLAY_NAME }}
138
+ DefaultGroupName=${{ env.APP_DISPLAY_NAME }}
139
+ AllowNoIcons=yes
140
+ OutputDir=.
141
+ OutputBaseFilename=${{ env.APP_FILENAME_BASE }}-${{ steps.app-info.outputs.app_version }}-Setup
142
+ SetupIconFile=assets\icon.ico
143
+ Compression=lzma2/normal
144
+ SolidCompression=no
145
+ WizardStyle=modern
146
+ PrivilegesRequired=lowest
147
+ PrivilegesRequiredOverridesAllowed=dialog
148
+
149
+ [Languages]
150
+ Name: "english"; MessagesFile: "compiler:Default.isl"
151
+
152
+ [Tasks]
153
+ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
154
+
155
+ [Files]
156
+ ; Exclude EXE from compression to preserve icon quality
157
+ Source: "gui_dist\${{ steps.app-info.outputs.exe_name }}"; DestDir: "{app}"; Flags: ignoreversion nocompression
158
+ ; Compress everything else
159
+ Source: "gui_dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "${{ steps.app-info.outputs.exe_name }}"
160
+
161
+ [Icons]
162
+ Name: "{group}\${{ env.APP_DISPLAY_NAME }}"; Filename: "{app}\${{ steps.app-info.outputs.exe_name }}"
163
+ Name: "{group}\{cm:UninstallProgram,${{ env.APP_DISPLAY_NAME }}}"; Filename: "{uninstallexe}"
164
+ Name: "{autodesktop}\${{ env.APP_DISPLAY_NAME }}"; Filename: "{app}\${{ steps.app-info.outputs.exe_name }}"; Tasks: desktopicon
165
+
166
+ [Run]
167
+ Filename: "{app}\${{ steps.app-info.outputs.exe_name }}"; Description: "{cm:LaunchProgram,${{ env.APP_DISPLAY_NAME }}}"; Flags: nowait postinstall skipifsilent
168
+ "@ | Out-File -FilePath "setup.iss" -Encoding UTF8
169
+ - name: Build Setup with InnoSetup
170
+ run: |
171
+ # Compile the installer
172
+ & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup.iss
173
+
174
+ if ($LASTEXITCODE -ne 0) {
175
+ Write-Output "❌ InnoSetup compilation failed with exit code: $LASTEXITCODE"
176
+ exit 1
177
+ }
178
+
179
+ Write-Output "✅ Installer created successfully"
180
+
181
+ - name: Sign Installer (if certificate available)
182
+ if: ${{ env.HAS_WINDOWS_CERTIFICATE == 'true' && env.HAS_WINDOWS_CERTIFICATE_PASSWORD == 'true' }}
183
+ uses: dlemstra/code-sign-action@v1
184
+ with:
185
+ certificate: '${{ secrets.WINDOWS_CERTIFICATE }}'
186
+ password: '${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}'
187
+ files: '${{ env.APP_FILENAME_BASE }}-${{ steps.app-info.outputs.app_version }}-Setup.exe'
188
+
189
+ - name: Upload Installer to Release
190
+ env:
191
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
192
+ run: |
193
+ $installerFile = "${{ env.APP_FILENAME_BASE }}-${{ steps.app-info.outputs.app_version }}-Setup.exe"
194
+
195
+ gh release upload ${{ github.event.release.tag_name }} `
196
+ $installerFile `
197
+ --clobber `
198
+ --repo ${{ github.repository }}
@@ -206,3 +206,6 @@ cython_debug/
206
206
  marimo/_static/
207
207
  marimo/_lsp/
208
208
  __marimo__/
209
+
210
+ gui_dist/
211
+ scratch/
@@ -3,6 +3,36 @@
3
3
 
4
4
  ---
5
5
 
6
+ ## 0.3.1 (September 5, 2025)
7
+
8
+ Notes:
9
+ * Added a GUI to serve as a desktop app
10
+ * Added retry behavior to Kindle and Libro on get_book call
11
+ * Saving all pricing info to be used for historical pricing details
12
+ * Added version checking to the CLI
13
+
14
+ BUG FIXES:
15
+ * Improvements to grouping titles in TBR
16
+ * Fixed issue where known books were being marked as unknown if not found on a run
17
+ * Fixed bug where books not found were sometimes not added to Unknown books
18
+ * Fixed regression on Windows devices when adding Kindle support
19
+
20
+ ---
21
+
22
+ ## 0.2.1 (August 25, 2025)
23
+
24
+ Notes:
25
+ * Added Kindle Library support
26
+ * Wishlist support is looking unlikely
27
+ * Running into auth issues on the only viable endpoint https://www.amazon.com/kindle-reader-api
28
+ * No longer attempting to retrieve details on books not previously found on every run
29
+ * Full check is now performed weekly or when a change has been made to the user config
30
+
31
+ BUG FIXES:
32
+ * Failed Libro login no longer causing crash
33
+
34
+ ---
35
+
6
36
  ## 0.2.0 (August 15, 2025)
7
37
 
8
38
  Notes:
@@ -16,6 +46,7 @@ Notes:
16
46
 
17
47
  BUG FIXES:
18
48
  * Fixed breaking import on Windows systems
49
+ * Fixed displayed discount percent
19
50
 
20
51
  ---
21
52
 
@@ -0,0 +1,143 @@
1
+ # TBR Deal Finder Build System
2
+ .PHONY: help build-mac build-windows build-windows-docker build-linux build-all clean clean-all test-mac status create-cert
3
+
4
+ # Default target
5
+ help:
6
+ @echo "TBR Deal Finder Build Commands:"
7
+ @echo ""
8
+ @echo "Setup:"
9
+ @echo " make create-cert Create self-signed certificate (one-time setup) 🔐"
10
+ @echo ""
11
+ @echo "Building:"
12
+ @echo " make build-mac Build self-signed macOS DMG ⭐"
13
+ @echo " make build-windows Build Windows EXE (GitHub Actions) ⭐"
14
+ @echo " make build-linux Build Linux executable"
15
+ @echo " make build-all Build for current platform"
16
+ @echo ""
17
+ @echo "Testing:"
18
+ @echo " make test-mac Test macOS DMG"
19
+ @echo ""
20
+ @echo "Utilities:"
21
+ @echo " make clean Clean build artifacts (keeps .spec)"
22
+ @echo " make clean-all Clean everything including .spec"
23
+ @echo ""
24
+ @echo "Current platform: $(shell uname -s)"
25
+
26
+ # Variables
27
+ PROJECT_NAME := TBR Deal Finder
28
+ DIST_DIR := gui_dist
29
+ BUILD_SCRIPT := scripts/packaging/build_cross_platform.py
30
+
31
+ # Build self-signed macOS DMG (recommended)
32
+ build-mac:
33
+ @echo "🍎 Building app"
34
+ uv run flet build macos --output ${DIST_DIR}/app/
35
+ @echo ""
36
+ @echo "📦 Creating self-signed macOS DMG for app"
37
+ bash scripts/packaging/create_dmg.sh
38
+ @echo "✅ Self-signed macOS DMG built successfully!"
39
+
40
+ # Build Windows EXE (requires Windows or GitHub Actions)
41
+ build-windows:
42
+ @echo "🪟 Building Windows EXE..."
43
+ uv run flet build windows --output ${DIST_DIR}/ --verbose
44
+
45
+ # Test macOS DMG
46
+ test-mac:
47
+ @echo "🧪 Testing macOS DMG..."
48
+ @if [ ! -f "$(DIST_DIR)/TBRDealFinder.dmg" ]; then \
49
+ echo "❌ No DMG found. Run 'make build-mac' first."; \
50
+ exit 1; \
51
+ fi
52
+ @echo "📂 DMG file info:" && \
53
+ ls -lh $(DIST_DIR)/TBRDealFinder.dmg && \
54
+ echo "🔍 Testing DMG mount..." && \
55
+ hdiutil attach $(DIST_DIR)/TBRDealFinder.dmg -mountpoint /tmp/tbr_test -nobrowse && \
56
+ echo "✅ DMG mounts successfully" && \
57
+ ls -la /tmp/tbr_test/ && \
58
+ hdiutil detach /tmp/tbr_test 2>/dev/null || \
59
+ echo "❌ DMG mount failed"
60
+
61
+ # Build Linux executable (works on Linux)
62
+ build-linux:
63
+ @echo "🐧 Building Linux executable..."
64
+ @if [ "$(shell uname -s)" != "Linux" ]; then \
65
+ echo "⚠️ Linux builds require Linux OS"; \
66
+ echo " Run this on Linux or use GitHub Actions for cross-platform builds"; \
67
+ exit 1; \
68
+ fi
69
+ uv run python $(BUILD_SCRIPT)
70
+ @echo ""
71
+ @echo "✅ Linux executable built successfully!"
72
+ @echo "📦 Output: $(DIST_DIR)/TBRDealFinder"
73
+ @ls -lh $(DIST_DIR)/TBRDealFinder 2>/dev/null || true
74
+
75
+ # Build for current platform
76
+ build-all:
77
+ @echo "🌍 Building for current platform..."
78
+ @case "$(shell uname -s)" in \
79
+ Darwin) \
80
+ echo "On macOS - building self-signed DMG"; \
81
+ $(MAKE) build-mac; \
82
+ ;; \
83
+ Linux) \
84
+ echo "On Linux - building executable"; \
85
+ $(MAKE) build-linux; \
86
+ ;; \
87
+ MINGW*|MSYS*|CYGWIN*) \
88
+ echo "On Windows - building Windows EXE"; \
89
+ $(MAKE) build-windows; \
90
+ ;; \
91
+ *) \
92
+ if [ "$(OS)" = "Windows_NT" ]; then \
93
+ echo "On Windows - building Windows EXE"; \
94
+ $(MAKE) build-windows; \
95
+ else \
96
+ echo "❌ Unsupported platform: $(shell uname -s)"; \
97
+ echo " Supported: macOS (with Docker), Windows, Linux"; \
98
+ exit 1; \
99
+ fi; \
100
+ ;; \
101
+ esac
102
+
103
+ # Clean build artifacts (preserves .spec file for version control)
104
+ clean:
105
+ @echo "🧹 Cleaning build artifacts..."
106
+ rm -rf $(DIST_DIR)/
107
+ rm -rf build/
108
+ @echo "✅ Clean complete (kept .spec file)"
109
+
110
+ # Clean everything including .spec file
111
+ clean-all:
112
+ @echo "🧹 Cleaning everything..."
113
+ rm -rf $(DIST_DIR)/
114
+ rm -rf build/
115
+ rm -rf dist/
116
+ rm -f *.spec
117
+ @echo "✅ Complete clean finished"
118
+
119
+ # Create self-signed certificate for consistent code signing
120
+ create-cert:
121
+ @echo "🔐 Creating self-signed certificate for consistent code signing..."
122
+ @echo ""
123
+ @bash scripts/create-self-signed-cert.sh
124
+
125
+ # Show build status
126
+ status:
127
+ @echo "📊 Build Status:"
128
+ @echo ""
129
+ @echo "Platform: $(shell uname -s)"
130
+ @echo "Build directory: $(DIST_DIR)/"
131
+ @echo ""
132
+ @echo "Built artifacts:"
133
+ @if [ -d "$(DIST_DIR)" ]; then \
134
+ ls -la $(DIST_DIR)/ 2>/dev/null || echo " None found"; \
135
+ else \
136
+ echo " Build directory doesn't exist"; \
137
+ fi
138
+ @echo ""
139
+ @echo "Dependencies:"
140
+ @uv tree --depth 1 | grep -E "(flet|pyinstaller)" || echo " Not installed"
141
+ @echo ""
142
+ @echo "Code signing certificates:"
143
+ @security find-identity -v -p codesigning 2>/dev/null | grep -E "(TBR Deal Finder|Developer ID)" || echo " None found (will use ad-hoc signing)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tbr-deal-finder
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: Track price drops and find deals on books in your TBR list across audiobook and ebook formats.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -9,26 +9,32 @@ Requires-Dist: aiohttp>=3.12.14
9
9
  Requires-Dist: audible==0.8.2
10
10
  Requires-Dist: click>=8.2.1
11
11
  Requires-Dist: duckdb>=1.3.2
12
+ Requires-Dist: flet[all]==0.28.2
12
13
  Requires-Dist: levenshtein>=0.27.1
14
+ Requires-Dist: pandas-stubs==2.3.0.250703
13
15
  Requires-Dist: pandas>=2.3.1
16
+ Requires-Dist: plotly>=5.17.0
17
+ Requires-Dist: pyinstaller>=6.15.0
14
18
  Requires-Dist: questionary>=2.1.0
15
19
  Requires-Dist: tqdm>=4.67.1
16
20
  Requires-Dist: unidecode>=1.4.0
17
21
  Description-Content-Type: text/markdown
18
22
 
19
- # tbr-deal-finder
20
-
23
+ <div>
24
+ <h1>TBR Deal Finder <img src="assets/icon.png" alt="TBR Deal Finder" width="128" height="128" style="vertical-align: middle; margin-left: 10px;"></h1>
25
+ </div>
21
26
  Track price drops and find deals on books in your TBR (To Be Read) and wishlist across digital book retailers.
22
27
 
23
28
  ## Features
24
29
  - Use your StoryGraph exports, Goodreads exports, and custom csvs (spreadsheet) to track book deals
25
- - Supports multiple of the library exports above
26
- - Tracks deals on the wishlist of all your configured retailers like audible
27
- - Supports multiple locales and currencies
30
+ - Supports multiple library exports
31
+ - Tracks deals on the wishlist of all your configured retailers like audible (excluding kindle)
32
+ - Supports multiple locales
28
33
  - Find the latest and active deals from supported sellers
29
- - Simple CLI interface for setup and usage
30
34
  - Only get notified for new deals or view all active deals
31
35
  - Filters out books you already own to prevent purchasing the same book on multiple retailers
36
+ - Track historical pricing* (History limited to your runs making it more accurate over time)
37
+ - Compare pricing across digital retailers
32
38
 
33
39
  ## Support
34
40
 
@@ -53,24 +59,6 @@ Track price drops and find deals on books in your TBR (To Be Read) and wishlist
53
59
  * ES
54
60
  * BR
55
61
 
56
- ## Installation Guide
57
-
58
- ### Python (Recommended)
59
- 1. If it's not already on your computer, download Python https://www.python.org/downloads/
60
- 1. tbr-deal-finder requires Python3.13 or higher
61
- 2. Optional: Install and use virtualenv
62
- 3. Open your Terminal/Command Prompt
63
- 4. Run `pip3.13 install tbr-deal-finder`
64
-
65
- ### UV
66
- 1. Clone the repository:
67
- ```sh
68
- git clone https://github.com/yourusername/tbr-deal-finder.git
69
- cd tbr-deal-finder
70
- ```
71
- 2. Install uv:
72
- https://docs.astral.sh/uv/getting-started/installation/
73
-
74
62
  ## Configuration
75
63
  This tool can use the csv generated by the app you use to track your TBRs.
76
64
  Here are the steps to get your export.
@@ -103,70 +91,13 @@ If you've got your own CSV you're using to track your TBRs all you need are the
103
91
  Optionally, you can add the `Read Status` column. Set `to-read` for all books you want to be tracked.
104
92
  If you don't add this column the deal finder will run on ALL books in the CSV.
105
93
 
106
- ### tbr-deal-finder setup
107
-
108
- #### Python
109
- ```sh
110
- tbr-deal-finder setup
111
- ```
112
-
113
- #### UV
114
- ```sh
115
- uv run -m tbr_deal_finder.cli setup
116
- ```
117
-
118
- You will be prompted to:
119
- - Enter the path(s) to your StoryGraph export CSV file(s)
120
- - Select your locale (country/region)
121
- - Set your maximum price for deals
122
- - Set your minimum discount percentage
123
-
124
- The configuration will be saved for future runs.
125
-
126
- ## Usage
127
- All commands are available via the CLI:
128
-
129
- - `setup` – Set up or update your configuration interactively.
130
- - `latest-deals` – Find and print the latest book deals based on your config.
131
- - `active-deals` – Show all currently active deals.
132
-
133
- #### Python
134
- ```sh
135
- tbr-deal-finder [COMMAND]
136
- ```
137
-
138
- #### UV
139
- ```sh
140
- uv run -m tbr_deal_finder.cli [COMMAND]
141
- ```
142
-
143
- Example:
144
- ```sh
145
- tbr-deal-finder latest-deals
146
-
147
- # or
148
-
149
- uv run -m tbr_deal_finder.cli latest-deals
150
- ```
151
-
152
- ## Updating your TBR
153
- To update tbr-deal-finder as your TBR changes, regenerate and download your library export.
154
- See [Configuration](#Configuration) for steps.
155
-
156
-
157
- ## Updating the tbr-deal-finder
158
-
159
- ### Python
160
- ```sh
161
- pip3.13 install tbr-deal-finder --upgrade
162
- ```
163
-
164
- ### UV
165
- ```sh
166
- # From the repo directory
167
- git checkout main && git fetch
168
- ```
94
+ ## Installation Guide
95
+ Each guide contains everything you need: installation, usage, and updating instructions.
169
96
 
97
+ ### Choose Your Guide
98
+ - [📱 **Desktop App Guide**](docs/desktop-app.md) - For users who prefer graphical interfaces
99
+ - [🐍 **Python CLI Guide**](docs/python-cli.md) - For command-line and automation users
100
+ - [🛠️ **Development Guide**](docs/development.md) - For developers and contributors
170
101
 
171
102
  ---
172
103