How an external download tool tells Floppy what you want and what you own, by
provider id, without Floppy running anything new. FlexGet's floppy_list
plugin is the reference client; the same calls work from curl or any script.
The runnable half of this document is
src/api/tests/test_fork_media_collection.py, plus the list-membership tests in
src/api/tests/test_media_core.py. If this page and those files disagree, the
files are right.
SECRET=test-only scripts/test.sh api.tests.test_fork_media_collectionTwo things in Floppy, kept separate on purpose:
| Concept | Meaning | Where it shows |
|---|---|---|
| A custom list (for example "To Download") | You want this | Lists; add-to-list button on cards and detail pages |
| Collection | You own this | Collection page; the collected / not collected library filter |
Status is a third, independent axis: Planning means "I intend to watch
this", not "I have not downloaded it". A title that is Planning and collected
is downloaded and waiting to be watched.
Create a token in Settings → Integrations → App tokens and send it as
Authorization: Bearer flp_xxx (or X-API-Key: flp_xxx).
| To | Scope |
|---|---|
| Read lists and their items | lists:read |
| Add to or remove from a list | lists:write |
| Read the collection | watchlist:read |
| Add to or remove from the collection | watchlist:write |
See docs/architecture/api-scopes.md for the scope contract.
Movies and shows are addressed as {media_type}/{source}/{media_id}, and the
API accepts tmdb as the provider source for both. A client holding only a
TVDB or IMDb id must resolve it to a TMDB id first (TMDB's /find/{id}
endpoint does this); FlexGet's plugin does so automatically, and falls back to
a TMDB search by name when an entry carries no id at all.
Episodes are addressed by their show's TMDB id plus season and episode numbers. No episode-level id is needed.
A title Floppy has never seen is created from provider metadata on first use,
so a client does not have to track or search for it beforehand. A movie or show
created this way is stored with its release date and its IMDb and TVDB ids, so
list reads return them in release_datetime and ids straight away.
| Operation | Call |
|---|---|
| Find a list's id by name | GET /api/v1/lists/ |
| Read a list | GET /api/v1/lists/{list_id}/items/ |
| Add a movie or show | PUT /api/v1/media/{movie|tv}/tmdb/{id}/lists/{list_id}/ |
| Remove a movie or show | DELETE /api/v1/media/{movie|tv}/tmdb/{id}/lists/{list_id}/ |
| Add or remove a season | PUT / DELETE /api/v1/media/tv/tmdb/{id}/{season}/lists/{list_id}/ |
curl -X PUT -H "Authorization: Bearer $TOKEN" \
"$FLOPPY/api/v1/media/movie/tmdb/603/lists/7/"| Status | Meaning |
|---|---|
200 |
Added; the body lists the item's list memberships |
409 |
Already in the list |
404 |
The list does not exist, or the provider does not know the id |
502 |
The provider could not be reached; nothing was created, retry later |
List reads are paginated with limit (at most 200) and offset; follow
pagination.next until it is null. Each result carries an item with
media_type, source, media_id, title, season_number,
episode_number, release_datetime, and ids.
Limits:
- Lists do not hold single episodes.
- A season can only be added when Floppy already has that season; movies and
shows are created on demand. Anime on the TMDB or TVDB route is not created
on demand (it is stored as TV in the anime bucket); use
tvfor it. - Smart lists are filled from their rules, so write to manual lists only. A
smart list with a
Planningstatus rule is the way to read "everything in Planning" through the list endpoint.
| Operation | Call |
|---|---|
| Read the collection | GET /api/v1/collection/ |
| Collect a movie | PUT /api/v1/media/movie/tmdb/{id}/collection/ |
| Collect an episode | PUT /api/v1/media/tv/tmdb/{show_id}/{season}/episodes/{episode}/collection/ |
| Remove either | DELETE on the same URL |
curl -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"resolution": "1080p"}' \
"$FLOPPY/api/v1/media/tv/tmdb/1396/2/episodes/5/collection/"The body and every field in it are optional. A repeat call changes only the fields it sends.
| Field | Value |
|---|---|
resolution |
Free text, at most 100 characters, shown as the entry's quality |
media_type |
Free text, at most 20 characters (bluray, dvd, digital) |
hdr, audio_codec |
Free text, at most 30 characters |
audio_channels |
Free text, at most 20 characters (5.1, 7.1.2) |
is_3d |
true or false |
bitrate |
Audio bitrate in kbps, a whole number |
collected_at |
ISO 8601 date and time (a time without an offset is read in Floppy's time zone); defaults to now |
| Status | Meaning |
|---|---|
201 |
Collected; the body is the new collection entry |
200 |
Already collected; the existing entry is returned, with the sent fields updated |
204 |
Removed (DELETE) |
400 |
Unsupported media type or source, a body that is not a JSON object, an invalid field, or a show without season and episode |
404 |
The provider does not know the id, or (DELETE) there was nothing to remove |
502 |
The provider could not be reached; nothing was created, retry later |
PUT is idempotent, so replaying a download event, or reporting a quality
upgrade, updates one entry instead of adding copies. Two calls arriving at the
same moment still produce one entry.
Until the API has created a copy, PUT reuses a copy added elsewhere (by hand
or by an import) only when that copy has no media_type or the same one (case
and punctuation are ignored, so Blu-ray matches bluray); without a sent
media_type, any copy is reused. Otherwise it adds its own copy (201) and
leaves the other one unchanged.
DELETE removes only the copy the API created. A copy added by hand in
Floppy (for example a disc with its own details) is left alone, and DELETE
answers 404 when only such copies exist. Add ?all=true to remove every
copy of the title.
Limits:
- Shows are collected per episode.
PUT .../media/tv/tmdb/{id}/collection/without a season and episode is rejected, because marking a whole show needs every episode to be known first. - Entries created this way are ordinary collection entries, the same as ones added in the UI. They are not labelled with the tool that reported them.
FlexGet's floppy_list plugin wraps the calls above as a managed list, so it
works as an input and with list_add, list_remove, list_match, and
list_clear.
Download what is on a Floppy list:
tasks:
queue-movies:
floppy_list:
base_url: http://localhost:8000
api_key: flp_xxx
list: To Download
type: movies
accept_all: yes
list_add:
- movie_list: wantedMark what was downloaded as collected, and take movies off the list:
tasks:
download:
# ... your inputs, series/movie filters and download output ...
tmdb_lookup: yes
list_add:
- floppy_list:
base_url: http://localhost:8000
api_key: flp_xxx
list: collection
list_remove:
- floppy_list:
base_url: http://localhost:8000
api_key: flp_xxx
list: To Download
type: moviesSkip what is already owned:
list_match:
from:
- floppy_list:
base_url: http://localhost:8000
api_key: flp_xxx
list: collection
action: reject
remove_on_match: noThe plugin's own option reference lives on the FlexGet wiki under
Plugins/List/floppy_list.