pull down to refresh

Get notification for OCEAN.xyz earnings every time a new block is found (every ~18h currently) with your share of it through Gotify.
Here is the Python script:
#!/usr/bin/env python3

import requests
import csv
import os
import sys
from datetime import datetime
from io import StringIO

# Configuration
OCEAN_API_URL = "https://www.ocean.xyz/data/csv/bc1q.../earnings"
GOTIFY_URL = "https://gotify.domain.tld/message"
GOTIFY_TOKEN = "secret"
LAST_BLOCK_FILE = "/tmp/last_btc_block.txt"

def get_earnings_data():
    """Fetch earnings data from Ocean API"""
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
    }

    try:
        response = requests.post(OCEAN_API_URL, headers=headers, timeout=30)
        response.raise_for_status()
        return response.text
    except requests.RequestException as e:
        print(f"Error fetching data: {e}")
        return None

def parse_csv_data(csv_text):
    """Parse CSV data and return list of earnings records"""
    csv_reader = csv.DictReader(StringIO(csv_text))
    return list(csv_reader)

def get_last_processed_block():
    """Get the last processed block hash from file"""
    if os.path.exists(LAST_BLOCK_FILE):
        with open(LAST_BLOCK_FILE, 'r') as f:
            return f.read().strip()
    return None

def save_last_processed_block(block_hash):
    """Save the last processed block hash to file"""
    with open(LAST_BLOCK_FILE, 'w') as f:
        f.write(block_hash)

def send_notification(title, message):
    """Send notification via Gotify"""
    data = {
        'title': title,
        'message': message,
        'priority': 5  # Higher priority for earnings notifications
    }

    try:
        response = requests.post(
            f"{GOTIFY_URL}?token={GOTIFY_TOKEN}",
            data=data,
            timeout=10
        )
        response.raise_for_status()
        print(f"Notification sent successfully: {title}")
        return True
    except requests.RequestException as e:
        print(f"Error sending notification: {e}")
        return False

def format_btc_amount(btc_str):
    """Format BTC amount for better readability"""
    try:
        btc_float = float(btc_str)
        satoshis = int(btc_float * 100000000)
        return f"{btc_float:.8f} BTC ({satoshis:,} sats)"
    except ValueError:
        return btc_str


def main():
    print(f"[{datetime.now()}] Checking for new Bitcoin earnings...")

    # Fetch current earnings data
    csv_data = get_earnings_data()
    if not csv_data:
        print("Failed to fetch earnings data")
        sys.exit(1)

    # Parse the data
    try:
        earnings_records = parse_csv_data(csv_data)
        if not earnings_records:
            print("No earnings records found")
            return
    except Exception as e:
        print(f"Error parsing CSV data: {e}")
        sys.exit(1)

    # Get the most recent record (first in the list)
    latest_record = earnings_records[0]
    latest_block = latest_record['Block']

    # Check if this is a new block
    last_processed_block = get_last_processed_block()

    if last_processed_block == latest_block:
        print("No new earnings since last check")
        return

    # We have new earnings!
    earnings_btc = latest_record['Earnings (BTC)']
    pool_fees_btc = latest_record['Pool Fees (BTC)']
    share_percentage = latest_record['Share Log %']
    timestamp = latest_record['Time']

    # Format notification message
    title = "šŸš€ New Bitcoin Earnings!"
    message = f"""
New block found: {timestamp}

šŸ’° Earnings: {format_btc_amount(earnings_btc)}
šŸ’ø Pool Fees: {format_btc_amount(pool_fees_btc)}
šŸ“Š Share: {share_percentage}
""".strip()

    # Send notification
    if send_notification(title, message):
        # Save the new block hash
        save_last_processed_block(latest_block)
        print(f"New earnings processed: {earnings_btc} BTC")
    else:
        print("Failed to send notification, not updating last block")
        sys.exit(1)

if __name__ == "__main__":
    main()
You can run it every 5-15 minutes via cron.
this territory is moderated