| Age | Commit message (Collapse) | Author |
|
Amp-Thread-ID:
https://ampcode.com/threads/T-51eb1377-abce-430c-bde5-ef909ac79444
Co-authored-by: Amp <amp@ampcode.com>
|
|
|
|
- Fix get_usage() to count from user_episodes table instead of
episodes.user_id
- Now correctly tracks when episodes are added to user's feed -
Handles shared/existing episodes properly (count against the user
who added them)
- Add comprehensive test suite for usage limits (TestUsageLimits):
- test_usage_counts_episodes_added_to_feed -
test_usage_counts_existing_episodes_correctly -
test_free_tier_limit_enforcement (10 articles) -
test_can_submit_blocks_at_limit - test_paid_tier_unlimited
- Billing.can_submit() now properly enforces 10 article limit
for free tier - Usage tracking via user_episodes.added_at ensures
accurate billing
Completes t-144eKR1
|
|
- Change primary feed URLs to use .rss extension (more semantically
correct)
- /feed/{token}.xml -> /feed/{token}.rss - /public.rss stays the same
- Add .xml aliases for backwards compatibility
- /feed/{token}.xml redirects to .rss handler - /public.xml redirects
to .rss handler
- Add tests to verify both extensions work and return identical
content - Update all references in UI and tests to use .rss
This provides consistency (.rss everywhere) while maintaining backwards
compatibility for existing feed subscribers using .xml URLs.
Amp-Thread-ID:
https://ampcode.com/threads/T-6d73d458-3d80-44e5-865f-358a69e5b2bf
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Fix dashboard-updates endpoint to return Response with both
components
concatenated as HTML strings, preventing episodes from disappearing
after HTMX innerHTML swap
- Add viewing_own_feed flag to EpisodeList to hide 'In your feed'
button
when users are viewing their own feed on homepage
- Add test coverage for admin adding user episodes to own feed -
Add test coverage for admin adding user episodes to public feed
Amp-Thread-ID:
https://ampcode.com/threads/T-6d73d458-3d80-44e5-865f-358a69e5b2bf
Co-authored-by: Amp <amp@ampcode.com>
|
|
When viewing the public feed (or any episode list), logged-in users
now see: - 'Add to my feed' button if episode is not in their feed -
'In your feed' button (disabled) if they already have it
Implementation: - Added user_button logic to EpisodeList component
- Checks Core.Database.user_has_episode() for each episode - Shows
blue outline button for add action - Shows gray disabled button when
already added - Buttons displayed in flex row with admin buttons
Updated add_episode_to_feed endpoint: - Changed to redirect back
to referer page after adding - Uses HX-Redirect to reload the page
showing updated state - This allows the button to change from 'Add
to my feed' to 'In your feed'
All tests passing (48 tests)
|
|
Privacy improvements: - Removed email address from episode page
signup banner - Changed 'This episode was created by <email>' to
'This episode was created using PodcastItLater' - Protects user
privacy while still showing the signup prompt
Admin UI improvements: - Removed floating Public/Private toggle
button (was confusing) - Added '+ Add to public feed' button at
bottom of episode cards - Button only visible to admin users - Shows
'Added to public feed' with checkmark when already public - Shows '+
Add to public feed' with plus icon when private - Clearer and more
actionable UX for managing public feed content
All tests passing (48 tests)
|
|
Issue #1: demo@example.com admin status - Confirmed demo@example.com
IS in ADMIN_EMAILS (working as intended) - Both Core.py and UI.py
have demo@example.com in whitelist
Issue #2: /public page auto-refresh causing disappearing articles -
Created PublicFeedPage component without auto-refresh - Separated
from HomePage which has dashboard auto-updates - /public route now
uses PublicFeedPage instead of HomePage
Issue #3: Homepage missing public feed for logged-out users - Updated
HomePage to show public feed when user is not logged in - Shows
login form with public episodes below - Includes marketing message:
'Sign up to create your own personal feed!' - Public episodes are
fetched and displayed prominently
Additional improvements: - Added 'Public Feed' link to navbar for
easy access - PublicFeedPage shows RSS feed link for public.rss -
Clear separation between user dashboard (auto-refresh) and public feed
(static)
All tests passing (48 tests)
|
|
- Added Core.Database.get_metrics_summary() for aggregate stats -
Added Core.Database.get_episode_metric_events() for raw event data -
Created MetricsDashboard component with summary cards and top episodes
tables - Added /admin/metrics route with admin authentication -
Added metrics link to admin dropdown menu - Added comprehensive tests
for metrics functionality - Fixed type errors in Admin.py by adding
MetricCardAttrs - All tests passing (48 tests total in Web.py) -
Completed epic t-ga8V8O (24/24 tasks)
|
|
- Enhanced Worker.py to extract publication date and author from
articles - Added intro TTS with metadata (title, author, publication
date) - Added outro TTS with attribution - Combined intro, pauses,
content, and outro in Worker.py - Added comprehensive tests for public
feed, deduplication, metrics, and intro/outro
All tests passing (Worker: 30 tests, Web: 43 tests)
Tasks completed: - t-gcNemK: Extract metadata in Worker.py - t-gcPraJ:
Add intro TTS generation - t-gcRCzw: Add outro TTS generation -
t-gcTPQn: Combine audio segments - t-gcW6zN: Tests for public feed
- t-gdlWtu: Tests for deduplication - t-gdoeYo: Tests for metrics
tracking - t-gdqsl7: Tests for audio intro/outro
|
|
- Added POST /episode/{id}/track endpoint to track play/download
events - Added JavaScript to audio player to track first play event -
JavaScript sends fetch request to tracking endpoint on play - Tracks
user_id if logged in, otherwise anonymous - Added main() function to
Episode.py for test compatibility
Tasks completed: t-gcdFSb, t-gcfTnG
|
|
- Episode pages now show 'Add to feed' button for logged-in users
who don't have the episode - Added POST /episode/{id}/add-to-feed
endpoint - Tracks 'added' metric when user adds episode to their feed -
Added Database.track_episode_metric() function for metrics tracking -
Fixed typecheck.sh to use bild instead of broken repl.sh approach
Tasks completed: t-gc9aud, t-gcbqDl
|
|
- Add toggle button to episode cards (admins only) - Button shows
globe icon for public, lock icon for private - Toggle endpoint at
POST /admin/episode/{id}/toggle-public - Updates episode is_public
status and redirects to home
Tasks completed: t-gcbqDl, t-gc6Vrk (partially - admin toggle complete)
|
|
- test_session_persistence: Check for navbar links instead of removed
'Logged in as:' text - test_delete_action: Add referer header to
trigger HX-Redirect response
|
|
When tests create episodes directly, they must also add them to
the user_episodes junction table for them to appear in user feeds.
This maintains the new many-to-many relationship architecture.
Test suite now has same 2 pre-existing failures as before (unrelated
to this work): - test_session_persistence (expects 'Logged in as:'
text that doesn't exist) - test_delete_action (expects HX-Redirect
header from admin delete)
All new functionality tests pass.
|
|
- Add /public route showing public episodes - Add /public.rss RSS
feed for public episodes - Update home page to show public feed when
not logged in - Use user_episodes junction table instead of user_id
filtering - All tests passing
|
|
- Check for existing episodes by URL hash before processing - Reuse
existing episodes when user submits duplicate URL - Add episode
to user's feed if they don't have it - Track 'added' metrics when
episode added to feed - Worker now creates user_episodes link and
tracks metrics - Show appropriate messages for already-in-feed vs
newly-added episodes
|
|
Maintain compatibility with old sequential integer episode URLs by
redirecting them to the new sqid-based URLs with a 301 permanent
redirect.
- Add /episode/{episode_id:int} route for legacy integer IDs - Redirect
with 301 status to indicate permanent move to new URL - Add test to
verify redirect behavior - Mark route as deprecated in documentation
This allows existing shared links to continue working while encouraging
adoption of the new non-sequential URLs. The legacy route can be
removed after a deprecation period.
Amp-Thread-ID:
https://ampcode.com/threads/T-cc5d29f0-454e-4864-8d7e-1ad69a42afa9
Co-authored-by: Amp <amp@ampcode.com>
|
|
Replace sequential integer IDs with sqids in episode URLs for better
privacy and security. Episode IDs are no longer easily guessable.
- Add sqids dependency to Web.py - Create encode_episode_id() and
decode_episode_id() helper functions - Update /episode/{episode_sqid}
route to accept and decode sqids - Update EpisodeList to generate
sqid-based links - Update RSS feed to use sqids in episode URLs -
Update EpisodeDetailPage to accept and use sqids for share URLs -
Update all tests to use sqids
Episode URLs now look like /episode/AbCd1234 instead of /episode/1
Database still uses integer IDs internally for efficiency.
Amp-Thread-ID:
https://ampcode.com/threads/T-cc5d29f0-454e-4864-8d7e-1ad69a42afa9
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Create new Episode.py module with episode-specific components
- EpisodePlayer: HTML5 audio player - ShareButton: Clipboard copy
with Bootstrap input-group pattern - SignupBanner: Promotional banner
for non-authenticated users - EpisodeDetailPage: Full page layout
- Update Web.py to add /episode/<id> route (public, no auth required)
- Make episode titles clickable in EpisodeList component - Add
Database.get_episode_by_id() method for efficient queries - Update
RSS feed and share buttons to use Bootstrap input-group pattern -
Add comprehensive test suite for episode detail pages
All episode pages are publicly accessible and include: - Media player
to listen to episodes - Share button with URL copying - Links to
original articles - Creator attribution banner for non-logged-in users
Amp-Thread-ID:
https://ampcode.com/threads/T-cc5d29f0-454e-4864-8d7e-1ad69a42afa9
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Created reusable PageLayout component in UI.py with consistent
header/navbar - Added Home link and Admin dropdown menu (Queue
Status, Manage Users) - Updated all pages to use PageLayout: home,
account, admin queue, admin users - Added demo@example.com to admin
whitelist for testing - Added dark mode styling for table headers -
Fixed component children syntax for Ludic framework - Proper type
annotations instead of type: ignore comments
|
|
Change 'Manage Subscription' from HTMX link to regular form POST.
HTMX AJAX requests can't follow redirects to external domains like
Stripe.
|
|
- Remove user-facing error messages for portal configuration -
Just log the error server-side and return 500 status - Use Bootstrap
card-header class for proper padding on section headers - This fixes
icons touching the card borders
Portal errors will now be logged but won't break the UI.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Catch Stripe exceptions when portal not configured - Redirect to
account page with user-friendly error message - Display error alert
on account page when present - Change portal return URL to /account
instead of /
Fixes issue when Stripe billing portal settings haven't been configured
in test/production dashboard.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Display account information (email, creation date) - Show
subscription details (plan, status, features) - Display cancellation
warning if subscription ending - Add Upgrade button for free users -
Add Manage Subscription button for paid users (goes to Stripe portal) -
Add logout button in Actions section - Replace Coming Soon placeholder
with functional UI
Addresses account management epic tasks.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Add 'Remove' button for non-pending queue items (error, processing,
cancelled) - Keep 'Cancel' button for pending items - Update
delete_queue_item to check referer and return appropriate response -
Use HX-Trigger for queue updates from user page, HX-Redirect for admin
- Add confirmation dialog for remove action - Allow admins to delete
any job, users can only delete their own
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Remove 'Logged in as' user email display - Convert button-styled
links to standard Bootstrap nav-link style - Left-align navigation
links (removed me-auto from wrapper) - Remove logout button from navbar
(will be in account page) - Use proper ul/li structure for navbar items
The navbar is now cleaner and follows Bootstrap navbar conventions.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Add mx-1 (horizontal margin) to code element for better text spacing
- Pre-fill email input with demo@example.com in dev/test mode -
Makes it faster to test login flow in development
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
Moved format_duration function from Web.py to UI.py for better code
organization. This is a UI utility function used for displaying
episode durations, so it belongs in the shared UI module rather than
the web-specific module.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Replace Exception with httpx.HTTPError, httpx.TimeoutException,
re.error in extract_og_metadata - Replace Exception with ValueError,
KeyError in auth verification - Replace Exception with httpx errors
and ValueError in submit_article - Replace Exception with ValueError,
KeyError, AttributeError in RSS feed generation - Replace Exception
with ValueError, KeyError in cancel/retry/delete job handlers
Improves error handling specificity and removes BLE001 linter
suppressions.
Amp-Thread-ID:
https://ampcode.com/threads/T-8edacbeb-b343-49ca-b524-1c999272acb6
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Remove /billing page and BillingPage component - Add callout box
on home page showing articles remaining for free users - Upgrade Now
button goes directly to Stripe checkout - Change tier from 'pro'
to 'paid' throughout - Update redirect URLs to go to / instead of
/billing - Remove Billing button from navbar, add Manage Account
link for all users - Add /account route with coming soon page -
Hide payment banner for paid users
Amp-Thread-ID:
https://ampcode.com/threads/T-7de89e42-947c-4243-be19-0cb75be607e7
Co-authored-by: Amp <amp@ampcode.com>
|
|
amp worked on this overnight, and I cleaned it up a bit this morning. I
think its all correct now.
|
|
This is a big test, and probably over-dependencied, but it's nice to
have an end-to-end test as an overall bug-catcher.
|
|
I think the calls to Log.setup() were accidentally creating multiple
loggers, hopefully this fixes the problem.
|
|
|
|
- Add hamburger toggle button positioned on right side - Navbar
collapses on small screens (< lg breakpoint) - Mobile view shows
vertically stacked elements:
- Logged in as: email - Free: X articles left [Upgrade Now] (free
users) - Billing (paid users only) - Admin Queue (admins only)
- Logout
- Remove 'Plan: Pro' text for paid users (just show Billing button)
- Add rounded corners to navbar with 'rounded' class - Remove 1px
bottom border in dark mode - Toggle controlled by Bootstrap's collapse
component
|
|
- Change Upgrade Now button from btn-warning to btn-success -
Convert user info card to Bootstrap navbar with horizontal layout -
Free tier: quota text and Upgrade Now button inline with navbar-text
styling - Paid tier: plan name displayed inline as navbar-text -
Email, plan info, and action buttons all in single horizontal bar -
Uses bg-body-tertiary for automatic light/dark mode compatibility
|
|
- Replace '[Upgrade Now]' text link with proper btn-warning button -
Add arrow-up-circle icon to Upgrade Now button - Hide Billing button
for free tier users (they now have Upgrade Now) - Keep Billing button
visible for paid tier users
|
|
- Create shared UI module (Biz/PodcastItLater/UI.py) with:
- create_bootstrap_styles() - create_auto_dark_mode_style() -
create_htmx_script() - create_bootstrap_js()
- Update Admin.py to use shared UI module and add dark mode support -
Update Web.py to use shared UI module - Admin Queue and User Management
pages now support automatic dark mode
|
|
Subscribe link now appears inline next to label. Click copies URL to
clipboard and shows 'Copied!' feedback for 2 seconds. Link truncates
if too long to fit in bounding box.
|
|
Free tier users now see 'Free: X articles left [Upgrade Now]' banner.
Paid users see plan name with icon as before. Banner replaces the
old plan display in user info card.
|
|
Simplified pricing to two tiers: - Free: 10 articles total (lifetime)
- Pro: $29/month unlimited articles
Removed STRIPE_PRICE_ID_PERSONAL from configuration.
|
|
New accounts now default to 'active' status instead of 'pending'.
Users can start using the service immediately after signup.
|
|
- Implement Biz.PodcastItLater.Billing with checkout sessions, billing
portal, webhook handling - Add subscription database schema: plan_tier,
stripe fields, period dates, stripe_events table - Three-tier pricing:
free (10/month), personal (/month, 50 articles), pro (9/month,
unlimited) - Usage tracking and enforcement with tier-based limits
- Full billing UI with plan display, usage stats, pricing cards,
upgrade buttons - Dashboard shows current tier with billing button -
Update Web.nix with Stripe environment variables - Fix POST redirects
to Stripe with 303 status code for CloudFront compatibility
Amp-Thread-ID:
https://ampcode.com/threads/T-c139e5b5-1901-4cd6-8030-5623bfe1df35
Co-authored-by: Amp <amp@ampcode.com>
|
|
The bg-light class was forcing the 'Logged in as' card to stay
light even in dark mode. Removing it allows Bootstrap's default card
background to adapt to dark mode.
|
|
- Set all CSS variables on :root instead of html/body - Added RGB
variants needed by Bootstrap - Added secondary, tertiary, and border
color variants - Removed unnecessary light mode media query
This should now properly apply dark theme when system prefers dark
mode.
|
|
- Removed JavaScript theme switcher (not needed) - Removed toggle
buttons from all pages - Added automatic dark mode CSS based on
prefers-color-scheme media query - Added color-scheme meta tag
for native UI hints - Uses inline CSS instead of external file
(build system constraint) - Zero JavaScript - pure CSS solution -
Automatically follows system/browser dark mode preference
Task: t-64tkB5
|
|
- Added theme switcher script with localStorage persistence -
Respects system dark mode preference (prefers-color-scheme) - Added
theme toggle button to HomePage and BillingPage - Uses Bootstrap 5.3
data-bs-theme attribute for dark mode - Theme persists across page
loads - Icon changes between moon (light) and sun (dark)
Task: t-64tkB5
|
|
- Implemented complete Stripe integration (Billing.py)
- Checkout sessions for subscription upgrades - Billing portal for
subscription management - Webhook handling for subscription events
- Usage tracking with tier-based limits (free: 10, personal: 50,
pro: unlimited)
- Added billing page UI (BillingPage component)
- Current plan display with usage stats - Pricing cards for all
tiers with upgrade buttons - Manage subscription button for paid
users - Success/error messaging
- Database migrations for billing
- Added plan_tier, stripe_customer_id, stripe_subscription_id - Added
subscription_status, period dates, cancel_at_period_end - Created
stripe_events table for webhook idempotency - Added get_usage()
method for usage tracking
- Made UI mobile-friendly and responsive
- Added viewport meta tags to all pages - Replaced pages.HtmlPage
with raw html.html for meta tag control - Responsive button layouts
with flexbox wrapping - Responsive pricing cards (1 col mobile,
2 col tablet, 3 col desktop) - Touch-friendly forms and buttons
(44px minimum) - Responsive padding and containers - Admin tables
with horizontal scroll
- Added Stripe testing guide (STRIPE_TESTING.md)
- Fixed CSS bug in pricing cards (cardh-100 text rendering) - Updated
tasks: completed t-144e7lF, t-1pIV0ZF, t-1s8ADC0
Amp-Thread-ID:
https://ampcode.com/threads/T-42fd5fb3-3dc5-4cbc-a9a3-78db9e13187e
Co-authored-by: Amp <amp@ampcode.com>
|
|
- Enforce tier limits before article submission - Display current
plan in user info card (Free/Personal/Pro) - Add Billing button to
dashboard navigation - Show friendly upgrade prompt when limit reached
- Link to /billing page for plan management
Limits enforced: - Free: 10 articles/month - Personal: 50
articles/month - Pro: Unlimited
Related to task t-144e7lF
|