misc docs/helpers
This commit is contained in:
parent
dffc54c0d2
commit
5983774e22
5 changed files with 792 additions and 0 deletions
139
misc-aio/publish_profiles_from_csv.py
Normal file
139
misc-aio/publish_profiles_from_csv.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Bulk publish Nostr profiles from CSV file
|
||||
Usage: python publish_profiles_from_csv.py <csv_file> <relay_url>
|
||||
"""
|
||||
import sys
|
||||
import csv
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
import secp256k1
|
||||
from websocket import create_connection
|
||||
|
||||
def sign_event(event, public_key_hex, private_key):
|
||||
"""Sign a Nostr event"""
|
||||
# Create the signature data
|
||||
signature_data = json.dumps([
|
||||
0,
|
||||
public_key_hex,
|
||||
event["created_at"],
|
||||
event["kind"],
|
||||
event["tags"],
|
||||
event["content"]
|
||||
], separators=(',', ':'), ensure_ascii=False)
|
||||
|
||||
# Calculate event ID
|
||||
event_id = hashlib.sha256(signature_data.encode()).hexdigest()
|
||||
event["id"] = event_id
|
||||
event["pubkey"] = public_key_hex
|
||||
|
||||
# Sign the event
|
||||
signature = private_key.schnorr_sign(bytes.fromhex(event_id), None, raw=True).hex()
|
||||
event["sig"] = signature
|
||||
|
||||
return event
|
||||
|
||||
def publish_profile_metadata(private_key_hex, profile_name, relay_url):
|
||||
"""Publish a Nostr kind 0 metadata event"""
|
||||
try:
|
||||
# Convert hex private key to secp256k1 PrivateKey and get public key
|
||||
private_key = secp256k1.PrivateKey(bytes.fromhex(private_key_hex))
|
||||
public_key_hex = private_key.pubkey.serialize()[1:].hex() # Remove the 0x02 prefix
|
||||
|
||||
print(f"Publishing profile for: {profile_name}")
|
||||
print(f" Public key: {public_key_hex}")
|
||||
|
||||
# Create Nostr kind 0 metadata event
|
||||
metadata = {
|
||||
"name": profile_name,
|
||||
"display_name": profile_name,
|
||||
"about": f"Profile for {profile_name}"
|
||||
}
|
||||
|
||||
event = {
|
||||
"kind": 0,
|
||||
"created_at": int(time.time()),
|
||||
"tags": [],
|
||||
"content": json.dumps(metadata, separators=(',', ':'))
|
||||
}
|
||||
|
||||
# Sign the event
|
||||
signed_event = sign_event(event, public_key_hex, private_key)
|
||||
|
||||
# Connect to relay and publish
|
||||
ws = create_connection(relay_url, timeout=15)
|
||||
|
||||
# Send the event
|
||||
event_message = f'["EVENT",{json.dumps(signed_event)}]'
|
||||
ws.send(event_message)
|
||||
|
||||
# Wait for response
|
||||
try:
|
||||
response = ws.recv()
|
||||
print(f" ✅ Published successfully: {response}")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ No immediate response: {e}")
|
||||
|
||||
# Close connection
|
||||
ws.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Failed to publish: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: python publish_profiles_from_csv.py <csv_file> <relay_url>")
|
||||
print("Example: python publish_profiles_from_csv.py publish-these.csv wss://relay.example.com")
|
||||
sys.exit(1)
|
||||
|
||||
csv_file = sys.argv[1]
|
||||
relay_url = sys.argv[2]
|
||||
|
||||
print(f"Publishing profiles from {csv_file} to {relay_url}")
|
||||
print("=" * 60)
|
||||
|
||||
published_count = 0
|
||||
failed_count = 0
|
||||
|
||||
try:
|
||||
with open(csv_file, 'r') as file:
|
||||
csv_reader = csv.DictReader(file)
|
||||
|
||||
for row_num, row in enumerate(csv_reader, start=2): # start=2 because header is line 1
|
||||
username = row['username'].strip()
|
||||
private_key_hex = row['prvkey'].strip()
|
||||
|
||||
if not username or not private_key_hex:
|
||||
print(f"Row {row_num}: Skipping empty row")
|
||||
continue
|
||||
|
||||
print(f"\nRow {row_num}: Processing {username}")
|
||||
|
||||
success = publish_profile_metadata(private_key_hex, username, relay_url)
|
||||
|
||||
if success:
|
||||
published_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
# Small delay between publishes to be nice to the relay
|
||||
time.sleep(1)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"❌ File not found: {csv_file}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"❌ Error processing CSV: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(f"Publishing complete!")
|
||||
print(f"✅ Successfully published: {published_count}")
|
||||
print(f"❌ Failed: {failed_count}")
|
||||
print(f"📊 Total processed: {published_count + failed_count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue