require 'csv' require 'json' require 'httpx' # Require the httpx gem # --- Configuration --- LINKDING_API_URL = '/api/bookmarks/' # Replace with your Linkding API URL LINKDING_API_TOKEN = '' # Replace with your Linkding API token POCKET_CSV_DIR = File.expand_path('') # Replace with the path to your Pocket CSV directory # --- Script Logic --- def import_bookmark(bookmark_data) headers = { 'Content-Type' => 'application/json', 'Authorization' => "Token #{LINKDING_API_TOKEN}" } begin response = HTTPX.post(LINKDING_API_URL, json: bookmark_data, headers: headers) if response.status == 201 puts "Successfully imported: #{bookmark_data[:url]}" else puts "Failed to import #{bookmark_data[:url]}. Status: #{response.status}, Body: #{response.body.to_s}" end rescue HTTPX::Error => e puts "HTTPX error importing #{bookmark_data[:url]}: #{e.message}" rescue StandardError => e puts "General error importing #{bookmark_data[:url]}: #{e.message}" end end def process_pocket_csv(csv_file_path) puts "Processing CSV file: #{csv_file_path}" CSV.foreach(csv_file_path, headers: true) do |row| title = row['title'] url = row['url'] time_added = row['time_added'] # This is a Unix timestamp tags = row['tags'] status = row['status'] # Skip invalid rows (e.g., if URL is missing or malformed) next if url.nil? || url.strip.empty? || !url.start_with?('http') # Prepare data for Linkding API bookmark = { url: url, title: title.to_s.empty? ? url : title, # Use URL as title if title is empty description: '', # Pocket export doesn't seem to have descriptions, so leave empty is_archived: status == 'read', # Linkding uses 'is_archived' for read status tag_names: tags.to_s.split(',').map(&:strip).reject(&:empty?) # Split tags by comma and clean up } # Convert Unix timestamp to ISO 8601 format for Linkding's `added_at` begin bookmark[:added_at] = Time.at(time_added.to_i).iso8601 rescue ArgumentError => e puts "Warning: Could not parse timestamp '#{time_added}' for URL: #{url}. Skipping 'added_at'. Error: #{e.message}" bookmark.delete(:added_at) # Remove if invalid end import_bookmark(bookmark) sleep(0.1) # Be kind to the API, add a small delay end end # --- Main Execution --- puts "Starting Pocket to Linkding import..." Dir.glob(File.join(POCKET_CSV_DIR, 'part_*.csv')).sort.each do |csv_file| process_pocket_csv(csv_file) end puts "Import process finished."