feat(sync): refonte import Takeout complet (playlists, musique, recherches, identité)

This commit is contained in:
2026-09-27 11:10:05 -04:00
parent 03ad46e91b
commit 6c218e8773
5 changed files with 338 additions and 152 deletions
+11
View File
@@ -409,6 +409,17 @@ export function insertSearchHistory({ userId, query, filters }) {
return { id, created_at };
}
/** Variante Takeout : date d'origine conservée (ISO valide exigée). */
export function insertSearchHistoryAt({ userId, query, createdAt }) {
const id = cryptoRandomId();
const d = new Date(String(createdAt || ''));
const created_at = !Number.isNaN(d.getTime()) ? d.toISOString() : nowIso();
db.prepare(`INSERT INTO search_history (id, user_id, query, filters_json, created_at)
VALUES (?, ?, ?, ?, ?)`)
.run(id, userId, query, null, created_at);
return { id, created_at };
}
export function listSearchHistory({ userId, limit = 50, before, q, provider }) {
const lim = Math.max(1, Math.min(200, Number(limit) || 50));
const conds = ['user_id = ?'];
+23
View File
@@ -40,6 +40,7 @@ import {
cryptoRandomId,
cryptoRandomUUID,
insertSearchHistory,
insertSearchHistoryAt,
listSearchHistory,
deleteSearchHistoryById,
deleteAllSearchHistory,
@@ -2550,6 +2551,28 @@ r.post('/user/history/search', authMiddleware, (req, res) => {
return res.status(201).json(row);
});
// Import en lot des recherches Takeout (historique-recherches.html).
r.post('/user/history/search/batch', authMiddleware, oauthLimiter, (req, res) => {
try {
const items = Array.isArray(req.body?.items) ? req.body.items : [];
if (!items.length) return res.status(400).json({ error: 'items_required' });
if (items.length > 1000) return res.status(400).json({ error: 'batch_too_large' });
let imported = 0;
let skipped = 0;
for (const it of items) {
const query = String(it?.query || '').trim().slice(0, 300);
if (!query) { skipped++; continue; }
try {
insertSearchHistoryAt({ userId: req.user.id, query, createdAt: it?.createdAt });
imported++;
} catch { skipped++; }
}
return res.json({ imported, skipped, total: items.length });
} catch {
return res.status(500).json({ error: 'search_batch_failed' });
}
});
r.get('/user/history/search', authMiddleware, (req, res) => {
const limit = Math.min(200, Number(req.query.limit || 50));
const before = req.query.before ? String(req.query.before) : undefined;