From becfb6a72ea14d5eef6fd356a14ca7ce291ef6e9 Mon Sep 17 00:00:00 2001
From: neon <18559658+neonsolstice@users.noreply.github.com>
Date: Thu, 13 Aug 2026 19:08:53 +0000
Subject: [PATCH] fix(settings): display complete endpoint path in koreader
sync url
The KOReader settings page displayed the origin-only base URL without the /api/v1/koreader path suffix, causing manual URL copy and built-in progress sync setup to fail due to incomplete endpoint paths.
Updates the UI to display the full KOReader sync URL with the API endpoint path included, consolidates redundant copy fields, and updates plugin URL normalization to handle full stock sync URLs seamlessly.
Closes #981
---
.../features/settings/KoreaderSettings.vue | 67 +++++++------------
.../__tests__/KoreaderSettings.spec.ts | 14 ++--
client/src/locales/en.json | 2 +
koreader-plugin/spec/bookorbit_api_test.lua | 5 ++
4 files changed, 38 insertions(+), 50 deletions(-)
diff --git a/client/src/features/settings/KoreaderSettings.vue b/client/src/features/settings/KoreaderSettings.vue
index a72aa7eac..09baf33de 100644
--- a/client/src/features/settings/KoreaderSettings.vue
+++ b/client/src/features/settings/KoreaderSettings.vue
@@ -120,7 +120,7 @@ const creating = ref(false)
const showPassword = ref(false)
const deleteConfirmOpen = ref(false)
const helpOpen = ref(false)
-const copiedUrlTarget = ref<'plugin' | 'stock' | null>(null)
+const urlCopied = ref(false)
const selectedUnmatched = ref(null)
const selectedManualLink = ref(null)
const linkSearchQuery = ref('')
@@ -152,10 +152,7 @@ onUnmounted(() => {
if (copiedUrlTimer) clearTimeout(copiedUrlTimer)
})
-const syncUrl = computed(() => getSyncUrl())
-const stockSyncUrl = computed(() => new URL('/api/v1/koreader', syncUrl.value).toString())
-const urlCopied = computed(() => copiedUrlTarget.value === 'plugin')
-const stockUrlCopied = computed(() => copiedUrlTarget.value === 'stock')
+const syncUrl = computed(() => new URL('/api/v1/koreader', getSyncUrl()).toString())
const hasCredentials = computed(() => !!credentials.value)
const deviceCount = computed(() => syncStatus.value?.devices.length ?? 0)
const totalSyncedBooks = computed(() => syncStatus.value?.totalSyncedBooks ?? 0)
@@ -383,30 +380,22 @@ async function handleDelete() {
}
}
-async function copyUrlWithFeedback(url: string, target: 'plugin' | 'stock') {
- const copied = await copyToClipboard(url)
+async function handleCopySyncUrl() {
+ const copied = await copyToClipboard(syncUrl.value)
if (!copied) {
toast.error(t('settings.reader.koreader.syncUrlCopyFailed'))
return
}
- copiedUrlTarget.value = target
+ urlCopied.value = true
toast.success(t('settings.reader.koreader.syncUrlCopied'))
if (copiedUrlTimer) clearTimeout(copiedUrlTimer)
copiedUrlTimer = setTimeout(() => {
- copiedUrlTarget.value = null
+ urlCopied.value = false
copiedUrlTimer = null
}, 2000)
}
-async function handleCopyUrl() {
- await copyUrlWithFeedback(syncUrl.value, 'plugin')
-}
-
-async function handleCopyStockUrl() {
- await copyUrlWithFeedback(stockSyncUrl.value, 'stock')
-}
-
async function handleRefresh() {
try {
await fetchSyncStatus(true)
@@ -793,13 +782,24 @@ async function handleDownloadPlugin() {
-
-
-
+
+
+
+
+
+
+
+ {{ t('settings.reader.koreader.syncUrlHint') }}
+
+
-
-
-