Skip to content

Content Filtering

rhoopr edited this page Jun 1, 2026 · 13 revisions

Content Filtering

kei provides several ways to control which assets are downloaded. Persistent filters live in TOML.

Media type

[filters]
media = ["photos", "videos", "live-photos"]

To skip standalone videos:

[filters]
media = ["photos", "live-photos"]

To skip normal photos but keep videos and live photos:

[filters]
media = ["videos", "live-photos"]

Live photo component handling is separate:

[photos]
live_photo_mode = "both" # both, image-only, video-only, skip

Date range

For one run:

kei sync --skip-created-before 2024-01-01 --skip-created-after 2024-12-31

For a permanent mirror scope:

[filters]
skip_created_before = "2024-01-01"
skip_created_after = "2024-12-31"

Both accept ISO dates or relative intervals such as 30d.

Libraries

[filters]
libraries = ["primary"]

Accepted selectors:

  • primary
  • shared
  • all
  • none
  • a CloudKit zone name
  • !name to exclude
  • =literal to escape a value that looks like a sentinel

Use kei list libraries to see available libraries.

Albums, smart folders, and unfiled

[filters]
albums = ["all", "!Drafts"]
smart_folders = ["none"]
unfiled = true

Defaults:

Key Default Picks
albums ["all"] User-created albums
smart_folders ["none"] Apple smart folders
unfiled true Photos not in any user album

Example: only Favorites, no user albums, no unfiled pass:

[filters]
albums = ["none"]
smart_folders = ["Favorites"]
unfiled = false

Example: every smart folder including sensitive folders:

[filters]
smart_folders = ["all-with-sensitive"]

Explicit albums and smart folders are collection-scoped. If you name an album or smart folder, kei resolves that pass across every visible library so shared-library albums can pull their source assets. [filters].libraries still controls unfiled photos and library-wide enumeration.

Selected album syncs can use trusted album membership snapshots after kei has built them. That lets later runs route album changes through incremental sync or a targeted album backfill instead of forcing a full library enumeration every time. Smart-folder refreshes can also split from album and unfiled work, so an expensive smart-folder pass does not have to pull unfiled changes out of incremental mode.

Filename patterns

[filters]
filename_exclude = ["*.AAE", "Screenshot*"]

Patterns are case-insensitive globs.

Recency

For one run:

kei sync --recent 100
kei sync --recent 30d

For a permanent mirror scope:

[filters]
recent = 100
recent_scope = "global" # global, per-filter

Numeric limits use recent_scope:

  • global is the default. kei takes the library-wide recent N, then album, smart-folder, unfiled, media, filename, and date filters narrow that set.
  • per-filter takes up to N from each selected album, smart folder, or unfiled pass.

The days form maps to skip_created_before and does not use recent_scope.

RAW policy

[photos]
raw_policy = "as-is" # as-is, prefer-raw, prefer-jpeg
Policy Effect
as-is Keep Apple's primary/alternative ordering
prefer-raw Prefer RAW when RAW+JPEG are available
prefer-jpeg Prefer JPEG when RAW+JPEG are available

Filter order

  1. Library, album, smart-folder, and unfiled selectors decide which passes run.
  2. Media filters and live-photo mode filter tasks.
  3. Date range filters run.
  4. Filename patterns run.
  5. Count-form recency limits apply at the library level by default, or per selected pass with recent_scope = "per-filter".
  6. Existing files and state DB rows skip already-downloaded work.

Commands

Getting Started

Features

Clone this wiki locally