UwU 2 месяцев назад
Родитель
Сommit
43641beb7e

+ 19 - 20
src/main/services/library.service.ts

@@ -6,6 +6,7 @@ import * as fs from 'fs'
 import { randomUUID } from 'crypto'
 import { randomUUID } from 'crypto'
 import { cleanupPlaylists } from './playlist.service'
 import { cleanupPlaylists } from './playlist.service'
 import { getWorkshopTimesUpdated } from './workshop.service'
 import { getWorkshopTimesUpdated } from './workshop.service'
+import { findAndMutate } from '../utils/collections'
 
 
 interface LibraryStore {
 interface LibraryStore {
   wallpapers: Record<string, WallpaperMeta>
   wallpapers: Record<string, WallpaperMeta>
@@ -373,39 +374,37 @@ export function createFolder(title: string): WallpaperFolder {
   return folder
   return folder
 }
 }
 
 
-export function renameFolder(id: string, title: string): WallpaperFolder | null {
+function updateFolder(id: string, mutate: (folder: WallpaperFolder) => void): WallpaperFolder | null {
   const folders = store.get('folders')
   const folders = store.get('folders')
-  const folder = folders.find((f) => f.id === id)
-  if (!folder) return null
-  folder.title = title
-  store.set('folders', folders)
+  const folder = findAndMutate(folders, id, mutate)
+  if (folder) store.set('folders', folders)
   return folder
   return folder
 }
 }
 
 
+export function renameFolder(id: string, title: string): WallpaperFolder | null {
+  return updateFolder(id, (folder) => {
+    folder.title = title
+  })
+}
+
 export function deleteFolder(id: string): void {
 export function deleteFolder(id: string): void {
   const folders = store.get('folders').filter((f) => f.id !== id)
   const folders = store.get('folders').filter((f) => f.id !== id)
   store.set('folders', folders)
   store.set('folders', folders)
 }
 }
 
 
 export function addItemsToFolder(folderId: string, itemIds: string[]): WallpaperFolder | null {
 export function addItemsToFolder(folderId: string, itemIds: string[]): WallpaperFolder | null {
-  const folders = store.get('folders')
-  const folder = folders.find((f) => f.id === folderId)
-  if (!folder) return null
-  const set = new Set(folder.items)
-  for (const id of itemIds) set.add(id)
-  folder.items = [...set]
-  store.set('folders', folders)
-  return folder
+  return updateFolder(folderId, (folder) => {
+    const set = new Set(folder.items)
+    for (const id of itemIds) set.add(id)
+    folder.items = [...set]
+  })
 }
 }
 
 
 export function removeItemsFromFolder(folderId: string, itemIds: string[]): WallpaperFolder | null {
 export function removeItemsFromFolder(folderId: string, itemIds: string[]): WallpaperFolder | null {
-  const folders = store.get('folders')
-  const folder = folders.find((f) => f.id === folderId)
-  if (!folder) return null
-  const remove = new Set(itemIds)
-  folder.items = folder.items.filter((id) => !remove.has(id))
-  store.set('folders', folders)
-  return folder
+  return updateFolder(folderId, (folder) => {
+    const remove = new Set(itemIds)
+    folder.items = folder.items.filter((id) => !remove.has(id))
+  })
 }
 }
 
 
 /**
 /**

+ 48 - 61
src/main/services/playlist.service.ts

@@ -1,6 +1,7 @@
 import Store from 'electron-store'
 import Store from 'electron-store'
 import { randomUUID } from 'crypto'
 import { randomUUID } from 'crypto'
 import type { Playlist, PlaylistItem, PlaylistSettings } from '@shared/types'
 import type { Playlist, PlaylistItem, PlaylistSettings } from '@shared/types'
+import { findAndMutate } from '../utils/collections'
 
 
 interface PlaylistStore {
 interface PlaylistStore {
   playlists: Playlist[]
   playlists: Playlist[]
@@ -18,6 +19,16 @@ const store = new Store<PlaylistStore>({
   defaults: { playlists: [] }
   defaults: { playlists: [] }
 })
 })
 
 
+function updatePlaylist(id: string, mutate: (playlist: Playlist) => void | false): Playlist | null {
+  const playlists = store.get('playlists')
+  const playlist = findAndMutate(playlists, id, (p) => {
+    if (mutate(p) === false) return false
+    p.updatedAt = Date.now()
+  })
+  if (playlist) store.set('playlists', playlists)
+  return playlist
+}
+
 export function getAllPlaylists(): Playlist[] {
 export function getAllPlaylists(): Playlist[] {
   return store.get('playlists')
   return store.get('playlists')
 }
 }
@@ -43,13 +54,9 @@ export function createPlaylist(title: string): Playlist {
 }
 }
 
 
 export function renamePlaylist(id: string, title: string): Playlist | null {
 export function renamePlaylist(id: string, title: string): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  playlist.title = title
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+  return updatePlaylist(id, (playlist) => {
+    playlist.title = title
+  })
 }
 }
 
 
 export function deletePlaylist(id: string): void {
 export function deletePlaylist(id: string): void {
@@ -61,62 +68,46 @@ export function updatePlaylistSettings(
   id: string,
   id: string,
   patch: Partial<PlaylistSettings>
   patch: Partial<PlaylistSettings>
 ): Playlist | null {
 ): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  playlist.settings = { ...playlist.settings, ...patch }
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+  return updatePlaylist(id, (playlist) => {
+    playlist.settings = { ...playlist.settings, ...patch }
+  })
 }
 }
 
 
 export function addItemsToPlaylist(id: string, wallpaperIds: string[]): Playlist | null {
 export function addItemsToPlaylist(id: string, wallpaperIds: string[]): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  const existing = new Set(playlist.items.map((i) => i.wallpaperId))
-  for (const wallpaperId of wallpaperIds) {
-    if (!existing.has(wallpaperId)) {
-      playlist.items.push({ wallpaperId })
-      existing.add(wallpaperId)
+  return updatePlaylist(id, (playlist) => {
+    const existing = new Set(playlist.items.map((i) => i.wallpaperId))
+    for (const wallpaperId of wallpaperIds) {
+      if (!existing.has(wallpaperId)) {
+        playlist.items.push({ wallpaperId })
+        existing.add(wallpaperId)
+      }
     }
     }
-  }
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+  })
 }
 }
 
 
 export function removeItemsFromPlaylist(id: string, wallpaperIds: string[]): Playlist | null {
 export function removeItemsFromPlaylist(id: string, wallpaperIds: string[]): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  const remove = new Set(wallpaperIds)
-  playlist.items = playlist.items.filter((i) => !remove.has(i.wallpaperId))
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+  return updatePlaylist(id, (playlist) => {
+    const remove = new Set(wallpaperIds)
+    playlist.items = playlist.items.filter((i) => !remove.has(i.wallpaperId))
+  })
 }
 }
 
 
 /** Reorders items to match the given wallpaperId sequence (used for manual drag-reorder). */
 /** Reorders items to match the given wallpaperId sequence (used for manual drag-reorder). */
 export function reorderPlaylistItems(id: string, orderedWallpaperIds: string[]): Playlist | null {
 export function reorderPlaylistItems(id: string, orderedWallpaperIds: string[]): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  const byId = new Map(playlist.items.map((i) => [i.wallpaperId, i]))
-  const reordered: PlaylistItem[] = []
-  for (const wallpaperId of orderedWallpaperIds) {
-    const item = byId.get(wallpaperId)
-    if (item) {
-      reordered.push(item)
-      byId.delete(wallpaperId)
+  return updatePlaylist(id, (playlist) => {
+    const byId = new Map(playlist.items.map((i) => [i.wallpaperId, i]))
+    const reordered: PlaylistItem[] = []
+    for (const wallpaperId of orderedWallpaperIds) {
+      const item = byId.get(wallpaperId)
+      if (item) {
+        reordered.push(item)
+        byId.delete(wallpaperId)
+      }
     }
     }
-  }
-  // Append anything not mentioned in orderedWallpaperIds (defensive, shouldn't normally happen)
-  reordered.push(...byId.values())
-  playlist.items = reordered
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+    // Append anything not mentioned in orderedWallpaperIds (defensive, shouldn't normally happen)
+    reordered.push(...byId.values())
+    playlist.items = reordered
+  })
 }
 }
 
 
 export function updatePlaylistItem(
 export function updatePlaylistItem(
@@ -124,16 +115,12 @@ export function updatePlaylistItem(
   wallpaperId: string,
   wallpaperId: string,
   patch: { volume?: number; durationSec?: number }
   patch: { volume?: number; durationSec?: number }
 ): Playlist | null {
 ): Playlist | null {
-  const playlists = store.get('playlists')
-  const playlist = playlists.find((p) => p.id === id)
-  if (!playlist) return null
-  const item = playlist.items.find((i) => i.wallpaperId === wallpaperId)
-  if (!item) return null
-  if ('volume' in patch) item.volume = patch.volume
-  if ('durationSec' in patch) item.durationSec = patch.durationSec
-  playlist.updatedAt = Date.now()
-  store.set('playlists', playlists)
-  return playlist
+  return updatePlaylist(id, (playlist) => {
+    const item = playlist.items.find((i) => i.wallpaperId === wallpaperId)
+    if (!item) return false
+    if ('volume' in patch) item.volume = patch.volume
+    if ('durationSec' in patch) item.durationSec = patch.durationSec
+  })
 }
 }
 
 
 /**
 /**

+ 10 - 0
src/main/utils/collections.ts

@@ -0,0 +1,10 @@
+export function findAndMutate<T extends { id: string }>(
+  items: T[],
+  id: string,
+  mutate: (item: T) => void | false
+): T | null {
+  const item = items.find((i) => i.id === id)
+  if (!item) return null
+  if (mutate(item) === false) return null
+  return item
+}

+ 2 - 3
src/renderer/src/components/library/WallpaperCard.tsx

@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'
 import { Play, Loader2, Check, ThumbsUp, Trash2, ExternalLink, Download, Archive } from 'lucide-react'
 import { Play, Loader2, Check, ThumbsUp, Trash2, ExternalLink, Download, Archive } from 'lucide-react'
 import type { WallpaperMeta } from '@shared/types'
 import type { WallpaperMeta } from '@shared/types'
 import clsx from 'clsx'
 import clsx from 'clsx'
+import { getPreviewSrc } from '../../utils/preview'
 
 
 interface WallpaperCardProps {
 interface WallpaperCardProps {
   wallpaper: WallpaperMeta
   wallpaper: WallpaperMeta
@@ -117,9 +118,7 @@ export default function WallpaperCard({
     }
     }
   }
   }
 
 
-  const previewSrc = wallpaper.previewLocal
-    ? `wallpaper://${wallpaper.previewLocal}`
-    : wallpaper.previewUrl
+  const previewSrc = getPreviewSrc(wallpaper)
 
 
   return (
   return (
     <div
     <div

+ 2 - 3
src/renderer/src/components/playlist/PlaylistItemRow.tsx

@@ -2,6 +2,7 @@ import { useState } from 'react'
 import { GripVertical, Trash2, Volume2, Clock, ChevronDown, ChevronUp } from 'lucide-react'
 import { GripVertical, Trash2, Volume2, Clock, ChevronDown, ChevronUp } from 'lucide-react'
 import clsx from 'clsx'
 import clsx from 'clsx'
 import type { PlaylistItem, WallpaperMeta } from '@shared/types'
 import type { PlaylistItem, WallpaperMeta } from '@shared/types'
+import { getPreviewSrc } from '../../utils/preview'
 
 
 interface PlaylistItemRowProps {
 interface PlaylistItemRowProps {
   item: PlaylistItem
   item: PlaylistItem
@@ -33,9 +34,7 @@ export default function PlaylistItemRow({
 }: PlaylistItemRowProps) {
 }: PlaylistItemRowProps) {
   const [expanded, setExpanded] = useState(false)
   const [expanded, setExpanded] = useState(false)
 
 
-  const previewSrc = wallpaper?.previewLocal
-    ? `wallpaper://${wallpaper.previewLocal}`
-    : wallpaper?.previewUrl
+  const previewSrc = getPreviewSrc(wallpaper)
 
 
   return (
   return (
     <div
     <div

+ 2 - 1
src/renderer/src/components/playlist/WallpaperPickerModal.tsx

@@ -1,6 +1,7 @@
 import { useMemo, useState } from 'react'
 import { useMemo, useState } from 'react'
 import { useQuery } from '@tanstack/react-query'
 import { useQuery } from '@tanstack/react-query'
 import { Search, X, Plus, Check } from 'lucide-react'
 import { Search, X, Plus, Check } from 'lucide-react'
+import { getPreviewSrc } from '../../utils/preview'
 
 
 interface WallpaperPickerModalProps {
 interface WallpaperPickerModalProps {
   excludeIds: Set<string>
   excludeIds: Set<string>
@@ -81,7 +82,7 @@ export default function WallpaperPickerModal({
           <div className="grid grid-cols-3 gap-2">
           <div className="grid grid-cols-3 gap-2">
             {filtered.map((w) => {
             {filtered.map((w) => {
               const isSelected = selected.has(w.id)
               const isSelected = selected.has(w.id)
-              const previewSrc = w.previewLocal ? `wallpaper://${w.previewLocal}` : w.previewUrl
+              const previewSrc = getPreviewSrc(w)
               return (
               return (
                 <button
                 <button
                   key={w.id}
                   key={w.id}

+ 9 - 0
src/renderer/src/utils/preview.ts

@@ -0,0 +1,9 @@
+interface Previewable {
+  previewLocal?: string
+  previewUrl?: string
+}
+
+export function getPreviewSrc(wallpaper: Previewable | undefined): string | undefined {
+  if (!wallpaper) return undefined
+  return wallpaper.previewLocal ? `wallpaper://${wallpaper.previewLocal}` : wallpaper.previewUrl
+}