~aleteoryx/tclfeed-bsky

ref: 951aa944b42e9c60684dae9e7355486582f1cff6 tclfeed-bsky/bin/importlist.tcl -rwxr-xr-x 3.0 KiB
951aa944Aleteoryx add lists, make blocker prettier 28 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/bin/env tclsh

if {$argc < 2} { return -code error "Usage: bin/importlist.tcl DB ?-pds PDS? ?-feed FEED? LIST ?LIST ...?\n-feed may be passed repeatedly." }

cd [file dirname [file dirname [dict get [info frame [info frame]] file]]]

package require sqlite3
package require json
package require http
package require tls
::http::register https 443 ::tls::socket

set lists [lassign $argv db]
sqlite3 db $db

set pds "bsky.social"
if {[lindex $lists 0] == "-pds"} {
  set lists [lassign $lists _ pds]
}

set block 1
while {[lindex $lists 0] == "-feed"} {
  set block 0
  set lists [lassign $lists _ feed]
  lappend feeds $feed
}

if ![info exists feeds] {
  set feeds [db eval {SELECT name FROM sqlite_master WHERE type = 'table' AND sql LIKE '%uri TEXT%'}]
}

set count 0
set newcount 0

set reqcount 0

foreach list $lists {
  switch -regexp -matchvar matches -- $list {
    {^at://.+} {}
    {^(?:(?:(?:(?:(?:https://)?bsky.app)?/)?profile)?/)?([^/]+)/lists/(.+)$} {
      lassign $matches _ pub rkey

      set endpoint "https://$pds/xrpc/com.atproto.repo.describeRepo"

      set http_state [http::geturl "$endpoint?repo=$pub"]
      if {[::http::ncode $http_state] != 200} { return -code error "couldn't resolve handle $repo!\n[::http::data $http_state]" }
      set pub [dict get [::json::json2dict [::http::data $http_state]] did]


      set list "at://$pub/app.bsky.graph.list/$rkey"
    }
    default {
      return -code error "unknown list URI format $list!"
    }
  }

  set endpoint "https://public.api.bsky.app/xrpc/app.bsky.graph.getList"

  set http_state [http::geturl "$endpoint?list=$list"]
  if {[::http::ncode $http_state] != 200} { return -code error "couldn't resolve list $list!\n[::http::data $http_state]" }
  set data [::json::json2dict [::http::data $http_state]]
  set items [dict get $data items]

  while {[llength $items]} {
    foreach item $items {
      incr count
      set repo [dict get $item subject did]

      set seen [db eval {SELECT count(*) FROM blocked_repos WHERE repo = :repo;}]

      if {!$seen} {
        incr newcount
        if {$block} {
          puts "Blocking $repo ($list)."
          db eval {INSERT OR IGNORE INTO blocked_repos VALUES (:repo);}
        } else {
          incr newcount
          puts "Removing $repo ($list) from feeds."
        }
      } else {
      }


      set repo_pat "%${repo}%"
      foreach table $feeds {
        db eval "DELETE FROM $table WHERE uri LIKE :repo_pat;"
      }
    }

    if ![dict exists $data cursor] {
      break
    }

    incr reqcount
    puts -nonewline "importing $list [string index {/-\|} [expr {$reqcount % 4}]]\r"
    flush stdout

    set cursor [dict get $data cursor]

    set http_state [http::geturl "$endpoint?list=$list&cursor=$cursor"]
    if {[::http::ncode $http_state] != 200} { return -code error "couldn't read list $list at pos $cursor!\n[::http::data $http_state]" }
    set data [::json::json2dict [::http::data $http_state]]
    set items [dict get $data items]
  }
}

puts "\33\[2K\r$count accounts ($newcount new) blocked from [llength $lists] lists."