fix(playlists): a refused push spends none of the push allowance
The cooldown was checked before the list was found pushable and before its sync claim, so Watch later or a list another sync held used up the push allowance. It now counts only a push that runs. The docstring that called a YouTube mirror unpushable is corrected: its local edits sync back.
This commit is contained in:
@@ -261,8 +261,9 @@ def _check_push_cooldown(user: User) -> None:
|
||||
|
||||
|
||||
def _pushable(db: Session, user: User, playlist_id: int) -> "Playlist":
|
||||
"""A local playlist the user may push to YouTube (create or update). The built-in
|
||||
Watch later and read-only YouTube mirrors are never pushable."""
|
||||
"""A playlist the user may push to YouTube: a local one (created there on its first push) or a
|
||||
mirror of their own YouTube list (its local edits merged back). Only the built-in Watch later is
|
||||
never pushable."""
|
||||
pl = _own_playlist(db, user, playlist_id)
|
||||
if pl.kind == "watch_later":
|
||||
raise _refused(400, "watch_later_not_pushable")
|
||||
@@ -278,8 +279,8 @@ def push_plan(
|
||||
"""Dry run: what a two-way 'Sync to YouTube' merge would do (what each side gains/loses) +
|
||||
the quota estimate, so the UI can show a confirm. For a linked playlist this reads the live
|
||||
YouTube state (cheap, 1 unit/page). Write scope is required — syncing is a YouTube write."""
|
||||
_check_push_cooldown(user)
|
||||
pl = _pushable(db, user, playlist_id)
|
||||
_check_push_cooldown(user) # after the refusal: a list that cannot be pushed spends nothing
|
||||
try:
|
||||
with quota.attribute(user.id, quota.QuotaAction.PLAYLISTS_PUSH):
|
||||
plan = plan_merge(db, user, pl)
|
||||
@@ -299,13 +300,14 @@ def push(
|
||||
"""Two-way sync a local playlist with YouTube (create it on first push, else 3-way merge so
|
||||
neither side loses an item). Refuses if the estimated quota exceeds what's left today, so a
|
||||
big sync can't strand half-applied. Write scope required (require_write_scope)."""
|
||||
_check_push_cooldown(user)
|
||||
pl = _pushable(db, user, playlist_id)
|
||||
# One sync of a list at a time, across tabs, devices and the scheduler (`sync_claim`): the
|
||||
# client's own in-flight flag only covers the menus of one page.
|
||||
with sync_claim(db, pl.id) as free:
|
||||
if not free:
|
||||
raise _refused(409, "sync_busy")
|
||||
# Spent only by a push that runs, as Revert's pull: a busy list or Watch later costs nothing.
|
||||
_check_push_cooldown(user)
|
||||
try:
|
||||
with quota.attribute(user.id, quota.QuotaAction.PLAYLISTS_PUSH):
|
||||
# Read the live playlist ONCE (linked playlists only) and share it with both the
|
||||
|
||||
Reference in New Issue
Block a user