Files
libnovel/ui/src/routes/api/home/+server.ts
Admin f51113a2f8
Some checks failed
Deploy / Deploy Production (push) Has been skipped
Deploy / Cleanup Preview (push) Has been skipped
Deploy / Deploy Preview (push) Failing after 0s
CI / Scraper / Test (pull_request) Successful in 11s
CI / UI / Build (pull_request) Failing after 14s
CI / Scraper / Lint (pull_request) Successful in 23s
CI / Scraper / Build (pull_request) Successful in 24s
iOS CI / Build (push) Has been cancelled
iOS CI / Test (push) Has been cancelled
iOS CI / Build (pull_request) Failing after 2s
iOS CI / Test (pull_request) Has been skipped
Add iOS app, SvelteKit JSON API endpoints, and Gitea CI workflow
- iOS SwiftUI app (ios/LibNovel/) targeting iOS 17+, generated via xcodegen
  - Full feature set: auth, home, library, book detail, chapter reader, browse, audio player, profile
  - Kingfisher for image loading, swift-markdown-ui for chapter rendering
  - Base URL: https://v2.libnovel.kalekber.cc
- SvelteKit JSON API routes (ui/src/routes/api/) for iOS consumption:
  auth/login, auth/register, auth/me, auth/logout, auth/change-password,
  home, library, book/[slug], chapter/[slug]/[n], search, ranking,
  progress/[slug], presign/audio (updated)
- Gitea Actions CI: .gitea/workflows/ios.yaml (build + test on macos-latest)
- justfile: ios-gen, ios-build, ios-test recipes
2026-03-07 18:17:51 +05:00

49 lines
1.5 KiB
TypeScript

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { listBooks, recentlyAddedBooks, allProgress, getHomeStats } from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
import type { Book, Progress } from '$lib/server/pocketbase';
/**
* GET /api/home
* Returns home screen data: continue-reading list, recently updated books, and stats.
* Requires authentication (enforced by layout guard).
*/
export const GET: RequestHandler = async ({ locals }) => {
let allBooks: Book[] = [];
let recentBooks: Book[] = [];
let progressList: Progress[] = [];
let stats = { totalBooks: 0, totalChapters: 0 };
try {
[allBooks, recentBooks, progressList, stats] = await Promise.all([
listBooks(),
recentlyAddedBooks(8),
allProgress(locals.sessionId, locals.user?.id),
getHomeStats()
]);
} catch (e) {
log.error('api/home', 'failed to load home data', { err: String(e) });
}
const bookMap = new Map<string, Book>(allBooks.map((b) => [b.slug, b]));
const continueReading = progressList
.filter((p) => bookMap.has(p.slug))
.slice(0, 6)
.map((p) => ({ book: bookMap.get(p.slug)!, chapter: p.chapter }));
const inProgressSlugs = new Set(continueReading.map((c) => c.book.slug));
const recentlyUpdated = recentBooks.filter((b) => !inProgressSlugs.has(b.slug)).slice(0, 6);
return json({
continue_reading: continueReading,
recently_updated: recentlyUpdated,
stats: {
totalBooks: stats.totalBooks,
totalChapters: stats.totalChapters,
booksInProgress: continueReading.length
}
});
};