Visualize your sats
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial commit

LittleBit d71b735e

+116
+10
.gitignore
··· 1 + # Python-generated files 2 + __pycache__/ 3 + *.py[oc] 4 + build/ 5 + dist/ 6 + wheels/ 7 + *.egg-info 8 + 9 + # Virtual environments 10 + .venv
+1
.python-version
··· 1 + 3.14
+13
.vscode/settings.json
··· 1 + { 2 + "python.languageServer": "Pylance", 3 + "python.analysis.diagnosticSeverityOverrides": { 4 + "reportMissingModuleSource": "none", 5 + "reportShadowedImports": "none" 6 + }, 7 + "python.analysis.extraPaths": [ 8 + "", 9 + "/home/jaherron/.vscode/extensions/joedevivo.vscode-circuitpython-0.2.0-linux-x64/stubs", 10 + "/home/jaherron/.config/Code/User/globalStorage/joedevivo.vscode-circuitpython/bundle/20260402/adafruit-circuitpython-bundle-py-20260402/lib" 11 + ], 12 + "circuitpython.board.version": null 13 + }
README.md

This is a binary file and will not be displayed.

+6
example-wallets.yaml
··· 1 + local-currency: USD # the fiat currency to display prices in 2 + input-format: sats # input/output can be "sats" (100M sats = 1 BTC) or "btc" (decimal bitcoins) 3 + wallets: 4 + - name: An Exchange 5 + type: exchange # the type can be anything, the string here will just be displayed 6 + btc-amount: 5000 # what you write here depends on what input-format is set to
+10
pyproject.toml
··· 1 + [project] 2 + name = "bitview-cli" 3 + version = "0.1.0" 4 + description = "Visualize your sats" 5 + readme = "README.md" 6 + requires-python = ">=3.14" 7 + dependencies = ["tabulate", "pyyaml", "requests"] 8 + 9 + [project.scripts] 10 + bitview = "main:main"
+3
requirements.txt
··· 1 + tabulate 2 + pyyaml 3 + requests
+73
src/main.py
··· 1 + import sys 2 + import os 3 + import yaml 4 + import requests 5 + from tabulate import tabulate 6 + 7 + def main(): 8 + if len(sys.argv) < 2: 9 + print("Provide a path to a YAML configuration file") 10 + exit(1) 11 + elif len(sys.argv) > 2: 12 + print("Too many arguments") 13 + exit(1) 14 + 15 + # Import configuration to variables 16 + configPath = sys.argv[1] 17 + if not os.path.exists(configPath): 18 + print("Invalid path or file doesn't exist") 19 + exit("1") 20 + 21 + config = {} 22 + with open(os.path.expanduser(configPath)) as f: 23 + config=yaml.safe_load(f) 24 + 25 + localCurrency:str = config.get("local-currency") 26 + inputFormat:str = config.get("input-format") 27 + wallets:list[dict] = config.get("wallets") 28 + 29 + # Validate configuration 30 + if inputFormat not in ['sats', 'btc']: 31 + print("input-format must be sats or btc") 32 + exit(1) 33 + 34 + exchangeRate = None 35 + try: 36 + exchangeRequest = requests.get(f"https://api.coinbase.com/v2/prices/BTC-{localCurrency}/spot") 37 + exchangeRequest.raise_for_status() 38 + exchangeData = exchangeRequest.json() 39 + exchangeRate = float(exchangeData.get("data", {}).get("amount")) 40 + except: 41 + print("Couldn't get exchange rate data. Table will be shown without fiat prices.") 42 + 43 + print(f"Exchange Rate: {exchangeRate:.2f} {localCurrency}") 44 + 45 + walletsTable = None 46 + totalBtcAmount = 0 47 + totalFiatAmount = 0 48 + 49 + if exchangeRate: 50 + walletsTable = [['Name', 'Type', 'BTC Amount', 'Fiat Amount']] 51 + for wallet in wallets: 52 + btcAmount = wallet.get("btc-amount") 53 + totalBtcAmount += btcAmount 54 + 55 + if inputFormat == "sats": 56 + btcAmount = btcAmount/100000000 57 + 58 + fiatAmount = btcAmount*exchangeRate 59 + totalFiatAmount += fiatAmount 60 + 61 + walletsTable.append([wallet.get('name'), wallet.get('type'), f'{wallet.get('btc-amount')} {inputFormat}', f'{fiatAmount:.2f} {localCurrency}']) 62 + else: 63 + walletsTable = [['Name', 'Type', 'BTC Amount']] 64 + for wallet in wallets: 65 + walletsTable.append([wallet.get('name'), wallet.get('type'), f'{wallet.get('btc-amount')} {inputFormat}']) 66 + 67 + print() 68 + print(tabulate(walletsTable, headers = "firstrow")) 69 + print() 70 + print(f"Total amounts: {totalBtcAmount} {inputFormat} / {totalFiatAmount:.2f} {localCurrency}") 71 + 72 + if __name__ == "__main__": 73 + main()