Skip to content

links: Open Dropbox shared folder links as a playlist - #266

Draft
cmicali wants to merge 3 commits into
mainfrom
dropbox-folder-links
Draft

cmicali wants to merge 3 commits into
mainfrom
dropbox-folder-links

Conversation

@cmicali

@cmicali cmicali commented Oct 14, 2026

Copy link
Copy Markdown
Owner

What it does

Open URL now accepts a Dropbox shared folder link (/scl/fo/… or /sh/…), such as https://www.dropbox.com/scl/fo/<key>/<hash>?rlkey=…. The folder opens as a playlist of its audio files, subfolders included, in the order Dropbox lists them. It works on the Mac and on iOS, with no Dropbox account.

On iOS, when a Dropbox account is signed in, the folder is listed through the account instead. If the account cannot open it, Open URL falls back to the no-account road.

Why it is built this way

Without an account there is no documented way to list a folder link. Dropbox's files/list_folder with shared_link takes only a user token. The app uses PKCE, so it has no app secret for app auth. A folder link's dl=1 answers a zip built on the fly, with no size and no ranges. So the no-account road lists the folder the way its own share page does: it fetches the page for its t cookie, then posts to /list_shared_link_folder_entries a page at a time. The request shape comes from JDownloader's maintained crawler. Each file then plays from its own link with dl=1, as a single-file link already does.

The playlist is an M3U, so neither shell changed. The resolve still answers one file. Each audio file gets its own directory under the folder link's directory, with a placeholder sized from the listing, and no file is probed. The M3U names them relative to itself, so pruning, Recents and an offline reopen treat the folder as one link.

Signed in on iOS, it uses the documented API. sharing/get_shared_link_metadata names the folder, files/list_folder with shared_link lists it, and sharing/get_shared_link_file downloads by {url, path}. The folder lives beside the account's directory, because a listing of the account's root deletes any name Dropbox does not hold. The budget, sign-out and Recents cover it.

Pros and cons

  • Pro: a link someone sends plays with no sign-in, on both platforms.
  • Pro: a reopen keeps downloads whose size and date did not change, and drops files that left the folder.
  • Con: the no-account listing is undocumented. Dropbox can change it without notice, and its Acceptable Use Policy asks for "publicly supported interfaces". A broken listing fails as "not an audio file", which is vague.
  • Con: the account road needs the sharing.read scope. Existing users must sign in again to get it. Until then, their links take the no-account road.
  • Con: no folder sort setting applies. The playlist keeps Dropbox's order.

Before it can ship

  • Nothing here has been compiled or run. It was written without Xcode. CI is the first build.
  • Enable sharing.read in the Dropbox App Console before release. Otherwise every new sign-in asks for a scope the app lacks.
  • Probe a real folder link (Phase 0 in docs/future/dropbox-shared-links.md). Check that the share page sets t on its final response and not only on a redirect, that a file's href takes dl=1 and answers ranges, and that get_shared_link_file honours Range.

Size

  • Vibe/: +1,163 / −186. About 130 of that is the debug fakes, and about 40 is docs. Tests/: +469.
  • New files: none. New types: none.
  • Unified: the iCloud lookup's resends moved into one call helper that the Dropbox listing shares. settleLink's placement is shared with the folder's files. refreshDropboxFolder: became one listing for the account and its links. The store's readTarget: hook now gets the placeholder's URL, as every other hook does.

Testing

  • New tests: folder link parsing, the listing form and answer (DropboxLinkRulesTests), the folder's open, reopen, departures, offline open, cancel and failures over the stub (DropboxLinkStoreTests). The account road, a missing scope that keeps the account linked, and pruning with the account (DropboxMirrorTests). The fake server's folder link (VibeFakeHTTPTests).
  • make check-vocabulary and make check-layout pass.
  • In a Debug build, set_fake_http <directory> then open_url https://www.dropbox.com/scl/fo/<folder>/x?rlkey=y opens the directory <folder> as a playlist on either platform. On iOS, set_fake_dropbox answers the account road the same way.

Generated by Claude Code

Open URL now opens a Dropbox folder link (/scl/fo/ or /sh/) as a playlist.

With no account, on both platforms, LinkClient lists the folder as its
share page does. LinkStore places one placeholder per audio file under
the folder link's directory and answers an M3U that names them in the
listing's order. The listing endpoint is undocumented and may change.

On iOS with a Dropbox account linked, the mirror lists the folder through
files/list_folder with shared_link. Its files download through
sharing/get_shared_link_file. The links' tree sits beside the account's
directory. When the account cannot open the link, Open URL falls back to
the no-account road. This adds the sharing.read scope, which needs the
App Console and a fresh sign-in.

The iCloud lookup's resends move into one call helper the listing shares.
settleLink's placement is shared with the folder's files. The store's
readTarget hook now gets the placeholder's URL.

Not compiled or run: written without Xcode.
A grant from before sharing.read answers a shared link's first call with
401 missing_scope. The failure ladder unlinked on any 401 but an expired
token, so that call signed the user out and pruned every download before
Open URL fell back to the no-account road. A missing scope now fails the
call and leaves the account linked.

Also from review:
- The shared-link tree is written only for the account the open started
  with. An account change between the calls writes nothing.
- A cancelled folder listing reads no answer that lands after the cancel.
- A Dropbox listing that names a page it already sent ends.
- The docs say what the listing's timeouts are: each request's idle
  timeout, with two resends, and no deadline for the whole listing.
The account now sends a share's own link, with the folder's path below
it. That is how the API names a share. The folder's directory is then
the top of what the account lists for that link.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants