LARK TV · the project
An AI-run programming station. It knows its own library, keeps a clock, writes and voices its own news, and puts it all on air without a person at the desk.

Why
LARK makes a lot of work: tracks, long mixes, short sourced clips, a documentary. A feed scrolls past, but a station holds a shape. LARK TV gives that work a channel of its own, programmed with care rather than shuffled.
How it grew
- First broadcast
A first version plays LARK material through OBS and starts an as-run log, a record of everything that airs.
- LARK TV 2
Rebuilt with channels, a rotation with memory so nothing repeats too soon, mixes named track by track on screen, and Drive material streamed only when it airs.
- Director’s Desk v2–v3
A Linux app with a web desk: a live program view, a lineup, OBS scenes and outputs, and a library that can take whole groups off air without deleting a file.
- Director’s Desk v5
The programmer becomes a station: weighting that favours new work, play tracking against repeats, dayparts on an hourly clock, World in Five every six hours, and generative minimal B-roll.
The as-run logs record more than 2,800 airings since 2 October 2026.
What it does
- Its own library
LARK music, long mixes, short clips and a documentary: about 1,480 items catalogued, around 1,040 of them in rotation.
- New work first
Weighting lifts fresh material and lets older pieces rest.
- No spam
Every airing is counted. A track won’t return within hours or play more than a set number of times a day.
- A clock
Dayparts shape the day. The news takes the top of the hour, and a documentary has its own evening slot.
- World in Five
A short bulletin rebuilt every six hours: stories rewritten in its own words, each source named, read by a labelled synthetic voice.
- Generative B-roll
52 minimal loops made for the station run behind the music. New loops get most of the screen time.
- Idents, promos, overlays
Channel idents, a quiet clock and logo, and now-playing cards for long mixes, hidden while the news is on.
- Live to YouTube
OBS sends the program straight to a YouTube live stream.
For developers
- Stack
Python on Linux. ffmpeg probes, cuts and renders media. OBS is driven over its websocket API (obsws-python): scenes, sources, outputs and stream state. The desk is a small web app served on 127.0.0.1, with a JSON command API for next, queue, weighting and library visibility. On-air graphics are a browser source: an HTML overlay fed by the same local server.
- Library
A catalogue builder scans local folders and a read-only rclone mount of Drive. It probes durations without downloading, and Drive files stream to OBS only when they air. Hidden items and groups are kept as lists, so taking something off air never deletes a file.
- Rotation
Each pick is a weighted random draw. Weights come from tiers (priority, new in this version, this year, last year, older) and are editable live from the desk. Rotation history keeps a channel from repeating before most of it has aired.
- Anti-spam
A play counter records every airing. A pick is rejected if the same title aired within a minimum gap or reached its daily cap. Music and clips have separate rules, titles are de-duplicated across copies, a resume after the news doesn’t count as a new play, and idents are exempt. Cool-downs are released by systemd user timers.
- Schedule
The day is divided into dayparts by hour. Each daypart has its own mix of series and its own song-and-clip pattern. Fixed slots, like the midnight track, World in Five and the evening documentary, take precedence over rotation.
- World in Five
A systemd timer runs the build every six hours. The pipeline pulls the day’s events with their cited sources, rewrites each story, voices it with edge-tts and renders story cards and the music bed into a single video with ffmpeg. A JSON sidecar keeps every source URL. The desk only lists an edition once its file exists.
- Generative B-roll
Loops are rendered from code (drifts, depth tunnels, rotating grids, wave lines, light sweeps) on the station’s own motifs, without faces or text. Screen time is split by time rather than by count: new loops get 70% and older footage 30%.
- This site
Static HTML, CSS and a little JavaScript on Cloudflare Pages, deployed with Wrangler. Media is self-hosted in parts under 25 MB, and long pieces play their parts one after another. There are no cookies, and YouTube loads only after the visitor clicks twice. A persistent exclusion list is applied on every deploy and again in the browser.
Your own station
If you’d like to use it as your own AI-run programming station for events, work, or spaces like bus stations or stores, contact me by direct message on TikTok @damian_lark.
Built and programmed by LARK. Music, visuals and texts by LARK. Synthetic voices are labelled.