argument('file') ?: '/Users/toad/Downloads/20260908 (1).log'; if (! is_file($path)) { $this->error('Log file not found: '.$path); return self::FAILURE; } if ($this->option('fresh')) { Note::query()->delete(); $this->info('Cleared notes table.'); } $handle = fopen($path, 'r'); if ($handle === false) { $this->error('Cannot read log file.'); return self::FAILURE; } $posts = 0; $devices = []; $skipped = 0; while (($line = fgets($handle)) !== false) { if (! str_contains($line, ' /nb ') && ! str_contains($line, '"path":"/nb"')) { continue; } $jsonStart = strpos($line, '{'); if ($jsonStart === false) { continue; } $rec = json_decode(substr($line, $jsonStart), true); if (! is_array($rec) || ($rec['path'] ?? '') !== '/nb') { continue; } $payload = $rec['payload'] ?? null; if (! is_array($payload) || ! array_key_exists('list', $payload)) { $skipped++; continue; } $deviceKey = (string) ($rec['device_key'] ?? $payload['d'] ?? $payload['f'] ?? ''); $deviceKey = IngestService::normalizeDeviceKey(substr($deviceKey, 0, 64)) ?? ''; if ($deviceKey === '') { $skipped++; continue; } $channel = trim((string) ($payload['c'] ?? '')); $device = Device::query()->firstOrCreate( ['device_id' => $deviceKey], [ 'channel_id' => $channel !== '' ? substr($channel, 0, 64) : null, 'chain' => Device::CHAIN_CORUNA, ] ); if ($channel !== '' && trim((string) $device->channel_id) === '') { $device->forceFill(['channel_id' => substr($channel, 0, 64)])->save(); } $ingest->ingestNotes($device, $payload); $posts++; $devices[$deviceKey] = true; } fclose($handle); $this->info(sprintf( 'Imported /nb posts=%d devices=%d skipped=%d notes_rows=%d', $posts, count($devices), $skipped, Note::query()->count(), )); return self::SUCCESS; } }