๐Ÿ“ฆโž”๐Ÿฆ‹ Store and retrieve files on the ATmosphere

replace complex at:// handler with PDSls

Changed files
+113 -272
src
+105
src/commands/handle.sh
··· 1 + #!/usr/bin/env bash 2 + 3 + function atfile.handle() { 4 + uri="$1" 5 + handler="$2" 6 + 7 + function atfile.handle.is_temp_file_needed() { 8 + handler="${1//.desktop/}" 9 + type="$2" 10 + 11 + handlers=( 12 + "app.drey.EarTag" 13 + "com.github.neithern.g4music" 14 + ) 15 + 16 + if [[ ${handlers[*]} =~ $handler ]]; then 17 + echo 1 18 + elif [[ $type == "text/"* ]]; then 19 + echo 1 20 + else 21 + echo 0 22 + fi 23 + } 24 + 25 + [[ $_output_json == 1 ]] && atfile.die "Command not available as JSON" 26 + 27 + actor="$(echo "$uri" | cut -d "/" -f 3)" 28 + key="$(echo "$uri" | cut -d "/" -f 4)" 29 + 30 + atfile.util.create_dir "$_path_blobs_tmp" 31 + 32 + if [[ -n "$actor" && -n "$key" ]]; then 33 + atfile.util.override_actor "$actor" 34 + 35 + atfile.say.debug "Getting record...\nโ†ณ NSID: $_nsid_upload\nโ†ณ Repo: $_username\nโ†ณ Key: $key" 36 + record="$(com.atproto.repo.getRecord "$_username" "$_nsid_upload" "$key")" 37 + error="$(atfile.util.get_xrpc_error $? "$record")" 38 + [[ -n "$error" ]] && atfile.die.gui.xrpc_error "Unable to get '$key'" "$error" 39 + 40 + blob_cid="$(echo "$record" | jq -r ".value.blob.ref.\"\$link\"")" 41 + blob_uri="$(atfile.util.build_blob_uri "$_username" "$blob_cid")" 42 + file_type="$(echo "$record" | jq -r '.value.file.mimeType')" 43 + 44 + if [[ $_os == "linux"* ]] && \ 45 + [ -x "$(command -v xdg-mime)" ] && \ 46 + [ -x "$(command -v xdg-open)" ] && \ 47 + [ -x "$(command -v gtk-launch)" ]; then 48 + 49 + # HACK: Open with browser if $file_type isn't set 50 + [[ -z $file_type ]] && file_type="text/html" 51 + 52 + if [[ -z $handler ]]; then 53 + atfile.say.debug "Querying for handler '$file_type'..." 54 + handler="$(xdg-mime query default "$file_type")" 55 + else 56 + handler="$handler.desktop" 57 + atfile.say.debug "Handler manually set to '$handler'" 58 + fi 59 + 60 + # shellcheck disable=SC2319 61 + # shellcheck disable=SC2181 62 + if [[ -n $handler ]] || [[ $? != 0 ]]; then 63 + atfile.say.debug "Opening '$key' ($file_type) with '${handler//.desktop/}'..." 64 + 65 + # HACK: Some apps don't like http(s)://; we'll need to handle these 66 + if [[ $(atfile.handle.is_temp_file_needed "$handler" "$file_type") == 1 ]]; then 67 + atfile.say.debug "Unsupported for streaming" 68 + 69 + download_success=1 70 + # shellcheck disable=SC2154 71 + tmp_path="$_path_blobs_tmp/$blob_cid" 72 + 73 + if ! [[ -f "$tmp_path" ]]; then 74 + atfile.say.debug "Downloading '$blob_cid'..." 75 + atfile.http.download "$blob_uri" "$tmp_path" 76 + [[ $? != 0 ]] && download_success=0 77 + else 78 + atfile.say.debug "Blob '$blob_cid' already exists" 79 + fi 80 + 81 + if [[ $download_success == 1 ]]; then 82 + atfile.say.debug "Launching '$handler'..." 83 + gtk-launch "$handler" "$tmp_path" </dev/null &>/dev/null & 84 + else 85 + atfile.die.gui \ 86 + "Unable to download '$key'" 87 + fi 88 + else 89 + atfile.say.debug "Launching '$handler'..." 90 + gtk-launch "$handler" "$blob_uri" </dev/null &>/dev/null & 91 + fi 92 + else 93 + atfile.say.debug "No handler for '$file_type'. Launching URI..." 94 + atfile.util.launch_uri "$blob_uri" 95 + fi 96 + else 97 + atfile.say.debug "Relevant tools not installed. Launching URI..." 98 + atfile.util.launch_uri "$blob_uri" 99 + fi 100 + else 101 + atfile.die.gui \ 102 + "Invalid ATFile URI\nโ†ณ Must be 'atfile://<actor>/<key>'" \ 103 + "Invalid ATFile URI" 104 + fi 105 + }
+1 -2
src/commands/help.sh
··· 75 75 bsky [<actor>] 76 76 Get Bluesky profile for <actor>\n 77 77 handle <at-uri> 78 - Open at:// URI with relevant App\n 78 + Open at:// URI with PDSls\n 79 79 handle <atfile-uri> [<handler>] 80 80 Open atfile:// URI with relevant App 81 81 โ„น๏ธ Set <handler> to a .desktop entry (with '.desktop') to force the ··· 191 191 192 192 Usage 193 193 $_prog <command> [<arguments>] 194 - $_prog at://<actor>[/<collection>/<rkey>] 195 194 $_prog atfile://<actor>/<key>\n\n" 196 195 197 196 [[ $ATFILE_DEVEL == 1 ]] && usage+="$usage_commands_devel\n\n"
-128
src/commands/old_cmds.sh
··· 289 289 fi 290 290 } 291 291 292 - function atfile.invoke.handle_atfile() { 293 - uri="$1" 294 - handler="$2" 295 - 296 - function atfile.invoke.handle_atfile.is_temp_file_needed() { 297 - handler="${1//.desktop/}" 298 - type="$2" 299 - 300 - handlers=( 301 - "app.drey.EarTag" 302 - "com.github.neithern.g4music" 303 - ) 304 - 305 - if [[ ${handlers[*]} =~ $handler ]]; then 306 - echo 1 307 - elif [[ $type == "text/"* ]]; then 308 - echo 1 309 - else 310 - echo 0 311 - fi 312 - } 313 - 314 - [[ $_output_json == 1 ]] && atfile.die "Command not available as JSON" 315 - 316 - actor="$(echo "$uri" | cut -d "/" -f 3)" 317 - key="$(echo "$uri" | cut -d "/" -f 4)" 318 - 319 - atfile.util.create_dir "$_path_blobs_tmp" 320 - 321 - if [[ -n "$actor" && -n "$key" ]]; then 322 - atfile.util.override_actor "$actor" 323 - 324 - atfile.say.debug "Getting record...\nโ†ณ NSID: $_nsid_upload\nโ†ณ Repo: $_username\nโ†ณ Key: $key" 325 - record="$(com.atproto.repo.getRecord "$_username" "$_nsid_upload" "$key")" 326 - error="$(atfile.util.get_xrpc_error $? "$record")" 327 - [[ -n "$error" ]] && atfile.die.gui.xrpc_error "Unable to get '$key'" "$error" 328 - 329 - blob_cid="$(echo "$record" | jq -r ".value.blob.ref.\"\$link\"")" 330 - blob_uri="$(atfile.util.build_blob_uri "$_username" "$blob_cid")" 331 - file_type="$(echo "$record" | jq -r '.value.file.mimeType')" 332 - 333 - if [[ $_os == "linux"* ]] && \ 334 - [ -x "$(command -v xdg-mime)" ] && \ 335 - [ -x "$(command -v xdg-open)" ] && \ 336 - [ -x "$(command -v gtk-launch)" ]; then 337 - 338 - # HACK: Open with browser if $file_type isn't set 339 - [[ -z $file_type ]] && file_type="text/html" 340 - 341 - if [[ -z $handler ]]; then 342 - atfile.say.debug "Querying for handler '$file_type'..." 343 - handler="$(xdg-mime query default "$file_type")" 344 - else 345 - handler="$handler.desktop" 346 - atfile.say.debug "Handler manually set to '$handler'" 347 - fi 348 - 349 - # shellcheck disable=SC2319 350 - # shellcheck disable=SC2181 351 - if [[ -n $handler ]] || [[ $? != 0 ]]; then 352 - atfile.say.debug "Opening '$key' ($file_type) with '${handler//.desktop/}'..." 353 - 354 - # HACK: Some apps don't like http(s)://; we'll need to handle these 355 - if [[ $(atfile.invoke.handle_atfile.is_temp_file_needed "$handler" "$file_type") == 1 ]]; then 356 - atfile.say.debug "Unsupported for streaming" 357 - 358 - download_success=1 359 - # shellcheck disable=SC2154 360 - tmp_path="$_path_blobs_tmp/$blob_cid" 361 - 362 - if ! [[ -f "$tmp_path" ]]; then 363 - atfile.say.debug "Downloading '$blob_cid'..." 364 - atfile.http.download "$blob_uri" "$tmp_path" 365 - [[ $? != 0 ]] && download_success=0 366 - else 367 - atfile.say.debug "Blob '$blob_cid' already exists" 368 - fi 369 - 370 - if [[ $download_success == 1 ]]; then 371 - atfile.say.debug "Launching '$handler'..." 372 - gtk-launch "$handler" "$tmp_path" </dev/null &>/dev/null & 373 - else 374 - atfile.die.gui \ 375 - "Unable to download '$key'" 376 - fi 377 - else 378 - atfile.say.debug "Launching '$handler'..." 379 - gtk-launch "$handler" "$blob_uri" </dev/null &>/dev/null & 380 - fi 381 - else 382 - atfile.say.debug "No handler for '$file_type'. Launching URI..." 383 - atfile.util.launch_uri "$blob_uri" 384 - fi 385 - else 386 - atfile.say.debug "Relevant tools not installed. Launching URI..." 387 - atfile.util.launch_uri "$blob_uri" 388 - fi 389 - else 390 - atfile.die.gui \ 391 - "Invalid ATFile URI\nโ†ณ Must be 'atfile://<actor>/<key>'" \ 392 - "Invalid ATFile URI" 393 - fi 394 - } 395 - 396 - function atfile.invoke.handle_aturi() { 397 - uri="$1" 398 - 399 - [[ $_output_json == 1 ]] && atfile.die "Command not available as JSON" 400 - [[ "$uri" != "at://"* ]] && atfile.die.gui \ 401 - "Invalid AT URI\nโ†ณ Must be 'at://<actor>[/<collection>/<rkey>]'" \ 402 - "Invalid AT URI" 403 - 404 - atfile.say.debug "Resolving '$uri'..." 405 - app_uri="$(atfile.util.get_app_url_for_at_uri "$uri")" 406 - [[ -z "$app_uri" ]] && atfile.die.gui \ 407 - "Unable to resolve AT URI to App" 408 - 409 - app_proto="$(echo "$app_uri" | cut -d ":" -f 1)" 410 - 411 - atfile.say.debug "Opening '$app_uri' ($app_proto)..." 412 - 413 - if [[ $app_proto == "atfile" ]]; then 414 - atfile.invoke.handle_atfile "$app_uri" 415 - else 416 - atfile.util.launch_uri "$app_uri" 417 - fi 418 - } 419 - 420 292 function atfile.invoke.list() { 421 293 cursor="$1" 422 294 unset error
+7 -15
src/shared/invoke.sh
··· 68 68 uri="${args[0]}" 69 69 protocol="$(atfile.util.get_uri_segment "$uri" protocol)" 70 70 71 - if [[ $protocol == "https" ]]; then 72 - http_uri="$uri" 73 - uri="$(atfile.util.map_http_to_at "$http_uri")" 74 - 75 - atfile.say.debug "Mapping '$http_uri'..." 76 - 77 - if [[ -z "$uri" ]]; then 78 - atfile.die "Unable to map '$http_uri' to at:// URI" 79 - else 80 - protocol="$(atfile.util.get_uri_segment "$uri" protocol)" 81 - fi 82 - fi 83 - 84 71 atfile.say.debug "Handling protocol '$protocol://'..." 85 72 86 73 case $protocol in 87 - "at") atfile.invoke.handle_aturi "$uri" ;; 88 - "atfile") atfile.invoke.handle_atfile "$uri" "${args[1]}" ;; 74 + "at") 75 + atfile.say.debug "Launching '$uri' in PDSls..." 76 + atfile.util.launch_uri "https://pdsls.dev/$uri" 77 + ;; 78 + "atfile") 79 + atfile.handle "$uri" "${args[1]}" 80 + ;; 89 81 esac 90 82 ;; 91 83 "help")
-127
src/shared/util.sh
··· 86 86 printf "%'d\n" "$1" 87 87 } 88 88 89 - # TODO: Check if record actually exists 90 - function atfile.util.get_app_url_for_at_uri() { 91 - uri="$1" 92 - 93 - actor="$(echo "$uri" | cut -d / -f 3)" 94 - collection="$(echo "$uri" | cut -d / -f 4)" 95 - rkey="$(echo "$uri" | cut -d / -f 5)" 96 - 97 - ignore_url_validation=0 98 - resolved_actor="$(atfile.util.resolve_identity "$actor")" 99 - error="$(atfile.util.get_xrpc_error $? "$resolved_actor")" 100 - [[ -n "$error" ]] && atfile.die.xrpc_error "Unable to resolve '$actor'" "$resolved_actor" 101 - 102 - unset actor_handle 103 - unset actor_pds 104 - unset resolved_url 105 - 106 - # shellcheck disable=SC2181 107 - if [[ $? == 0 ]]; then 108 - actor="$(echo "$resolved_actor" | cut -d "|" -f 1)" 109 - actor_handle="$(echo "$resolved_actor" | cut -d "|" -f 3 | cut -d "/" -f 3)" 110 - actor_pds="$(echo "$resolved_actor" | cut -d "|" -f 2)" 111 - else 112 - unset actor 113 - fi 114 - 115 - [[ -z "$rkey" ]] && rkey="self" 116 - 117 - if [[ -n "$actor" && -n "$collection" && -n "$rkey" ]]; then 118 - case "$collection" in 119 - "app.bsky.actor.profile") resolved_url="$_endpoint_social_app/profile/$actor" ;; 120 - "app.bsky.feed.generator") resolved_url="$_endpoint_social_app/profile/$actor/feed/$rkey" ;; 121 - "app.bsky.graph.list") resolved_url="$_endpoint_social_app/profile/$actor/lists/$rkey" ;; 122 - "app.bsky.graph.starterpack") resolved_url="$_endpoint_social_app/starter-pack/$actor/$rkey" ;; 123 - "app.bsky.feed.post") resolved_url="$_endpoint_social_app/profile/$actor/post/$rkey" ;; 124 - "blue.linkat.board") resolved_url="https://linkat.blue/$actor_handle" ;; 125 - "blue.zio.atfile.upload") ignore_url_validation=1 && resolved_url="atfile://$actor/$rkey" ;; 126 - "chat.bsky.actor.declaration") resolved_url="$_endpoint_social_app/messages/settings" ;; 127 - "com.shinolabs.pinksea.oekaki") resolved_url="https://pinksea.art/$actor/oekaki/$rkey" ;; 128 - "com.whtwnd.blog.entry") resolved_url="https://whtwnd.com/$actor/$rkey" ;; 129 - "events.smokesignal.app.profile") resolved_url="https://smokesignal.events/$actor" ;; 130 - "events.smokesignal.calendar.event") resolved_url="https://smokesignal.events/$actor/$rkey" ;; 131 - "fyi.unravel.frontpage.post") resolved_url="https://frontpage.fyi/post/$actor/$rkey" ;; 132 - "link.pastesphere.snippet") resolved_url="https://pastesphere.link/user/$actor/snippet/$rkey" ;; 133 - "app.bsky.feed.like"| \ 134 - "app.bsky.feed.postgate"| \ 135 - "app.bsky.feed.repost"| \ 136 - "app.bsky.feed.threadgate"| \ 137 - "app.bsky.graph.follow"| \ 138 - "app.bsky.graph.listblock"| \ 139 - "app.bsky.graph.listitem"| \ 140 - "events.smokesignal.calendar.rsvp"| \ 141 - "fyi.unravel.frontpage.comment"| \ 142 - "fyi.unravel.frontpage.vote") 143 - record="$(atfile.xrpc.pds.get "com.atproto.repo.getRecord" "repo=$actor&collection=$collection&rkey=$rkey" "" "$actor_pds")" 144 - 145 - if [[ -z "$(atfile.util.get_xrpc_error $? "$record")" ]]; then 146 - case "$collection" in 147 - "app.bsky.feed.like") 148 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.subject.uri')")" ;; 149 - "app.bsky.feed.postgate") 150 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.post')")" ;; 151 - "app.bsky.feed.repost") 152 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.subject.uri')")" ;; 153 - "app.bsky.feed.threadgate") 154 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.post')")" ;; 155 - "app.bsky.graph.follow") 156 - resolved_url="$_endpoint_social_app/profile/$(echo "$record" | jq -r '.value.subject')" ;; 157 - "app.bsky.graph.listblock") 158 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.subject')")" ;; 159 - "app.bsky.graph.listitem") 160 - resolved_url="$_endpoint_social_app/profile/$(echo "$record" | jq -r '.value.subject')" ;; 161 - "events.smokesignal.calendar.rsvp") 162 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.subject.uri')")" ;; 163 - "fyi.unravel.frontpage.comment") 164 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.post.uri')")/$actor/$rkey" ;; 165 - "fyi.unravel.frontpage.vote") 166 - resolved_url="$(atfile.util.get_app_url_for_at_uri "$(echo "$record" | jq -r '.value.subject.uri')")" ;; 167 - esac 168 - fi 169 - ;; 170 - esac 171 - elif [[ -n "$actor" ]]; then 172 - resolved_url="https://pdsls.dev/at://$actor" 173 - fi 174 - 175 - if [[ -n "$resolved_url" && $ignore_url_validation == 0 ]]; then 176 - if [[ $(atfile.util.is_url_okay "$resolved_url") == 0 ]]; then 177 - unset resolved_url 178 - fi 179 - fi 180 - 181 - echo "$resolved_url" 182 - } 183 - 184 89 function atfile.util.get_cache_path() { 185 90 # shellcheck disable=SC2154 186 91 mkdir -fp "$_path_cache" ··· 941 846 "protocol") echo "$uri" | cut -d ":" -f 1 ;; 942 847 *) echo "$uri" | cut -d "/" -f "$segment" ;; 943 848 esac 944 - } 945 - 946 - function atfile.util.map_http_to_at() { 947 - http_uri="$1" 948 - unset at_uri 949 - unset actor 950 - unset collection 951 - unset rkey 952 - 953 - case "$(atfile.util.get_uri_segment "$http_uri" host)" in 954 - "atproto-browser.vercel.app"|\ 955 - "pdsls.dev"|\ 956 - "pdsls.pages.dev") 957 - actor="$(atfile.util.get_uri_segment "$http_uri" 6)" 958 - collection="$(atfile.util.get_uri_segment "$http_uri" 7)" 959 - rkey="$(atfile.util.get_uri_segment "$http_uri" 8)" 960 - ;; 961 - esac 962 - 963 - if [[ -n "$actor" ]]; then 964 - at_uri="at://$actor" 965 - 966 - if [[ -n "$collection" ]]; then 967 - at_uri="$at_uri/$collection" 968 - 969 - if [[ -n "$rkey" ]]; then 970 - at_uri="$at_uri/$rkey" 971 - fi 972 - fi 973 - fi 974 - 975 - echo "$at_uri" 976 849 } 977 850 978 851 # HACK: This essentially breaks the entire session (it overrides $_username and