diff --git a/electron/main.cjs b/electron/main.cjs
index 3c8cb03c..b2060edb 100644
--- a/electron/main.cjs
+++ b/electron/main.cjs
@@ -1,6 +1,6 @@
'use strict'
-const { app, BrowserWindow, ipcMain, shell, Menu } = require('electron')
+const { app, BrowserWindow, ipcMain, shell, Menu, session } = require('electron')
const fs = require('fs')
const http = require('http')
const path = require('path')
@@ -188,6 +188,36 @@ function loadRenderer(win) {
})
}
+/**
+ * Packaged (and dev) renderer runs on http://127.0.0.1; hls.js and other fetches hit third-party
+ * streams without CORS. Chromium still enforces CORS, so inject a permissive ACAO on subresources only.
+ */
+function relaxCorsForRendererSubresources() {
+ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
+ if (details.resourceType === 'mainFrame' || details.resourceType === 'subFrame') {
+ callback({ cancel: false, responseHeaders: details.responseHeaders })
+ return
+ }
+ const raw = details.responseHeaders
+ if (!raw) {
+ callback({ cancel: false })
+ return
+ }
+ const responseHeaders = { ...raw }
+ for (const key of Object.keys(responseHeaders)) {
+ const lower = key.toLowerCase()
+ if (
+ lower === 'access-control-allow-origin' ||
+ lower === 'access-control-allow-credentials'
+ ) {
+ delete responseHeaders[key]
+ }
+ }
+ responseHeaders['Access-Control-Allow-Origin'] = ['*']
+ callback({ cancel: false, responseHeaders })
+ })
+}
+
function createWindow() {
const win = new BrowserWindow({
width: 1280,
@@ -249,6 +279,8 @@ function createWindow() {
}
app.whenReady().then(() => {
+ relaxCorsForRendererSubresources()
+
ipcMain.handle('imwald:reload-app', async (event) => {
const win = BrowserWindow.fromWebContents(event.sender)
if (!win || win.isDestroyed()) return false
diff --git a/package-lock.json b/package-lock.json
index 09d7d2b1..547acae1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "imwald",
- "version": "22.5.6",
+ "version": "22.5.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "imwald",
- "version": "22.5.6",
+ "version": "22.5.7",
"license": "MIT",
"dependencies": {
"@asciidoctor/core": "^3.0.4",
diff --git a/package.json b/package.json
index 61169be2..88ee6227 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "imwald",
- "version": "22.5.6",
+ "version": "22.5.7",
"description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery",
"private": true,
"type": "module",
diff --git a/src/components/AudioPlayer/index.tsx b/src/components/AudioPlayer/index.tsx
index 3de1c4d8..3658a1cf 100644
--- a/src/components/AudioPlayer/index.tsx
+++ b/src/components/AudioPlayer/index.tsx
@@ -51,10 +51,16 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl
const updateTime = () => {
if (!isSeeking.current) {
- setCurrentTime(audio.currentTime)
+ const t = audio.currentTime
+ if (Number.isFinite(t)) {
+ setCurrentTime(t)
+ }
}
}
- const updateDuration = () => setDuration(audio.duration)
+ const updateDuration = () => {
+ const d = audio.duration
+ setDuration(Number.isFinite(d) && d > 0 ? d : 0)
+ }
const handleEnded = () => setIsPlaying(false)
const handlePause = () => setIsPlaying(false)
const handlePlay = () => setIsPlaying(true)
@@ -92,15 +98,26 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl
const audio = audioRef.current
if (!audio) return
+ let t = value[0]
+ if (!Number.isFinite(t) || t < 0) {
+ return
+ }
+ const d = audio.duration
+ if (Number.isFinite(d) && d > 0) {
+ t = Math.min(t, d)
+ }
+
isSeeking.current = true
- setCurrentTime(value[0])
+ setCurrentTime(t)
if (seekTimeoutRef.current) {
clearTimeout(seekTimeoutRef.current)
}
seekTimeoutRef.current = setTimeout(() => {
- audio.currentTime = value[0]
+ if (Number.isFinite(t) && t >= 0) {
+ audio.currentTime = t
+ }
isSeeking.current = false
}, 300)
}
@@ -148,8 +165,8 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl
0 ? duration : 100}
step={1}
onValueChange={handleSeek}
hideThumb
diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx
index 5ff67abd..240f9ebf 100644
--- a/src/components/PostEditor/PostContent.tsx
+++ b/src/components/PostEditor/PostContent.tsx
@@ -309,7 +309,12 @@ export default function PostContent({
const [hasPrivateRelaysAvailable, setHasPrivateRelaysAvailable] = useState(false)
const [showMediaKindDialog, setShowMediaKindDialog] = useState(false)
- const [pendingMediaUpload, setPendingMediaUpload] = useState<{ url: string; tags: string[][]; file: File } | null>(null)
+ const [pendingMediaUpload, setPendingMediaUpload] = useState<{
+ url: string
+ tags: string[][]
+ file: File
+ urlAlreadyInEditor?: boolean
+ } | null>(null)
const uploadedMediaFileMap = useRef