this repo has no description
4
fork

Configure Feed

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

pds-upload thingy

dawn 9de84f0a 8654f779

+282 -13
+49
pkgs-set/pkgs/pds-upload.nix/default.nix
··· 1 + { lib 2 + , stdenvNoCC 3 + , makeWrapper 4 + , nushell 5 + , file 6 + , secretsFile ? null 7 + , ... 8 + }: 9 + 10 + stdenvNoCC.mkDerivation { 11 + pname = "pds-upload"; 12 + version = "0.1.0"; 13 + 14 + src = ./pds-upload.nu; 15 + 16 + nativeBuildInputs = [ makeWrapper ]; 17 + 18 + buildInputs = [ nushell ]; 19 + 20 + dontUnpack = true; 21 + dontBuild = true; 22 + 23 + installPhase = '' 24 + runHook preInstall 25 + 26 + mkdir -p $out/bin $out/libexec 27 + 28 + install -Dm755 $src $out/libexec/pds-upload.nu 29 + 30 + makeWrapper ${nushell}/bin/nu $out/bin/pds-upload \ 31 + --add-flags "$out/libexec/pds-upload.nu" \ 32 + --prefix PATH : ${lib.makeBinPath [ file ]} \ 33 + --run ${lib.escapeShellArg '' 34 + # Optional: Set secrets file from argument override 35 + ${lib.optionalString (secretsFile != null) '' 36 + export ATPROTO_SECRETS_FILE="${secretsFile}" 37 + ''} 38 + 39 + # Load secrets if the file exists (to populate ATPROTO_DID/PASSWORD) 40 + if [ -n "$ATPROTO_SECRETS_FILE" ] && [ -f "$ATPROTO_SECRETS_FILE" ]; then 41 + set -a 42 + source "$ATPROTO_SECRETS_FILE" 43 + set +a 44 + fi 45 + ''} 46 + 47 + runHook postInstall 48 + ''; 49 + }
+96
pkgs-set/pkgs/pds-upload.nix/pds-upload.nu
··· 1 + #!/usr/bin/env nu 2 + 3 + # A script to upload a blob and create a record in the AT Protocol (Bluesky). 4 + # Usage: nu pds-upload.nu <path-to-image> 5 + 6 + def main [ 7 + file_path: path # The path to the file you want to upload 8 + ] { 9 + # --- 1. Setup & Configuration --- 10 + let identifier = ($env.ATPROTO_DID? | default "") 11 + let password = ($env.ATPROTO_PASSWORD? | default "") 12 + 13 + # Default to the main network if not specified in env 14 + let pds_host = ($env.ATPROTO_PDS_URL? | default "https://bsky.social") 15 + 16 + # Validation 17 + if ($identifier | is-empty) or ($password | is-empty) { 18 + error make { 19 + msg: "Missing Credentials", 20 + label: { 21 + text: "Please set ATPROTO_DID and ATPROTO_PASSWORD environment variables.", 22 + span: (metadata $identifier).span 23 + } 24 + } 25 + } 26 + 27 + if not ($file_path | path exists) { 28 + error make { msg: $"File not found: ($file_path)" } 29 + } 30 + 31 + # Detect mime-type 32 + let mime_type = (try { 33 + ^file --mime-type -b $file_path | str trim 34 + } catch { 35 + "application/octet-stream" 36 + }) 37 + 38 + # --- 2. Create Session (Authentication) --- 39 + let session_res = (http post 40 + --content-type "application/json" 41 + $"($pds_host)/xrpc/com.atproto.server.createSession" 42 + { identifier: $identifier, password: $password } 43 + ) 44 + 45 + let access_token = $session_res.accessJwt 46 + let repo_did = $session_res.did 47 + 48 + # --- 3. Upload Blob --- 49 + let file_data = (open $file_path) 50 + 51 + let blob_res = (http post 52 + --content-type $mime_type 53 + --headers { Authorization: $"Bearer ($access_token)" } 54 + $"($pds_host)/xrpc/com.atproto.repo.uploadBlob" 55 + $file_data 56 + ) 57 + 58 + let blob_ref = $blob_res.blob 59 + 60 + # --- 4. Create Record --- 61 + let file_name = ($file_path | path basename) 62 + let now = (date now | format date "%Y-%m-%dT%H:%M:%SZ") 63 + 64 + let record_payload = { 65 + repo: $repo_did 66 + collection: "systems.gaze.file" 67 + record: { 68 + "$type": "systems.gaze.file" 69 + createdAt: $now 70 + file: $blob_ref 71 + filename: $file_name 72 + } 73 + } 74 + 75 + let record_res = (http post 76 + --content-type "application/json" 77 + --headers { Authorization: $"Bearer ($access_token)" } 78 + $"($pds_host)/xrpc/com.atproto.repo.createRecord" 79 + $record_payload 80 + ) 81 + 82 + # --- 5. Construct Return Value --- 83 + # We construct the public URL for the blob 84 + # The '$link' key requires special handling to extract 85 + let cid = ($blob_ref.ref | get '$link') 86 + let blob_url = $"($pds_host)/xrpc/com.atproto.sync.getBlob?did=($repo_did)&cid=($cid)" 87 + 88 + # Return a structured record with both the URI and the direct URL 89 + let result = { 90 + uri: $record_res.uri 91 + cid: $record_res.cid 92 + blob_url: $blob_url 93 + } | to json 94 + 95 + return $result 96 + }
+17
secrets/atfileCfg.age
··· 1 + age-encryption.org/v1 2 + -> ssh-rsa Abmvag 3 + cslEDLMgbmTeCxKXG4isYQdts8ET2tb4NSRgoHpk9g3jB3bEOlYdY7LZtZ8YLxJ0 4 + 78YD6v81ssVQzCOoD0MQKveEkDIAie9JlYYDQS0pv/ACP+E1fqbIRo5pE7t9s26x 5 + rBMZntIDx1vzGRM/+87Wz2NOPpNseP7P2CEIltMn3S5xbsl4N9WVx1mnH4NfsPCu 6 + VRh3APe/Ee/Ph0/wBK2wQWRG97dd+p1bY7nzkRYE26DpODez1f9kTlTppIyivJDc 7 + dIPMkykJOos/dwu6nR1XKS6l8f7Y+pQcYF24cqMe3PDQbhb19qwcpMiy0I11R2ik 8 + /yb8pRziazd01gJsSKUWz/WVhKx7A4dj9TQloWO1FXoIB/mPaxZBghQfP55oV6b9 9 + MGIxRcn/fekbCYNSxVo9WFyBsfg4vNzUcBlUInANrxU2mUS5YFpY7jf2iHGeGfRU 10 + ZQsgB/ftScvtoSdKJ3dW4fW/2MZ2qyzjcrvFvikL50fucXhhOGa4ToDy2e04TLpm 11 + fXlKHBgS+xYIgnjw/6P54SwMbgC1fGUq7mC7TVKZiA/AyDyZMxQvNIfx6MKlffDM 12 + ItU2mHjV2i23g3Nk9V6EmSxy/RCivVNZMWktLJrR+XYKGjhqjqObF83kE9vlzl1g 13 + 6hU80Ys0H8q0iCBnceLL1UlODByXczzRhiqrFetkmlc 14 + --- goQ5BSnSK0NTZ13BPhqmduMllp9tF8n4mNHEVvm1dA8 15 + ��?eO��X �=/@��c�fg�7  �ciG��ד`�,q(HT�rPs'Z��l����L�w@2"�?[�:��9��B�] �{+�����8%���%�w_vR���9�N 16 + Q�G�0 �Z�l�C��u 17 + �y���>J
+1 -5
secrets/secrets.nix
··· 2 2 yusdacra = builtins.readFile ./yusdacra.key.pub; 3 3 dzwonek = builtins.readFile ./dzwonek.key.pub; 4 4 trimounts = builtins.readFile ./trimounts.key.pub; 5 - develMobi = builtins.readFile ./develMobi.key.pub; 6 5 in 7 6 { 8 7 "nixGithubAccessToken.age".publicKeys = [ yusdacra ]; ··· 26 25 yusdacra 27 26 dzwonek 28 27 ]; 29 - "develMobiTailscaleAuthKey.age".publicKeys = [ 30 - yusdacra 31 - develMobi 32 - ]; 33 28 "cloudflareDnsEdit.age".publicKeys = [ 34 29 yusdacra 35 30 dzwonek ··· 40 35 dzwonek 41 36 trimounts 42 37 ]; 38 + "atfileCfg.age".publicKeys = [yusdacra]; 43 39 }
+14 -3
users/mayer/default.nix
··· 2 2 pkgs, 3 3 lib, 4 4 tlib, 5 - config, 6 5 terra, 7 6 ... 8 7 }@globalAttrs: ··· 98 97 99 98 home-manager.users.mayer = 100 99 { 100 + config, 101 101 pkgs, 102 102 inputs, 103 103 ... ··· 135 135 l.flatten [ 136 136 (tlib.prefixStrings "${inputs.self}/users/modules/" modulesToEnable) 137 137 ../modules/discord/service.nix 138 + "${inputs.agenix}/modules/age-home.nix" 138 139 ]; 139 140 140 141 home = { ··· 158 159 bs-manager 159 160 cemu 160 161 tor-browser 161 - supersonic-wayland 162 + # supersonic-wayland 162 163 feishin 163 - ]) ++ [terra.helium]; 164 + ]) ++ [ 165 + terra.helium 166 + (terra.pds-upload.override { 167 + secretsFile = config.age.secrets.atfileCfg.path; 168 + }) 169 + ]; 170 + }; 171 + 172 + age.secrets.atfileCfg = { 173 + file = ../../secrets/atfileCfg.age; 174 + mode = "600"; 164 175 }; 165 176 166 177 fonts.fontconfig.enable = l.mkForce true;
+6
users/modules/clipman/default.nix
··· 1 + { 2 + services.clipman = { 3 + enable = true; 4 + systemdTarget = "graphical-session.target"; 5 + }; 6 + }
+1 -1
users/modules/discord/service.nix
··· 8 8 9 9 Service = { 10 10 Type = "simple"; 11 - ExecStart = "${pkgs.openssh}/bin/ssh -N -D 127.0.0.1:1338 root@dzwonek"; 11 + ExecStart = "${pkgs.openssh}/bin/ssh -N -D 127.0.0.1:1338 root@trimounts"; 12 12 Restart = "on-failure"; 13 13 RestartSec = "3s"; 14 14 };
+21
users/modules/niri/clipboard.nu
··· 1 + #!/usr/bin/env nu 2 + 3 + def main [] { 4 + # Get clipboard history from clipman 5 + let history = clipman show-history 6 + 7 + if ($history | is-empty) { 8 + notify-send "Clipman" "No clipboard history" 9 + exit 1 10 + } 11 + 12 + # Show in tofi and get selection 13 + let selection = ($history | lines | tofi --prompt-text "select clipboard item: " | str trim) 14 + 15 + if ($selection | is-empty) { 16 + exit 0 17 + } 18 + 19 + # Copy selection to clipboard 20 + $selection | wl-copy 21 + }
+3
users/modules/niri/config.kdl
··· 179 179 XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+10%"; } 180 180 XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "10%-"; } 181 181 182 + Ctrl+Shift+U { spawn-sh "nu %%clipboard-upload%%"; } 183 + Ctrl+Shift+S { spawn-sh "nu %%clipboard-select%%"; } 184 + 182 185 Mod+O repeat=false { toggle-overview; } 183 186 Mod+Q cooldown-ms=50 { close-window; } 184 187
+4 -4
users/modules/niri/default.nix
··· 1 1 { 2 - config, 3 - nixosConfig, 4 2 pkgs, 5 3 lib, 6 - tlib, 7 4 ... 8 5 }: 9 6 let ··· 15 12 ../wlsunset 16 13 ../mako 17 14 ../tofi 15 + ../clipman 18 16 ]; 19 17 20 - home.packages = with pkgs; [niri xwayland-satellite brightnessctl swaybg]; 18 + home.packages = with pkgs; [file libnotify clipman niri xwayland-satellite brightnessctl swaybg]; 21 19 xdg.configFile."niri/config.kdl".text = 22 20 let 23 21 replace = { 24 22 wallpaper = toString ../../mayer/wallpaper.png; 23 + clipboard-upload = toString ./uploader.nu; 24 + clipboard-select = toString ./clipboard.nu; 25 25 }; 26 26 in 27 27 l.replaceStrings
+70
users/modules/niri/uploader.nu
··· 1 + #!/usr/bin/env nu 2 + 3 + def main [] { 4 + # --- 1. Get Clipboard Content --- 5 + let timestamp = (date now | format date '%Y%m%d_%H%M%S') 6 + let temp_file = $"/tmp/clip_($timestamp)" 7 + 8 + # Save clipboard to temp file 9 + # We remove --no-newline to safely handle binary data if necessary, 10 + # though wl-paste usually handles it. 11 + try { 12 + wl-paste | save -f $temp_file 13 + } catch { 14 + notify-send "Upload Failed" "Could not get content from clipboard" 15 + exit 1 16 + } 17 + 18 + # Detect MIME type just for logging/notification 19 + let mime_type = (try { 20 + ^file --mime-type -b $temp_file | str trim 21 + } catch { 22 + "application/octet-stream" 23 + }) 24 + 25 + print $"📤 Uploading ($mime_type)..." 26 + notify-send "ATProto Upload" $"Uploading ($mime_type)..." -t 2000 27 + 28 + try { 29 + # --- 2. Call pds-upload --- 30 + # pds-upload now returns: { uri, cid, blob_url } 31 + let res = pds-upload $temp_file | from json 32 + 33 + let record_uri = $res.uri 34 + let blob_url = $res.blob_url 35 + 36 + print $"🔗 Blob URL: ($blob_url)" 37 + print "✂️ Shortening with is.gd..." 38 + 39 + # --- 3. Shorten URL --- 40 + # is.gd expects the URL to be passed as a query parameter 'url' 41 + # We must URL-encode the blob_url 42 + let encoded_target = ($blob_url | url encode) 43 + let shorten_api = $"https://is.gd/create.php?format=simple&url=($encoded_target)" 44 + 45 + # is.gd returns the short URL as the body text 46 + let short_url = (http get $shorten_api) 47 + 48 + # --- 4. Success & Clipboard --- 49 + # Check if is.gd returned a URL (starts with http) or an error 50 + if ($short_url | str starts-with "http") { 51 + $short_url | wl-copy 52 + notify-send "ATProto Upload" $"Shortened: ($short_url)" 53 + print $"✅ Shortened: ($short_url)" 54 + } else { 55 + # Fallback to the long blob URL if shortening failed 56 + $blob_url | wl-copy 57 + notify-send "ATProto Upload" $"Uploaded (Shorten failed)" 58 + print $"⚠️ Shorten failed: ($short_url)" 59 + } 60 + 61 + } catch {|e| 62 + # Parse error for notification 63 + let err_msg = ($e | to text) 64 + notify-send "ATProto Upload" $"Upload failed: ($err_msg)" -u critical 65 + print $"❌ Upload failed: ($err_msg)" 66 + } 67 + 68 + # Cleanup 69 + rm -f $temp_file 70 + }