Add rootless Podman fixes, and others

improve container startup for rootless Podman, plus related refactors and tests. Key changes:

- Add/modify Audiobookshelf-related code and wiring (src/lib/services/audiobookshelf/api.ts, library service refs) and update documentation TABLEOFCONTENTS to reference ABS implementation.
- Detect user namespace in docker/unified app-start.sh and redis-start.sh and skip gosu when running in rootless Podman to preserve UID mapping; improve startup logging and verification.
- Add utility/service files (auth-token-cache.service.ts, credential-migration.service.ts, cleanup-helpers.ts) and corresponding tests; update chapter-merger and metadata-tagger utilities/tests.
- Update many admin/auth API routes and tests to reflect changes in settings and integrations.
- Remove large AI agent and Audiobookshelf implementation guide docs (AGENTS.md and the implementation guide) and add README note about AI-assisted workflow.

These changes enable Audiobookshelf backend mode, improve compatibility with rootless container runtimes, and include cleanup/refactor work and unit tests.
This commit is contained in:
kikootwo
2026-02-04 14:05:28 -05:00
parent 2ef9ac7be1
commit a0f2ba680d
42 changed files with 1843 additions and 3820 deletions
+20 -2
View File
@@ -30,6 +30,12 @@ const fsMock = vi.hoisted(() => ({
access: vi.fn(),
constants: { R_OK: 4 },
}));
const configServiceMock = vi.hoisted(() => ({
get: vi.fn(),
}));
const downloadClientManagerMock = vi.hoisted(() => ({
getAllClients: vi.fn(),
}));
vi.mock('@/lib/db', () => ({
prisma: prismaMock,
@@ -73,6 +79,14 @@ vi.mock('fs/promises', () => ({
...fsMock,
}));
vi.mock('@/lib/services/config.service', () => ({
getConfigService: () => configServiceMock,
}));
vi.mock('@/lib/services/download-client-manager.service', () => ({
getDownloadClientManager: () => downloadClientManagerMock,
}));
describe('Admin settings test routes', () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -211,7 +225,10 @@ describe('Admin settings test routes', () => {
});
it('uses stored password when masked password is provided', async () => {
prismaMock.configuration.findUnique.mockResolvedValueOnce({ value: 'stored-pass' });
// Mock download client manager to return the stored password
downloadClientManagerMock.getAllClients.mockResolvedValueOnce([
{ type: 'qbittorrent', password: 'stored-pass' },
]);
qbtMock.testConnectionWithCredentials.mockResolvedValueOnce('4.1.0');
const request = {
json: vi.fn().mockResolvedValue({
@@ -236,7 +253,8 @@ describe('Admin settings test routes', () => {
});
it('returns error when masked password is missing in storage', async () => {
prismaMock.configuration.findUnique.mockResolvedValueOnce(null);
// Mock download client manager to return no matching client
downloadClientManagerMock.getAllClients.mockResolvedValueOnce([]);
const request = {
json: vi.fn().mockResolvedValue({
type: 'qbittorrent',