mirror of
https://github.com/mudabbir-ahmad/Media-Aggregation-and-Sorting-System.git
synced 2026-10-08 03:40:20 +00:00
feat: enhance database service with centralized error logging and improve media handling across services
This commit is contained in:
1 parent
04046702d3
commit
ad0cc1a7f5
5 files changed
+384
-165
No files matched your search
+69
-19
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user