diff --git a/index.html b/index.html
index 99f203f..7723bc8 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
-
Tauri + Vue + Typescript App
+ Thing
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 862e5ae..3d7c2b3 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -44,13 +44,14 @@ use monitor_kernel::{
};
use music::{
feiniu_activate_connection, feiniu_cache_clear, feiniu_cache_fetch, feiniu_cache_status,
- feiniu_delete_connection, feiniu_delete_local, feiniu_fnconnect_resolve, feiniu_get_config,
- feiniu_list_connections, feiniu_list_tracks, feiniu_login, feiniu_logout, feiniu_lyric,
- feiniu_media_prefix, feiniu_save_connection, feiniu_scan_local, feiniu_test_connection,
- music_cancel_runtime_install, music_download, music_download_cancel, music_env_status,
- music_get_settings, music_get_sources, music_install_runtime, music_parse_playlist, music_ping,
- music_resolve, music_save_settings, music_search, music_stop_bridge, webdav_delete,
- webdav_get_secret, webdav_save_secret, webdav_test, webdav_upload, MusicManager,
+ feiniu_cover_data, feiniu_delete_connection, feiniu_delete_local, feiniu_fnconnect_resolve,
+ feiniu_get_config, feiniu_list_connections, feiniu_list_tracks, feiniu_login, feiniu_logout,
+ feiniu_lyric, feiniu_media_prefix, feiniu_save_connection, feiniu_scan_local,
+ feiniu_test_connection, music_cancel_runtime_install, music_download, music_download_cancel,
+ music_env_status, music_get_settings, music_get_sources, music_install_runtime,
+ music_parse_playlist, music_ping, music_resolve, music_save_settings, music_search,
+ music_stop_bridge, webdav_delete, webdav_get_secret, webdav_save_secret, webdav_test,
+ webdav_upload, MusicManager,
};
use network_monitor::network_status;
use osd_window::{
@@ -281,6 +282,7 @@ pub fn run() {
feiniu_get_config,
feiniu_list_tracks,
feiniu_lyric,
+ feiniu_cover_data,
feiniu_media_prefix,
feiniu_scan_local,
feiniu_cache_status,
diff --git a/src-tauri/src/music/commands.rs b/src-tauri/src/music/commands.rs
index de76f9b..c172b13 100644
--- a/src-tauri/src/music/commands.rs
+++ b/src-tauri/src/music/commands.rs
@@ -380,6 +380,28 @@ pub async fn feiniu_lyric(
Ok(json!({ "lyric": text }))
}
+/// 封面 data URL(Windows SMTC / MediaSession artwork 用):
+/// Rust 侧取 NAS 封面字节转 base64,规避 WebView 对 artwork 的 CORS 要求。
+/// 返回 Value 且未标注 specta:前端直接按 JSON 使用(同 music_ping 豁免模式)。
+#[tauri::command]
+pub async fn feiniu_cover_data(
+ state: State<'_, MusicManager>,
+ cover_id: String,
+ size: Option,
+) -> Result {
+ state.feiniu.sync_with_settings(&state.load_settings());
+ let (bytes, ct) = state
+ .feiniu
+ .cover_bytes(&cover_id, size.unwrap_or(320))
+ .await?;
+ use base64::Engine;
+ let data = format!(
+ "data:{ct};base64,{}",
+ base64::engine::general_purpose::STANDARD.encode(bytes)
+ );
+ Ok(json!({ "data": data }))
+}
+
/// 本地媒体地址前缀:{ mediaPrefix }(首次调用惰性启动本地流代理)。
#[tauri::command]
pub async fn feiniu_media_prefix(
diff --git a/src-tauri/src/music/feiniu/mod.rs b/src-tauri/src/music/feiniu/mod.rs
index 5833c85..47452cc 100644
--- a/src-tauri/src/music/feiniu/mod.rs
+++ b/src-tauri/src/music/feiniu/mod.rs
@@ -315,6 +315,44 @@ impl Feiniu {
Ok(extract_lyric_text(&v))
}
+ /// 封面二进制(MediaSession artwork 用):`GET /music/api/v1/static/cover`。
+ /// 返回 (字节, content-type)。与流代理同款认证注入,但不走代理——
+ /// 前端拿到的是 data URL,规避 WebView 对 artwork 的 CORS 要求。
+ pub async fn cover_bytes(&self, cover_id: &str, size: u32) -> Result<(Vec, String), String> {
+ let (base, token, access_code) = self.auth_triple();
+ if base.is_empty() || token.is_empty() {
+ return Err("未登录".into());
+ }
+ let (_, client) = self.conn_client();
+ let query = [
+ ("coverId".to_string(), cover_id.to_string()),
+ ("size".to_string(), size.to_string()),
+ ];
+ let mut rb = client.get(format!("{base}/music/api/v1/static/cover")).query(&query);
+ rb = rb.header("cookie", format!("music-token={token}"));
+ if !access_code.is_empty() {
+ use base64::Engine;
+ rb = rb
+ .header(
+ "x-access-code",
+ base64::engine::general_purpose::STANDARD.encode(access_code.as_bytes()),
+ )
+ .header("x-access-source", "app");
+ }
+ let resp = rb.send().await.map_err(|e| format!("请求失败: {e}"))?;
+ if !resp.status().is_success() {
+ return Err(format!("请求失败(HTTP {})", resp.status().as_u16()));
+ }
+ let ct = resp
+ .headers()
+ .get(reqwest::header::CONTENT_TYPE)
+ .and_then(|v| v.to_str().ok())
+ .unwrap_or("image/jpeg")
+ .to_string();
+ let bytes = resp.bytes().await.map_err(|e| format!("读取失败: {e}"))?;
+ Ok((bytes.to_vec(), ct))
+ }
+
/// 本地媒体地址前缀:`http://127.0.0.1:/feiniu`。首次调用惰性启动代理。
pub async fn media_prefix(&self) -> Result {
let port = self.ensure_proxy().await?;
diff --git a/src-tauri/src/music/mod.rs b/src-tauri/src/music/mod.rs
index a13ddaa..37115d6 100644
--- a/src-tauri/src/music/mod.rs
+++ b/src-tauri/src/music/mod.rs
@@ -24,13 +24,14 @@ pub use feiniu::{extract_fn_id, normalize_base_url, resolve_base_url, Feiniu, Fe
pub use commands::{
feiniu_activate_connection, feiniu_cache_clear, feiniu_cache_fetch, feiniu_cache_status,
- feiniu_delete_connection, feiniu_delete_local, feiniu_fnconnect_resolve, feiniu_get_config,
- feiniu_list_connections, feiniu_list_tracks, feiniu_login, feiniu_logout, feiniu_lyric,
- feiniu_media_prefix, feiniu_save_connection, feiniu_scan_local, feiniu_test_connection,
- music_cancel_runtime_install, music_download, music_download_cancel, music_env_status,
- music_get_settings, music_get_sources, music_install_runtime, music_parse_playlist, music_ping,
- music_resolve, music_save_settings, music_search, music_stop_bridge, webdav_delete,
- webdav_get_secret, webdav_save_secret, webdav_test, webdav_upload,
+ feiniu_cover_data, feiniu_delete_connection, feiniu_delete_local, feiniu_fnconnect_resolve,
+ feiniu_get_config, feiniu_list_connections, feiniu_list_tracks, feiniu_login, feiniu_logout,
+ feiniu_lyric, feiniu_media_prefix, feiniu_save_connection, feiniu_scan_local,
+ feiniu_test_connection, music_cancel_runtime_install, music_download, music_download_cancel,
+ music_env_status, music_get_settings, music_get_sources, music_install_runtime,
+ music_parse_playlist, music_ping, music_resolve, music_save_settings, music_search,
+ music_stop_bridge, webdav_delete, webdav_get_secret, webdav_save_secret, webdav_test,
+ webdav_upload,
};
use serde::{Deserialize, Serialize};
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 0d5726f..aff9de2 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -24,7 +24,7 @@
}
],
"security": {
- "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: asset: http://asset.localhost; font-src 'self' data:; connect-src ipc: http://ipc.localhost; media-src 'self' data: blob:"
+ "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: asset: http://asset.localhost http: https:; font-src 'self' data:; connect-src ipc: http://ipc.localhost http: https:; media-src 'self' data: blob: file: http: https:"
}
},
"bundle": {
diff --git a/src/stores/feiniuStore.ts b/src/stores/feiniuStore.ts
index 830b297..fd23f23 100644
--- a/src/stores/feiniuStore.ts
+++ b/src/stores/feiniuStore.ts
@@ -96,14 +96,14 @@ function writeLS(key: string, value: string) {
}
}
-/** 把浏览器抛出的播放异常翻译成可读文案 */
-function describePlayError(e: unknown): string {
- const name = (e as { name?: string })?.name ?? ''
- if (name === 'NotSupportedError') return '该音频无法播放:格式不支持或链接已失效'
- if (name === 'NotAllowedError') return '播放被浏览器策略阻止,请再次点击播放'
- if (name === 'AbortError') return '播放已中断'
- return `播放失败:${e instanceof Error ? e.message : String(e)}`
-}
+ /** 把浏览器抛出的播放异常翻译成可读文案 */
+ function describePlayError(e: unknown): string {
+ const name = (e as { name?: string })?.name ?? ''
+ if (name === 'NotSupportedError') return '该音频无法播放:格式不支持或链接已失效'
+ if (name === 'NotAllowedError') return '播放被浏览器策略阻止,请再次点击播放'
+ if (name === 'AbortError') return '播放已中断'
+ return `播放失败:${e instanceof Error ? e.message : String(e)}`
+ }
export const useFeiniuStore = defineStore('feiniu', () => {
// ===== 连接 =====
@@ -185,6 +185,100 @@ export const useFeiniuStore = defineStore('feiniu', () => {
const shufflePool = ref([])
const historyStack = ref([])
+ // ===== Windows 系统媒体(SMTC)集成 =====
+ // WebView2 会把页面媒体暴露给系统媒体浮层/媒体键,元数据需通过 MediaSession API 提供;
+ // 不提供时系统显示的是 document.title(此前为 "Tauri+Vue+Typescript App")。
+
+ /** 封面 data URL 缓存(coverId → dataUrl),避免同一首歌重复取封面 */
+ const smtcCoverCache = new Map()
+ /** SMTC 进度上报节流(timeupdate ~4Hz,1s 一次足够) */
+ let smtcLastPosAt = 0
+
+ /** 设置系统媒体浮层的歌曲信息(歌名/歌手/专辑/封面)。封面为飞牛曲目时经
+ * Rust 命令取字节转 data URL——MediaSession artwork 由 WebView 以 CORS 模式
+ * 拉取,代理地址无 CORS 头会失败,data URL 可绕过。 */
+ function updateMediaSession(item: PlayableItem) {
+ if (!('mediaSession' in navigator)) return
+ const base = {
+ title: item.title,
+ artist: item.artistNames || '未知歌手',
+ album: item.album || ''
+ }
+ if (item.source === 'feiniu' && item.coverId) {
+ const key = item.coverId
+ const cached = smtcCoverCache.get(key)
+ // 歌名/歌手立即上屏,封面就绪后补挂
+ navigator.mediaSession.metadata = new MediaMetadata({
+ ...base,
+ artwork: cached ? [{ src: cached, sizes: '320x320' }] : []
+ })
+ if (!cached) {
+ invoke<{ data: string }>('feiniu_cover_data', { coverId: key, size: 320 })
+ .then((r) => {
+ if (!r?.data) return
+ if (smtcCoverCache.size > 50) smtcCoverCache.clear()
+ smtcCoverCache.set(key, r.data)
+ // 播放期间用户可能已切歌:仅当仍是这首时才刷新封面
+ const cur = navigator.mediaSession.metadata
+ if (cur?.title === item.title) {
+ navigator.mediaSession.metadata = new MediaMetadata({
+ ...base,
+ artwork: [{ src: r.data, sizes: '320x320' }]
+ })
+ }
+ })
+ .catch(() => {
+ /* 封面取不到就只显示文字信息 */
+ })
+ }
+ return
+ }
+ // preview 源有直链封面;local/无封面源仅文字信息
+ const artwork: MediaImage[] = []
+ if (item.coverUrl) artwork.push({ src: item.coverUrl, sizes: '320x320' })
+ navigator.mediaSession.metadata = new MediaMetadata({ ...base, artwork })
+ }
+
+ /** 注册系统媒体键/浮层按钮动作(一次性) */
+ function setupMediaSessionHandlers(a: HTMLAudioElement) {
+ if (!('mediaSession' in navigator)) return
+ const ms = navigator.mediaSession
+ try {
+ ms.setActionHandler('play', () => void a.play().catch(() => {}))
+ ms.setActionHandler('pause', () => a.pause())
+ ms.setActionHandler('previoustrack', () => prev())
+ ms.setActionHandler('nexttrack', () => next())
+ ms.setActionHandler('seekbackward', (d) => seek(Math.max(0, position.value - (d?.seekOffset ?? 10))))
+ ms.setActionHandler('seekforward', (d) => seek(position.value + (d?.seekOffset ?? 10)))
+ ms.setActionHandler('seekto', (d) => {
+ if (d.seekTime != null) seek(d.seekTime)
+ })
+ } catch {
+ /* 个别动作类型 WebView 不支持时忽略 */
+ }
+ }
+
+ function setSmtcState(state: 'playing' | 'paused') {
+ if ('mediaSession' in navigator) navigator.mediaSession.playbackState = state
+ }
+
+ /** 同步播放进度到系统媒体浮层(SMTC 时间轴)。必须在时长已知后调用,
+ * 否则浮层只显示歌名没有进度条;position 越界会被 WebView 拒绝,做夹取。 */
+ function updateSmtcPosition() {
+ if (!('mediaSession' in navigator)) return
+ const d = duration.value
+ if (!isFinite(d) || d <= 0) return
+ try {
+ navigator.mediaSession.setPositionState({
+ duration: d,
+ playbackRate: audioEl?.playbackRate || 1,
+ position: Math.min(Math.max(position.value, 0), d)
+ })
+ } catch {
+ /* 元数据切换瞬间的非法参数(如新歌时长未就绪)忽略 */
+ }
+ }
+
function computeBuffered(a: HTMLAudioElement): number {
const d = a.duration
if (!isFinite(d) || d <= 0 || a.buffered.length === 0) return 0
@@ -204,28 +298,47 @@ export const useFeiniuStore = defineStore('feiniu', () => {
a.addEventListener('loadedmetadata', () => {
duration.value = isFinite(a.duration) ? a.duration : 0
bufferedPercent.value = computeBuffered(a)
+ updateSmtcPosition()
})
a.addEventListener('durationchange', () => {
duration.value = isFinite(a.duration) ? a.duration : 0
+ updateSmtcPosition()
})
- a.addEventListener('timeupdate', () => (position.value = a.currentTime))
+ a.addEventListener('timeupdate', () => {
+ position.value = a.currentTime
+ const now = Date.now()
+ if (now - smtcLastPosAt >= 1000) {
+ smtcLastPosAt = now
+ updateSmtcPosition()
+ }
+ })
+ a.addEventListener('seeked', () => updateSmtcPosition())
a.addEventListener('progress', () => (bufferedPercent.value = computeBuffered(a)))
a.addEventListener('waiting', () => (loadingPlay.value = true))
a.addEventListener('canplay', () => (loadingPlay.value = false))
a.addEventListener('playing', () => {
loadingPlay.value = false
playing.value = true
+ setSmtcState('playing')
+ })
+ a.addEventListener('play', () => {
+ playing.value = true
+ setSmtcState('playing')
+ })
+ a.addEventListener('pause', () => {
+ playing.value = false
+ setSmtcState('paused')
})
- a.addEventListener('play', () => (playing.value = true))
- a.addEventListener('pause', () => (playing.value = false))
a.addEventListener('ended', () => onEnded())
a.addEventListener('error', () => {
// 主动清空 src 时也会触发 error,此时不应报错
if (!a.getAttribute('src')) return
loadingPlay.value = false
playing.value = false
+ setSmtcState('paused')
playError.value = '音频加载失败:网络不可达或链接已失效'
})
+ setupMediaSessionHandlers(a)
audioEl = a
}
return audioEl
@@ -238,6 +351,7 @@ export const useFeiniuStore = defineStore('feiniu', () => {
position.value = 0
duration.value = 0
bufferedPercent.value = 0
+ setSmtcState('paused')
if (audioEl) {
audioEl.pause()
audioEl.removeAttribute('src')
@@ -805,6 +919,7 @@ export const useFeiniuStore = defineStore('feiniu', () => {
const t = current.value
if (!t) return
preview.value = null
+ updateMediaSession(t)
if (t.source === 'feiniu') {
void loadLyric(t.guid)
} else {
@@ -872,6 +987,7 @@ export const useFeiniuStore = defineStore('feiniu', () => {
const a = ensureAudio()
a.pause()
preview.value = { ...item, source: 'preview' }
+ updateMediaSession(preview.value)
lyricLines.value = []
lyricRaw = ''
lyricIdx = -1
diff --git a/temp/icon2.png b/temp/icon2.png
deleted file mode 100644
index 89c96e3..0000000
Binary files a/temp/icon2.png and /dev/null differ
diff --git a/temp/icon_s.png b/temp/icon_s.png
deleted file mode 100644
index d0b7388..0000000
Binary files a/temp/icon_s.png and /dev/null differ
diff --git a/temp/snap2.json b/temp/snap2.json
deleted file mode 100644
index 2062d94..0000000
--- a/temp/snap2.json
+++ /dev/null
@@ -1 +0,0 @@
-{"schemaVersion":1,"timestamp":1785393390698,"coldStartMs":346.1,"isAdmin":true,"ready":true,"groups":[{"id":"cpu","name":"CPU","sensors":[{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#1","name":"CPU Core #1","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":19.05,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#2","name":"CPU Core #2","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":9.52,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#3","name":"CPU Core #3","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":1.59,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#4","name":"CPU Core #4","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#5","name":"CPU Core #5","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":1.59,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#6","name":"CPU Core #6","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#7","name":"CPU Core #7","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":11.11,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#8","name":"CPU Core #8","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":3.17,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#9","name":"CPU Core #9","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":4.76,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#10","name":"CPU Core #10","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":6.35,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#11","name":"CPU Core #11","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#12","name":"CPU Core #12","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#13","name":"CPU Core #13","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":1.59,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#14","name":"CPU Core #14","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#15","name":"CPU Core #15","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_#16","name":"CPU Core #16","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":1.59,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_total","name":"CPU Total","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":3.77,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/load/cpu_core_max","name":"CPU Core Max","type":"load","hardwareName":"AMD Ryzen 7 9800X3D","value":19.05,"unit":"%"},{"id":"cpu/amd_ryzen_7_9800x3d/power/package","name":"Package","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/cores_(average)","name":"Cores (Average)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/cores_(average_effective)","name":"Cores (Average Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#1","name":"Core #1","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#1_(effective)","name":"Core #1 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#1_(smu)","name":"Core #1 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#2","name":"Core #2","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#2_(effective)","name":"Core #2 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#2_(smu)","name":"Core #2 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#3","name":"Core #3","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#3_(effective)","name":"Core #3 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#3_(smu)","name":"Core #3 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#4","name":"Core #4","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#4_(effective)","name":"Core #4 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#4_(smu)","name":"Core #4 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#5","name":"Core #5","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#5_(effective)","name":"Core #5 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#5_(smu)","name":"Core #5 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#6","name":"Core #6","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#6_(effective)","name":"Core #6 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#6_(smu)","name":"Core #6 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#7","name":"Core #7","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#7_(effective)","name":"Core #7 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#7_(smu)","name":"Core #7 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#8","name":"Core #8","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/clock/core_#8_(effective)","name":"Core #8 (Effective)","type":"clock","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"MHz"},{"id":"cpu/amd_ryzen_7_9800x3d/power/core_#8_(smu)","name":"Core #8 (SMU)","type":"power","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"W"},{"id":"cpu/amd_ryzen_7_9800x3d/temperature/core_(tctl/tdie)","name":"Core (Tctl/Tdie)","type":"temperature","hardwareName":"AMD Ryzen 7 9800X3D","value":0,"unit":"\u00B0C"}]},{"id":"memory","name":"Memory","sensors":[{"id":"memory/virtual_memory/data/memory_used","name":"Memory Used","type":"data","hardwareName":"Virtual Memory","value":29.933598,"unit":"GB"},{"id":"memory/virtual_memory/data/memory_available","name":"Memory Available","type":"data","hardwareName":"Virtual Memory","value":22.446678,"unit":"GB"},{"id":"memory/virtual_memory/load/memory","name":"Memory","type":"load","hardwareName":"Virtual Memory","value":57.146698,"unit":"%"},{"id":"memory/total_memory/data/memory_used","name":"Memory Used","type":"data","hardwareName":"Total Memory","value":12.919495,"unit":"GB"},{"id":"memory/total_memory/data/memory_available","name":"Memory Available","type":"data","hardwareName":"Total Memory","value":18.460781,"unit":"GB"},{"id":"memory/total_memory/load/memory","name":"Memory","type":"load","hardwareName":"Total Memory","value":41.17075,"unit":"%"}]},{"id":"storage","name":"Storage","sensors":[{"id":"storage/samsung_ssd_970_evo_plus_2tb/temperature/temperature","name":"Temperature","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":40,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/temperature/temperature_2","name":"Temperature 2","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":46.850006,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/temperature/temperature_warning","name":"Temperature warning","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":81,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/temperature/temperature_critical","name":"Temperature critical","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":84,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/data/data_read","name":"Data read","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":66645,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/data/data_written","name":"Data written","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":37186,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/load/used_space","name":"Used Space","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":-922153000,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/data/free_space","name":"Free Space","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":1.8446744E+10,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/data/total_space","name":"Total Space","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":2000.3989,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/load/read_activity","name":"Read Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":0,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/load/write_activity","name":"Write Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":0,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_2tb/load/total_activity","name":"Total Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 2TB","value":0,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/temperature/temperature","name":"Temperature","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":43,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/temperature/temperature_2","name":"Temperature 2","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":43.850006,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/temperature/temperature_warning","name":"Temperature warning","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":84,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/temperature/temperature_critical","name":"Temperature critical","type":"temperature","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":84,"unit":"\u00B0C"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/data/data_read","name":"Data read","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":68692,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/data/data_written","name":"Data written","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":57143,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/load/used_space","name":"Used Space","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":63.86202,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/data/free_space","name":"Free Space","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":180.72888,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/data/total_space","name":"Total Space","type":"data","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":500.10785,"unit":"GB"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/load/read_activity","name":"Read Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":0,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/load/write_activity","name":"Write Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":0.041056305,"unit":"%"},{"id":"storage/samsung_ssd_970_evo_plus_500gb/load/total_activity","name":"Total Activity","type":"load","hardwareName":"Samsung SSD 970 EVO Plus 500GB","value":0,"unit":"%"},{"id":"storage/zss11da02c/temperature/temperature","name":"Temperature","type":"temperature","hardwareName":"ZSS11DA02C","value":32,"unit":"\u00B0C"},{"id":"storage/zss11da02c/load/used_space","name":"Used Space","type":"load","hardwareName":"ZSS11DA02C","value":43.86588,"unit":"%"},{"id":"storage/zss11da02c/data/free_space","name":"Free Space","type":"data","hardwareName":"ZSS11DA02C","value":287.46854,"unit":"GB"},{"id":"storage/zss11da02c/data/total_space","name":"Total Space","type":"data","hardwareName":"ZSS11DA02C","value":512.11017,"unit":"GB"},{"id":"storage/zss11da02c/load/read_activity","name":"Read Activity","type":"load","hardwareName":"ZSS11DA02C","value":0,"unit":"%"},{"id":"storage/zss11da02c/load/write_activity","name":"Write Activity","type":"load","hardwareName":"ZSS11DA02C","value":0,"unit":"%"},{"id":"storage/zss11da02c/load/total_activity","name":"Total Activity","type":"load","hardwareName":"ZSS11DA02C","value":0.03464339,"unit":"%"}]},{"id":"gpuamd","name":"GpuAmd","sensors":[{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_3d","name":"D3D 3D","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":14.1529455,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_copy","name":"D3D Copy","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_compute_0","name":"D3D Compute 0","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_copy","name":"D3D Copy","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0.010940037,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_timer_0","name":"D3D Timer 0","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_security_1","name":"D3D Security 1","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_video_jpeg_0","name":"D3D Video JPEG 0","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":0,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/d3d_video_codec_engine","name":"D3D Video Codec Engine","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":10.0678215,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/power/gpu_package","name":"GPU Package","type":"power","hardwareName":"AMD Radeon RX 7900 XT","value":103,"unit":"W"},{"id":"gpuamd/amd_radeon_rx_7900_xt/clock/gpu_core","name":"GPU Core","type":"clock","hardwareName":"AMD Radeon RX 7900 XT","value":1444,"unit":"MHz"},{"id":"gpuamd/amd_radeon_rx_7900_xt/clock/gpu_memory","name":"GPU Memory","type":"clock","hardwareName":"AMD Radeon RX 7900 XT","value":2487,"unit":"MHz"},{"id":"gpuamd/amd_radeon_rx_7900_xt/temperature/gpu_core","name":"GPU Core","type":"temperature","hardwareName":"AMD Radeon RX 7900 XT","value":54,"unit":"\u00B0C"},{"id":"gpuamd/amd_radeon_rx_7900_xt/temperature/gpu_memory","name":"GPU Memory","type":"temperature","hardwareName":"AMD Radeon RX 7900 XT","value":68,"unit":"\u00B0C"},{"id":"gpuamd/amd_radeon_rx_7900_xt/temperature/gpu_hot_spot","name":"GPU Hot Spot","type":"temperature","hardwareName":"AMD Radeon RX 7900 XT","value":62,"unit":"\u00B0C"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/gpu_core","name":"GPU Core","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":34,"unit":"%"},{"id":"gpuamd/amd_radeon_rx_7900_xt/load/gpu_memory","name":"GPU Memory","type":"load","hardwareName":"AMD Radeon RX 7900 XT","value":5,"unit":"%"}]}]}
\ No newline at end of file
diff --git a/temp/snapshot.json b/temp/snapshot.json
deleted file mode 100644
index 3e0b7fe..0000000
--- a/temp/snapshot.json
+++ /dev/null
@@ -1 +0,0 @@
-{"error":"internal","message":".NET number values such as positive and negative infinity cannot be written as valid JSON. To make it work when using 'JsonSerializer', consider specifying 'JsonNumberHandling.AllowNamedFloatingPointLiterals' (see https://docs.microsoft.com/dotnet/api/system.text.json.serialization.jsonnumberhandling)."}
\ No newline at end of file