#!/usr/bin/env node // Add a bookmark to Music/Wishlist folder in Floccus bookmarks // Usage: node add_bookmark_to_wishlist.js const crypto = require('crypto'); const fs = require('fs'); const BOOKMARKS_PATH = '/var/www/webdav/bookmarks.xbel'; const PASSWORD = process.env.BOOKMARKS_PASSWORD || JSON.parse(require('fs').readFileSync('/etc/automation/bookmarks.json', 'utf8')).password; const WISHLIST_FOLDER_TITLE = 'Wishlist'; const url = process.argv[2]; const title = process.argv[3]; if (!url || !title) { console.error('Usage: node add_bookmark_to_wishlist.js <url> <title>'); process.exit(1); } function decrypt(data, password) { const ciphertext = Buffer.from(data.ciphertext, 'base64'); const salt = data.salt; const key = crypto.pbkdf2Sync(password, salt, 250000, 32, 'sha256'); const iv = ciphertext.slice(0, 16); const encrypted = ciphertext.slice(16, -16); const tag = ciphertext.slice(-16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); decipher.setAuthTag(tag); return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8'); } function encrypt(plaintext, password, salt) { const key = crypto.pbkdf2Sync(password, salt, 250000, 32, 'sha256'); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]); const tag = cipher.getAuthTag(); return Buffer.concat([iv, encrypted, tag]).toString('base64'); } const escapeXml = (str) => str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); try { const data = JSON.parse(fs.readFileSync(BOOKMARKS_PATH, 'utf8')); let xml = decrypt(data, PASSWORD); // Check if bookmark already exists if (xml.includes(escapeXml(url)) || xml.includes(url)) { console.log('Bookmark already exists'); process.exit(0); } // Find highest ID const idMatch = xml.match(/highestId :(\d+):/); let highestId = idMatch ? parseInt(idMatch[1]) : 100; const newId = highestId + 1; // Find the Wishlist folder and add bookmark inside it const wishlistPattern = /<folder id="\d+">\s*<title>Wishlist<\/title>/; if (wishlistPattern.test(xml)) { // Add bookmark inside existing Wishlist folder const newBookmark = `<bookmark href="${escapeXml(url)}" id="${newId}"> <title>${escapeXml(title)} `; // Find Wishlist folder's closing tag and insert before it xml = xml.replace( /(\s*Wishlist<\/title>[\s\S]*?)(<\/folder>)/, (match, folderContent, closingTag) => folderContent + newBookmark ); } else { console.error('Wishlist folder not found'); process.exit(1); } // Update highest ID xml = xml.replace(/highestId :(\d+):/, `highestId :${newId}:`); // Save const newCiphertext = encrypt(xml, PASSWORD, data.salt); fs.writeFileSync(BOOKMARKS_PATH, JSON.stringify({ ciphertext: newCiphertext, salt: data.salt })); console.log(`Added: ${title}`); } catch (e) { console.error('Error:', e.message); process.exit(1); }