feat: enhance database service with centralized error logging and improve media handling across services

This commit is contained in:
bobbert committed 2026-02-25 00:14:00 +00:00
1 parent 04046702d3
commit ad0cc1a7f5
5 files changed
+384 -165

No files matched your search

+69 -19
View File
@@ -14,6 +14,62 @@ import MediaViewer from '../components/MediaViewer';
import { logError } from '../services/ErrorHandler';
import { TouchableOpacity } from 'react-native';
/**
* Merge media items from different services.
* Items with the same filename (title) are merged into a single entry
* with a `sources` array listing every service it appears in.
* The best local_path is kept (prefer file:// from DEVICE over a cached
* Picker download, since device URIs are always fresh).
*/
const mergeMediaAcrossServices = (items) => {
// First pass: group by normalised filename
const byFilename = new Map();
const noFilename = [];
for (const item of items) {
const key = item.title?.toLowerCase().trim();
if (!key || key === 'untitled') {
noFilename.push({ ...item, sources: [item.source_service] });
continue;
}
if (byFilename.has(key)) {
const existing = byFilename.get(key);
// Add this service to the sources list
if (!existing.sources.includes(item.source_service)) {
existing.sources.push(item.source_service);
}
// Prefer a local device path over a cached download
if (item.source_service === 'DEVICE' && item.local_path) {
existing.local_path = item.local_path;
}
// Keep the best local_path if the existing one is missing
if (!existing.local_path && item.local_path) {
existing.local_path = item.local_path;
}
} else {
byFilename.set(key, { ...item, sources: [item.source_service] });
}
}
// Second pass: also deduplicate by source_id for items with different titles
const bySourceId = new Map();
for (const item of [...byFilename.values(), ...noFilename]) {
const key = item.source_id || item.id || item.local_path || Math.random().toString();
if (bySourceId.has(key)) {
const existing = bySourceId.get(key);
for (const src of (item.sources || [])) {
if (!existing.sources.includes(src)) existing.sources.push(src);
}
if (!existing.local_path && item.local_path) existing.local_path = item.local_path;
} else {
bySourceId.set(key, item);
}
}
return Array.from(bySourceId.values());
};
const HomeScreen = ({ navigation, route }) => {
const userId = route?.params?.userId;
const { theme } = useTheme();
@@ -102,11 +158,11 @@ const HomeScreen = ({ navigation, route }) => {
console.log('iCloud: placeholder — would fetch photos here');
}
// Deduplicate
const unique = Array.from(
new Map(newMedia.map((m) => [m.source_id || m.id || m.local_path, m])).values()
);
setAllMedia(unique);
// ─── Merge & cross-reference across services ───
// Match items across sources by filename so we can show "this photo
// exists on Device AND Google Photos" etc.
const merged = mergeMediaAcrossServices(newMedia);
setAllMedia(merged);
} catch (err) {
console.error('Error loading media:', err);
} finally {
@@ -158,13 +214,8 @@ const HomeScreen = ({ navigation, route }) => {
setGoogleNextPage(result.nextPageToken || null);
setGoogleSessionId(result.sessionId || null);
// Merge into current view
setAllMedia((prev) => {
const combined = [...prev, ...result.mediaItems];
return Array.from(
new Map(combined.map((m) => [m.source_id || m.id || m.local_path, m])).values()
);
});
// Merge into current view with cross-service matching
setAllMedia((prev) => mergeMediaAcrossServices([...prev, ...result.mediaItems]));
console.log(`Imported ${result.mediaItems.length} photos from Google`);
}
@@ -188,7 +239,11 @@ const HomeScreen = ({ navigation, route }) => {
const filterMedia = () => {
let filtered = allMedia;
if (selectedFilter !== 'all') {
filtered = allMedia.filter((m) => m.source_service === selectedFilter);
// Check both source_service and the sources array for cross-service items
filtered = allMedia.filter((m) =>
m.source_service === selectedFilter ||
(m.sources && m.sources.includes(selectedFilter))
);
}
filtered.sort((a, b) => new Date(b.created_date || 0) - new Date(a.created_date || 0));
setFilteredMedia(filtered);
@@ -233,12 +288,7 @@ const HomeScreen = ({ navigation, route }) => {
}
if (moreMedia.length) {
setAllMedia((prev) => {
const combined = [...prev, ...moreMedia];
return Array.from(
new Map(combined.map((m) => [m.source_id || m.id || m.local_path, m])).values()
);
});
setAllMedia((prev) => mergeMediaAcrossServices([...prev, ...moreMedia]));
}
} catch (err) {
console.error('Error loading more photos:', err);