fix: share, upload, crop, auto-skip, tag chips and See all hold what they claim

- Share: a link that expired is never copied (the dialog and one-click Share pick a live one,
  else make one), says it expired, and the copy-on-open claim clears on the next copy.
- A password-protected file link asks to open a file, not to watch a video.
- Upload: Cancel, the close button or the backdrop while naming a folder makes no folder; a failed
  refetch keeps the target; a folder being made says so.
- Crop: an infinite number is dropped, not a 500; an unprobed clip's size follows a shown-size crop;
  the edit_spec docs name frame_w/frame_h; the join and rotated paths are tested.
- Auto-skip: the wait gives way on a marker too short for it, so the skip still fires.
- Tag chips count the followed channels (subscribed_count) and a toggled chip keeps the focus.
- Continue watching's See all sorts by last watched when in progress was already on.
This commit is contained in:
2026-11-06 00:09:39 +01:00
parent c34f6f3297
commit 8383459f70
39 changed files with 760 additions and 82 deletions
+16 -4
View File
@@ -41,11 +41,23 @@ def video(db: Session, video_id: str) -> Video | None:
# --- tags ------------------------------------------------------------------------------------
def tags_with_counts(db: Session, user: User) -> list[tuple[Tag, int]]:
"""The tags this user sees (the shared system ones and their own), each with how many channel
links it has, by category then name."""
def tags_with_counts(db: Session, user: User) -> list[tuple[Tag, int, int]]:
"""The tags this user sees (the shared system ones and their own), by category then name, each
with how many channel links it has and how many of the user's own links sit on a channel they
subscribe to — the rows the Channels page's tag filter shows. A link outlives an unsubscribe,
so the two differ."""
subscribed = select(Subscription.channel_id).where(owned_by(Subscription.user_id, user))
on_subscribed = dict(
db.execute(
select(ChannelTag.tag_id, func.count(ChannelTag.id))
.where(owned_by(ChannelTag.user_id, user), ChannelTag.channel_id.in_(subscribed))
.group_by(ChannelTag.tag_id)
)
.tuples()
.all()
)
return [
(tag, count)
(tag, count, on_subscribed.get(tag.id, 0))
for tag, count in db.execute(
select(Tag, func.count(ChannelTag.id))
.outerjoin(ChannelTag, ChannelTag.tag_id == Tag.id)