Commit graph

822 commits

Author SHA1 Message Date
dd140842ca skip backfill retry when source file missing from S3 (NoSuchKey) 2026-02-18 07:13:28 -05:00
015121b600 include voxsplit.c in package data 2026-02-18 06:52:01 -05:00
8a0eef7b39 keep unsandbox keys on validation failure, let user fix them 2026-02-18 06:49:19 -05:00
16314eeee5 fix backfill: use get_object/put_object instead of download_file/upload_file
boto3 TransferManager spawns its own ThreadPoolExecutor internally,
which crashes with 'cannot schedule new futures after interpreter
shutdown' when uWSGI recycles the worker process.
2026-02-18 06:09:57 -05:00
a9a9ba69b1 add unsandbox key extension link in shop settings 2026-02-18 06:01:50 -05:00
c8b9dd310a validate unsandbox keys on save, reject invalid/expired 2026-02-18 06:01:11 -05:00
be40ab432b vendor voxsplit.c into lib/ — was pointing at local dev path 2026-02-18 00:22:54 -05:00
f77d06a80b vendor unsandbox SDK into lib/un.py 2026-02-17 23:55:59 -05:00
f8ce118305 fix karaoke: lazy-load unsandbox SDK to avoid import failure in CI 2026-02-17 23:51:06 -05:00
1135eb24e4 add karaoke mode: vocal isolation via unsandbox zerotrust containers
Per-shop unsandbox API keys in shop settings. On upload, audio/video
products are processed through voxsplit in a zerotrust container (no
network, destroyed after use) producing both instrumentals and vocals
tracks. Background backfill with ThreadPoolExecutor sized to account
concurrency, exponential backoff retries. Player cycles Original →
Instrumentals → Vocals with toggle button or K shortcut.
2026-02-17 23:46:45 -05:00
6e40886cd7 Fix RGB color filters: use pure CSS filter chains instead of SVG references
Chrome blocks external SVG filter references via CSS url(). Replace with
native CSS filter functions (grayscale + sepia + hue-rotate + saturate)
that work in all browsers. Delete the now-unused SVG file.
2026-02-15 12:25:45 -05:00
9310360903 Fix edit page media previews: add presigned URL generation, type-aware embeds, mock S3 in test 2026-02-15 11:47:27 -05:00
6a536f18c9 Fix RGB color filters: use external SVG file for filter definitions
Inline SVG filter url(#id) fails when the SVG defs are inside the
filtered element (both on <html> and <body>). Data URI SVG filters
are blocked by Chrome. External SVG file at /static/svg/color-filters.svg
avoids both issues — no DOM circular reference, no security block.
Browser fetches the SVG once and caches it.
2026-02-15 11:04:27 -05:00
f0a5a392d0 Fix RGB color filters: apply to body, not html, with inline SVG defs
Data URI SVG filters don't work in Chrome (blocked for security).
Inline url(#id) on <html> fails due to root-element rendering order.
Fix: keep data-color-filter attribute on <html>, apply filter to <body>
via descendant selector. SVG filter defs in <body> with <defs> wrapper
resolve correctly since DOM is parsed before CSS filter is applied.
2026-02-15 10:49:44 -05:00
85b1a2d033 Fix RGB color filters: use data URI SVG instead of inline DOM references
CSS filter: url(#id) on <html> fails because the SVG filter definitions
are children of the element being filtered (circular reference). Grayscale
worked because it uses native CSS filter, not SVG. Now all feColorMatrix
filters are self-contained data URIs in CSS — no DOM SVG block needed.
2026-02-15 09:23:14 -05:00
25b9f53c99 Add random button to watch ring, RGB color filters, move comment email below textarea
- Add shuffle button next to Next in SPA ring navigation
- Expand grayscale mode to full color filter system (off, grayscale, R, G, B, R+G, R+B, G+B)
  using SVG feColorMatrix filters for selective channel isolation
- Move comment email field below textarea, fix email input theming for dark mode
2026-02-15 08:10:15 -05:00
dfb70666b4 Add grayscale mode: CSS filter renders entire shop in black and white
Server renders data-grayscale="on" on <html> so it works without JS.
Toggle in Ribbon & Layout settings, off by default. Original assets
untouched — purely presentational via filter: grayscale(100%).
2026-02-15 05:25:30 -05:00
d07195568b Fix mobile related content showing 42 items instead of 7
The .related-content-overflow display:none rule was being overridden by
.related-content-row display:grid later in the file (equal specificity,
cascade order wins). Bump specificity with .related-content-row.related-content-overflow.
2026-02-14 11:38:32 -05:00
7e4b691882 Trigger salt highstate: add origin.makepostsell.com caddy site block 2026-02-13 19:42:31 -05:00
8aad7037a3 Trigger salt highstate: refresh caddy configuration 2026-02-13 13:51:41 -05:00
d7e98e7148 Redirect no-shop users to /s/new, improve anonymous landing page
Authenticated users on the SaaS domain with no shop get redirected
from / to /s/new instead of seeing a bare message. Flash messages
are preserved by skipping the redirect when peek_flash() has content.

Anonymous visitors now see a proper landing with tagline and CTA.
2026-02-13 12:10:13 -05:00
c4d3537a28 Queue-add flash: green bg + purple glow on entire row, 5s fade
Clicking the + button flashes the entire related-content-row with green
background, purple box-shadow glow, and white text. Animation fades out
over 5 seconds. Repeated clicks reset the animation and add duplicates
to the queue.
2026-02-12 13:56:43 -05:00
2ad12262df Update CLAUDE.md with Salt deploy notes, CI/CD details, mobile layout docs 2026-02-12 13:51:37 -05:00
11056cf208 Add green flash animation on queue-add button click
Visual feedback when adding items to the queue: the "+" button
pops to 1.3x scale with a green background, then eases back.
Reflow trick allows re-triggering on repeated clicks.
2026-02-12 12:48:38 -05:00
fd39b2ae80 Fix CI build: ensure bin/python symlink exists for virtualenv-clone
Python 3.12 venv may only create bin/python3 and bin/python3.12 without
a bin/python symlink. virtualenv-clone 0.5.7 expects bin/python to exist
when introspecting the cloned venv, causing FileNotFoundError.
2026-02-12 08:03:01 -05:00
0967e4d6fb Fix mobile video overflow: constrain watch container to viewport width
Product images container now uses overflow:hidden + min-width:0 to
prevent the CSS grid child from expanding beyond the viewport. Watch
video container also gets max-width:100% + min-width:0 for the same
grid overflow fix.
2026-02-12 07:32:54 -05:00
47fb7a5440 Add Comments link below download button on mobile
Shows "Comments (N)" anchor link below the purchase/download well,
visible only on mobile where comments section is further down the page.
SPA navigation updates the count dynamically.
2026-02-12 07:32:14 -05:00
0299f85fc9 Mobile: limit related content to 7 items, add Comments anchor link
On mobile (<800px), hide related content items beyond offset 7 to
reduce scroll. Add a "Comments (N)" link at the bottom of the related
content panel that jumps to the comments section below. Hidden on
desktop where comments are already visible in the sidebar layout.
Updated all three layers: template, watch.js SPA, and watch JSON.
2026-02-12 07:27:26 -05:00
1e5fe27d38 Price history on product pages, Fresh toggle, media type filters for ring
Price history: expandable <details> section on sellable product pages,
gated to shop editors. SPA-synced via watch.py JSON + watch.js rebuild.
Ticket 09 for future membership-gated access.

Fresh toggle: hides already-watched ring items (display:none vs dimmed),
persisted in localStorage, so loopers see only unwatched content.

Media type filters: Video/Audio/Image/Docs/Other pill buttons below
ring controls. Toggle off a type to hide those rows from the ring.
All on by default, persisted in localStorage. Server-rendered via
Jinja macro + data-media-type attribute, JS-synced during SPA nav.
2026-02-11 19:22:44 -05:00
13aeab7188 Retry deploy: added reload_on_rss to caddy_sites.sls 2026-02-11 18:49:29 -05:00
69ee077cb4 Retry deploy: confirmed salt fileserver has reload_on_rss 2026-02-11 18:22:50 -05:00
f4661ad6b8 Retry deploy after salt fileserver update 2026-02-11 17:49:29 -05:00
7c79304fcb Retry deploy: salt master now has reload_on_rss in sites.sls 2026-02-11 15:45:18 -05:00
d9a565b57a Add tickets MPS-4 and MPS-5 for 502 worker recycling fix
MPS-4: Eliminate intermittent 502s via uwsgi config tuning
MPS-5: Investigate root cause of worker memory growth (~40MB/min)
2026-02-11 10:13:52 -05:00
faefd94abf Video watch metrics, per-product analytics page, SPA thumbnail sync
Analytics:
- Add video watch metrics section to shop dashboard (avg % played,
  completion rate, seeks, rewinds, pauses, speed) with per-product
  video breakdown table
- Add per-product analytics detail page at /s/{shop_id}/analytics/{product_id}
  with views over time, video watch, traffic, devices, ring entries,
  engagement, comment sentiment, and price history
- Product title links on shop analytics now go to per-product analytics
- Add get_sentiment_summary_for_product() helper

SPA fix:
- Update thumbnail image src and wrapping link href during DJ fade
- Clear stale extra thumbnails from previous product
- Add file_url to watch JSON for thumbnail-to-file links
2026-02-11 09:03:29 -05:00
2f5498a1f4 deleted: docs/tickets/an-algo/01-engagement-signal-weighting.md
deleted:    docs/tickets/an-algo/02-truth-fidelity-score.md
	deleted:    docs/tickets/an-algo/05-love-chains-referrals.md
	deleted:    docs/tickets/an-algo/06-love-letters-messaging.md
	deleted:    docs/tickets/an-algo/08-pillars-score-dashboard.md
	modified:   make_post_sell/GIT_HASH
2026-02-10 16:53:31 -05:00
7401b4a3c3 Fix 502s from anonymous visitors: guard request.user.can_edit_shop with null check
Bot crawlers (AhrefsBot, SemrushBot) hitting content pages caused
jinja2.UndefinedError: 'None' has no attribute 'can_edit_shop' because
request.user is None for unauthenticated visitors.
2026-02-10 08:54:51 -05:00
a950304a49 Epic DJ transitions: fade video/audio to black before static, smooth 20fps countdown fade on all content types
Video/audio → static/cross-type now fades volume + opacity over 7 seconds
instead of abrupt cut. Static content (images, PDFs) fades out smoothly
during the 7-second countdown. All transitions cancelable, no abrupt stops.
2026-02-10 07:37:41 -05:00
2c4237f136 Fix cutoffs test for dict return value 2026-02-09 19:02:01 -05:00
ed9c2a6a08 Show ring consumed across 5 time periods: today, 7d, 28d, year, lifetime 2026-02-09 18:22:28 -05:00
f2e88989a2 Fix ring consumed to count unique products viewed, not average position index 2026-02-09 18:20:07 -05:00
6c71af4017 Change avg ring depth to avg ring consumed percentage 2026-02-09 17:58:07 -05:00
fb04cf0159 Show top 42 ring entry points instead of 7 2026-02-09 17:47:30 -05:00
fca2f4a051 Isolate parallel test runs with PID-based database filenames
When two processes run pytest simultaneously, they no longer share
test_make_post_sell_master.sqlite. Each gets its own file keyed by PID,
preventing table-exists and readonly-database errors. Also clean up
WAL/SHM journal files on exit.
2026-02-09 16:24:25 -05:00
e1a8b2f236 Yield GIL in discovery ring computation to unblock uwsgi during reforge
The O(n²) greedy walk held the GIL for the entire computation, starving
uwsgi workers on the 2 vCPU box. time.sleep(0) in the inner loop
releases the GIL each iteration so request handling can interleave.
2026-02-09 15:24:15 -05:00
3e6786155a Anonymous signal gathering with view counts (MPS-2)
One beacon per page visit sent on unload (~300 bytes JSON). No cookies,
no IPs, no fingerprints. A view counts after 7 seconds of visible time.
Creators see view counts on product pages; raw data feeds future analytics.

New: PageSession model, /signals/beacon endpoint, signals.js client
collector, product view_count column with human_view_count property,
Alembic migration, SPA integration, 30 new tests (667 total, all pass).
2026-02-09 15:01:36 -05:00
dac8cc9280 Add unit, integration, and functional tests for async ring reforge
Unit (6 tests): thread spawning, dirty bit behavior, debounce
collapse, session.expire_all on re-run, exception cleanup, missing
shop handling.

Integration (3 tests): ring persisted to DB, dirty bit picks up
latest state, private/unlisted products excluded.

Functional (5 tests): edit doesn't block, product page uses existing
ring, watch JSON never reforges, new product triggers async reforge,
no trigger when watch mode off.
2026-02-09 14:08:11 -05:00
bda4d39858 Use dirty bit instead of drop for async ring reforge debounce
When a reforge is already running, set a dirty flag so the thread
loops once more after finishing — picks up latest product state
from rapid saves without queueing multiple reforges.
2026-02-09 13:55:00 -05:00
3ba8802d9a Fix SQLAlchemy deprecation in async reforge, add playback progress restore, add signal gathering tickets 2026-02-09 13:52:34 -05:00
7b7a2d1edb Async ring reforge, update og:image during SPA navigation, remove inline reforge
Ring reforge now runs in a background thread to avoid blocking requests.
Product/content views no longer reforge inline — they use the existing ring
or fall back to related products. og:image meta tag updated during SPA
navigation so the now-playing row shows the correct thumbnail.
2026-02-09 13:45:42 -05:00