Compare commits
3 Commits
0e5eb84097
...
v2.5.75
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0d8c02787 | ||
|
|
5b4c1db931 | ||
|
|
0c54c59586 |
@@ -130,7 +130,14 @@ func (s *Store) upsertChapterIdx(ctx context.Context, slug string, ref domain.Ch
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
postErr := s.pb.post(ctx, "/api/collections/chapters_idx/records", payload, nil)
|
// Set created timestamp on first insert so recentlyUpdatedBooks can sort by it.
|
||||||
|
insertPayload := map[string]any{
|
||||||
|
"slug": slug,
|
||||||
|
"number": ref.Number,
|
||||||
|
"title": ref.Title,
|
||||||
|
"created": time.Now().UTC().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
postErr := s.pb.post(ctx, "/api/collections/chapters_idx/records", insertPayload, nil)
|
||||||
if postErr == nil {
|
if postErr == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ services:
|
|||||||
image: kalekber/libnovel-runner:latest
|
image: kalekber/libnovel-runner:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
stop_grace_period: 135s
|
stop_grace_period: 135s
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
depends_on:
|
depends_on:
|
||||||
- libretranslate
|
- libretranslate
|
||||||
# Pin prod subdomains to the prod server IP to bypass Cloudflare's 100s
|
# Pin prod subdomains to the prod server IP to bypass Cloudflare's 100s
|
||||||
|
|||||||
@@ -62,6 +62,39 @@ create() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# add_index COLLECTION INDEX_NAME SQL_EXPR
|
||||||
|
# Fetches current schema, adds index if absent by name, PATCHes collection.
|
||||||
|
add_index() {
|
||||||
|
COLL="$1"; INAME="$2"; ISQL="$3"
|
||||||
|
SCHEMA=$(curl -sf -H "Authorization: Bearer $TOK" "$PB/api/collections/$COLL" 2>/dev/null)
|
||||||
|
PARSED=$(echo "$SCHEMA" | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
indexes = d.get('indexes', [])
|
||||||
|
exists = any('$INAME' in idx for idx in indexes)
|
||||||
|
print('exists=' + str(exists))
|
||||||
|
print('id=' + d.get('id', ''))
|
||||||
|
if not exists:
|
||||||
|
indexes.append('$ISQL')
|
||||||
|
print('indexes=' + json.dumps(indexes))
|
||||||
|
" 2>/dev/null)
|
||||||
|
if echo "$PARSED" | grep -q "^exists=True"; then
|
||||||
|
log "index exists (skip): $COLL.$INAME"; return
|
||||||
|
fi
|
||||||
|
COLL_ID=$(echo "$PARSED" | grep "^id=" | sed 's/^id=//')
|
||||||
|
[ -z "$COLL_ID" ] && { log "WARNING: cannot resolve id for $COLL"; return; }
|
||||||
|
NEW_INDEXES=$(echo "$PARSED" | grep "^indexes=" | sed 's/^indexes=//')
|
||||||
|
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X PATCH "$PB/api/collections/$COLL_ID" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer $TOK" \
|
||||||
|
-d "{\"indexes\":${NEW_INDEXES}}")
|
||||||
|
case "$STATUS" in
|
||||||
|
200|201) log "added index: $COLL.$INAME" ;;
|
||||||
|
*) log "WARNING: add_index $COLL.$INAME returned $STATUS" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
# add_field COLLECTION FIELD_NAME FIELD_TYPE
|
# add_field COLLECTION FIELD_NAME FIELD_TYPE
|
||||||
# Fetches current schema, appends field if absent, PATCHes collection.
|
# Fetches current schema, appends field if absent, PATCHes collection.
|
||||||
# Requires python3 for safe JSON manipulation.
|
# Requires python3 for safe JSON manipulation.
|
||||||
@@ -116,9 +149,10 @@ create "books" '{
|
|||||||
|
|
||||||
create "chapters_idx" '{
|
create "chapters_idx" '{
|
||||||
"name":"chapters_idx","type":"base","fields":[
|
"name":"chapters_idx","type":"base","fields":[
|
||||||
{"name":"slug", "type":"text", "required":true},
|
{"name":"slug", "type":"text", "required":true},
|
||||||
{"name":"number","type":"number", "required":true},
|
{"name":"number", "type":"number", "required":true},
|
||||||
{"name":"title", "type":"text"}
|
{"name":"title", "type":"text"},
|
||||||
|
{"name":"created", "type":"date"}
|
||||||
]}'
|
]}'
|
||||||
|
|
||||||
create "ranking" '{
|
create "ranking" '{
|
||||||
@@ -293,5 +327,12 @@ add_field "app_users" "polar_customer_id" "text"
|
|||||||
add_field "app_users" "polar_subscription_id" "text"
|
add_field "app_users" "polar_subscription_id" "text"
|
||||||
add_field "user_library" "shelf" "text"
|
add_field "user_library" "shelf" "text"
|
||||||
add_field "user_sessions" "device_fingerprint" "text"
|
add_field "user_sessions" "device_fingerprint" "text"
|
||||||
|
add_field "chapters_idx" "created" "date"
|
||||||
|
|
||||||
|
# ── 6. Indexes ────────────────────────────────────────────────────────────────
|
||||||
|
add_index "chapters_idx" "idx_chapters_idx_slug_number" \
|
||||||
|
"CREATE UNIQUE INDEX idx_chapters_idx_slug_number ON chapters_idx (slug, number)"
|
||||||
|
add_index "chapters_idx" "idx_chapters_idx_created" \
|
||||||
|
"CREATE INDEX idx_chapters_idx_created ON chapters_idx (created)"
|
||||||
|
|
||||||
log "done"
|
log "done"
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export * from './messages/_index.js'
|
export * from './messages/_index.js'
|
||||||
// enabling auto-import by exposing all messages as m
|
|
||||||
export * as m from './messages/_index.js'
|
|
||||||
@@ -28,7 +28,7 @@ export const load: LayoutServerLoad = async ({ locals, url, cookies }) => {
|
|||||||
theme: row.theme ?? 'amber',
|
theme: row.theme ?? 'amber',
|
||||||
locale: row.locale ?? 'en',
|
locale: row.locale ?? 'en',
|
||||||
fontFamily: row.font_family ?? 'system',
|
fontFamily: row.font_family ?? 'system',
|
||||||
fontSize: row.font_size ?? 1.0
|
fontSize: row.font_size || 1.0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
// Always sync theme + font (profile page calls invalidateAll after saving)
|
// Always sync theme + font (profile page calls invalidateAll after saving)
|
||||||
currentTheme = data.settings.theme ?? 'amber';
|
currentTheme = data.settings.theme ?? 'amber';
|
||||||
currentFontFamily = data.settings.fontFamily ?? 'system';
|
currentFontFamily = data.settings.fontFamily ?? 'system';
|
||||||
currentFontSize = data.settings.fontSize ?? 1.0;
|
currentFontSize = data.settings.fontSize || 1.0;
|
||||||
// Mark dirty only after the synchronous apply is done so the save
|
// Mark dirty only after the synchronous apply is done so the save
|
||||||
// effect doesn't fire for this initial load.
|
// effect doesn't fire for this initial load.
|
||||||
setTimeout(() => { settingsDirty = true; }, 0);
|
setTimeout(() => { settingsDirty = true; }, 0);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const GET: RequestHandler = async ({ locals }) => {
|
|||||||
theme: settings?.theme ?? 'amber',
|
theme: settings?.theme ?? 'amber',
|
||||||
locale: settings?.locale ?? 'en',
|
locale: settings?.locale ?? 'en',
|
||||||
fontFamily: settings?.font_family ?? 'system',
|
fontFamily: settings?.font_family ?? 'system',
|
||||||
fontSize: settings?.font_size ?? 1.0
|
fontSize: settings?.font_size || 1.0
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('settings', 'GET failed', { err: String(e) });
|
log.error('settings', 'GET failed', { err: String(e) });
|
||||||
@@ -61,9 +61,9 @@ export const PUT: RequestHandler = async ({ request, locals }) => {
|
|||||||
error(400, `Invalid fontFamily — must be one of: ${validFontFamilies.join(', ')}`);
|
error(400, `Invalid fontFamily — must be one of: ${validFontFamilies.join(', ')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fontSize is optional — if provided (and non-zero) it must be one of the valid steps
|
// fontSize is optional — if provided it must be one of the valid steps (0 is not valid)
|
||||||
const validFontSizes = [0.9, 1.0, 1.15, 1.3];
|
const validFontSizes = [0.9, 1.0, 1.15, 1.3];
|
||||||
if (body.fontSize !== undefined && body.fontSize !== 0 && !validFontSizes.includes(body.fontSize)) {
|
if (body.fontSize !== undefined && !validFontSizes.includes(body.fontSize)) {
|
||||||
error(400, `Invalid fontSize — must be one of: ${validFontSizes.join(', ')}`);
|
error(400, `Invalid fontSize — must be one of: ${validFontSizes.join(', ')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user