Compare commits
3 Commits
3a25e42a20
...
11c80a16a3
| Author | SHA1 | Date | |
|---|---|---|---|
| 11c80a16a3 | |||
| c366b44c54 | |||
| 92f80542e6 |
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -64,7 +64,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api"
|
name = "api"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
@@ -1233,7 +1233,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexer"
|
name = "indexer"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -1667,7 +1667,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notifications"
|
name = "notifications"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -1786,7 +1786,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parsers"
|
name = "parsers"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"flate2",
|
"flate2",
|
||||||
@@ -2923,7 +2923,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stripstream-core"
|
name = "stripstream-core"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ resolver = "2"
|
|||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -110,6 +110,12 @@ The backoffice will be available at http://localhost:7082
|
|||||||
- Batch auto-matching and scheduled metadata refresh
|
- Batch auto-matching and scheduled metadata refresh
|
||||||
- Field locking to protect manual edits from sync
|
- Field locking to protect manual edits from sync
|
||||||
|
|
||||||
|
### Notifications
|
||||||
|
- **Telegram**: real-time notifications via Telegram Bot API
|
||||||
|
- 12 granular event toggles (scans, thumbnails, conversions, metadata)
|
||||||
|
- Book thumbnail images included in notifications where applicable
|
||||||
|
- Test connection from settings
|
||||||
|
|
||||||
### External Integrations
|
### External Integrations
|
||||||
- **Komga**: import reading progress
|
- **Komga**: import reading progress
|
||||||
- **Prowlarr**: search for missing volumes
|
- **Prowlarr**: search for missing volumes
|
||||||
@@ -130,9 +136,11 @@ The backoffice will be available at http://localhost:7082
|
|||||||
- Rate limiting, token expiration and revocation
|
- Rate limiting, token expiration and revocation
|
||||||
|
|
||||||
### Web UI (Backoffice)
|
### Web UI (Backoffice)
|
||||||
- Dashboard with statistics, charts, and reading progress
|
- Dashboard with statistics, interactive charts (recharts), and reading progress
|
||||||
|
- Currently reading & recently read sections
|
||||||
- Library, book, series, author management
|
- Library, book, series, author management
|
||||||
- Live job monitoring, metadata search modals, settings panel
|
- Live job monitoring, metadata search modals, settings panel
|
||||||
|
- Notification settings with per-event toggle configuration
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
|
|||||||
@@ -21,19 +21,16 @@ export async function GET(
|
|||||||
const response = await fetch(apiUrl.toString(), {
|
const response = await fetch(apiUrl.toString(), {
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return new NextResponse(`Failed to fetch image: ${response.status}`, {
|
return new NextResponse(`Failed to fetch image: ${response.status}`, {
|
||||||
status: response.status
|
status: response.status
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Récupérer le content-type et les données
|
|
||||||
const contentType = response.headers.get("content-type") || "image/webp";
|
const contentType = response.headers.get("content-type") || "image/webp";
|
||||||
const imageBuffer = await response.arrayBuffer();
|
|
||||||
|
return new NextResponse(response.body, {
|
||||||
// Retourner l'image avec le bon content-type
|
|
||||||
return new NextResponse(imageBuffer, {
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": contentType,
|
"Content-Type": contentType,
|
||||||
"Cache-Control": "public, max-age=300",
|
"Cache-Control": "public, max-age=300",
|
||||||
|
|||||||
@@ -6,23 +6,22 @@ export async function GET(
|
|||||||
{ params }: { params: Promise<{ bookId: string }> }
|
{ params }: { params: Promise<{ bookId: string }> }
|
||||||
) {
|
) {
|
||||||
const { bookId } = await params;
|
const { bookId } = await params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { baseUrl, token } = config();
|
const { baseUrl, token } = config();
|
||||||
const response = await fetch(`${baseUrl}/books/${bookId}/thumbnail`, {
|
const response = await fetch(`${baseUrl}/books/${bookId}/thumbnail`, {
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return new NextResponse(`Failed to fetch thumbnail: ${response.status}`, {
|
return new NextResponse(`Failed to fetch thumbnail: ${response.status}`, {
|
||||||
status: response.status
|
status: response.status
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentType = response.headers.get("content-type") || "image/webp";
|
const contentType = response.headers.get("content-type") || "image/webp";
|
||||||
const imageBuffer = await response.arrayBuffer();
|
|
||||||
|
return new NextResponse(response.body, {
|
||||||
return new NextResponse(imageBuffer, {
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": contentType,
|
"Content-Type": contentType,
|
||||||
"Cache-Control": "public, max-age=31536000, immutable",
|
"Cache-Control": "public, max-age=31536000, immutable",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const nextConfig = {
|
|||||||
typedRoutes: true,
|
typedRoutes: true,
|
||||||
images: {
|
images: {
|
||||||
minimumCacheTTL: 86400,
|
minimumCacheTTL: 86400,
|
||||||
|
unoptimized: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stripstream-backoffice",
|
"name": "stripstream-backoffice",
|
||||||
"version": "1.24.0",
|
"version": "1.24.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 7082",
|
"dev": "next dev -p 7082",
|
||||||
|
|||||||
@@ -170,6 +170,34 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
### Telegram
|
||||||
|
- Real-time notifications via Telegram Bot API (`sendMessage` and `sendPhoto`)
|
||||||
|
- Configuration: bot token, chat ID, enable/disable toggle
|
||||||
|
- Test connection button in settings
|
||||||
|
|
||||||
|
### Granular Event Toggles
|
||||||
|
12 individually configurable notification events grouped by category:
|
||||||
|
|
||||||
|
| Category | Events |
|
||||||
|
|----------|--------|
|
||||||
|
| Scans | `scan_completed`, `scan_failed`, `scan_cancelled` |
|
||||||
|
| Thumbnails | `thumbnail_completed`, `thumbnail_failed`, `thumbnail_cancelled` |
|
||||||
|
| Conversion | `conversion_completed`, `conversion_failed`, `conversion_cancelled` |
|
||||||
|
| Metadata | `metadata_approved`, `metadata_batch_completed`, `metadata_refresh_completed` |
|
||||||
|
|
||||||
|
### Thumbnail Images in Notifications
|
||||||
|
- Book cover thumbnails attached to applicable notifications (conversion, metadata approval)
|
||||||
|
- Uses `sendPhoto` multipart upload with fallback to text-only `sendMessage`
|
||||||
|
|
||||||
|
### Implementation
|
||||||
|
- Shared `crates/notifications` crate used by both API and indexer
|
||||||
|
- Fire-and-forget: notification failures are logged but never block the main operation
|
||||||
|
- Messages formatted in HTML with event-specific icons
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Page Rendering & Caching
|
## Page Rendering & Caching
|
||||||
|
|
||||||
### Page Extraction
|
### Page Extraction
|
||||||
@@ -238,13 +266,16 @@
|
|||||||
## Backoffice (Web UI)
|
## Backoffice (Web UI)
|
||||||
|
|
||||||
### Dashboard
|
### Dashboard
|
||||||
- Statistics cards: books, series, authors, libraries
|
- Statistics cards: books, series, authors, libraries, pages, total size
|
||||||
- Donut charts: reading status breakdown, format distribution
|
- Interactive charts (recharts): donut, area, stacked bar, horizontal bar
|
||||||
- Bar charts: books per language
|
- Reading status breakdown, format distribution, library distribution
|
||||||
- Per-library reading progress bars
|
- Currently reading section with progress bars
|
||||||
- Top series by book/page count
|
- Recently read section with cover thumbnails
|
||||||
- Monthly addition timeline
|
- Reading activity over time (area chart)
|
||||||
- Metadata coverage stats
|
- Books added over time (area chart)
|
||||||
|
- Per-library stacked reading progress
|
||||||
|
- Top series by book count
|
||||||
|
- Metadata coverage and provider breakdown
|
||||||
|
|
||||||
### Pages
|
### Pages
|
||||||
- **Libraries**: list, create, delete, configure monitoring and metadata provider
|
- **Libraries**: list, create, delete, configure monitoring and metadata provider
|
||||||
@@ -253,7 +284,7 @@
|
|||||||
- **Authors**: list with book/series counts, detail with author's books
|
- **Authors**: list with book/series counts, detail with author's books
|
||||||
- **Jobs**: history, live progress via SSE, error details
|
- **Jobs**: history, live progress via SSE, error details
|
||||||
- **Tokens**: create, list, revoke API tokens
|
- **Tokens**: create, list, revoke API tokens
|
||||||
- **Settings**: image processing, cache, thumbnails, external services (Prowlarr, qBittorrent)
|
- **Settings**: image processing, cache, thumbnails, external services (Prowlarr, qBittorrent), notifications (Telegram)
|
||||||
|
|
||||||
### Interactive Features
|
### Interactive Features
|
||||||
- Real-time search with suggestions
|
- Real-time search with suggestions
|
||||||
|
|||||||
Reference in New Issue
Block a user