Fix audio playback in History tab on Linux (#617)
* Add Portuguese translations for permission error messages Add error message translations for the permission check flow in the Portuguese locale, covering both check failures and request failures. * Fix history audio playback on Linux WebKitGTK cannot play audio files via the asset:// protocol (or at least not reliably), returning MEDIA_ERR_SRC_NOT_SUPPORTED. Additionally, convertFileSrc was double- encoding the path (/ became %2F). Changed to read audio files directly using the fs plugin and create blob URLs instead. Also added APPDATA to fs:scope permissions to allow reading recordings from the app data directory. * Fix audio playback on macOS by using asset protocol on non-Linux The blob URL approach for audio playback works on Linux but breaks macOS. This reverts the blob change to use convertFileSrc with the asset protocol on macOS/Windows while keeping the blob approach for Linux where it's needed. Also adds proper cleanup of blob URLs to prevent memory leaks when history entries are unmounted.
This commit is contained in:
parent
28d1d814b7
commit
246fb4e7da
3 changed files with 42 additions and 5 deletions
|
|
@ -15,6 +15,10 @@
|
|||
"global-shortcut:allow-unregister-all",
|
||||
"macos-permissions:default",
|
||||
"fs:read-files",
|
||||
"fs:allow-resource-read-recursive"
|
||||
"fs:allow-resource-read-recursive",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**/*" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@ import { Button } from "../../ui/Button";
|
|||
import { Copy, Star, Check, Trash2, FolderOpen } from "lucide-react";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { platform } from "@tauri-apps/plugin-os";
|
||||
import { readFile } from "@tauri-apps/plugin-fs";
|
||||
import { commands, type HistoryEntry } from "@/bindings";
|
||||
import { formatDateTime } from "@/utils/dateFormat";
|
||||
|
||||
const IS_LINUX = platform() === "linux";
|
||||
|
||||
interface OpenRecordingsButtonProps {
|
||||
onClick: () => void;
|
||||
label: string;
|
||||
|
|
@ -93,7 +97,14 @@ export const HistorySettings: React.FC = () => {
|
|||
try {
|
||||
const result = await commands.getAudioFilePath(fileName);
|
||||
if (result.status === "ok") {
|
||||
return convertFileSrc(`${result.data}`, "asset");
|
||||
if (IS_LINUX) {
|
||||
const fileData = await readFile(result.data);
|
||||
const blob = new Blob([fileData], { type: "audio/wav" });
|
||||
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
return convertFileSrc(result.data, "asset");
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
|
|
@ -222,12 +233,30 @@ const HistoryEntryComponent: React.FC<HistoryEntryProps> = ({
|
|||
const [showCopied, setShowCopied] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
let urlToRevoke: string | null = null;
|
||||
|
||||
const loadAudio = async () => {
|
||||
const url = await getAudioUrl(entry.file_name);
|
||||
setAudioUrl(url);
|
||||
|
||||
if (!cancelled) {
|
||||
urlToRevoke = url;
|
||||
setAudioUrl(url);
|
||||
} else if (url?.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
||||
|
||||
loadAudio();
|
||||
}, [entry.file_name, getAudioUrl]);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
|
||||
if (urlToRevoke?.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(urlToRevoke);
|
||||
}
|
||||
};
|
||||
}, [entry.file_name]);
|
||||
|
||||
const handleCopyText = () => {
|
||||
onCopyText();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,11 @@
|
|||
"grant": "Conceder Permissão",
|
||||
"granted": "Concedido",
|
||||
"waiting": "Aguardando...",
|
||||
"allGranted": "Tudo pronto!"
|
||||
"allGranted": "Tudo pronto!",
|
||||
"errors": {
|
||||
"checkFailed": "Erro ao verificar permissões. Por favor, tente novamente.",
|
||||
"requestFailed": "Erro ao solicitar permissão. Por favor, tente novamente."
|
||||
}
|
||||
}
|
||||
},
|
||||
"modelSelector": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue