diff --git a/database/schema/schema.sql b/database/schema/schema.sql index 1f82be99..ff0b982c 100644 --- a/database/schema/schema.sql +++ b/database/schema/schema.sql @@ -48,6 +48,14 @@ ALTER TABLE users ADD COLUMN IF NOT EXISTS default_audio_speed REAL NOT NULL DEF -- mid-session. On by default; the profile page's On/Off dropdown owns it. ALTER TABLE users ADD COLUMN IF NOT EXISTS keep_screen_awake BOOLEAN NOT NULL DEFAULT TRUE; +-- Audio resume rewind: seconds before the saved position the +-- audiobook/podcast player starts (on open-resume AND again on every +-- genuine unpause — the re-orientation gap, never stacked). Strict +-- allow-list 0/5/10 enforced handler-side; 0 = exact resume. The +-- profile page's dropdown owns it; the chapters payload carries it to +-- every client (web + Android, incl. the car path). +ALTER TABLE users ADD COLUMN IF NOT EXISTS audio_resume_rewind_seconds INT NOT NULL DEFAULT 0; + -- Create system_settings table CREATE TABLE IF NOT EXISTS system_settings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), diff --git a/internal/database/models.go b/internal/database/models.go index f5119da3..5499ba00 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -640,18 +640,19 @@ type UserDashboardPreferencesGlobal struct { } type Users struct { - ID pgtype.UUID `db:"id" json:"id"` - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - PasswordHash string `db:"password_hash" json:"password_hash"` - FirstName pgtype.Text `db:"first_name" json:"first_name"` - LastName pgtype.Text `db:"last_name" json:"last_name"` - Role string `db:"role" json:"role"` - Theme pgtype.Text `db:"theme" json:"theme"` - MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - Timezone pgtype.Text `db:"timezone" json:"timezone"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"` - KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"` + ID pgtype.UUID `db:"id" json:"id"` + Email string `db:"email" json:"email"` + Username string `db:"username" json:"username"` + PasswordHash string `db:"password_hash" json:"password_hash"` + FirstName pgtype.Text `db:"first_name" json:"first_name"` + LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` + Theme pgtype.Text `db:"theme" json:"theme"` + MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + Timezone pgtype.Text `db:"timezone" json:"timezone"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` + DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"` + KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"` + AudioResumeRewindSeconds int32 `db:"audio_resume_rewind_seconds" json:"audio_resume_rewind_seconds"` } diff --git a/internal/database/querier.go b/internal/database/querier.go index 36771d67..976c1b90 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -894,6 +894,7 @@ type Querier interface { UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) error // Update universal progress UpdateUniversalProgress(ctx context.Context, arg UpdateUniversalProgressParams) (ReadingProgress, error) + UpdateUserAudioResumeRewind(ctx context.Context, arg UpdateUserAudioResumeRewindParams) error UpdateUserDefaultAudioSpeed(ctx context.Context, arg UpdateUserDefaultAudioSpeedParams) error UpdateUserKeepScreenAwake(ctx context.Context, arg UpdateUserKeepScreenAwakeParams) error UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error) diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index a469d3c8..d17fa116 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -11407,26 +11407,28 @@ SELECT u.timezone, u.default_audio_speed, u.keep_screen_awake, + u.audio_resume_rewind_seconds, (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count FROM users u WHERE u.id = $1 ` type GetUserRow struct { - ID pgtype.UUID `db:"id" json:"id"` - Email string `db:"email" json:"email"` - Username string `db:"username" json:"username"` - Theme pgtype.Text `db:"theme" json:"theme"` - FirstName pgtype.Text `db:"first_name" json:"first_name"` - LastName pgtype.Text `db:"last_name" json:"last_name"` - Role string `db:"role" json:"role"` - MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` - CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` - UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` - Timezone pgtype.Text `db:"timezone" json:"timezone"` - DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"` - KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"` - DeviceCount int64 `db:"device_count" json:"device_count"` + ID pgtype.UUID `db:"id" json:"id"` + Email string `db:"email" json:"email"` + Username string `db:"username" json:"username"` + Theme pgtype.Text `db:"theme" json:"theme"` + FirstName pgtype.Text `db:"first_name" json:"first_name"` + LastName pgtype.Text `db:"last_name" json:"last_name"` + Role string `db:"role" json:"role"` + MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"` + CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"` + UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"` + Timezone pgtype.Text `db:"timezone" json:"timezone"` + DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"` + KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"` + AudioResumeRewindSeconds int32 `db:"audio_resume_rewind_seconds" json:"audio_resume_rewind_seconds"` + DeviceCount int64 `db:"device_count" json:"device_count"` } func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, error) { @@ -11446,6 +11448,7 @@ func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, erro &i.Timezone, &i.DefaultAudioSpeed, &i.KeepScreenAwake, + &i.AudioResumeRewindSeconds, &i.DeviceCount, ) return i, err @@ -20287,6 +20290,20 @@ func (q *Queries) UpdateUniversalProgress(ctx context.Context, arg UpdateUnivers return i, err } +const UpdateUserAudioResumeRewind = `-- name: UpdateUserAudioResumeRewind :exec +UPDATE users SET audio_resume_rewind_seconds = $2, updated_at = NOW() WHERE id = $1 +` + +type UpdateUserAudioResumeRewindParams struct { + ID pgtype.UUID `db:"id" json:"id"` + AudioResumeRewindSeconds int32 `db:"audio_resume_rewind_seconds" json:"audio_resume_rewind_seconds"` +} + +func (q *Queries) UpdateUserAudioResumeRewind(ctx context.Context, arg UpdateUserAudioResumeRewindParams) error { + _, err := q.db.Exec(ctx, UpdateUserAudioResumeRewind, arg.ID, arg.AudioResumeRewindSeconds) + return err +} + const UpdateUserDefaultAudioSpeed = `-- name: UpdateUserDefaultAudioSpeed :exec UPDATE users SET default_audio_speed = $2, updated_at = NOW() WHERE id = $1 ` @@ -20317,7 +20334,7 @@ func (q *Queries) UpdateUserKeepScreenAwake(ctx context.Context, arg UpdateUserK const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1 -RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, timezone, updated_at, default_audio_speed, keep_screen_awake +RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, timezone, updated_at, default_audio_speed, keep_screen_awake, audio_resume_rewind_seconds ` type UpdateUserMaxDevicesParams struct { @@ -20343,6 +20360,7 @@ func (q *Queries) UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDev &i.UpdatedAt, &i.DefaultAudioSpeed, &i.KeepScreenAwake, + &i.AudioResumeRewindSeconds, ) return i, err } diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index f409c009..e478eb67 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -30,6 +30,7 @@ SELECT u.timezone, u.default_audio_speed, u.keep_screen_awake, + u.audio_resume_rewind_seconds, (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count FROM users u WHERE u.id = $1; @@ -526,6 +527,9 @@ UPDATE users SET default_audio_speed = $2, updated_at = NOW() WHERE id = $1; -- name: UpdateUserKeepScreenAwake :exec UPDATE users SET keep_screen_awake = $2, updated_at = NOW() WHERE id = $1; +-- name: UpdateUserAudioResumeRewind :exec +UPDATE users SET audio_resume_rewind_seconds = $2, updated_at = NOW() WHERE id = $1; + -- Per-book playback speed preference (player plan §8). -- name: GetAudioPlaybackSpeed :one