tbr-deal-finder 0.2.1__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.
- tbr_deal_finder-0.3.1/.github/workflows/build-release-dmg.yml +115 -0
- tbr_deal_finder-0.3.1/.github/workflows/build-release-exe.yml +198 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/.gitignore +3 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/CHANGELOG.md +16 -0
- tbr_deal_finder-0.3.1/Makefile +143 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/PKG-INFO +18 -87
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/README.md +13 -86
- tbr_deal_finder-0.3.1/assets/icon.ico +0 -0
- tbr_deal_finder-0.3.1/assets/icon.png +0 -0
- tbr_deal_finder-0.3.1/docs/desktop-app.md +251 -0
- tbr_deal_finder-0.3.1/docs/development.md +198 -0
- tbr_deal_finder-0.3.1/docs/python-cli.md +413 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/pyproject.toml +13 -2
- tbr_deal_finder-0.3.1/scripts/packaging/create_dmg.sh +93 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/__init__.py +5 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/__main__.py +7 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/book.py +16 -8
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/cli.py +13 -27
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/config.py +2 -2
- tbr_deal_finder-0.3.1/tbr_deal_finder/desktop_updater.py +147 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/__init__.py +0 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/main.py +725 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/__init__.py +1 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/all_books.py +93 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/all_deals.py +63 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/base_book_page.py +291 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/book_details.py +604 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/latest_deals.py +370 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/gui/pages/settings.py +389 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/amazon.py +58 -7
- tbr_deal_finder-0.3.1/tbr_deal_finder/retailer/amazon_custom_auth.py +79 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/audible.py +2 -1
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/chirp.py +55 -11
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/kindle.py +31 -19
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/librofm.py +53 -20
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer/models.py +31 -1
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/retailer_deal.py +38 -14
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/tracked_books.py +24 -18
- tbr_deal_finder-0.3.1/tbr_deal_finder/utils.py +119 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder/version_check.py +40 -0
- tbr_deal_finder-0.3.1/tbr_deal_finder.py +7 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/uv.lock +768 -1
- tbr_deal_finder-0.2.1/tbr_deal_finder/__init__.py +0 -9
- tbr_deal_finder-0.2.1/tbr_deal_finder/utils.py +0 -57
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/.github/workflows/publish-to-pypi.yaml +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/.python-version +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/DESIGN.md +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/LICENSE +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/migrations.py +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/owned_books.py +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/get_active_deals.sql +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/get_deals_found_at.sql +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/latest_deal_last_ran_most_recent_success.sql +0 -0
- {tbr_deal_finder-0.2.1 → tbr_deal_finder-0.3.1}/tbr_deal_finder/queries/latest_unknown_book_sync.sql +0 -0
- {tbr_deal_finder-0.2.1 → 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 }}
|
@@ -3,6 +3,22 @@
|
|
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
|
+
|
6
22
|
## 0.2.1 (August 25, 2025)
|
7
23
|
|
8
24
|
Notes:
|
@@ -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.
|
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
|
-
|
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
|
30
|
+
- Supports multiple library exports
|
26
31
|
- Tracks deals on the wishlist of all your configured retailers like audible (excluding kindle)
|
27
|
-
- Supports multiple locales
|
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
|
-
|
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
|
|