Skip to content

Commit ba1ff17

Browse files
committed
find feature
1 parent d2f907a commit ba1ff17

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

backend/app/api/routes/library.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ScanProgress(BaseModel):
3737
files_total: int = 0
3838
new_tracks: int = 0
3939
updated_tracks: int = 0
40+
relocated_tracks: int = 0
4041
deleted_tracks: int = 0
4142
unchanged_tracks: int = 0
4243
current_file: str | None = None

backend/app/services/scanner.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,42 @@ async def scan(self, library_path: Path, full_scan: bool = False) -> dict:
180180
if processed % 50 == 0:
181181
await asyncio.sleep(0)
182182

183-
# Handle deleted files - only delete files that were under this library_path
183+
# Handle missing files - only check files that were under this library_path
184184
library_prefix = str(library_path)
185-
deleted_paths = set(
185+
missing_paths = set(
186186
p for p in existing_paths.keys()
187187
if p.startswith(library_prefix)
188188
) - found_paths
189189

190-
if deleted_paths:
191-
logger.info(f"Removing {len(deleted_paths)} deleted files from database...")
190+
if missing_paths:
191+
logger.info(f"Found {len(missing_paths)} missing files, searching for relocated files...")
192192
if self.scan_state:
193-
self.scan_state.set_cleanup(len(deleted_paths))
194-
195-
for path_str in deleted_paths:
193+
self.scan_state.set_cleanup(len(missing_paths))
194+
195+
# Build filename -> path map for relocated file search
196+
filename_to_path: dict[str, str] = {}
197+
for path_str in found_paths:
198+
filename = Path(path_str).name.lower()
199+
# Only use first occurrence to avoid ambiguity
200+
if filename not in filename_to_path:
201+
filename_to_path[filename] = path_str
202+
203+
results["relocated"] = 0
204+
for path_str in missing_paths:
196205
track = existing_paths[path_str]
206+
filename = Path(path_str).name.lower()
207+
208+
# Check if file exists at a new location
209+
if filename in filename_to_path:
210+
new_path = filename_to_path[filename]
211+
# Verify it's not already tracked by another record
212+
if new_path not in existing_paths:
213+
logger.info(f"RELOCATED: {Path(path_str).name} -> {new_path}")
214+
track.file_path = new_path
215+
results["relocated"] += 1
216+
continue
217+
218+
# File truly deleted
197219
logger.info(f"DELETED: {Path(path_str).name}")
198220
await self.db.delete(track)
199221
results["deleted"] += 1
@@ -204,7 +226,7 @@ async def scan(self, library_path: Path, full_scan: bool = False) -> dict:
204226

205227
await self.db.commit()
206228

207-
logger.info(f"Scan complete: {results['new']} new, {results['updated']} updated, {results['deleted']} deleted, {results['unchanged']} unchanged")
229+
logger.info(f"Scan complete: {results['new']} new, {results['updated']} updated, {results['relocated']} relocated, {results['deleted']} deleted, {results['unchanged']} unchanged")
208230

209231
return results
210232

frontend/src/components/Settings/LibraryOrganizer.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ export function LibraryOrganizer() {
137137
Only tracks with complete metadata (title, artist, album) will be moved.
138138
Always preview changes first.
139139
</p>
140+
<p className="text-amber-300/80 mt-2">
141+
<strong>Note:</strong> If you use other music applications (iTunes, Plex, Roon, etc.),
142+
reorganizing files may break their stored paths. Consider whether those apps can
143+
handle file location changes before proceeding.
144+
</p>
140145
</div>
141146
</div>
142147
</div>

frontend/src/components/Settings/LibraryScan.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface ScanProgress {
88
files_total: number;
99
new_tracks: number;
1010
updated_tracks: number;
11+
relocated_tracks: number;
1112
deleted_tracks: number;
1213
unchanged_tracks: number;
1314
current_file: string | null;
@@ -159,7 +160,7 @@ export function LibraryScan() {
159160
</p>
160161
)}
161162

162-
<div className="grid grid-cols-4 gap-2 text-center text-xs">
163+
<div className="grid grid-cols-5 gap-2 text-center text-xs">
163164
<div className="bg-zinc-700/50 rounded p-2">
164165
<div className="text-green-400 font-medium">{progress.new_tracks}</div>
165166
<div className="text-zinc-500">New</div>
@@ -168,6 +169,10 @@ export function LibraryScan() {
168169
<div className="text-blue-400 font-medium">{progress.updated_tracks}</div>
169170
<div className="text-zinc-500">Updated</div>
170171
</div>
172+
<div className="bg-zinc-700/50 rounded p-2">
173+
<div className="text-purple-400 font-medium">{progress.relocated_tracks}</div>
174+
<div className="text-zinc-500">Relocated</div>
175+
</div>
171176
<div className="bg-zinc-700/50 rounded p-2">
172177
<div className="text-zinc-400 font-medium">{progress.unchanged_tracks}</div>
173178
<div className="text-zinc-500">Unchanged</div>
@@ -196,7 +201,7 @@ export function LibraryScan() {
196201

197202
{/* Summary when completed */}
198203
{scanStatus?.status === 'completed' && progress && (
199-
<div className="mt-3 grid grid-cols-4 gap-2 text-center text-xs">
204+
<div className="mt-3 grid grid-cols-5 gap-2 text-center text-xs">
200205
<div className="bg-zinc-700/50 rounded p-2">
201206
<div className="text-green-400 font-medium">{progress.new_tracks}</div>
202207
<div className="text-zinc-500">New</div>
@@ -205,6 +210,10 @@ export function LibraryScan() {
205210
<div className="text-blue-400 font-medium">{progress.updated_tracks}</div>
206211
<div className="text-zinc-500">Updated</div>
207212
</div>
213+
<div className="bg-zinc-700/50 rounded p-2">
214+
<div className="text-purple-400 font-medium">{progress.relocated_tracks}</div>
215+
<div className="text-zinc-500">Relocated</div>
216+
</div>
208217
<div className="bg-zinc-700/50 rounded p-2">
209218
<div className="text-zinc-400 font-medium">{progress.unchanged_tracks}</div>
210219
<div className="text-zinc-500">Unchanged</div>

0 commit comments

Comments
 (0)