A lightweight personal media catalog built with CodeIgniter 4.
Collections 2 imports HTML table exports from Obsidian, stores them in MySQL, and serves fast searchable views for CDs, books, Blu-rays, and Arkas issues.
- Fast homepage and media page caching.
- AJAX search across creator/title with highlighted matches.
- Automatic import trigger from the
Aboutpage when source files change. - Responsive UI using Tailwind CSS + daisyUI.
- Simple content workflow: maintain data in Obsidian, export HTML, upload, done.
- PHP
^8.2 - CodeIgniter
^4.7 - MySQL (default driver:
MySQLi) - Tailwind CSS v4
- daisyUI
- esbuild
app/Controllers/Home.php: homepage, media pages, about page.app/Controllers/Ajax.php: AJAX endpoints (search).app/Models/ContentModel.php: media queries and stats helpers.app/Models/AjaxModel.php: search query model.app/Models/ImportModel.php: import pipeline from Obsidian HTML files.app/Views/: page templates and partials.public/js/src/: frontend JS source files.tailwind/: Tailwind input and utility layers.writable/obsidian_html/: import source folder + manifest tracking.
GET /-> homepageGET /media/{alias}-> media list by typeGET /about-> story page + import triggerGET /ajax/search?q=...-> JSON search results (AJAX only)
composer install
npm installCopy env to .env if needed, then set at least:
CI_ENVIRONMENT = development
database.default.hostname = localhost
database.default.database = collections
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.port = 3306For local development without caching:
cache.handler = dummyFor production, use file/redis/etc:
cache.handler = fileThis repository currently does not include migrations, so create tables manually.
Minimum required columns:
mediaid(PK)media_type_id(int)title(string)creator(string, nullable/empty allowed)collection(string, nullable/empty allowed)
media_typesid(PK)media_type(string label)alias(route alias, e.g.cds,books,arkas,blu-rays)position(int, for menu ordering)item_msrp(numeric)items_count(int)total_msrp(numeric)
Important:
media.media_type_idmust referencemedia_types.id.- Footer and navigation depend on
media_typesrecords existing.
Development (watch mode):
npm run devProduction build:
npm run buildCodeIgniter local server:
php spark serveOr serve via Apache/Nginx with document root set to public/.
Collections 2 expects Obsidian HTML exports in:
writable/obsidian_html/
Expected filenames:
cds-collection.htmlbooks-collection.htmlarkas-collection.htmlblu-ray-collection.html
How it works:
- Visit
/about. ImportModel::initImport()compares file mtimes againstwritable/obsidian_html/manifest.json.- If changed, importer parses the first table from each file.
mediatable is refreshed and repopulated.- Media type stats are recalculated and runtime cache/log/session artifacts are cleaned.
Current behavior:
Home::index()caches rendered homepage output (page-home).Home::media()caches rendered media pages (page-media-{alias}-p{page}).Home::about()is not cached.
Recommended setup:
- Development:
cache.handler = dummy - Production:
cache.handler = file(or Redis/Memcached if configured)
Endpoint:
GET /ajax/search?q=term
Behavior:
- Requires AJAX header (
X-Requested-With: XMLHttpRequest). - Ignores terms shorter than 2 characters.
- Searches
creatorandtitle. - Returns up to 15 rows with
creator,title,collection,type.
npm run dev: run CSS and JS watchers in parallel.npm run build: build minified CSS and JS bundles.composer test: run PHPUnit test suite.
mediaTypesis preloaded globally inBaseControllerfor navigation/footer rendering.- Version display uses
SYS_VERSIONand is shown in footer. - Public assets are versioned in layout with
?v=SYS_VERSION.
MIT
