Skip to content

Commit 7a29f73

Browse files
committed
refactor(api): move audiobook endpoints to new path
- Relocated all audiobook-related API routes from `/api/audio/convert/*` to `/api/audiobook/*`. - This change affects endpoints for chapter conversion, retrieval, deletion, and overall audiobook status. - Updated client-side calls in `AudiobookExportModal.tsx`, `EPUBContext.tsx`, and `PDFContext.tsx` to reflect the new API paths. - Modified API tests (`api.spec.ts`, `export.spec.ts`) to target the restructured endpoints. - The new API structure provides better organization and a clearer, more consistent interface for audiobook functionality.
1 parent 733b418 commit 7a29f73

File tree

8 files changed

+44
-43
lines changed

8 files changed

+44
-43
lines changed
File renamed without changes.
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NextRequest, NextResponse } from 'next/server';
22
import { spawn } from 'child_process';
3-
import { writeFile, readFile, mkdir, unlink, readdir } from 'fs/promises';
3+
import { writeFile, readFile, mkdir, unlink, readdir, rm } from 'fs/promises';
44
import { existsSync, createReadStream } from 'fs';
55
import { join } from 'path';
66
import { randomUUID } from 'crypto';
@@ -378,4 +378,31 @@ function streamFile(filePath: string, format: string) {
378378
'Cache-Control': 'no-cache',
379379
},
380380
});
381+
}
382+
export async function DELETE(request: NextRequest) {
383+
try {
384+
const bookId = request.nextUrl.searchParams.get('bookId');
385+
if (!bookId) {
386+
return NextResponse.json({ error: 'Missing bookId parameter' }, { status: 400 });
387+
}
388+
389+
const docstoreDir = join(process.cwd(), 'docstore');
390+
const intermediateDir = join(docstoreDir, `${bookId}-audiobook`);
391+
392+
// If directory doesn't exist, consider it already reset
393+
if (!existsSync(intermediateDir)) {
394+
return NextResponse.json({ success: true, existed: false });
395+
}
396+
397+
// Recursively delete the entire audiobook directory
398+
await rm(intermediateDir, { recursive: true, force: true });
399+
400+
return NextResponse.json({ success: true, existed: true });
401+
} catch (error) {
402+
console.error('Error resetting audiobook:', error);
403+
return NextResponse.json(
404+
{ error: 'Failed to reset audiobook' },
405+
{ status: 500 }
406+
);
407+
}
381408
}

src/app/api/audio/convert/chapters/route.ts renamed to src/app/api/audiobook/status/route.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NextRequest, NextResponse } from 'next/server';
2-
import { readdir, readFile, rm } from 'fs/promises';
2+
import { readdir, readFile } from 'fs/promises';
33
import { existsSync } from 'fs';
44
import { join } from 'path';
55

@@ -69,30 +69,4 @@ export async function GET(request: NextRequest) {
6969
}
7070
}
7171

72-
export async function DELETE(request: NextRequest) {
73-
try {
74-
const bookId = request.nextUrl.searchParams.get('bookId');
75-
if (!bookId) {
76-
return NextResponse.json({ error: 'Missing bookId parameter' }, { status: 400 });
77-
}
78-
79-
const docstoreDir = join(process.cwd(), 'docstore');
80-
const intermediateDir = join(docstoreDir, `${bookId}-audiobook`);
81-
82-
// If directory doesn't exist, consider it already reset
83-
if (!existsSync(intermediateDir)) {
84-
return NextResponse.json({ success: true, existed: false });
85-
}
86-
87-
// Recursively delete the entire audiobook directory
88-
await rm(intermediateDir, { recursive: true, force: true });
8972

90-
return NextResponse.json({ success: true, existed: true });
91-
} catch (error) {
92-
console.error('Error resetting audiobook:', error);
93-
return NextResponse.json(
94-
{ error: 'Failed to reset audiobook' },
95-
{ status: 500 }
96-
);
97-
}
98-
}

src/components/AudiobookExportModal.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function AudiobookExportModal({
6161
setIsLoadingExisting(true);
6262
}
6363
try {
64-
const response = await fetch(`/api/audio/convert/chapters?bookId=${documentId}`);
64+
const response = await fetch(`/api/audiobook/status?bookId=${documentId}`);
6565
if (response.ok) {
6666
const data = await response.json();
6767
if (data.exists && data.chapters.length > 0) {
@@ -241,7 +241,7 @@ export function AudiobookExportModal({
241241
const performDeleteChapter = useCallback(async () => {
242242
if (!bookId || !pendingDeleteChapter) return;
243243
try {
244-
const response = await fetch(`/api/audio/convert/chapter?bookId=${bookId}&chapterIndex=${pendingDeleteChapter.index}`, {
244+
const response = await fetch(`/api/audiobook/chapter?bookId=${bookId}&chapterIndex=${pendingDeleteChapter.index}`, {
245245
method: 'DELETE'
246246
});
247247
if (!response.ok) {
@@ -261,7 +261,7 @@ export function AudiobookExportModal({
261261
const targetBookId = bookId || documentId;
262262
if (!targetBookId) return;
263263
try {
264-
const resp = await fetch(`/api/audio/convert/chapters?bookId=${targetBookId}`, { method: 'DELETE' });
264+
const resp = await fetch(`/api/audiobook?bookId=${targetBookId}`, { method: 'DELETE' });
265265
if (!resp.ok) {
266266
throw new Error('Reset failed');
267267
}
@@ -281,7 +281,7 @@ export function AudiobookExportModal({
281281
if (!chapter.bookId) return;
282282

283283
try {
284-
const response = await fetch(`/api/audio/convert/chapter?bookId=${chapter.bookId}&chapterIndex=${chapter.index}`);
284+
const response = await fetch(`/api/audiobook/chapter?bookId=${chapter.bookId}&chapterIndex=${chapter.index}`);
285285
if (!response.ok) throw new Error('Download failed');
286286

287287
const blob = await response.blob();
@@ -306,7 +306,7 @@ export function AudiobookExportModal({
306306

307307
setIsCombining(true);
308308
try {
309-
const response = await fetch(`/api/audio/convert?bookId=${bookId}&format=${format}`);
309+
const response = await fetch(`/api/audiobook?bookId=${bookId}&format=${format}`);
310310
if (!response.ok) throw new Error('Download failed');
311311

312312
const reader = response.body?.getReader();

src/contexts/EPUBContext.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ export function EPUBProvider({ children }: { children: ReactNode }) {
339339
const existingIndices = new Set<number>();
340340
if (bookId) {
341341
try {
342-
const existingResponse = await fetch(`/api/audio/convert/chapters?bookId=${bookId}`);
342+
const existingResponse = await fetch(`/api/audiobook/status?bookId=${bookId}`);
343343
if (existingResponse.ok) {
344344
const existingData = await existingResponse.json();
345345
if (existingData.chapters && existingData.chapters.length > 0) {
@@ -469,7 +469,7 @@ export function EPUBProvider({ children }: { children: ReactNode }) {
469469
}
470470

471471
// Send to server for conversion and storage
472-
const convertResponse = await fetch('/api/audio/convert', {
472+
const convertResponse = await fetch(`/api/audiobook`, {
473473
method: 'POST',
474474
headers: {
475475
'Content-Type': 'application/json',
@@ -645,7 +645,7 @@ export function EPUBProvider({ children }: { children: ReactNode }) {
645645
}
646646

647647
// Send to server for conversion and storage
648-
const convertResponse = await fetch('/api/audio/convert', {
648+
const convertResponse = await fetch('/api/audiobook', {
649649
method: 'POST',
650650
headers: {
651651
'Content-Type': 'application/json',

src/contexts/PDFContext.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ export function PDFProvider({ children }: { children: ReactNode }) {
299299
const existingIndices = new Set<number>();
300300
if (bookId) {
301301
try {
302-
const existingResponse = await fetch(`/api/audio/convert/chapters?bookId=${bookId}`);
302+
const existingResponse = await fetch(`/api/audiobook/status?bookId=${bookId}`);
303303
if (existingResponse.ok) {
304304
const existingData = await existingResponse.json();
305305
if (existingData.chapters && existingData.chapters.length > 0) {
@@ -399,7 +399,7 @@ export function PDFProvider({ children }: { children: ReactNode }) {
399399
}
400400

401401
// Send to server for conversion and storage
402-
const convertResponse = await fetch('/api/audio/convert', {
402+
const convertResponse = await fetch(`/api/audiobook`, {
403403
method: 'POST',
404404
headers: {
405405
'Content-Type': 'application/json',
@@ -587,7 +587,7 @@ export function PDFProvider({ children }: { children: ReactNode }) {
587587
}
588588

589589
// Send to server for conversion and storage
590-
const convertResponse = await fetch('/api/audio/convert', {
590+
const convertResponse = await fetch('/api/audiobook', {
591591
method: 'POST',
592592
headers: {
593593
'Content-Type': 'application/json',

tests/api.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ test.describe('API health checks', () => {
99
expect(json.voices.length).toBeGreaterThan(0);
1010
});
1111

12-
test('GET /api/audio/convert/chapters returns 200 with exists flag and chapters array', async ({ request }) => {
12+
test('GET /api/audiobook/status returns 200 with exists flag and chapters array', async ({ request }) => {
1313
const bookId = `healthcheck-${Date.now()}`;
14-
const res = await request.get(`/api/audio/convert/chapters?bookId=${bookId}`);
14+
const res = await request.get(`/api/audiobook/status?bookId=${bookId}`);
1515
expect(res.ok()).toBeTruthy();
1616
const json = await res.json();
1717
expect(json).toHaveProperty('exists');

tests/export.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ async function getAudioDurationSeconds(filePath: string) {
6767
}
6868

6969
async function expectChaptersBackendState(page: Page, bookId: string) {
70-
const res = await page.request.get(`/api/audio/convert/chapters?bookId=${bookId}`);
70+
const res = await page.request.get(`/api/audiobook/status?bookId=${bookId}`);
7171
expect(res.ok()).toBeTruthy();
7272
const json = await res.json();
7373
return json;
@@ -271,7 +271,7 @@ test.describe('Audiobook export', () => {
271271
).toBeVisible({ timeout: 60_000 });
272272

273273
// Backend should report no existing chapters for this bookId
274-
const res = await page.request.get(`/api/audio/convert/chapters?bookId=${bookId}`);
274+
const res = await page.request.get(`/api/audiobook/status?bookId=${bookId}`);
275275
expect(res.ok()).toBeTruthy();
276276
const json = await res.json();
277277
expect(json.exists).toBe(false);

0 commit comments

Comments
 (0)