- C# 68.1%
- TypeScript 29.5%
- CSS 1.8%
- JavaScript 0.4%
- PowerShell 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
# Conflicts: # StuffApp.Core/GraphQL/SourceOperationsGraphQl.cs # StuffApp.Core/Importing/ConfiguredContentImportService.cs |
||
| deploy | ||
| docs | ||
| scripts | ||
| StuffApp.Cli | ||
| StuffApp.ComicImports | ||
| StuffApp.ComicImports.Tests | ||
| StuffApp.Core | ||
| StuffApp.Core.Abstractions | ||
| StuffApp.Core.Tests | ||
| StuffApp.Plugin.Albums | ||
| StuffApp.Plugin.Artists | ||
| StuffApp.Plugin.Audio | ||
| StuffApp.Plugin.AudioVisualizer.FrequencyBars | ||
| StuffApp.Plugin.Characters | ||
| StuffApp.Plugin.Collections | ||
| StuffApp.Plugin.Comics | ||
| StuffApp.Plugin.Comikey | ||
| StuffApp.Plugin.Directors | ||
| StuffApp.Plugin.Favorites | ||
| StuffApp.Plugin.Groups | ||
| StuffApp.Plugin.Identities | ||
| StuffApp.Plugin.ImageRelationships | ||
| StuffApp.Plugin.Images | ||
| StuffApp.Plugin.JsonApi | ||
| StuffApp.Plugin.LibraryStats | ||
| StuffApp.Plugin.Lists | ||
| StuffApp.Plugin.OCount | ||
| StuffApp.Plugin.Organized | ||
| StuffApp.Plugin.People | ||
| StuffApp.Plugin.Performers | ||
| StuffApp.Plugin.Pets | ||
| StuffApp.Plugin.Photographers | ||
| StuffApp.Plugin.Playlists | ||
| StuffApp.Plugin.Ratings | ||
| StuffApp.Plugin.Releases | ||
| StuffApp.Plugin.Renta | ||
| StuffApp.Plugin.Skin.Light | ||
| StuffApp.Plugin.Sources | ||
| StuffApp.Plugin.StashInstance | ||
| StuffApp.Plugin.Tapas | ||
| StuffApp.Plugin.Text | ||
| StuffApp.Plugin.Universes | ||
| StuffApp.Plugin.VideoRelationships | ||
| StuffApp.Plugin.Videos | ||
| StuffApp.Plugin.Works | ||
| StuffApp.PluginSdk | ||
| StuffApp.PluginSigner | ||
| StuffApp.Web | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| compose.yaml | ||
| global.json | ||
| README.md | ||
| StuffApp.slnx | ||
StuffApp
StuffApp is an early, plugin-oriented media application prototype. The current milestone provides a .NET 10 Kestrel and GraphQL backend, PostgreSQL persistence, a React application shell with a core Browser, and external declarative Images, Videos, and Albums plugins. Plugins supply frontend Entity classes and Big Grid tile renderers; the host owns storage, querying, server-side sorting, pagination, relationships, and view selection.
Prerequisites
- .NET SDK 10.0.400 (selected by
global.json) - PostgreSQL 18, or Docker with Compose
- pnpm 12
- FFmpeg and ffprobe for Video and Audio metadata and generated posters
The repository's default development connection is Host=localhost;Port=5432;Database=stuffapp;Username=stuffapp;Password=stuffapp. Override it with the ConnectionStrings__StuffApp environment variable when needed.
To run StuffApp on a Linux server with Docker instead, build a deploy bundle with scripts\Build-DeployBundle.ps1; see deploy/README.md.
Start the prototype
Build the external Images plugin:
pnpm --dir StuffApp.Plugin.Images install
pnpm --dir StuffApp.Plugin.Images build
pnpm --dir StuffApp.Plugin.Videos install
pnpm --dir StuffApp.Plugin.Videos build
pnpm --dir StuffApp.Plugin.Audio install
pnpm --dir StuffApp.Plugin.Audio build
pnpm --dir StuffApp.Plugin.AudioVisualizer.FrequencyBars install
pnpm --dir StuffApp.Plugin.AudioVisualizer.FrequencyBars build
pnpm --dir StuffApp.Plugin.Text install
pnpm --dir StuffApp.Plugin.Text build
pnpm --dir StuffApp.Plugin.Albums install
pnpm --dir StuffApp.Plugin.Albums build
The Source and comic plugins build the same way: StuffApp.Plugin.Sources, Identities, Works,
Artists, Groups, Universes, Characters, and Comics. Comics depends on its Identity
family plugins, so install those together. See Sources for the abstract Source foundation.
The Stash plugins and Studio Scenes are archived until the personal library model is built; see
Archived Stash code.
Start PostgreSQL:
docker compose up -d
Register the built plugin outputs once in PostgreSQL. Folders can be absolute or relative to StuffApp.Core:
INSERT INTO installed_plugins (id, folder_path, enabled, created_at, updated_at)
VALUES (
'stuffapp.content.images',
'C:\Projects\StuffApp\StuffApp.Plugin.Images\dist',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
ON CONFLICT (id) DO UPDATE
SET folder_path = EXCLUDED.folder_path,
enabled = EXCLUDED.enabled,
updated_at = EXCLUDED.updated_at;
INSERT INTO installed_plugins (id, folder_path, enabled, created_at, updated_at)
VALUES (
'stuffapp.content.videos',
'C:\Projects\StuffApp\StuffApp.Plugin.Videos\dist',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
ON CONFLICT (id) DO UPDATE
SET folder_path = EXCLUDED.folder_path,
enabled = EXCLUDED.enabled,
updated_at = EXCLUDED.updated_at;
INSERT INTO installed_plugins (id, folder_path, enabled, created_at, updated_at)
VALUES
('stuffapp.content.audio', 'C:\Projects\StuffApp\StuffApp.Plugin.Audio\dist', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('stuffapp.content.text', 'C:\Projects\StuffApp\StuffApp.Plugin.Text\dist', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('stuffapp.audio-visualizer.frequency-bars', 'C:\Projects\StuffApp\StuffApp.Plugin.AudioVisualizer.FrequencyBars\dist', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON CONFLICT (id) DO UPDATE
SET folder_path = EXCLUDED.folder_path,
enabled = EXCLUDED.enabled,
updated_at = EXCLUDED.updated_at;
INSERT INTO installed_plugins (id, folder_path, enabled, created_at, updated_at)
VALUES (
'stuffapp.albums',
'C:\Projects\StuffApp\StuffApp.Plugin.Albums\dist',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
ON CONFLICT (id) DO UPDATE
SET folder_path = EXCLUDED.folder_path,
enabled = EXCLUDED.enabled,
updated_at = EXCLUDED.updated_at;
In separate terminals, start the API and web application:
dotnet run --project StuffApp.Core
pnpm --dir StuffApp.Web dev
The web UI is available at http://localhost:5173; Vite proxies GraphQL and content requests to Kestrel at http://localhost:5087. To run a second instance beside it, set STUFFAPP_WEB_PORT and STUFFAPP_API_URL (for example 5174 and http://127.0.0.1:5088) before starting Vite.
Add explicit images
The prototype deliberately has no filesystem scanner. Register only paths you choose:
dotnet run --project StuffApp.Cli -- add-image "C:\path\to\first.jpg" "C:\path\to\second.png"
Each new Content record receives a UUIDv7. The browser obtains metadata through GraphQL and image bytes through /content/{uuid}; filesystem paths are not returned to the frontend.
Verify
dotnet restore StuffApp.slnx
dotnet build StuffApp.slnx --no-restore
dotnet test StuffApp.slnx --no-build
pnpm --dir StuffApp.Web test -- --run
pnpm --dir StuffApp.Web build
pnpm --dir StuffApp.Plugin.Images test
pnpm --dir StuffApp.Plugin.Images build
pnpm --dir StuffApp.Plugin.Videos test
pnpm --dir StuffApp.Plugin.Videos build
pnpm --dir StuffApp.Plugin.Audio test
pnpm --dir StuffApp.Plugin.Audio build
pnpm --dir StuffApp.Plugin.AudioVisualizer.FrequencyBars test
pnpm --dir StuffApp.Plugin.AudioVisualizer.FrequencyBars build
pnpm --dir StuffApp.Plugin.Text test
pnpm --dir StuffApp.Plugin.Text build
pnpm --dir StuffApp.Plugin.Albums test
pnpm --dir StuffApp.Plugin.Albums build
Architecture and milestone decisions are recorded in docs/.