Personal save-for-later and Miniflux e-reader proxy for Xteink X4 (wip)
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add title to device endpoint result metadata

+28 -6
+1
.gitignore
··· 4 4 *.sqlite3-* 5 5 .env 6 6 .env.local 7 + env.sh 7 8 result 8 9 data/
+18
scripts/device.http
··· 1 + ### 2 + 3 + @baseUrl = http://localhost:8787 4 + @token = {{DEVICE_TOKEN}} 5 + 6 + 7 + ### List posts 8 + 9 + GET {{baseUrl}}/device/list HTTP/1.1 10 + Authorization: Bearer {{token}} 11 + 12 + 13 + ### Get reading item by ID 14 + 15 + # @prompt itemId 16 + 17 + GET {{baseUrl}}/device/item/{{itemId}} HTTP/1.1 18 + Authorization: Bearer {{token}}
+6 -5
src/server/reader-format.ts
··· 11 11 lines.push(`R:${it.read ? 1 : 0}`); 12 12 lines.push(`D:${it.fetchedAt}`); 13 13 lines.push(`T:${singleLine(it.title)}`); 14 + if (it.publication) lines.push(`F:${singleLine(it.publication)}`); 14 15 lines.push("==="); 15 16 } 16 17 return lines.join("\n") + "\n"; ··· 24 25 fetchedAt: number, 25 26 body: string, 26 27 page: number, 28 + publication?: string, 27 29 ): string { 28 30 const wrapped = wrapLines(body, LINE_WIDTH); 29 31 const totalPages = Math.max(1, Math.ceil(wrapped.length / PAGE_BODY_LINES)); 30 32 const p = clamp(page, 1, totalPages); 31 33 const start = (p - 1) * PAGE_BODY_LINES; 32 34 const pageLines = wrapped.slice(start, start + PAGE_BODY_LINES); 33 - return [ 35 + const header = [ 34 36 `ID:${id}`, 35 37 `S:${source}`, 36 38 `T:${singleLine(title)}`, 37 39 `U:${singleLine(url)}`, 38 40 `D:${fetchedAt}`, 39 41 `P:${p}/${totalPages}`, 40 - "---", 41 - ...pageLines, 42 - "", 43 - ].join("\n"); 42 + ]; 43 + if (publication) header.push(`F:${singleLine(publication)}`); 44 + return [...header, "---", ...pageLines, ""].join("\n"); 44 45 } 45 46 46 47 function singleLine(s: string): string {
+2 -1
src/server/routes-device.ts
··· 61 61 title: e.title, 62 62 fetchedAt: Math.floor(new Date(e.published_at).getTime() / 1000), 63 63 read: e.status === "read", 64 + publication: e.feed?.title, 64 65 }); 65 66 } 66 67 const filteredSaves = all ? saves : saves.filter((s) => !s.record.readAt); ··· 112 113 : ""; 113 114 const ts = Math.floor(new Date(entry.published_at).getTime() / 1000); 114 115 return c.text( 115 - renderItem(rawId, "rss", entry.title, entry.url, ts, body, page), 116 + renderItem(rawId, "rss", entry.title, entry.url, ts, body, page, entry.feed?.title), 116 117 200, 117 118 { "Content-Type": "text/plain; charset=utf-8" }, 118 119 );
+1
src/shared/types.ts
··· 7 7 title: string; 8 8 fetchedAt: number; 9 9 read: boolean; 10 + publication?: string; 10 11 }; 11 12 12 13 export type MinifluxFeed = {