feat(sync): import Takeout HTML/CSV (historique, WL, abos) sans API
This commit is contained in:
@@ -357,6 +357,39 @@ r.post('/subscriptions', authMiddlewareCookieAware, subscriptionsLimiter, async
|
||||
}
|
||||
});
|
||||
|
||||
// Import en lot (ex. abonnements.csv de Takeout) : upsert direct, sans
|
||||
// résolution externe (les IDs Takeout sont déjà fiables).
|
||||
r.post('/subscriptions/batch', authMiddlewareCookieAware, subscriptionsLimiter, (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' });
|
||||
const allowed = new Set(['youtube', 'twitch', 'dailymotion', 'peertube', 'odysee', 'rumble', 'yt', 'dm', 'tw', 'pt', 'od', 'ru']);
|
||||
let imported = 0;
|
||||
let skipped = 0;
|
||||
for (const it of items) {
|
||||
const provider = String(it?.provider || 'youtube').trim().toLowerCase();
|
||||
const externalId = String(it?.externalId || '').trim().slice(0, 128);
|
||||
if (!allowed.has(provider) || !externalId) { skipped++; continue; }
|
||||
try {
|
||||
const row = upsertChannelRow({
|
||||
provider, externalId,
|
||||
title: String(it?.title || externalId).slice(0, 200) || null,
|
||||
handle: String(it?.handle || '').slice(0, 128) || null,
|
||||
avatarUrl: String(it?.avatarUrl || '').slice(0, 500) || null,
|
||||
url: String(it?.url || '').slice(0, 500) || null,
|
||||
lastRefreshedAt: Date.now(),
|
||||
});
|
||||
subscribeChannel({ userId: req.user.id, provider, externalId, channelId: row?.id });
|
||||
imported++;
|
||||
} catch { skipped++; }
|
||||
}
|
||||
return res.json({ imported, skipped, total: items.length });
|
||||
} catch {
|
||||
return res.status(500).json({ error: 'subscriptions_batch_failed' });
|
||||
}
|
||||
});
|
||||
|
||||
r.delete('/subscriptions/:subscriptionId', authMiddlewareCookieAware, subscriptionsLimiter, (req, res) => {
|
||||
try {
|
||||
const info = unsubscribeChannel({ userId: req.user.id, subscriptionId: req.params.subscriptionId });
|
||||
|
||||
Reference in New Issue
Block a user