After initially installing indi-allsky, I had experimented with various cameras, settings, and test recordings. Some of the time-lapse videos I’d created back then were long gone. However, the old entries still appeared in the video viewer, sometimes as black tiles without a preview.
I wanted to clean that up. But not by simply deleting everything before a certain date—rather, in a way that would leave productive footage untouched. In my case, I wanted the video archive to start only on or after December 23, 2025.
And here’s how I went about it…
Why don’t deleted videos always disappear from the video viewer?
indi-allsky manages timelapses not only as files on the SSD but also via entries in an SQLite database. If a file is removed outside of indi-allsky, the corresponding database entry may remain. In such cases, the interface may still display a video even though the MP4 file is long gone.
In my case, this affected recordings from the early testing phase in December 2025 and even some entries with dates from January 2025. Some of the old files were located in an archive directory that has since been removed. Important: A black tile alone does not necessarily prove that the video is missing. It’s also possible that only the thumbnail is affected.
1. Count existing video entries
The database for my installation is located at /var/lib/indi-allsky/indi-allsky.sqlite. First, I performed a read-only check to see how many entries existed prior to my selected cutoff date:
sudo sqlite3 -header -column /var/lib/indi-allsky/indi-allsky.sqlite <<'SQL'
SELECT 'video' AS typ, COUNT(*) AS count
FROM video WHERE "dayDate" < '2025-12-23'
UNION ALL
SELECT 'startrailvideo', COUNT(*)
FROM startrailvideo WHERE "dayDate" < '2025-12-23';
SQLThe result: 26 regular timelapses and 11 startrail videos, for a total of 37 outdated entries. The relevant field is `dayDate`, i.e., the recording date, not the time when the file might have been created later.
If you want a different start date, replace 2025-12-23 accordingly. The cutoff date itself is preserved by the < condition.
2. First, check whether the video files are actually missing
Before deleting anything, I ran a test to check all candidates individually against the file system. The following command does not modify the database:
sudo python3 - <<'PYCODE'
import sqlite3
from pathlib import Path
DB = '/var/lib/indi-allsky/indi-allsky.sqlite'
MEDIA = Path('/var/www/html/allsky/images')
CUTOFF = '2025-12-23'
conn = sqlite3.connect(f'file:{DB}?mode=ro', uri=True)
conn.row_factory = sqlite3.Row
present = missing = linked_thumbnails = 0
for table in ('video', 'startrailvideo'):
rows = conn.execute(
f'SELECT id, "dayDate", filename, thumbnail_uuid '
f'FROM {table} WHERE "dayDate" < ? ORDER BY "dayDate", id',
(CUTOFF,)
).fetchall()
print(f'\n{table}: {len(rows)} records')
for row in rows:
path = Path(row['filename'])
if not path.is_absolute():
path = MEDIA / path
exists = path.is_file()
present += bool(exists)
missing += not exists
thumb = 0
if row['thumbnail_uuid']:
thumb = conn.execute(
'SELECT COUNT(*) FROM thumbnail WHERE uuid = ?',
(row['thumbnail_uuid'],)
).fetchone()[0]
linked_thumbnails += thumb
print(row['dayDate'], row['id'],
'PRESENT' if exists else 'MISSING',
f'Thumbnail DB: {thumb}', row['filename'])
print('\nVideo files present:', present)
print('Missing video files:', missing)
print('Linked thumbnail entries:', linked_thumbnails)
print('NO CHANGES')
conn.close()
PYCODEIn my case, the result was clear: 37 database entries, 37 missing video files, and no associated thumbnail records. This made it clear that I wouldn’t lose any existing MP4 files from this selection. Note: The media path shown corresponds to my installation; it must be adjusted if your configuration differs.
3. Create a current database backup before cleaning up
Before making any changes to the production SQLite database, a current backup is mandatory. indi-allsky includes its own backup function for this purpose:
cd ~/indi-allsky
./misc/indi-allsky-ctl backup-dbYou should then see “Backup completed.” The new backup is usually located in /var/lib/indi-allsky/backup/. Optionally, you can verify it with gzip -t:
BACKUP="$(ls -t /var/lib/indi-allsky/backup/backup_indi-allsky_*.sqlite.gz | head -1)"
gzip -t "$BACKUP" && echo 'GZIP OK'
A successful GZIP check does not replace an SQLite integrity check. If you want to be extra thorough, unpack the backup into a temporary file and check it with ` PRAGMA integrity_check;`. In my case, the SQLite check had already been successfully performed.
4. Clean up the old entries via indi-allsky
I didn’t want to simply run ` DELETE FROM video `. indi-allsky has its own routine, ` deleteAsset() `, which also handles associated thumbnails and media files if necessary. Additionally, the actual database entry must be removed via the SQLAlchemy session.
Important: The following cleanup run is explicitly limited to my two video tables and the specified date. It stops as soon as it discovers an existing video file or an associated thumbnail record for a candidate. The final deletion only starts when the --apply parameter is provided.
First, save the small helper script:
cat > ~/cleanup_old_timelapses.py <<'PYCODE'
#!/usr/bin/env python3
import argparse
from datetime import date
from indi_allsky.flask import create_app, db
from indi_allsky.flask.models import (
IndiAllSkyDbVideoTable,
IndiAllSkyDbStarTrailsVideoTable,
IndiAllSkyDbThumbnailTable,
)
parser = argparse.ArgumentParser()
parser.add_argument('--apply', action='store_true',
help='Actually remove entries')
args = parser.parse_args()
cutoff = date(2025, 12, 23)
app = create_app()
with app.app_context():
entries = []
for model in (IndiAllSkyDbVideoTable,
IndiAllSkyDbStarTrailsVideoTable):
entries.extend(model.query.filter(model.dayDate < cutoff).all())
print(f'Affected entries: {len(entries)}')
if not entries:
print('Nothing to do.')
raise SystemExit(0)
for entry in entries:
print(entry.__class__.__name__, entry.id,
entry.dayDate, entry.filename)
if entry.getFilesystemPath().exists():
raise SystemExit('ABORT: Video still exists: ' + entry.filename)
if entry.thumbnail_uuid:
thumb = IndiAllSkyDbThumbnailTable.query.filter_by(
uuid=entry.thumbnail_uuid).first()
if thumb is not None:
raise SystemExit('ABORT: Thumbnail entry exists')
if not args.apply:
print('TEST RUN: No changes. Specify --apply to delete.')
raise SystemExit(0)
for entry in entries:
entry.deleteAsset()
db.session.delete(entry)
db.session.commit()
print(f'CLEANUP SUCCESSFUL: {len(entries)} entries removed')
PYCODEAfter that, first run only the test run:
cd ~/indi-allsky
./virtualenv/indi-allsky/bin/python ~/cleanup_old_timelapses.pyIf the displayed IDs and dates match, the backup has been verified, and no files actually exist anymore, you can proceed with the targeted deletion run:
cd ~/indi-allsky
./virtualenv/indi-allsky/bin/python ~/cleanup_old_timelapses.py --applyWarning: This is an actual database operation. The deleteAsset() function can also delete files; that is why an additional existence check is performed before execution. This procedure should not be applied to other tables or installation versions without verification. A database backup alone will not restore MP4 files that have already been deleted.
5. Check the Results
Finally, I counted again to see if any video entries from before the cutoff date still existed:
sudo sqlite3 -header -column /var/lib/indi-allsky/indi-allsky.sqlite <<'SQL'
SELECT 'video' AS type, COUNT(*) AS remaining
FROM video WHERE "dayDate" < '2025-12-23'
UNION ALL
SELECT 'startrailvideo', COUNT(*)
FROM startrailvideo WHERE "dayDate" < '2025-12-23';
SQLIn my case, both lines showed 0. After reloading the indi-allsky video viewer, the old black tiles had indeed disappeared.
What about newer videos without thumbnails?
I would be more cautious here. A missing thumbnail is not the same as a missing video file. Newer timelapses that exist on the SSD should be preserved. In such cases, it makes more sense to check the thumbnail generation—for example, using the included script `misc/create_thumbnails.py`—rather than deleting the videos across the board.
You also shouldn’t just blindly run the indi-allsky tool ` misc/validate_db_entries.py `: It checks not only videos but numerous media categories and can comprehensively remove missing entries from the database. For my specific case, the cleanup limited to two video tables and a specific date was therefore the more appropriate solution.
Conclusion
After installations, camera changes, and initial experiments, legacy data can certainly accumulate in indi-allsky. The associated files may have long since been deleted, but their entries in the database still remain.
In my case, there were 37 old time-lapse and star-trail entries dating from before December 23, 2025. After a test run in read-only mode, a fresh backup, and a targeted cleanup, they had disappeared from the video viewer. All newer entries were preserved.
The most important lesson: Not every missing preview is a reason to delete a video. First check whether the file is actually missing, then clean up selectively.
For those interested in my new backup strategy: My earlier guides on database and configuration backups (Phase 1) and file backups (Phase 2) still document the original approach.