feat: add reader infrastructure - Phase 0 database schema and queries

Implement Phase 0 prerequisites for reader functionality including
database schema, SQL queries, and frontend dependencies.

## Database Schema (5 New Tables + 1 Column Addition)

### New Tables Added:
1. **panel_data** - Comic/manga panel detection results
   - Stores detected panel boundaries (x, y, width, height)
   - Supports grid, ML, and manual detection methods
   - JSONB storage for flexible panel structures

2. **reading_speed** - User reading speed statistics
   - Tracks pages per minute and total reading time
   - Per-user per-media-item tracking
   - Enables progress estimation and analytics

3. **dictionary_cache** - Offline dictionary word definitions
   - Caches external dictionary lookups
   - Reduces API calls and improves performance
   - Supports offline reading functionality

4. **reader_settings** - User reader preferences (per-user)
   - Stores typography, theme, and display settings
   - JSONB storage for flexible configuration
   - Per-user customization (fonts, margins, themes)

5. **media_bookmarks** - Enhanced bookmarks with chapter/CFI support
   - Unified bookmarking for ebooks, comics, manga, PDFs
   - Supports page_number, chapter_number, and epubcfi_position
   - Includes notes field for annotations
   - Unique constraint on (media_item_id, user_id, title)

### Column Addition:
- **media_items.chapter_metadata** (JSONB) - Caches detected chapter structure
  - Stores TOC/chapter detection results
  - Prevents re-parsing files on every read
  - Populated by ReaderService.DetectChapters()

## Database Queries (12 New Queries)

Added queries for all reader functionality:
- Panel data: GetPanelData, UpsertPanelData
- Reading speed: GetReadingSpeed, CreateReadingSpeed, UpdateReadingSpeed
- Dictionary: GetDictionaryEntry, CreateDictionaryEntry, UpdateDictionaryAccessed
- Settings: GetReaderSettings, UpsertReaderSettings
- Bookmarks: GetMediaBookmarks, CreateMediaBookmark, DeleteMediaBookmark, UpdateMediaBookmark

## Frontend Dependencies

Added to package.json:
- jszip@^3.10.1 - EPUB/comic archive parsing (client-side)
- pdfjs-dist@^3.11.174 - PDF rendering library (Mozilla PDF.js)

## Generated Code

Ran `sqlc generate` to regenerate:
- models.go - Go structs for new tables (55 lines added)
- querier.go - Database query methods (14 lines added)
- queries.sql.go - Compiled SQL queries (504 lines added)

## Implementation Status

Phase 0 prerequisites now complete:
 Database schema (5 tables + 1 column)
 SQL queries (12 queries)
 Frontend dependencies (2 packages)
 Generated Go code (sqlc)
 Database recreated with new schema

Ready for Phase 1: Infrastructure & Basic Reader implementation.

Related to: Universal web reader for ebooks, comics, manga, PDFs
This commit is contained in:
2026-04-02 21:01:45 -04:00
parent 40f519ce6e
commit 0667cad8a9
6 changed files with 731 additions and 25 deletions
+90 -1
View File
@@ -166,7 +166,21 @@ CREATE TABLE IF NOT EXISTS media_items (
scan_information TEXT, -- Scan information (scanner group, resolution, etc.)
-- Summary (distinct from description - may merge with Calibre description)
summary TEXT -- Summary from ComicInfo.xml (may be merged with description from Calibre)
summary TEXT, -- Summary from ComicInfo.xml (may be merged with description from Calibre)
-- Chapter metadata for reader navigation and progress tracking
-- Caches detected chapter structure to avoid re-parsing files
-- Populated by ReaderService.DetectChapters() on first read
-- JSONB structure:
-- {
-- "chapters": [
-- {"id": "chap1", "title": "Chapter 1", "start_page": 1, "page_count": 20, "level": 1},
-- {"id": "chap2", "title": "Chapter 2", "start_page": 21, "page_count": 25, "level": 1}
-- ],
-- "detected_at": "2024-01-15T10:30:00Z",
-- "detection_method": "epub-toc" | "pdf-outline" | "page-breaks"
-- }
chapter_metadata JSONB
);
-- Add GIN indexes for fast array searches
@@ -1140,3 +1154,78 @@ CREATE TRIGGER update_saved_filters_updated_at
BEFORE UPDATE ON saved_filters
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Panel detection data
CREATE TABLE IF NOT EXISTS panel_data (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
media_item_id UUID NOT NULL REFERENCES media_items(id) ON DELETE CASCADE,
page_number INTEGER NOT NULL,
detection_method VARCHAR(20) NOT NULL, -- 'grid', 'ml', 'manual'
panels JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(media_item_id, page_number)
);
CREATE INDEX IF NOT EXISTS idx_panel_data_media_item ON panel_data(media_item_id);
-- Reading speed tracking
CREATE TABLE IF NOT EXISTS reading_speed (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
media_item_id UUID NOT NULL REFERENCES media_items(id) ON DELETE CASCADE,
words_per_minute DECIMAL(6,2),
pages_per_minute DECIMAL(6,2),
pages_read INTEGER DEFAULT 0,
total_reading_minutes DECIMAL(8,2) DEFAULT 0,
last_read_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, media_item_id)
);
CREATE INDEX IF NOT EXISTS idx_reading_speed_user ON reading_speed(user_id);
CREATE INDEX IF NOT EXISTS idx_reading_speed_item ON reading_speed(media_item_id);
-- Dictionary cache (for offline use)
CREATE TABLE IF NOT EXISTS dictionary_cache (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
word VARCHAR(100) NOT NULL UNIQUE,
definition TEXT NOT NULL,
part_of_speech VARCHAR(20),
example TEXT,
etymology TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
accessed_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_dictionary_word ON dictionary_cache(word);
-- Reader settings (per-user preferences)
CREATE TABLE IF NOT EXISTS reader_settings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
setting_key VARCHAR(50) NOT NULL,
setting_value JSONB NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, setting_key)
);
CREATE INDEX IF NOT EXISTS idx_reader_settings_user ON reader_settings(user_id);
-- PDF bookmarks (custom user bookmarks)
CREATE TABLE IF NOT EXISTS media_bookmarks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
media_item_id UUID NOT NULL REFERENCES media_items(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
page_number INTEGER,
chapter_number INTEGER,
cfi_position VARCHAR(255), -- For ebooks: EPUB CFI position
title VARCHAR(255) NOT NULL,
position VARCHAR(100), -- 'pdf:page:45', 'comic:page:12', 'chapter:3' for consistency
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(media_item_id, user_id, title)
);
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_media ON media_bookmarks(media_item_id);
CREATE INDEX IF NOT EXISTS idx_media_bookmarks_user ON media_bookmarks(user_id);
+55
View File
@@ -81,6 +81,17 @@ type Devices struct {
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
type DictionaryCache struct {
ID pgtype.UUID `db:"id" json:"id"`
Word string `db:"word" json:"word"`
Definition string `db:"definition" json:"definition"`
PartOfSpeech pgtype.Text `db:"part_of_speech" json:"part_of_speech"`
Example pgtype.Text `db:"example" json:"example"`
Etymology pgtype.Text `db:"etymology" json:"etymology"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
AccessedAt pgtype.Timestamptz `db:"accessed_at" json:"accessed_at"`
}
type KoboEntitlements struct {
ID pgtype.UUID `db:"id" json:"id"`
DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
@@ -143,6 +154,19 @@ type LibraryVisibility struct {
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
type MediaBookmarks struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
PageNumber pgtype.Int4 `db:"page_number" json:"page_number"`
ChapterNumber pgtype.Int4 `db:"chapter_number" json:"chapter_number"`
CfiPosition pgtype.Text `db:"cfi_position" json:"cfi_position"`
Title string `db:"title" json:"title"`
Position pgtype.Text `db:"position" json:"position"`
Notes pgtype.Text `db:"notes" json:"notes"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
}
type MediaHighlights struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
@@ -254,6 +278,7 @@ type MediaItems struct {
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
// Summary from ComicInfo.xml (may be merged with description from Calibre)
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -298,6 +323,24 @@ type OpdsTokens struct {
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
}
type PanelData struct {
ID pgtype.UUID `db:"id" json:"id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PageNumber int32 `db:"page_number" json:"page_number"`
DetectionMethod string `db:"detection_method" json:"detection_method"`
Panels []byte `db:"panels" json:"panels"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
type ReaderSettings struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
SettingKey string `db:"setting_key" json:"setting_key"`
SettingValue []byte `db:"setting_value" json:"setting_value"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
type ReadingHistory struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
@@ -338,6 +381,18 @@ type ReadingProgress struct {
ConflictResolved pgtype.Bool `db:"conflict_resolved" json:"conflict_resolved"`
}
type ReadingSpeed struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
WordsPerMinute pgtype.Numeric `db:"words_per_minute" json:"words_per_minute"`
PagesPerMinute pgtype.Numeric `db:"pages_per_minute" json:"pages_per_minute"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TotalReadingMinutes pgtype.Numeric `db:"total_reading_minutes" json:"total_reading_minutes"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}
type RefreshTokens struct {
ID pgtype.UUID `db:"id" json:"id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
+14
View File
@@ -49,8 +49,10 @@ type Querier interface {
// DEVICE SHELF MAPPINGS QUERIES
// Create device shelf mapping
CreateDeviceShelfMapping(ctx context.Context, arg CreateDeviceShelfMappingParams) (DeviceShelfMappings, error)
CreateDictionaryEntry(ctx context.Context, arg CreateDictionaryEntryParams) (DictionaryCache, error)
// Libraries queries
CreateLibrary(ctx context.Context, arg CreateLibraryParams) (Libraries, error)
CreateMediaBookmark(ctx context.Context, arg CreateMediaBookmarkParams) (MediaBookmarks, error)
// Media Highlights queries
CreateMediaHighlight(ctx context.Context, arg CreateMediaHighlightParams) (MediaHighlights, error)
// Media Items queries
@@ -70,6 +72,7 @@ type Querier interface {
CreateOrUpdateKoboEntitlement(ctx context.Context, arg CreateOrUpdateKoboEntitlementParams) (KoboEntitlements, error)
// Create reading history entry
CreateReadingHistory(ctx context.Context, arg CreateReadingHistoryParams) (ReadingHistory, error)
CreateReadingSpeed(ctx context.Context, arg CreateReadingSpeedParams) (ReadingSpeed, error)
// Refresh Tokens queries
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshTokens, error)
CreateSavedFilter(ctx context.Context, arg CreateSavedFilterParams) (SavedFilters, error)
@@ -98,6 +101,7 @@ type Querier interface {
DeleteKoboEntitlement(ctx context.Context, arg DeleteKoboEntitlementParams) error
DeleteLibrary(ctx context.Context, id pgtype.UUID) error
DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFolderParams) (LibraryFolders, error)
DeleteMediaBookmark(ctx context.Context, id pgtype.UUID) error
DeleteMediaHighlight(ctx context.Context, id pgtype.UUID) error
DeleteMediaItem(ctx context.Context, id pgtype.UUID) error
// Delete media item format
@@ -156,6 +160,7 @@ type Querier interface {
GetDeviceShelfMapping(ctx context.Context, arg GetDeviceShelfMappingParams) (DeviceShelfMappings, error)
// Get device shelf mappings
GetDeviceShelfMappings(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceShelfMappingsRow, error)
GetDictionaryEntry(ctx context.Context, word string) (DictionaryCache, error)
GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]SyncQueue, error)
GetKoboEntitlementByContentId(ctx context.Context, arg GetKoboEntitlementByContentIdParams) (GetKoboEntitlementByContentIdRow, error)
GetKoboEntitlementByEntitlementId(ctx context.Context, arg GetKoboEntitlementByEntitlementIdParams) (GetKoboEntitlementByEntitlementIdRow, error)
@@ -174,6 +179,7 @@ type Querier interface {
// Library Types queries
GetLibraryTypes(ctx context.Context) ([]LibraryTypes, error)
GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibilityParams) (LibraryVisibility, error)
GetMediaBookmarks(ctx context.Context, arg GetMediaBookmarksParams) ([]MediaBookmarks, error)
GetMediaHighlight(ctx context.Context, id pgtype.UUID) (MediaHighlights, error)
GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error)
GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error)
@@ -206,11 +212,14 @@ type Querier interface {
GetOpdsToken(ctx context.Context, token string) (GetOpdsTokenRow, error)
// Get OPDS tokens by device
GetOpdsTokensByDevice(ctx context.Context, deviceID pgtype.UUID) ([]OpdsTokens, error)
GetPanelData(ctx context.Context, arg GetPanelDataParams) (PanelData, error)
// Get most popular books for a user
GetPopularBooks(ctx context.Context, arg GetPopularBooksParams) ([]GetPopularBooksRow, error)
GetReaderSettings(ctx context.Context, userID pgtype.UUID) ([]byte, error)
// Get reading history for a user and book
GetReadingHistory(ctx context.Context, arg GetReadingHistoryParams) ([]ReadingHistory, error)
GetReadingProgress(ctx context.Context, arg GetReadingProgressParams) (ReadingProgress, error)
GetReadingSpeed(ctx context.Context, arg GetReadingSpeedParams) (ReadingSpeed, error)
GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAddedItemsParams) ([]MediaItems, error)
GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadItemsParams) ([]MediaItems, error)
GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error)
@@ -309,6 +318,7 @@ type Querier interface {
// Update device shelf mapping
UpdateDeviceShelfMapping(ctx context.Context, arg UpdateDeviceShelfMappingParams) (DeviceShelfMappings, error)
UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID) (Devices, error)
UpdateDictionaryAccessed(ctx context.Context, word string) (DictionaryCache, error)
UpdateEmail(ctx context.Context, arg UpdateEmailParams) error
UpdateKoboEntitlementRevision(ctx context.Context, arg UpdateKoboEntitlementRevisionParams) error
UpdateKoboEntitlementStatus(ctx context.Context, arg UpdateKoboEntitlementStatusParams) error
@@ -316,6 +326,7 @@ type Querier interface {
// Update Kobo shelves to support collections
UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error)
UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error)
UpdateMediaBookmark(ctx context.Context, arg UpdateMediaBookmarkParams) (MediaBookmarks, error)
UpdateMediaHighlight(ctx context.Context, arg UpdateMediaHighlightParams) (MediaHighlights, error)
UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error)
// Update media item format
@@ -336,6 +347,7 @@ type Querier interface {
UpdateMediaRating(ctx context.Context, arg UpdateMediaRatingParams) (MediaRatings, error)
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error)
UpdateReadingSpeed(ctx context.Context, arg UpdateReadingSpeedParams) (ReadingSpeed, error)
UpdateSavedFilter(ctx context.Context, arg UpdateSavedFilterParams) (SavedFilters, error)
UpdateSyncQueueItemStatus(ctx context.Context, arg UpdateSyncQueueItemStatusParams) (SyncQueue, error)
UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) error
@@ -347,6 +359,8 @@ type Querier interface {
UpdateUserTheme(ctx context.Context, arg UpdateUserThemeParams) error
UpdateUsername(ctx context.Context, arg UpdateUsernameParams) error
UpsertDashboardPreferences(ctx context.Context, arg UpsertDashboardPreferencesParams) (UserDashboardPreferences, error)
UpsertPanelData(ctx context.Context, arg UpsertPanelDataParams) (PanelData, error)
UpsertReaderSettings(ctx context.Context, arg UpsertReaderSettingsParams) (ReaderSettings, error)
}
var _ Querier = (*Queries)(nil)
+482 -22
View File
@@ -460,6 +460,42 @@ func (q *Queries) CreateDeviceShelfMapping(ctx context.Context, arg CreateDevice
return i, err
}
const CreateDictionaryEntry = `-- name: CreateDictionaryEntry :one
INSERT INTO dictionary_cache (word, definition, part_of_speech, example, etymology, accessed_at)
VALUES ($1, $2, $3, $4, $5, NOW())
RETURNING id, word, definition, part_of_speech, example, etymology, created_at, accessed_at
`
type CreateDictionaryEntryParams struct {
Word string `db:"word" json:"word"`
Definition string `db:"definition" json:"definition"`
PartOfSpeech pgtype.Text `db:"part_of_speech" json:"part_of_speech"`
Example pgtype.Text `db:"example" json:"example"`
Etymology pgtype.Text `db:"etymology" json:"etymology"`
}
func (q *Queries) CreateDictionaryEntry(ctx context.Context, arg CreateDictionaryEntryParams) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, CreateDictionaryEntry,
arg.Word,
arg.Definition,
arg.PartOfSpeech,
arg.Example,
arg.Etymology,
)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
return i, err
}
const CreateLibrary = `-- name: CreateLibrary :one
INSERT INTO libraries (name, description, library_type_id, created_by_admin_id)
VALUES ($1, $2, $3, $4)
@@ -494,6 +530,50 @@ func (q *Queries) CreateLibrary(ctx context.Context, arg CreateLibraryParams) (L
return i, err
}
const CreateMediaBookmark = `-- name: CreateMediaBookmark :one
INSERT INTO media_bookmarks (media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at
`
type CreateMediaBookmarkParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
PageNumber pgtype.Int4 `db:"page_number" json:"page_number"`
ChapterNumber pgtype.Int4 `db:"chapter_number" json:"chapter_number"`
CfiPosition pgtype.Text `db:"cfi_position" json:"cfi_position"`
Title string `db:"title" json:"title"`
Position pgtype.Text `db:"position" json:"position"`
Notes pgtype.Text `db:"notes" json:"notes"`
}
func (q *Queries) CreateMediaBookmark(ctx context.Context, arg CreateMediaBookmarkParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, CreateMediaBookmark,
arg.MediaItemID,
arg.UserID,
arg.PageNumber,
arg.ChapterNumber,
arg.CfiPosition,
arg.Title,
arg.Position,
arg.Notes,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
)
return i, err
}
const CreateMediaHighlight = `-- name: CreateMediaHighlight :one
INSERT INTO media_highlights (media_item_id, user_id, selection_text, start_position, end_position, color, note_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
@@ -551,7 +631,7 @@ func (q *Queries) CreateMediaHighlight(ctx context.Context, arg CreateMediaHighl
const CreateMediaItem = `-- name: CreateMediaItem :one
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42)
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type CreateMediaItemParams struct {
@@ -699,6 +779,7 @@ func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -975,6 +1056,45 @@ func (q *Queries) CreateReadingHistory(ctx context.Context, arg CreateReadingHis
return i, err
}
const CreateReadingSpeed = `-- name: CreateReadingSpeed :one
INSERT INTO reading_speed (user_id, media_item_id, pages_per_minute, pages_read, total_reading_minutes, last_read_at)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at
`
type CreateReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PagesPerMinute pgtype.Numeric `db:"pages_per_minute" json:"pages_per_minute"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TotalReadingMinutes pgtype.Numeric `db:"total_reading_minutes" json:"total_reading_minutes"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
}
func (q *Queries) CreateReadingSpeed(ctx context.Context, arg CreateReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, CreateReadingSpeed,
arg.UserID,
arg.MediaItemID,
arg.PagesPerMinute,
arg.PagesRead,
arg.TotalReadingMinutes,
arg.LastReadAt,
)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const CreateRefreshToken = `-- name: CreateRefreshToken :one
INSERT INTO refresh_tokens (user_id, token, expires_at)
VALUES ($1, $2, $3)
@@ -1399,6 +1519,16 @@ func (q *Queries) DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFold
return i, err
}
const DeleteMediaBookmark = `-- name: DeleteMediaBookmark :exec
DELETE FROM media_bookmarks
WHERE id = $1
`
func (q *Queries) DeleteMediaBookmark(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, DeleteMediaBookmark, id)
return err
}
const DeleteMediaHighlight = `-- name: DeleteMediaHighlight :exec
DELETE FROM media_highlights WHERE id = $1
`
@@ -1793,7 +1923,7 @@ func (q *Queries) GetCollectionItems(ctx context.Context, collectionID pgtype.UU
}
const GetCollectionItemsForDashboard = `-- name: GetCollectionItemsForDashboard :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi
INNER JOIN collection_items ci ON ci.media_item_id = mi.id
WHERE ci.collection_id = $1
AND mi.library_id = $2
@@ -1860,6 +1990,7 @@ type GetCollectionItemsForDashboardRow struct {
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -1931,6 +2062,7 @@ func (q *Queries) GetCollectionItemsForDashboard(ctx context.Context, arg GetCol
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -2081,7 +2213,7 @@ func (q *Queries) GetCollectionsForBook(ctx context.Context, mediaItemID pgtype.
}
const GetContinueReadingItems = `-- name: GetContinueReadingItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
FROM reading_progress
@@ -2164,6 +2296,7 @@ func (q *Queries) GetContinueReadingItems(ctx context.Context, arg GetContinueRe
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -2579,6 +2712,27 @@ func (q *Queries) GetDeviceShelfMappings(ctx context.Context, deviceID pgtype.UU
return items, nil
}
const GetDictionaryEntry = `-- name: GetDictionaryEntry :one
SELECT id, word, definition, part_of_speech, example, etymology, created_at, accessed_at FROM dictionary_cache
WHERE word = $1
`
func (q *Queries) GetDictionaryEntry(ctx context.Context, word string) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, GetDictionaryEntry, word)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
return i, err
}
const GetFailedSyncQueueItems = `-- name: GetFailedSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE status = 'failed' AND attempts < max_attempts
@@ -3098,7 +3252,7 @@ func (q *Queries) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID)
}
const GetLibraryItems = `-- name: GetLibraryItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
`
@@ -3165,6 +3319,7 @@ func (q *Queries) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3270,6 +3425,48 @@ func (q *Queries) GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibi
return i, err
}
const GetMediaBookmarks = `-- name: GetMediaBookmarks :many
SELECT id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at FROM media_bookmarks
WHERE media_item_id = $1 AND user_id = $2
ORDER BY created_at DESC
`
type GetMediaBookmarksParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) GetMediaBookmarks(ctx context.Context, arg GetMediaBookmarksParams) ([]MediaBookmarks, error) {
rows, err := q.db.Query(ctx, GetMediaBookmarks, arg.MediaItemID, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []MediaBookmarks{}
for rows.Next() {
var i MediaBookmarks
if err := rows.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetMediaHighlight = `-- name: GetMediaHighlight :one
SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data FROM media_highlights WHERE id = $1
`
@@ -3355,7 +3552,7 @@ func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlights
}
const GetMediaItem = `-- name: GetMediaItem :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE id = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE id = $1
`
func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) {
@@ -3414,6 +3611,7 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems,
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3425,7 +3623,7 @@ func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems,
}
const GetMediaItemByFilePath = `-- name: GetMediaItemByFilePath :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $2
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $2
`
type GetMediaItemByFilePathParams struct {
@@ -3489,6 +3687,7 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemBy
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3500,7 +3699,7 @@ func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemBy
}
const GetMediaItemByFilePathAnyLibrary = `-- name: GetMediaItemByFilePathAnyLibrary :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 1
`
func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath string) (MediaItems, error) {
@@ -3559,6 +3758,7 @@ func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3571,7 +3771,7 @@ func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath
const GetMediaItemByFilePathForSync = `-- name: GetMediaItemByFilePathForSync :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1
`
// ============================================
@@ -3633,6 +3833,7 @@ func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath st
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3644,7 +3845,7 @@ func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath st
}
const GetMediaItemByKoboContentId = `-- name: GetMediaItemByKoboContentId :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_id = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_id = $1
`
func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID pgtype.Text) (MediaItems, error) {
@@ -3703,6 +3904,7 @@ func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3714,7 +3916,7 @@ func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID
}
const GetMediaItemByOPFIdentifier = `-- name: GetMediaItemByOPFIdentifier :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $1
`
// Get media item by OPF identifier
@@ -3774,6 +3976,7 @@ func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3785,7 +3988,7 @@ func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier
}
const GetMediaItemByOPFUUID = `-- name: GetMediaItemByOPFUUID :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $1
`
// Get media item by OPF UUID
@@ -3845,6 +4048,7 @@ func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -3856,7 +4060,7 @@ func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text
}
const GetMediaItemBySHA256 = `-- name: GetMediaItemBySHA256 :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1
`
// Get media item by SHA-256 hash
@@ -3916,6 +4120,7 @@ func (q *Queries) GetMediaItemBySHA256(ctx context.Context, fileSha256 pgtype.Te
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -4169,7 +4374,7 @@ func (q *Queries) GetNextRetryTime(ctx context.Context) (interface{}, error) {
}
const GetNotStartedItems = `-- name: GetNotStartedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
AND NOT EXISTS (
SELECT 1 FROM reading_progress rp
@@ -4249,6 +4454,7 @@ func (q *Queries) GetNotStartedItems(ctx context.Context, arg GetNotStartedItems
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -4333,6 +4539,31 @@ func (q *Queries) GetOpdsTokensByDevice(ctx context.Context, deviceID pgtype.UUI
return items, nil
}
const GetPanelData = `-- name: GetPanelData :one
SELECT id, media_item_id, page_number, detection_method, panels, created_at, updated_at FROM panel_data
WHERE media_item_id = $1 AND page_number = $2
`
type GetPanelDataParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PageNumber int32 `db:"page_number" json:"page_number"`
}
func (q *Queries) GetPanelData(ctx context.Context, arg GetPanelDataParams) (PanelData, error) {
row := q.db.QueryRow(ctx, GetPanelData, arg.MediaItemID, arg.PageNumber)
var i PanelData
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.PageNumber,
&i.DetectionMethod,
&i.Panels,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetPopularBooks = `-- name: GetPopularBooks :many
SELECT
mi.id,
@@ -4391,6 +4622,18 @@ func (q *Queries) GetPopularBooks(ctx context.Context, arg GetPopularBooksParams
return items, nil
}
const GetReaderSettings = `-- name: GetReaderSettings :one
SELECT setting_value FROM reader_settings
WHERE user_id = $1 AND setting_key = 'reader_settings'
`
func (q *Queries) GetReaderSettings(ctx context.Context, userID pgtype.UUID) ([]byte, error) {
row := q.db.QueryRow(ctx, GetReaderSettings, userID)
var setting_value []byte
err := row.Scan(&setting_value)
return setting_value, err
}
const GetReadingHistory = `-- name: GetReadingHistory :many
SELECT id, user_id, media_item_id, device_id, progress_percentage, reading_session_start, reading_session_end, pages_read, time_spent_seconds, device_metadata, created_at
FROM reading_history
@@ -4478,8 +4721,35 @@ func (q *Queries) GetReadingProgress(ctx context.Context, arg GetReadingProgress
return i, err
}
const GetReadingSpeed = `-- name: GetReadingSpeed :one
SELECT id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at FROM reading_speed
WHERE user_id = $1 AND media_item_id = $2
`
type GetReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}
func (q *Queries) GetReadingSpeed(ctx context.Context, arg GetReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, GetReadingSpeed, arg.UserID, arg.MediaItemID)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const GetRecentlyAddedItems = `-- name: GetRecentlyAddedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
LIMIT $2
@@ -4552,6 +4822,7 @@ func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAdde
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -4570,7 +4841,7 @@ func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAdde
}
const GetRecentlyReadItems = `-- name: GetRecentlyReadItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
FROM reading_progress
@@ -4651,6 +4922,7 @@ func (q *Queries) GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadI
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -6099,7 +6371,7 @@ func (q *Queries) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error)
}
const ListMediaItems = `-- name: ListMediaItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
@@ -6164,6 +6436,7 @@ type ListMediaItemsRow struct {
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -6236,6 +6509,7 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams)
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -6256,7 +6530,7 @@ func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams)
}
const ListMediaItemsByLibrary = `-- name: ListMediaItemsByLibrary :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
@@ -6317,6 +6591,7 @@ type ListMediaItemsByLibraryRow struct {
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -6389,6 +6664,7 @@ func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -6409,7 +6685,7 @@ func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.
}
const ListMediaItemsSorted = `-- name: ListMediaItemsSorted :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
@@ -6543,6 +6819,7 @@ type ListMediaItemsSortedRow struct {
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -6620,6 +6897,7 @@ func (q *Queries) ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSo
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -7370,7 +7648,7 @@ func (q *Queries) SearchLanguageValues(ctx context.Context, arg SearchLanguageVa
}
const SearchMediaItems = `-- name: SearchMediaItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.manga_type, mi.reading_direction, mi.series_count, mi.volume, mi.imprint, mi.age_rating, mi.web_url, mi.story_arc, mi.is_black_and_white, mi.metadata_notes, mi.community_rating, mi.alternate_info, mi.scan_information, mi.summary, mi.chapter_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
@@ -7457,6 +7735,7 @@ type SearchMediaItemsRow struct {
AlternateInfo []byte `db:"alternate_info" json:"alternate_info"`
ScanInformation pgtype.Text `db:"scan_information" json:"scan_information"`
Summary pgtype.Text `db:"summary" json:"summary"`
ChapterMetadata []byte `db:"chapter_metadata" json:"chapter_metadata"`
TagsSearch []string `db:"tags_search" json:"tags_search"`
ContributorsSearch []string `db:"contributors_search" json:"contributors_search"`
FileSha256 pgtype.Text `db:"file_sha256" json:"file_sha256"`
@@ -7536,6 +7815,7 @@ func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsPara
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -8421,6 +8701,29 @@ func (q *Queries) UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID)
return i, err
}
const UpdateDictionaryAccessed = `-- name: UpdateDictionaryAccessed :one
UPDATE dictionary_cache
SET accessed_at = NOW()
WHERE word = $1
RETURNING id, word, definition, part_of_speech, example, etymology, created_at, accessed_at
`
func (q *Queries) UpdateDictionaryAccessed(ctx context.Context, word string) (DictionaryCache, error) {
row := q.db.QueryRow(ctx, UpdateDictionaryAccessed, word)
var i DictionaryCache
err := row.Scan(
&i.ID,
&i.Word,
&i.Definition,
&i.PartOfSpeech,
&i.Example,
&i.Etymology,
&i.CreatedAt,
&i.AccessedAt,
)
return i, err
}
const UpdateEmail = `-- name: UpdateEmail :exec
UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1
`
@@ -8550,6 +8853,49 @@ func (q *Queries) UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (L
return i, err
}
const UpdateMediaBookmark = `-- name: UpdateMediaBookmark :one
UPDATE media_bookmarks
SET
title = $2,
notes = $3,
position = $4,
updated_at = NOW()
WHERE id = $1 AND user_id = $5
RETURNING id, media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes, created_at
`
type UpdateMediaBookmarkParams struct {
ID pgtype.UUID `db:"id" json:"id"`
Title string `db:"title" json:"title"`
Notes pgtype.Text `db:"notes" json:"notes"`
Position pgtype.Text `db:"position" json:"position"`
UserID pgtype.UUID `db:"user_id" json:"user_id"`
}
func (q *Queries) UpdateMediaBookmark(ctx context.Context, arg UpdateMediaBookmarkParams) (MediaBookmarks, error) {
row := q.db.QueryRow(ctx, UpdateMediaBookmark,
arg.ID,
arg.Title,
arg.Notes,
arg.Position,
arg.UserID,
)
var i MediaBookmarks
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.UserID,
&i.PageNumber,
&i.ChapterNumber,
&i.CfiPosition,
&i.Title,
&i.Position,
&i.Notes,
&i.CreatedAt,
)
return i, err
}
const UpdateMediaHighlight = `-- name: UpdateMediaHighlight :one
UPDATE media_highlights SET
selection_text = $2,
@@ -8633,7 +8979,7 @@ UPDATE media_items SET
google_books_id = $23,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemParams struct {
@@ -8742,6 +9088,7 @@ func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -8847,7 +9194,7 @@ SET
hash_confidence = $5,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemIdentifiersParams struct {
@@ -8925,6 +9272,7 @@ func (q *Queries) UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMedi
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -8943,7 +9291,7 @@ SET entitlement_id = $2,
kobo_metadata = $5,
updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, chapter_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`
type UpdateMediaItemKoboMetadataParams struct {
@@ -9016,6 +9364,7 @@ func (q *Queries) UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMed
&i.AlternateInfo,
&i.ScanInformation,
&i.Summary,
&i.ChapterMetadata,
&i.TagsSearch,
&i.ContributorsSearch,
&i.FileSha256,
@@ -9159,6 +9508,51 @@ func (q *Queries) UpdateReadingProgress(ctx context.Context, arg UpdateReadingPr
return i, err
}
const UpdateReadingSpeed = `-- name: UpdateReadingSpeed :one
UPDATE reading_speed
SET
pages_per_minute = $3,
pages_read = pages_read + $4,
total_reading_minutes = total_reading_minutes + $5,
last_read_at = $6,
updated_at = NOW()
WHERE user_id = $1 AND media_item_id = $2
RETURNING id, user_id, media_item_id, words_per_minute, pages_per_minute, pages_read, total_reading_minutes, last_read_at, updated_at
`
type UpdateReadingSpeedParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PagesPerMinute pgtype.Numeric `db:"pages_per_minute" json:"pages_per_minute"`
PagesRead pgtype.Int4 `db:"pages_read" json:"pages_read"`
TotalReadingMinutes pgtype.Numeric `db:"total_reading_minutes" json:"total_reading_minutes"`
LastReadAt pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
}
func (q *Queries) UpdateReadingSpeed(ctx context.Context, arg UpdateReadingSpeedParams) (ReadingSpeed, error) {
row := q.db.QueryRow(ctx, UpdateReadingSpeed,
arg.UserID,
arg.MediaItemID,
arg.PagesPerMinute,
arg.PagesRead,
arg.TotalReadingMinutes,
arg.LastReadAt,
)
var i ReadingSpeed
err := row.Scan(
&i.ID,
&i.UserID,
&i.MediaItemID,
&i.WordsPerMinute,
&i.PagesPerMinute,
&i.PagesRead,
&i.TotalReadingMinutes,
&i.LastReadAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateSavedFilter = `-- name: UpdateSavedFilter :one
UPDATE saved_filters
SET name = $1,
@@ -9509,3 +9903,69 @@ func (q *Queries) UpsertDashboardPreferences(ctx context.Context, arg UpsertDash
)
return i, err
}
const UpsertPanelData = `-- name: UpsertPanelData :one
INSERT INTO panel_data (media_item_id, page_number, detection_method, panels)
VALUES ($1, $2, $3, $4)
ON CONFLICT (media_item_id, page_number)
DO UPDATE SET
detection_method = EXCLUDED.detection_method,
panels = EXCLUDED.panels,
updated_at = NOW()
RETURNING id, media_item_id, page_number, detection_method, panels, created_at, updated_at
`
type UpsertPanelDataParams struct {
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
PageNumber int32 `db:"page_number" json:"page_number"`
DetectionMethod string `db:"detection_method" json:"detection_method"`
Panels []byte `db:"panels" json:"panels"`
}
func (q *Queries) UpsertPanelData(ctx context.Context, arg UpsertPanelDataParams) (PanelData, error) {
row := q.db.QueryRow(ctx, UpsertPanelData,
arg.MediaItemID,
arg.PageNumber,
arg.DetectionMethod,
arg.Panels,
)
var i PanelData
err := row.Scan(
&i.ID,
&i.MediaItemID,
&i.PageNumber,
&i.DetectionMethod,
&i.Panels,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpsertReaderSettings = `-- name: UpsertReaderSettings :one
INSERT INTO reader_settings (user_id, setting_key, setting_value)
VALUES ($1, 'reader_settings', $2)
ON CONFLICT (user_id, setting_key)
DO UPDATE SET
setting_value = EXCLUDED.setting_value,
updated_at = NOW()
RETURNING id, user_id, setting_key, setting_value, updated_at
`
type UpsertReaderSettingsParams struct {
UserID pgtype.UUID `db:"user_id" json:"user_id"`
SettingValue []byte `db:"setting_value" json:"setting_value"`
}
func (q *Queries) UpsertReaderSettings(ctx context.Context, arg UpsertReaderSettingsParams) (ReaderSettings, error) {
row := q.db.QueryRow(ctx, UpsertReaderSettings, arg.UserID, arg.SettingValue)
var i ReaderSettings
err := row.Scan(
&i.ID,
&i.UserID,
&i.SettingKey,
&i.SettingValue,
&i.UpdatedAt,
)
return i, err
}
+86
View File
@@ -1924,3 +1924,89 @@ RETURNING *;
DELETE FROM saved_filters
WHERE id = @id AND user_id = @user_id
RETURNING *;
-- name: GetPanelData :one
SELECT * FROM panel_data
WHERE media_item_id = $1 AND page_number = $2;
-- name: UpsertPanelData :one
INSERT INTO panel_data (media_item_id, page_number, detection_method, panels)
VALUES ($1, $2, $3, $4)
ON CONFLICT (media_item_id, page_number)
DO UPDATE SET
detection_method = EXCLUDED.detection_method,
panels = EXCLUDED.panels,
updated_at = NOW()
RETURNING *;
-- name: GetReadingSpeed :one
SELECT * FROM reading_speed
WHERE user_id = $1 AND media_item_id = $2;
-- name: CreateReadingSpeed :one
INSERT INTO reading_speed (user_id, media_item_id, pages_per_minute, pages_read, total_reading_minutes, last_read_at)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;
-- name: UpdateReadingSpeed :one
UPDATE reading_speed
SET
pages_per_minute = $3,
pages_read = pages_read + $4,
total_reading_minutes = total_reading_minutes + $5,
last_read_at = $6,
updated_at = NOW()
WHERE user_id = $1 AND media_item_id = $2
RETURNING *;
-- name: GetDictionaryEntry :one
SELECT * FROM dictionary_cache
WHERE word = $1;
-- name: CreateDictionaryEntry :one
INSERT INTO dictionary_cache (word, definition, part_of_speech, example, etymology, accessed_at)
VALUES ($1, $2, $3, $4, $5, NOW())
RETURNING *;
-- name: UpdateDictionaryAccessed :one
UPDATE dictionary_cache
SET accessed_at = NOW()
WHERE word = $1
RETURNING *;
-- name: GetReaderSettings :one
SELECT setting_value FROM reader_settings
WHERE user_id = $1 AND setting_key = 'reader_settings';
-- name: UpsertReaderSettings :one
INSERT INTO reader_settings (user_id, setting_key, setting_value)
VALUES ($1, 'reader_settings', $2)
ON CONFLICT (user_id, setting_key)
DO UPDATE SET
setting_value = EXCLUDED.setting_value,
updated_at = NOW()
RETURNING *;
-- name: GetMediaBookmarks :many
SELECT * FROM media_bookmarks
WHERE media_item_id = $1 AND user_id = $2
ORDER BY created_at DESC;
-- name: CreateMediaBookmark :one
INSERT INTO media_bookmarks (media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;
-- name: DeleteMediaBookmark :exec
DELETE FROM media_bookmarks
WHERE id = $1;
-- name: UpdateMediaBookmark :one
UPDATE media_bookmarks
SET
title = $2,
notes = $3,
position = $4,
updated_at = NOW()
WHERE id = $1 AND user_id = $5
RETURNING *;
+3 -1
View File
@@ -16,7 +16,9 @@
"chart.js": "^4.5.1",
"highlight.js": "^11.11.1",
"htmx.org": "^2.0.8",
"lunr": "^2.3.9"
"jszip": "3.10.1",
"lunr": "^2.3.9",
"pdfjs-dist": "^5.6.205"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.11",