mcpField
M
moonlitlynx-food-run

moonlitlynx-food-run

github.com/gkwaProductivity073 installsUpdated 2d ago
Repository

About moonlitlynx-food-run

moonlitlynx-food-run is a skill for classifying media in specified digiKam collections and tagging food-related files using YAML metadata. It reports proposed tags for confirmation before applying them to the database.

Key features

  1. 01Finds untagged or undated media
  2. 02Reads YAML metadata for classification
  3. 03Maps food signals to digiKam tags
  4. 04Backs up and updates the database
  5. 05Verifies tags and records run results

Use cases

  1. 01Classifying food videos from selected collections
  2. 02Adding food and matching subcategory tags
  3. 03Reviewing proposed tags before database changes

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/gkwa/volcanicviper --skill moonlitlynx-food-run

After installing, type/moonlitlynx-food-runin Claude Code to confirm it loaded.

Bundled filesREADME.mdtile.json

Details

From the project README

What This Skill Does

Finds media files that match digikam's "untagged or undated" saved search within the grouchygiraffe and shamblingshark collections, reads their YAML metadata, classifies food vs. non-food content, and applies the appropriate digikam tags.

Always report what you find before applying any tags.

Database

Path: ~/Pictures/digikam4.db

Back up before every run:

cp ~/Pictures/digikam4.db ~/Pictures/digikam4.db.bak.$(date +%Y%m%d_%H%M%S)

Finding the Files

The digikam saved search "untagged or undated" (id=42) translates to this SQL.

Both conditions must be true (AND, not OR):

SELECT i.name, ar.label
FROM Images i
JOIN Albums al ON al.id = i.album
JOIN AlbumRoots ar ON ar.id = al.albumRoot
LEFT JOIN ImageInformation ii ON ii.imageid = i.id
WHERE ar.label IN ('grouchygiraffe', 'shamblingshark')
AND i.id NOT IN (
  SELECT imageid FROM ImageTags
  WHERE tagid NOT IN (SELECT id FROM Tags WHERE name LIKE 'Color Label%')
)
AND (ii.creationDate IS NULL OR ii.creationDate < '1904-01-01T00:00:00')
ORDER BY ar.label, i.name;

The Color Label% exclusion is required — files with only a color label tag are treated as untagged by digikam's UI.

Reading YAML Files

For grouchygiraffe files: /Users/mtm/pdev/taylormonacelli/grouchygiraffe/data/<shortcode>.yaml

Strip the file extension to get the shortcode (e.g. DZY_GI9tCs5.mp4 → DZY_GI9tCs5.yaml).

Shamblingshark files in /output are UUID-named and have no YAML counterparts — skip classification, apply noyamldesc.

Read uploader, title, and description fields from each YAML.

Classification

Food — apply food (id=109) plus any matching subtags:

keyword patternsubtagdigikam id
sourdough, levain, batard, boule, bulk ferment, crumbsourdough113
salsa, enchilada sauce, tomatillo, salsa verde, salsa rojasalsa115
pepper, chile, jalapeño, chipotle, guajillo, cayennepeppers151
curry, masala, tikka, korma, biryani, desi, indianindian114
paneerpaneer123
soup, stew, broth, ramensoup153
bean, lentil, chickpeabeans133
tomatotomato131
coffee, espresso, baristacoffee130
dumpling, potsticker, gyozadumpling233
vegan, plant-basedvegan234
pizza, pasta, focaccia, ciabatta, bread, loafpizza (pizza) or food only (bread)235
mushroomfood only (no subtag exists)—
honeyhoney156

Match against the lowercased description and uploader fields.

Apply food even when no subtag matches — food is the base tag for all food content.

Probably food / empty description — apply food + noyamldesc when the YAML description is empty or null but the uploader username strongly implies food content (e.g. eatinghealthytoday, thesourdoughnerd, katrina.the.earthy.vegan, myhealthydish).

No signal — apply only noyamldesc when description is empty and uploader gives no food signal (e.g. stealth_health_life with no description, generic lifestyle accounts).

Non-food — skip entirely. Do not apply any tags. Examples: fitness/mobility, fashion, political, medical, humor, lifestyle.

Special Tag: noyamldesc

noyamldesc (id=242, pid=0) marks files whose YAML has no useful description, making classification impossible.

Apply it alongside food when the username suggests food content, or alone when there is no content signal at all.

Always pair with ai-tagged.

Tag IDs Quick Reference

tagidpid
food1090
sourdough113109
salsa115109
indian114109
paneer123109
peppers151109
soup153109
tomato131109
beans133109
coffee1300
honey156109
dumpling233109
vegan234109
pizza235109
ai-tagged1920
noyamldesc2420

Applying Tags

Use INSERT OR IGNORE — the ImageTags table has a UNIQUE constraint on (imageid, tagid).

Look up image IDs by filename scoped to the correct album root:

SELECT i.id FROM Images i
JOIN Albums al ON al.id = i.album
JOIN AlbumRoots ar ON ar.id = al.albumRoot
WHERE ar.label = 'grouchygiraffe' AND i.name = 'DZY_GI9tCs5.mp4';

Or batch by name with subqueries in a single transaction:

BEGIN;
INSERT OR IGNORE INTO ImageTags (imageid, tagid)
SELECT i.id, 192 FROM Images i
JOIN Albums al ON al.id = i.album
JOIN AlbumRoots ar ON ar.id = al.albumRoot
WHERE ar.label IN ('grouchygiraffe', 'shamblingshark')
AND i.name IN ('DZY_GI9tCs5.mp4', ...);
COMMIT;

Scoping inserts by ar.label avoids tagging duplicate filename entries from other collections.

Workflow

  1. Back up the database.
  2. Run the untagged/undated query and report the file count.
  3. Read YAML for each file and classify: food, probably-food, no-signal, or non-food.
  4. Present findings to the user before applying any tags. Show: shortcode, content summary, proposed tags.
  5. On confirmation, apply tags in a single transaction.
  6. Verify counts by checking SELECT t.name, COUNT(*) FROM ImageTags it JOIN Tags t ON t.id = it.tagid JOIN Images i ON i.id = it.imageid WHERE i.name IN (...) GROUP BY t.name.
  7. Update moonlitlynx progress.md in the Obsidian vault with the run summary.
  8. Commit the progress note.

Progress Note

Progress is tracked in /Users/mtm/Documents/Obsidian Vault/moonlitlynx progress.md.

After each run, add a dated section under ## Food/recipe batch tag run documenting:

  • File count found and tagged
  • New tags created (if any)
  • Breakdown of subtags applied
  • Files skipped and why

Comments

Markdown supported