refactor(linkedin-studio): M0-6 — quick-import.mjs via getDataRoot + fix printed path
This commit is contained in:
parent
55e8816764
commit
0f12306d05
2 changed files with 114 additions and 52 deletions
|
|
@ -6,16 +6,25 @@ import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync } from 'node
|
|||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { exec } from 'node:child_process';
|
||||
import { getDataRoot } from './data-root.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PLUGIN_ROOT = join(__dirname, '..', '..');
|
||||
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
||||
const EXPORTS_DIR = join(PLUGIN_ROOT, 'assets', 'analytics', 'exports');
|
||||
const EXPORTS_DIR = join(getDataRoot('analytics'), 'exports');
|
||||
const DOWNLOADS_DIR = join(HOME, 'Downloads');
|
||||
const POLL_INTERVAL = 3000;
|
||||
const MAX_WAIT = 300000; // 5 minutes
|
||||
|
||||
mkdirSync(EXPORTS_DIR, { recursive: true });
|
||||
// Manual import command we print for the user. It must NOT pin ANALYTICS_ROOT to
|
||||
// the in-plugin tree anymore — the CLI defaults to the external data root
|
||||
// (storage.ts:getDataRoot), so the data path is omitted. The plugin path stays
|
||||
// only for the in-plugin tsx executable (cli.ts), which is bundled, not data.
|
||||
export function buildImportCommand(pluginRoot, filename) {
|
||||
return `node --import tsx "${pluginRoot}/scripts/analytics/src/cli.ts" import "${filename}"`;
|
||||
}
|
||||
|
||||
export { EXPORTS_DIR };
|
||||
|
||||
// Snapshot existing CSV files
|
||||
function getCsvFiles() {
|
||||
|
|
@ -34,53 +43,61 @@ function openUrl(url) {
|
|||
exec(`${cmd} "${url}"`, () => {});
|
||||
}
|
||||
|
||||
const beforeFiles = new Set(getCsvFiles());
|
||||
function main() {
|
||||
mkdirSync(EXPORTS_DIR, { recursive: true });
|
||||
|
||||
console.log('Opening LinkedIn Analytics in your browser...');
|
||||
openUrl('https://www.linkedin.com/analytics/creator/content/');
|
||||
const beforeFiles = new Set(getCsvFiles());
|
||||
|
||||
console.log('\nInstructions:');
|
||||
console.log(' 1. Click \'Export\' (top right) in LinkedIn Analytics');
|
||||
console.log(' 2. LinkedIn will download a CSV to ~/Downloads');
|
||||
console.log(' 3. This script will detect it automatically\n');
|
||||
console.log('Watching ~/Downloads for new CSV files (max 5 minutes)...\n');
|
||||
console.log('Opening LinkedIn Analytics in your browser...');
|
||||
openUrl('https://www.linkedin.com/analytics/creator/content/');
|
||||
|
||||
let elapsed = 0;
|
||||
const timer = setInterval(() => {
|
||||
elapsed += POLL_INTERVAL;
|
||||
console.log('\nInstructions:');
|
||||
console.log(' 1. Click \'Export\' (top right) in LinkedIn Analytics');
|
||||
console.log(' 2. LinkedIn will download a CSV to ~/Downloads');
|
||||
console.log(' 3. This script will detect it automatically\n');
|
||||
console.log('Watching ~/Downloads for new CSV files (max 5 minutes)...\n');
|
||||
|
||||
const currentFiles = getCsvFiles();
|
||||
const newFiles = currentFiles.filter(f => !beforeFiles.has(f));
|
||||
let elapsed = 0;
|
||||
const timer = setInterval(() => {
|
||||
elapsed += POLL_INTERVAL;
|
||||
|
||||
for (const filename of newFiles) {
|
||||
const filePath = join(DOWNLOADS_DIR, filename);
|
||||
try {
|
||||
const age = (Date.now() - statSync(filePath).mtime.getTime()) / 1000;
|
||||
if (/linkedin|analytics|content|export/i.test(filename) || age < 60) {
|
||||
console.log(`Detected: ${filename}`);
|
||||
copyFileSync(filePath, join(EXPORTS_DIR, filename));
|
||||
console.log(`Copied to: ${EXPORTS_DIR}/${filename}\n`);
|
||||
console.log('File is ready for import. Run:');
|
||||
console.log(' /linkedin:import\n');
|
||||
console.log('Or import directly with:');
|
||||
console.log(` ANALYTICS_ROOT="${PLUGIN_ROOT}/assets/analytics" node --import tsx "${PLUGIN_ROOT}/scripts/analytics/src/cli.ts" import "${filename}"`);
|
||||
clearInterval(timer);
|
||||
process.exit(0);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
const currentFiles = getCsvFiles();
|
||||
const newFiles = currentFiles.filter(f => !beforeFiles.has(f));
|
||||
|
||||
if (elapsed % 15000 === 0) {
|
||||
const remaining = Math.floor((MAX_WAIT - elapsed) / 60000);
|
||||
console.log(` Still waiting... (${remaining}m remaining)`);
|
||||
}
|
||||
for (const filename of newFiles) {
|
||||
const filePath = join(DOWNLOADS_DIR, filename);
|
||||
try {
|
||||
const age = (Date.now() - statSync(filePath).mtime.getTime()) / 1000;
|
||||
if (/linkedin|analytics|content|export/i.test(filename) || age < 60) {
|
||||
console.log(`Detected: ${filename}`);
|
||||
copyFileSync(filePath, join(EXPORTS_DIR, filename));
|
||||
console.log(`Copied to: ${EXPORTS_DIR}/${filename}\n`);
|
||||
console.log('File is ready for import. Run:');
|
||||
console.log(' /linkedin:import\n');
|
||||
console.log('Or import directly with:');
|
||||
console.log(` ${buildImportCommand(PLUGIN_ROOT, filename)}`);
|
||||
clearInterval(timer);
|
||||
process.exit(0);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
if (elapsed >= MAX_WAIT) {
|
||||
console.log('\nTimed out after 5 minutes. No new CSV detected.\n');
|
||||
console.log('You can manually copy the file:');
|
||||
console.log(` mv ~/Downloads/<linkedin-csv-file>.csv ${EXPORTS_DIR}/`);
|
||||
console.log(' /linkedin:import');
|
||||
clearInterval(timer);
|
||||
process.exit(1);
|
||||
}
|
||||
}, POLL_INTERVAL);
|
||||
if (elapsed % 15000 === 0) {
|
||||
const remaining = Math.floor((MAX_WAIT - elapsed) / 60000);
|
||||
console.log(` Still waiting... (${remaining}m remaining)`);
|
||||
}
|
||||
|
||||
if (elapsed >= MAX_WAIT) {
|
||||
console.log('\nTimed out after 5 minutes. No new CSV detected.\n');
|
||||
console.log('You can manually copy the file:');
|
||||
console.log(` mv ~/Downloads/<linkedin-csv-file>.csv ${EXPORTS_DIR}/`);
|
||||
console.log(' /linkedin:import');
|
||||
clearInterval(timer);
|
||||
process.exit(1);
|
||||
}
|
||||
}, POLL_INTERVAL);
|
||||
}
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue