minisky 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a753ae5a6f7d2dd3089ee9b6a637e578051261c615fedd28a44f63ac1774b4d
4
- data.tar.gz: 479240c065cb3ba705aa4a9d07efa8c4904ec2aca2e6ed0e847d391ab8cd62fe
3
+ metadata.gz: b22e3b707a428f0381e5c194ce6b5bd4118f6b6dfb7f2d249140c8025e3b1dd7
4
+ data.tar.gz: 2a6370ea6cb538c680252836295c411ff4c6df93b8c5aab9d8b73b843753febb
5
5
  SHA512:
6
- metadata.gz: f87814325757d1b19cee4e403d6e13afbf84b1353b932eedbce23faa6cb1abfe772d0cf2c459b21bb45ea08fa34173457dea3fdb266f32f1f4334e2e90d22692
7
- data.tar.gz: c4bea17a09982db0462e15e092fdf43c454fd94163d04099b119104fde555387621c5c1b8d51e1a1247ad2cece0b5fd9258b1c98555b0ffb7eca4b96107dd83a
6
+ metadata.gz: 3f86def9480e86d2989a52f143eacee8e5b78fede45bd6ba49ea7ad54f1da88a55555421d3fdfdddad025bed21a708c830e5e9b2c351ba57e016234e200b9f74
7
+ data.tar.gz: f8f7faa8d7e5df7807d6e9bb7ee1b87d1d5ab5503c0193fd031190be6e6346004618c66efdba96970fc93117d4f587c53ff5f17585a2ffa3ddafb503abc5a3cc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.4.0] - 2024-03-31 🐣
2
+
3
+ * allow passing non-JSON body to requests (e.g. when uploading blobs)
4
+ * allow passing custom headers to requests, including overriding `Content-Type`
5
+ * fixed error when the response is success but not JSON (e.g. an empty body like in deleteRecord)
6
+ * allow passing options to the client in the initializer
7
+ * aliased `default_progress` setting as `progress`
8
+ * added `base64` dependency explicitly to the gemspec - fixes a warning in Ruby 3.3, since it will be extracted as an optional gem in 3.4
9
+
1
10
  ## [0.3.1] - 2023-10-10
2
11
 
3
12
  * fixed Minisky not working on Ruby 2.x
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Example: print 10 latest posts from the user's home feed.
4
+ #
5
+ # Instead of using a config file to read & store authentication info, this example uses a customized client class
6
+ # which reads the password from the console and creates a throwaway access token.
7
+ #
8
+ # This approach makes sense for one-off scripts, but it shouldn't be used for things that need to be done repeatedly
9
+ # and often (the authentication-related endpoints have lower rate limits than others).
10
+
11
+ # load minisky from a local folder - you normally won't need this
12
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
13
+
14
+ require 'io/console'
15
+ require 'minisky'
16
+
17
+ class TransientClient
18
+ include Minisky::Requests
19
+
20
+ attr_reader :config, :host
21
+
22
+ def initialize(host, user)
23
+ @host = host
24
+ @config = { 'id' => user.gsub(/^@/, '') }
25
+ end
26
+
27
+ def ask_for_password
28
+ print "Enter password for @#{config['id']}: "
29
+ @config['pass'] = STDIN.noecho(&:gets).chomp
30
+ puts
31
+ end
32
+
33
+ def save_config
34
+ # ignore
35
+ end
36
+ end
37
+
38
+ host, handle = ARGV
39
+
40
+ unless host && handle
41
+ puts "Usage: #{$PROGRAM_NAME} <pds_hostname> <handle>"
42
+ exit 1
43
+ end
44
+
45
+ # create a client instance & read password
46
+ bsky = TransientClient.new(host, handle)
47
+ bsky.ask_for_password
48
+
49
+ # fetch 10 posts from the user's home feed
50
+ result = bsky.get_request('app.bsky.feed.getTimeline', { limit: 10 })
51
+
52
+ result['feed'].each do |r|
53
+ reason = r['reason']
54
+ reply = r['reply']
55
+ post = r['post']
56
+
57
+ if reason && reason['$type'] == 'app.bsky.feed.defs#reasonRepost'
58
+ puts "[Reposted by @#{reason['by']['handle']}]"
59
+ end
60
+
61
+ handle = post['author']['handle']
62
+ timestamp = Time.parse(post['record']['createdAt']).getlocal
63
+
64
+ puts "@#{handle} • #{timestamp}"
65
+ puts
66
+
67
+ if reply
68
+ puts "[in reply to @#{reply['parent']['author']['handle']}]"
69
+ puts
70
+ end
71
+
72
+ puts post['record']['text']
73
+ puts
74
+ puts "=" * 120
75
+ puts
76
+ end
@@ -3,7 +3,7 @@ require 'yaml'
3
3
  class Minisky
4
4
  attr_reader :host, :config
5
5
 
6
- def initialize(host, config_file)
6
+ def initialize(host, config_file, options = {})
7
7
  @host = host
8
8
  @config_file = config_file
9
9
 
@@ -18,6 +18,12 @@ class Minisky
18
18
  @send_auth_headers = false
19
19
  @auto_manage_tokens = false
20
20
  end
21
+
22
+ if options
23
+ options.each do |k, v|
24
+ self.send("#{k}=", v)
25
+ end
26
+ end
21
27
  end
22
28
 
23
29
  def save_config
@@ -39,6 +39,9 @@ class Minisky
39
39
  instance_variable_defined?('@auto_manage_tokens') ? @auto_manage_tokens : true
40
40
  end
41
41
 
42
+ alias progress default_progress
43
+ alias progress= default_progress=
44
+
42
45
  def base_url
43
46
  @base_url ||= "https://#{host}/xrpc"
44
47
  end
@@ -47,10 +50,10 @@ class Minisky
47
50
  @user ||= User.new(config)
48
51
  end
49
52
 
50
- def get_request(method, params = nil, auth: default_auth_mode)
53
+ def get_request(method, params = nil, auth: default_auth_mode, headers: nil)
51
54
  check_access if auto_manage_tokens && auth == true
52
55
 
53
- headers = authentication_header(auth)
56
+ headers = authentication_header(auth).merge(headers || {})
54
57
  url = URI("#{base_url}/#{method}")
55
58
 
56
59
  if params && !params.empty?
@@ -63,18 +66,24 @@ class Minisky
63
66
  handle_response(response)
64
67
  end
65
68
 
66
- def post_request(method, params = nil, auth: default_auth_mode)
69
+ def post_request(method, params = nil, auth: default_auth_mode, headers: nil)
67
70
  check_access if auto_manage_tokens && auth == true
68
71
 
69
- headers = authentication_header(auth).merge({ "Content-Type" => "application/json" })
70
- body = params ? params.to_json : ''
72
+ headers = authentication_header(auth).merge(headers || {})
73
+ headers["Content-Type"] = "application/json" unless headers.keys.any? { |k| k.to_s.downcase == 'content-type' }
74
+
75
+ body = if params.is_a?(String) || params.nil?
76
+ params.to_s
77
+ else
78
+ params.to_json
79
+ end
71
80
 
72
81
  response = Net::HTTP.post(URI("#{base_url}/#{method}"), body, headers)
73
82
  handle_response(response)
74
83
  end
75
84
 
76
85
  def fetch_all(method, params = nil, field:,
77
- auth: default_auth_mode, break_when: nil, max_pages: nil, progress: @default_progress)
86
+ auth: default_auth_mode, break_when: nil, max_pages: nil, headers: nil, progress: @default_progress)
78
87
  data = []
79
88
  params = {} if params.nil?
80
89
  pages = 0
@@ -82,7 +91,7 @@ class Minisky
82
91
  loop do
83
92
  print(progress) if progress
84
93
 
85
- response = get_request(method, params, auth: auth)
94
+ response = get_request(method, params, auth: auth, headers: headers)
86
95
  records = response[field]
87
96
  cursor = response['cursor']
88
97
 
@@ -152,14 +161,14 @@ class Minisky
152
161
  alias_method :do_post_request, :post_request
153
162
  private :do_get_request, :do_post_request
154
163
 
155
- def get_request(method, params = nil, auth: default_auth_mode, **kwargs)
164
+ def get_request(method, params = nil, auth: default_auth_mode, headers: nil, **kwargs)
156
165
  params ||= kwargs unless kwargs.empty?
157
- do_get_request(method, params, auth: auth)
166
+ do_get_request(method, params, auth: auth, headers: headers)
158
167
  end
159
168
 
160
- def post_request(method, params = nil, auth: default_auth_mode, **kwargs)
169
+ def post_request(method, params = nil, auth: default_auth_mode, headers: nil, **kwargs)
161
170
  params ||= kwargs unless kwargs.empty?
162
- do_post_request(method, params, auth: auth)
171
+ do_post_request(method, params, auth: auth, headers: headers)
163
172
  end
164
173
  end
165
174
 
@@ -210,16 +219,15 @@ class Minisky
210
219
  def handle_response(response)
211
220
  status = response.code.to_i
212
221
  message = response.message
222
+ response_body = (response.content_type == 'application/json') ? JSON.parse(response.body) : response.body
213
223
 
214
224
  case response
215
225
  when Net::HTTPSuccess
216
- JSON.parse(response.body)
226
+ response_body
217
227
  when Net::HTTPRedirection
218
228
  raise UnexpectedRedirect.new(status, message, response['location'])
219
229
  else
220
- data = (response.content_type == 'application/json') ? JSON.parse(response.body) : response.body
221
-
222
- error_class = if data.is_a?(Hash) && data['error'] == 'ExpiredToken'
230
+ error_class = if response_body.is_a?(Hash) && response_body['error'] == 'ExpiredToken'
223
231
  ExpiredTokenError
224
232
  elsif response.is_a?(Net::HTTPClientError)
225
233
  ClientErrorResponse
@@ -229,7 +237,7 @@ class Minisky
229
237
  BadResponse
230
238
  end
231
239
 
232
- raise error_class.new(status, message, data)
240
+ raise error_class.new(status, message, response_body)
233
241
  end
234
242
  end
235
243
  end
@@ -1,5 +1,5 @@
1
1
  require_relative 'minisky'
2
2
 
3
3
  class Minisky
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minisky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuba Suder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
13
27
  description: A very simple client class that lets you log in to the Bluesky API and
14
28
  make any requests there.
15
29
  email:
@@ -21,6 +35,7 @@ files:
21
35
  - CHANGELOG.md
22
36
  - LICENSE.txt
23
37
  - README.md
38
+ - example/ask_password.rb
24
39
  - example/fetch_my_posts.rb
25
40
  - example/fetch_profile.rb
26
41
  - example/post_skeet.rb