# Media and the Media Archive

**For administrators.** How to get an Image, Video, Audio, or Attachment file into a Post, how the site-wide media inventory and the Dropbox-backed personal Media Archive work, and the reference detail behind permanent addresses and resize parameters for anyone who needs it. See [Welcome to Kartotek](/_docs/kartotek) for the vocabulary this doc assumes, and each Content Type's own reference page for its specific fields.

## Adding media to a Post

Three ways in for Image/Video/Audio, all producing the same kind of content element in the end (Attachment supports only the first two — a downloadable file doesn't fit an embed-snippet model):

- **Upload** — a file, or several at once (each becomes its own element). Drag-and-drop and copy/paste both work the same way.
- **Fetch by URL** — paste a URL pointing at a downloadable file; the server fetches it and stores the result exactly as if it had been uploaded directly.
- **Embed** — paste a hand-provided embed snippet (e.g. a YouTube or Spotify embed code), keeping the media off-site entirely. This is the only path with **no local file** — nothing is stored or served from this site at all; the element renders via its own snippet instead.

Once added, choose its **Role** (what it's for — `cover`, `gallery`, and so on) and an optional **caption**. Upload and Fetch by URL both end up with a real, locally-stored original that gets its own permanent address (see "Advanced reference," below); Embed doesn't.

**What's copied in versus left external:** Upload and Fetch by URL copy the actual bytes onto this site — if the original source later disappears, your copy still works. Embed deliberately does the opposite — nothing is copied, so if the embedded source goes away or changes, so does what visitors see.

**Your responsibility:** you're responsible for having the rights to whatever you upload, fetch, or embed — Kartotek doesn't check copyright or licensing on your behalf.

**Supported formats:** common image formats are supported for all the features below (resize, EXIF). Locally-uploaded or fetched-by-URL Video is restricted to **MP4 and WebM**; Audio to **MP3 and M4A** — a file's actual contents are checked, not just its name or file-picker extension, so renaming an unsupported file to look like an accepted one doesn't bypass this. Attachment accepts a fixed set of common document formats (PDF, plain text, zip, RTF, Word, Excel, PowerPoint) — a PDF or plain text file opens inline when clicked; every other type downloads instead.

An Embed (no local file — see above) isn't subject to this restriction at all, since nothing is uploaded; a third-party provider's own supported formats apply instead.

**If something fails:** a failed upload or fetch shows an error rather than silently doing nothing — retry it, or try a different source URL.

**Who can see a media file:** visiting a media address directly respects the owning Post's Stage exactly like visiting the Post itself — a Private Post's file isn't reachable at all, and a PrePub/Hidden Post's file is reachable only while logged in as the admin. This applies to every kind (Image/Video/Audio/Attachment) alike.

## Metadata shown to admins

When an Image is uploaded or fetched by URL (not an embed, which has no local file to inspect), relevant embedded metadata — currently just **captured date** and **GPS location**, where present in the file's EXIF data — is extracted and shown read-only in the admin editor next to that image's caption.

A locally-uploaded or fetched-by-URL Video or Audio file similarly has technical facts extracted automatically — duration, container/codec, frame rate, bit rate, and (Video) resolution and rotation, or (Audio) sample rate, channel count, and embedded title/artist/album tags where present. This happens right after the file is stored and never blocks or fails the upload itself: a file with no readable metadata, or one this extraction step genuinely can't process, is still accepted and stored — only the technical details are missing. Embedded tags (title/artist/album, capture dates) are descriptive only, never treated as authoritative editorial metadata — they don't overwrite anything you've entered by hand.

Re-uploading or re-fetching an already-processed file, or re-running the maintenance catch-up (see [Dashboard and maintenance](/_docs/dashboard)'s Backfill operations), is always safe — it reconciles the same technical facts without touching your own Caption, Role, or other editorial fields.

## Video thumbnails

A locally-uploaded (or fetched-by-URL) MP4/WebM Video automatically gets a representative still-image thumbnail shortly after it's added — used anywhere a Video needs a non-playing preview (a Gallery's thumbnail grid, the "Additional Information" media list, and similar contexts), with a small play icon so it's never mistaken for an ordinary Image. This never blocks saving the Post — a Video is usable immediately, and the thumbnail simply appears once generation finishes.

Generation deliberately avoids the very first frame (often a black frame, a fade-in, or a title card): several candidate moments across the earlier-to-middle part of the Video are sampled, near-black or visually flat ones are rejected, and the most representative of what's left is chosen automatically. A very short Video degrades safely to its best available frame rather than failing.

**Admin can override the automatic choice**, from the Video's own field in the editor:

- **Pick an exact timestamp** — enter a time in seconds and use that exact frame.
- **Upload a custom still** — any of the same image formats/validation as an ordinary Image upload, replacing the Video-derived frame entirely.
- **Restore automatic** — discards a manual/custom choice and goes back to automatic generation.

A manual timestamp or custom upload is never silently overwritten by automatic (re)generation — only an explicit "Restore automatic" click replaces it. If generation genuinely fails (a corrupt file, an unusual encoding it can't read), the Video itself is completely unaffected — it's still playable — and a generic Video placeholder is shown wherever the thumbnail would have appeared, until a manual/custom choice or a successful regeneration provides one.

## Deduplication

Uploading or fetching-by-URL the exact same file more than once — including through a historical import — doesn't store a second copy: the file's contents are checksummed, and an identical match reuses the already-stored original rather than duplicating it. This is entirely automatic and invisible in normal use; each element still keeps its own Role, Rank, caption, and Reference independently, even when two elements happen to share the same underlying file.

## Post Media: the site-wide inventory

The admin sidebar's **Media** section is the single entry point for all media management, expanding into three entries: **Post Media**, **Archive Media**, and **Archive Roots**.

**Post Media** lists every Image, Video, Audio, and Attachment Content Element currently referenced by any Post, regardless of which one — summary tiles at the top break the total down by kind. This is a read-only inventory, not a media library with its own upload/ingestion flow — media is always added through the Post it belongs to (above).

Post Media and Archive Media (below) share the same browsing framework: **List**, **Gallery** (a responsive thumbnail grid), **Time Chart**, and **Map** views, switchable without losing your current filters, with the active view, filters, sorting, and pagination all reflected in the page's address — reload or share the link and you get back the same filtered results. Selecting an item's detail — Archive Media's "Filename"/thumbnail, Post Media's "Edit" (Categories/Tags), or a Map marker — opens it in a modal overlay above the inventory rather than appended below it (Post Media's Map/Gallery instead go straight to that item's own Post, the same as clicking it in Gallery), so the List/Gallery itself and your scroll position within it are never disturbed; closing it (the **×** in the corner, Escape, clicking outside, or its own **Close** button) returns you to exactly where you were, and it warns before discarding an edited Title/Description/Notes/Tags you haven't saved. List and Gallery show, where available: a thumbnail, kind, the owning Post and Role (Post Media) or the archive folder/path (Archive Media), file type and size, capture date and when it was added, capture device, and whether the item has location coordinates ("Geocode"); Archive Media's List view additionally shows its own Privacy/Quality classification (below) — Post Media carries no such field. A field a given kind doesn't support (Video/Audio/Attachment have no capture-date/location extraction today) simply shows as not available rather than a wrong or made-up value. Filters — kind, Geocode (Yes/No/Any), capture device, whether a capture date is present (Yes/No/Any), Category (Post Media) or Archive Root (Archive Media), and more — combine together, and their dropdown choices (e.g. which devices show up) are drawn from what's actually in your inventory, not a fixed list. Archive Media's own filters additionally include Privacy, Quality, and "Not publicly eligible." The result count and a **Clear all filters** action are both always visible, and an empty result reads differently depending on whether the whole collection is empty or your filters simply matched nothing.

**A From/To time filter** sits above all four views, so it narrows List, Gallery, Time Chart, and Map consistently, and both ends are inclusive. It filters by each item's *resolved time* — its capture date when one was found (from EXIF or, failing that, the filename), or otherwise the date it was added/discovered, visibly labeled as a fallback rather than presented as a real capture date; an item with neither is an **Unknown date**, always counted separately rather than silently dropped, and excluded from the results only while a concrete time range is active. **Clear time filter** resets it.

**Time Chart** renders a histogram of your current filtered results — one bar per time period, counted at whichever level (year, month, day, or hour) fits the span you're viewing — with Unknown-date items called out as their own count alongside the bars, never folded into them. Clicking a bar, or dragging across several, both narrows the chart to that period and sets the From/To filter to match, so you can drill from a whole collection down to a single day and then switch to another view to see exactly those items; **Zoom out**/**Reset zoom** widen what the chart displays without touching your filter. A **View as table** link exposes the same data as a plain accessible table, with each bar's capture-date and file-date-fallback counts shown side by side.

**Map view** plots every currently-filtered item that has location coordinates, clustering nearby markers together where the density warrants it and separating them again as you zoom in; clicking a marker (or a cluster, to spread it apart first) opens that item the same way clicking it in Gallery would. The map's own bounds start fitted to whatever's currently plotted, and the number of filtered results with no coordinates — never simply hidden without explanation — is always shown alongside it. **Geographic filtering**: click anywhere on the map to set (or move) a circular filter centre, then enter a diameter and choose kilometres or miles; the circle and its centre stay visible and editable (drag the centre, or click elsewhere to move it), and a point exactly on the circle's edge counts as inside it. This filter isn't Map-only — once set, it narrows List, Gallery, and Time Chart the same way any other filter does, stays applied when you switch views, and survives a reload or a shared link exactly like every other filter here. **Clear geographic filter** removes it entirely, in one action.

## Media health and storage

Post Media and Archive Media each show a **Metadata & derivative health** group of stat cards above their List/Gallery view, alongside their own **Storage** group. Clicking a health card opens the same filtered List view a matching sidebar filter would, switching out of Gallery first if needed; a card at zero still opens (a genuinely empty filtered list), just shown visually muted.

**Metadata & derivative health:**

- **EXIF extracted** — media with at least one normalized EXIF value (capture date, geocode, or device) successfully found. A file that was genuinely scanned and simply has no EXIF data isn't a failure and doesn't count here either.
- **Missing thumbnails** — thumbnail-capable media with no current, usable thumbnail. Only Video is thumbnail-capable this way today (see "Video thumbnails," above, and Archive Media's own scan-time thumbnail generation) — an Image serves its own file directly, and Audio/Attachment intentionally use a fixed icon, so neither ever counts here.
- **EXIF extraction failed** — an extraction attempt genuinely errored. Distinct from: never attempted, and from a successful scan that simply found no data (above).
- **With EXIF capture date / geocode / capture device** — the same normalized values "EXIF extracted" checks for, broken out individually. Capture date never counts a file-date fallback; an invalid/binary device value never counts either.

**Storage** (measured periodically in the background, never on page load — the panel shows when it was last measured, and a not-yet-measured figure reads as a dash rather than a misleading zero):

- **Total database size** is a global, whole-installation figure — identical on both Post Media's and Archive Media's pages, not specific to either collection.
- **Thumbnail/cache size** is local disk used by generated thumbnails for that collection specifically; each physical cached file is counted once even if several records reference it. The two collections' own cache directories don't overlap, but the two displayed figures aren't guaranteed to sum to the sitewide total shown in the panel's own footnote.
- **Original media size** (Post Media only — Archive Media's originals live in Dropbox, not on this site) is local disk used by Post Media's own stored original files, each physical file counted once even when several Content Elements reference the same underlying file (see "Deduplication," above).

**Backfilling missing thumbnails or failed EXIF extraction** happens from the Dashboard's Backfill operations section, not from either media page directly — see [Dashboard and maintenance](/_docs/dashboard)'s "Backfill operations." Both jobs let you choose which collection (or both) to run against, offer a dry run that reports scope without writing anything, and are always safe to re-run — an already-resolved item is a fast no-op. Neither job ever touches your own editorial fields (Caption, Title, Category, Tags, and — Archive Media only — Privacy, Quality) — only the derived technical facts each is named for.

## Visual classification (scene and potentially identifiable people)

Every Image in Post Media and Archive Media can be automatically analysed, entirely on this Kartotek installation itself — no image is ever sent to a third-party service for this. Two independent signals are stored per Image:

- **Environment**: Indoor, Outdoor, Mixed, Uncertain, or Unknown. A genuinely ambiguous or mixed scene is recorded as such rather than forced into a false Indoor/Outdoor choice.
- **Potentially identifiable people**: No people detected, People present (not identifiable), Potentially identifiable people, Uncertain, or Unknown. This is a conservative *signal*, never a claim that a specific person was identified — no facial recognition, identity matching, or biometric data is used or retained, only whether people and clearly usable faces are visible at all. An ambiguous case (small, blurred, obscured, turned away, or crowded) is recorded as Uncertain rather than a confident "no."

Environment is produced by a small, general-purpose local image classifier combined with a hand-curated mapping to Indoor/Outdoor — most everyday photos genuinely won't match a scene the classifier recognises, so a large share of results read Uncertain rather than a confident answer; that's deliberately conservative behaviour, not a malfunction.

**The People signal is produced by local face detection — not full-body people detection.** It can reliably say a face is visible (and roughly how prominent it is), but it cannot see a person who has no visible face in the photo — turned away from the camera, too far away, or out of frame. Because of that real limitation, "No people detected" specifically means *no face was confidently or plausibly detected, in an image with enough resolution that one likely would have been if a face were clearly visible* — a deliberately hedged reading, not a guarantee that no one is in the photo. Any face too small, blurred, or otherwise unclear to judge reads as Uncertain rather than a guess in either direction; a photo too low-resolution to trust a "no faces" reading at all also reads as Uncertain. No facial recognition, identity matching, or biometric data is used or retained anywhere in this feature, and no face image, crop, or detection outline is ever stored — only the classification itself.

**Automatic vs. manual.** A successful automatic analysis sets the automatic result; you can always set a manual override for either signal instead, which then takes over as the effective value shown everywhere (List/Gallery filters, overview cards, the item's own detail view) until you clear it. Re-analysing an Image later never overwrites a manual override. If a later analysis attempt fails (for example, the local model is temporarily unavailable), the last successful automatic result is kept exactly as it was — a failed attempt is recorded as a failure, never silently blanked.

**Per-Image**, open its detail view (Post Media or Archive Media) to see the effective Environment/People values, confidence, whether each is automatic or manually overridden, the model/version used and when it last ran, and any failure detail — plus an **Analyse image** (or **Re-analyse image**) action and the manual override controls themselves.

**Backfill**: a "Visual classification" job on the Dashboard's Backfill operations section (see [Dashboard and maintenance](/_docs/dashboard)) analyses existing Images across Post Media, Archive Media, or both. It defaults to Images never yet attempted, previously failed, or marked stale (the model/logic version changed since the last successful run); an explicit "re-analyse everything" option additionally covers Images already successfully classified. Offers a dry run (reports what's eligible without writing anything) and Apply, and — because a full-corpus pass can run for a while — can be paused and resumed, or cancelled outright, without losing work already done.

**Filters and overview counts**: both Post Media and Archive Media's List views can filter by effective Environment, effective People classification, visual-analysis status, and whether a manual override is set. Both pages' health overview also shows Indoor / Outdoor / Environment uncertain / Potentially identifiable people / People uncertain / Visual analysis failed-or-not-attempted counts, each opening the matching filtered list.

**These classifications are Admin metadata.** They never automatically change an item's Privacy or Quality (above), and are not exposed publicly by this feature — any future public use or automatic linkage to Privacy/Quality would be its own separate, explicit decision.

## Privacy and Quality classification (Archive Media only)

Every Archive Media item carries two independent, editorial classifications, both defaulting to **Unset** for new media and never inferred automatically:

- **Privacy** — Unset, Private, or Public.
- **Quality** — Unset, Low, Medium, or High.

**Post Media has no such field.** A Post Media item — an Image, Video, Audio, or Attachment an editor explicitly attaches to a Post — is public exactly whenever its owning Post/Version is: governed solely by the Post's own Stage (see [Posts](/_docs/posts)'s "Stage"), the same as every other Content Element on that Post. There's nothing to set, and nothing shown for it in the Post Media List/Gallery view.

**Unset is a real, distinct choice**, not the same as "Private" or "Low" — it means nobody has classified this Archive Media item yet, and stays separately filterable from an explicit answer.

Edit either field directly from Archive Media's List view row (single item), or its own item detail panel, or select several rows and use the bulk-edit action to set one or both fields across the whole selection at once.

**Privacy and Quality together decide Archive Media's own public eligibility.** An Archive Media item is publicly eligible only when its Privacy is explicitly **Public** and its Quality is **Medium** or **High** — Low Quality, Unset Quality, and anything other than Public Privacy are all equally ineligible, shown as "Not publicly eligible" in Archive Media's own List view. This is the same rule that governs whether an Archive Media item can appear on a public Category/Tag page or its own detail page (below) — an ineligible item is simply excluded from both, never shown in a degraded or partial form.

Admin views — including Preview — always show every Archive Media item regardless of classification, clearly marked when it wouldn't otherwise be publicly eligible.

Archive Media items are always classified individually, one value per item. Every classification change is recorded with who made it and when, the same as any other editorial change in Kartotek.

**Categories and Tags on a media item** — a Post Media element (from its row's "Categories/Tags" column) or an Archive Media item (from its detail panel) can be assigned any number of the site's existing Categories and existing Tags, the same ones Posts use — see [Organizing and presenting content](/_docs/categories)'s "Categories and Tags on media" for the full detail, including how a Category/Tag admin listing counts Posts and Media separately plus combined, and how a Category/Tag rename, merge, or delete carries through to media the same way it already does for Posts.

## Media on a public Category or Tag page

A media item directly assigned to a Category or Tag (above) shows up on that Category's or Tag's own public page, alongside its Posts — in List view as a Media Brief card, in Gallery view as a thumbnail, and in Chronology view as part of the same mixed date histogram — see [Organizing and presenting content](/_docs/categories)'s "Media alongside Posts in List and Gallery" and "Chronology view" for exactly how Posts and media interleave, and how a Post's own cover image is never duplicated as a separate media card. Post Media follows its owning Post's own Stage-based visibility there, same as everywhere else; Archive Media follows the Privacy/Quality eligibility rule above.

Selecting a Post Media card opens that element's own existing public detail page (the same one a `{{...}}` inline reference or an Additional Information listing already links to). Selecting an Archive Media card opens that item's own public detail page — Title, Description, Capture date, Capture device, and its thumbnail when one's ready; there's no public download of the original file, since Archive Media's own originals live in Dropbox, not on this site.

## Archive Media

The **Archive Media** entries (Full Admin only) are a private, Dropbox-backed personal photo archive — entirely separate from the Post Media inventory above, which only ever shows files already attached to a Post. Archive Media catalogues images sitting in your own Dropbox folders without ever copying them into Kartotek. There's currently no way to select an archive photo for direct use in a Post — it's a browsing and organizing tool for your own reference.

**Archive Roots** is where you connect the archive to Dropbox (the same connection used for [Backup and disaster recovery](/_docs/backups) — connecting once covers both) and pick one or more folders as archive roots. Browse into a folder and click "Use this folder as an archive root"; adding a folder never changes anything in Dropbox itself. A scan recursively finds every supported image beneath that folder, records its metadata, and generates a small thumbnail, all without downloading or keeping the original anywhere in Kartotek once processing finishes. Removing a root stops future scans of it but never deletes anything already catalogued or anything in Dropbox — an active scan for a removed root is also stopped immediately, with that as its recorded reason.

Every scan or rescan is a resumable, observable job — this page's own **Scan job** column is a concise summary (current status, last activity, processed/error counts, a pause or failure reason) linking to its full status; the Dashboard's **Backfill operations** section (see [Dashboard and maintenance](/_docs/dashboard)) is the actual operational home for it, with Pause/Resume/Retry failed items/Restart controls, a per-item issue breakdown, and a downloadable diagnostic report. This page stays the place to configure or remove roots.

**Folders under Temaer/Begivenheder become Categories automatically.** If a scanned folder structure contains a top-level **Temaer** or **Begivenheder** folder, a scan projects that folder tree into ordinary Categories nested under the existing **Media** Category — `Media → Temaer → Natur → Fugle`, for example, mirroring `Temaer/Natur/Fugle` in Dropbox exactly — and assigns every photo to the Category matching its containing folder. These are ordinary Categories once created: rename, translate, or reorganize them like any other. A rescan keeps this in sync — renaming or moving a folder in Dropbox updates the matching Category's name/parent on the next scan rather than creating a duplicate, and moving a photo between folders updates which Category it's assigned to. A Category you assign to an Archive Media item by hand (above) is entirely separate from this automatic assignment and is never added, changed, or removed by a scan. An emptied-out folder Category isn't deleted automatically — it's left in place for you to review. Other top-level folders aren't projected into Categories this way; they're still scanned and catalogued normally.

**Archive Media** is the catalogue itself, browsable in List, Gallery, Time Chart, or Map view (see above) with a state filter (Available, Changed, Moved, Missing, Inaccessible, Unsupported, Failed) alongside the shared filters. Clicking a thumbnail or filename opens its detail in a modal overlay, showing the extracted metadata (capture date and where it came from — the photo's own EXIF data or, failing that, a best-effort guess from the filename — camera, dimensions, Dropbox path) plus fields you can set yourself: Title, Description, private Notes, and Tags. None of these edits are ever written back to Dropbox — they live only in Kartotek's own catalogue. **Open in Dropbox** sends you straight to the file in Dropbox's own web view (you'll need to be logged into the Dropbox account that has access); Kartotek never generates a public link to it. If extraction or thumbnail generation failed for an item, **Retry** tries again.

**"Already used in a Post."** An Archive Media item's detail panel shows this note, with a link to the Post, whenever the same underlying file has also been uploaded as Post Media somewhere — Kartotek recognizes it's the exact same photo (a real content checksum, the same one Post Media's own deduplication uses — see "Deduplication," above), not just a similar filename or capture date. This is computed automatically and doesn't require you to do anything for an item newly found by a scan; catching up the pre-existing catalogue is a bounded, repeatable job (**Archive Media content-hash matching**) in the Dashboard's **Backfill operations** — see [Dashboard and maintenance](/_docs/dashboard). No match showing yet doesn't necessarily mean the photo has never been used in a Post — it may simply not have been checked yet.

The catalogue itself (which folders are roots, every item's metadata and scan state, any Tags/notes you've added) lives in Kartotek's own primary database, so it's covered by the same daily database export and Dropbox backup as any other data — see [Backup and disaster recovery](/_docs/backups)'s "Personal Media Archive and backup/recovery" for the recovery-specific detail. The original photos themselves are never stored in Kartotek at all — Dropbox remains the one authoritative copy.

## Advanced reference: addresses and resize parameters

This section is reference detail for a permanent link, a resized-image embed, or debugging a broken image — not something you need for everyday publishing.

**Permanent addresses**, one per element, forever (elements are immutable once created — see [Posts and publishing](/_docs/posts)):

- **`/_media/<content-id>.<ext>`** for Images.
- **`/_media/video/<content-id>.<ext>`**, **`/_media/audio/<content-id>.<ext>`**, and **`/_media/attachment/<content-id>.<ext>`** for Video/Audio/Attachment (an explicit kind segment, since a content id isn't shared across kinds).
- **`/_media/video/<content-id>/thumbnail.jpg`** — a Video's own active thumbnail (see "Video thumbnails," above), a genuinely separate address from the Video file itself. 404s (rather than serving anything) when no thumbnail is ready yet.

`<ext>` in the URL is cosmetic — the real stored file is always served regardless of what extension the request names, so a stale or "wrong" extension in an old shared link still resolves correctly.

**Resized/cropped variants — Images and Video thumbnails:** the same path, with query parameters: `/_media/<content-id>.<ext>?w=400&h=300&fit=crop&q=70`.

- **`w`, `h`** — target dimensions in pixels. Either alone scales proportionally; both together needs `fit` to resolve the mismatch.
- **`fit`** — `crop` (fill exactly, cropping overflow) or `contain` (scale to fit within, no cropping).
- **`q`** — quality, 1–100, for lossy re-encoding.
- **Never upscales** — a requested size larger than the original is clamped down to the original's own size.

The Video/Audio/Attachment file itself doesn't take these parameters — a request for one always gets the original file verbatim.

**Download filename:** never the original uploaded filename (which may be device-generated or reveal information not meant to be public) — always built from the Post's UID and the element's Role, e.g. `<uid>-cover.jpg`, or `<uid>-gallery-3.jpg` for a repeatable Role distinguished by its position.
