todon-api 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/mastodon/access_token.rb +21 -0
- data/lib/mastodon/account.rb +73 -0
- data/lib/mastodon/app.rb +17 -0
- data/lib/mastodon/base.rb +50 -0
- data/lib/mastodon/card.rb +41 -0
- data/lib/mastodon/client.rb +28 -0
- data/lib/mastodon/collection.rb +27 -0
- data/lib/mastodon/conversation.rb +25 -0
- data/lib/mastodon/emoji.rb +21 -0
- data/lib/mastodon/entities/app.rb +12 -0
- data/lib/mastodon/entities/hashtag.rb +12 -0
- data/lib/mastodon/entities/media.rb +28 -0
- data/lib/mastodon/entities/mention.rb +14 -0
- data/lib/mastodon/error.rb +34 -0
- data/lib/mastodon/field.rb +18 -0
- data/lib/mastodon/filter.rb +29 -0
- data/lib/mastodon/hashtag.rb +19 -0
- data/lib/mastodon/headers.rb +17 -0
- data/lib/mastodon/instance.rb +33 -0
- data/lib/mastodon/list.rb +15 -0
- data/lib/mastodon/media.rb +34 -0
- data/lib/mastodon/notification.rb +30 -0
- data/lib/mastodon/relationship.rb +41 -0
- data/lib/mastodon/rest/accounts.rb +87 -0
- data/lib/mastodon/rest/api.rb +45 -0
- data/lib/mastodon/rest/apps.rb +27 -0
- data/lib/mastodon/rest/client.rb +10 -0
- data/lib/mastodon/rest/conversations.rb +34 -0
- data/lib/mastodon/rest/custom_emojis.rb +16 -0
- data/lib/mastodon/rest/domain_blocks.rb +32 -0
- data/lib/mastodon/rest/endorsements.rb +36 -0
- data/lib/mastodon/rest/filters.rb +61 -0
- data/lib/mastodon/rest/instances.rb +28 -0
- data/lib/mastodon/rest/lists.rb +77 -0
- data/lib/mastodon/rest/media.rb +31 -0
- data/lib/mastodon/rest/notifications.rb +34 -0
- data/lib/mastodon/rest/relationships.rb +126 -0
- data/lib/mastodon/rest/reports.rb +20 -0
- data/lib/mastodon/rest/request.rb +41 -0
- data/lib/mastodon/rest/scheduled_statuses.rb +43 -0
- data/lib/mastodon/rest/search.rb +20 -0
- data/lib/mastodon/rest/statuses.rb +124 -0
- data/lib/mastodon/rest/suggestions.rb +27 -0
- data/lib/mastodon/rest/timelines.rb +60 -0
- data/lib/mastodon/rest/utils.rb +40 -0
- data/lib/mastodon/results.rb +18 -0
- data/lib/mastodon/scheduled_status.rb +25 -0
- data/lib/mastodon/status.rb +96 -0
- data/lib/mastodon/streaming/client.rb +97 -0
- data/lib/mastodon/streaming/connection.rb +44 -0
- data/lib/mastodon/streaming/events/filters_change.rb +7 -0
- data/lib/mastodon/streaming/events/status_delete.rb +16 -0
- data/lib/mastodon/streaming/message_parser.rb +23 -0
- data/lib/mastodon/streaming/response.rb +43 -0
- data/lib/mastodon/version.rb +29 -0
- data/lib/mastodon.rb +6 -0
- data/mastodon.gemspec +23 -0
- metadata +175 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'http'
|
3
|
+
require 'oj'
|
4
|
+
require 'mastodon/error'
|
5
|
+
require 'mastodon/headers'
|
6
|
+
|
7
|
+
module Mastodon
|
8
|
+
module REST
|
9
|
+
class Request
|
10
|
+
def initialize(client, request_method, path, options = {})
|
11
|
+
@client = client
|
12
|
+
@request_method = request_method
|
13
|
+
@uri = Addressable::URI.parse(@client.base_url + path)
|
14
|
+
@headers = Mastodon::Headers.new(@client).request_headers
|
15
|
+
@path = @uri.path
|
16
|
+
@options = options
|
17
|
+
@headers = @options.delete(:headers).merge @headers if @options.is_a?(Hash) && @options[:headers]
|
18
|
+
end
|
19
|
+
|
20
|
+
def perform
|
21
|
+
options_key = @request_method == :get ? :params : :form
|
22
|
+
response = http_client.headers(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
|
23
|
+
|
24
|
+
STDERR.puts response.body if ENV['DEBUG'] == 'true'
|
25
|
+
|
26
|
+
fail_or_return(response.code, response.body.empty? ? '' : Oj.load(response.to_s, mode: :null))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def fail_or_return(code, body)
|
32
|
+
raise Mastodon::Error::ERRORS[code].from_response(body) if Mastodon::Error::ERRORS.include?(code)
|
33
|
+
body
|
34
|
+
end
|
35
|
+
|
36
|
+
def http_client
|
37
|
+
HTTP.timeout(connect: @client.timeout[:connect], read: @client.timeout[:read], write: @client.timeout[:write])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mastodon/rest/utils'
|
2
|
+
require 'mastodon/scheduled_status'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module REST
|
6
|
+
module ScheduledStatuses
|
7
|
+
include Mastodon::REST::Utils
|
8
|
+
|
9
|
+
# Get a list of scheduled statuses
|
10
|
+
# @param options [Hash]
|
11
|
+
# @option options :max_id [Integer]
|
12
|
+
# @option options :since_id [Integer]
|
13
|
+
# @option options :min_id [Integer]
|
14
|
+
# @option options :limit [Integer]
|
15
|
+
# @return [Mastodon::Collection<Mastodon::ScheduledStatus>]
|
16
|
+
def scheduled_statuses(options = {})
|
17
|
+
perform_request_with_collection(:get, '/api/v1/scheduled_statuses', options, Mastodon::ScheduledStatus)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Retrieve a scheduled status
|
21
|
+
# @param id [Integer]
|
22
|
+
# @return [Mastodon::ScheduledStatus]
|
23
|
+
def scheduled_status(id)
|
24
|
+
perform_request_with_object(:get, "/api/v1/scheduled_statuses/#{id}", {}, Mastodon::ScheduledStatus)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Update a scheduled status
|
28
|
+
# @param id [Integer]
|
29
|
+
# @param params [Hash]
|
30
|
+
# @option params :scheduled_at [String]
|
31
|
+
# @return [Mastodon::ScheduledStatus]
|
32
|
+
def update_scheduled_status(id, params = {})
|
33
|
+
perform_request_with_object(:put, "/api/v1/scheduled_statuses/#{id}", params, Mastodon::ScheduledStatus)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Cancel a scheduled status
|
37
|
+
# @param id [Integer]
|
38
|
+
def delete_scheduled_status(id)
|
39
|
+
perform_request(:delete, "/api/v1/scheduled_statuses/#{id}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mastodon/rest/utils'
|
2
|
+
require 'mastodon/status'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module REST
|
6
|
+
module Search
|
7
|
+
include Mastodon::REST::Utils
|
8
|
+
|
9
|
+
# Search for content
|
10
|
+
# @param options [Hash]
|
11
|
+
# @option options :q [String] The search query
|
12
|
+
# @option options :resolve [Boolean] Whether to resolve non-local accounts
|
13
|
+
# @option options :limit [Integer]
|
14
|
+
# @return [Mastodon::Results]
|
15
|
+
def search(query, options = {})
|
16
|
+
perform_request_with_object(:get, '/api/v2/search', { q: query }.merge(options), Mastodon::Results)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'mastodon/rest/utils'
|
2
|
+
require 'mastodon/status'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module REST
|
6
|
+
module Statuses
|
7
|
+
include Mastodon::REST::Utils
|
8
|
+
|
9
|
+
# Create new status
|
10
|
+
# @param text [String]
|
11
|
+
# @param params [Hash]
|
12
|
+
# @option params :in_reply_to_id [Integer]
|
13
|
+
# @option params :media_ids [Array<Integer>]
|
14
|
+
# @option params :visibility [String]
|
15
|
+
# @option params :language [String]
|
16
|
+
# @option params :sensitive [Boolean]
|
17
|
+
# @option params :spoiler_text [String]
|
18
|
+
# @option params :scheduled_at [String]
|
19
|
+
# @return <Mastodon::Status>
|
20
|
+
def create_status(text, params = {})
|
21
|
+
params[:status] = text
|
22
|
+
params[:'media_ids[]'] = params.delete(:media_ids) if params.key?(:media_ids)
|
23
|
+
|
24
|
+
perform_request_with_object(:post, '/api/v1/statuses', params, Mastodon::Status)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retrieve status
|
28
|
+
# @param id [Integer]
|
29
|
+
# @return [Mastodon::Status]
|
30
|
+
def status(id)
|
31
|
+
perform_request_with_object(:get, "/api/v1/statuses/#{id}", {}, Mastodon::Status)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Destroy status
|
35
|
+
# @param id [Integer]
|
36
|
+
# @return [Boolean]
|
37
|
+
def destroy_status(id)
|
38
|
+
!perform_request(:delete, "/api/v1/statuses/#{id}").nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Reblog a status
|
42
|
+
# @param id [Integer]
|
43
|
+
# @return [Mastodon::Status]
|
44
|
+
def reblog(id)
|
45
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/reblog", {}, Mastodon::Status)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Undo a reblog of a status
|
49
|
+
# @param id [Integer]
|
50
|
+
# @return [Mastodon::Status]
|
51
|
+
def unreblog(id)
|
52
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/unreblog", {}, Mastodon::Status)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Favourite a status
|
56
|
+
# @param id [Integer]
|
57
|
+
# @return [Mastodon::Status]
|
58
|
+
def favourite(id)
|
59
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/favourite", {}, Mastodon::Status)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Undo a favourite of a status
|
63
|
+
# @param id [Integer]
|
64
|
+
# @return [Mastodon::Status]
|
65
|
+
def unfavourite(id)
|
66
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/unfavourite", {}, Mastodon::Status)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get a list of accounts that reblogged a toot
|
70
|
+
# @param id [Integer]
|
71
|
+
# @param options [Hash]
|
72
|
+
# @option options :max_id [Integer]
|
73
|
+
# @option options :since_id [Integer]
|
74
|
+
# @option options :min_id [Integer]
|
75
|
+
# @option options :limit [Integer]
|
76
|
+
# @return [Mastodon::Collection<Mastodon::Account>]
|
77
|
+
def reblogged_by(id, options = {})
|
78
|
+
perform_request_with_collection(:get, "/api/v1/statuses/#{id}/reblogged_by", options, Mastodon::Account)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get a list of accounts that favourited a toot
|
82
|
+
# @param id [Integer]
|
83
|
+
# @param options [Hash]
|
84
|
+
# @option options :max_id [Integer]
|
85
|
+
# @option options :since_id [Integer]
|
86
|
+
# @option options :min_id [Integer]
|
87
|
+
# @option options :limit [Integer]
|
88
|
+
# @return [Mastodon::Collection<Mastodon::Account>]
|
89
|
+
def favourited_by(id, options = {})
|
90
|
+
perform_request_with_collection(:get, "/api/v1/statuses/#{id}/favourited_by", options, Mastodon::Account)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Pin status on own profile
|
94
|
+
# @param id [Integer]
|
95
|
+
# @return [Mastodon::Status]
|
96
|
+
def pin(id)
|
97
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/pin", {}, Mastodon::Status)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Unpin status from own profile
|
101
|
+
# @param id [Integer]
|
102
|
+
# @return [Mastodon::Status]
|
103
|
+
def unpin(id)
|
104
|
+
perform_request_with_object(:post, "/api/v1/statuses/#{id}/unpin", {}, Mastodon::Status)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Get a list of statuses by a user
|
108
|
+
# @param account_id [Integer]
|
109
|
+
# @param options [Hash]
|
110
|
+
# @option options :max_id [Integer]
|
111
|
+
# @option options :since_id [Integer]
|
112
|
+
# @option options :min_id [Integer]
|
113
|
+
# @option options :limit [Integer]
|
114
|
+
# @option options :only_media [Boolean]
|
115
|
+
# @option options :pinned [Boolean]
|
116
|
+
# @option options :exclude_replies [Boolean]
|
117
|
+
# @option options :exclude_reblogs [Boolean]
|
118
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
119
|
+
def statuses(account_id, options = {})
|
120
|
+
perform_request_with_collection(:get, "/api/v1/accounts/#{account_id}/statuses", options, Mastodon::Status)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'mastodon/rest/utils'
|
2
|
+
require 'mastodon/account'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module REST
|
6
|
+
module Suggestions
|
7
|
+
include Mastodon::REST::Utils
|
8
|
+
|
9
|
+
# Get "who to follow" suggestions for authenticated user
|
10
|
+
# @param options [Hash]
|
11
|
+
# @option options :max_id [Integer]
|
12
|
+
# @option options :since_id [Integer]
|
13
|
+
# @option options :min_id [Boolean]
|
14
|
+
# @option options :limit [Integer]
|
15
|
+
# @return [Mastodon::Collection<Mastodon::Account>]
|
16
|
+
def suggestions(options = {})
|
17
|
+
perform_request_with_collection(:get, '/api/v1/suggestions', options, Mastodon::Account)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Remove a suggestion
|
21
|
+
# @param account_id [Integer]
|
22
|
+
def delete_suggestion(account_id)
|
23
|
+
perform_request(:delete, "/api/v1/suggestions/#{account_id}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'mastodon/rest/utils'
|
2
|
+
require 'mastodon/status'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module REST
|
6
|
+
module Timelines
|
7
|
+
include Mastodon::REST::Utils
|
8
|
+
|
9
|
+
# Retrieve statuses from the home timeline
|
10
|
+
# @param options [Hash]
|
11
|
+
# @option options :max_id [Integer]
|
12
|
+
# @option options :since_id [Integer]
|
13
|
+
# @option options :min_id [Integer]
|
14
|
+
# @option options :limit [Integer]
|
15
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
16
|
+
def home_timeline(options = {})
|
17
|
+
perform_request_with_collection(:get, '/api/v1/timelines/home', options, Mastodon::Status)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Retrieve statuses from the public timeline
|
21
|
+
# @param options [Hash]
|
22
|
+
# @option options :max_id [Integer]
|
23
|
+
# @option options :since_id [Integer]
|
24
|
+
# @option options :min_id [Integer]
|
25
|
+
# @option options :limit [Integer]
|
26
|
+
# @option options :local [Boolean]
|
27
|
+
# @option options :only_media [Boolean]
|
28
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
29
|
+
def public_timeline(options = {})
|
30
|
+
perform_request_with_collection(:get, '/api/v1/timelines/public', options, Mastodon::Status)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Retrieve statuses from a hashtag
|
34
|
+
# @param hashtag [String]
|
35
|
+
# @param options [Hash]
|
36
|
+
# @option options :max_id [Integer]
|
37
|
+
# @option options :since_id [Integer]
|
38
|
+
# @option options :min_id [Integer]
|
39
|
+
# @option options :limit [Integer]
|
40
|
+
# @option options :local [Boolean]
|
41
|
+
# @option options :only_media [Boolean]
|
42
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
43
|
+
def hashtag_timeline(hashtag, options = {})
|
44
|
+
perform_request_with_collection(:get, "/api/v1/timelines/tag/#{hashtag}", options, Mastodon::Status)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Retrieve statuses from a list
|
48
|
+
# @param id [String]
|
49
|
+
# @param options [Hash]
|
50
|
+
# @option options :max_id [Integer]
|
51
|
+
# @option options :since_id [Integer]
|
52
|
+
# @option options :min_id [Integer]
|
53
|
+
# @option options :limit [Integer]
|
54
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
55
|
+
def list_timeline(id, options = {})
|
56
|
+
perform_request_with_collection(:get, "/api/v1/timelines/list/#{id}", options, Mastodon::Status)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'mastodon/rest/request'
|
2
|
+
|
3
|
+
module Mastodon
|
4
|
+
module REST
|
5
|
+
module Utils
|
6
|
+
# @param request_method [Symbol]
|
7
|
+
# @param path [String]
|
8
|
+
# @param options [Hash]
|
9
|
+
def perform_request(request_method, path, options = {})
|
10
|
+
Mastodon::REST::Request.new(self, request_method, path, options).perform
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param request_method [Symbol]
|
14
|
+
# @param path [String]
|
15
|
+
# @param options [Hash]
|
16
|
+
# @param klass [Class]
|
17
|
+
def perform_request_with_object(request_method, path, options, klass)
|
18
|
+
response = perform_request(request_method, path, options)
|
19
|
+
klass.new(response)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param request_method [Symbol]
|
23
|
+
# @param path [String]
|
24
|
+
# @param options [Hash]
|
25
|
+
# @param klass [Class]
|
26
|
+
def perform_request_with_collection(request_method, path, options, klass)
|
27
|
+
response = perform_request(request_method, path, options)
|
28
|
+
Mastodon::Collection.new(response, klass)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Format an array of values into a query param
|
32
|
+
# @param key [Symbol]
|
33
|
+
# @param values [Enumerable]
|
34
|
+
# @return [Array]
|
35
|
+
def array_param(key, values)
|
36
|
+
values.map.with_index { |value, i| ["#{key}[]", value] }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'mastodon/account'
|
2
|
+
require 'mastodon/status'
|
3
|
+
require 'mastodon/hashtag'
|
4
|
+
|
5
|
+
module Mastodon
|
6
|
+
class Results < Mastodon::Base
|
7
|
+
# @!attribute [r] accounts
|
8
|
+
# @return [Mastodon::Collection<Mastodon::Account>]
|
9
|
+
# @!attribute [r] statuses
|
10
|
+
# @return [Mastodon::Collection<Mastodon::Status>]
|
11
|
+
# @!attribute [r] hashtags
|
12
|
+
# @return [Mastodon::Collection<Mastodon::Hashtag>]
|
13
|
+
|
14
|
+
collection_attr_reader :accounts, Mastodon::Account
|
15
|
+
collection_attr_reader :statuses, Mastodon::Status
|
16
|
+
collection_attr_reader :hashtags, Mastodon::Hashtag
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mastodon/entities/media'
|
2
|
+
|
3
|
+
module Mastodon
|
4
|
+
class ScheduledStatus < Mastodon::Base
|
5
|
+
# @!attribute [r] id
|
6
|
+
# @return [String]
|
7
|
+
# @!attribute [r] scheduled_at
|
8
|
+
# @return [String]
|
9
|
+
# @!attribute [r] params
|
10
|
+
# @return [Hash]
|
11
|
+
# @!attribute [r] media_attachments
|
12
|
+
# @return [Mastodon::Collection<Mastodon::Entities::Media>]
|
13
|
+
|
14
|
+
normal_attr_reader :id,
|
15
|
+
:scheduled_at,
|
16
|
+
:params
|
17
|
+
|
18
|
+
collection_attr_reader :media_attachments, Mastodon::Entities::Media
|
19
|
+
|
20
|
+
def initialize(attributes = {})
|
21
|
+
attributes.fetch('id')
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'mastodon/account'
|
2
|
+
require 'mastodon/entities/media'
|
3
|
+
require 'mastodon/entities/mention'
|
4
|
+
require 'mastodon/entities/app'
|
5
|
+
require 'mastodon/entities/hashtag'
|
6
|
+
require 'mastodon/emoji'
|
7
|
+
require 'mastodon/card'
|
8
|
+
|
9
|
+
module Mastodon
|
10
|
+
class Status < Mastodon::Base
|
11
|
+
# @!attribute [r] id
|
12
|
+
# @return [String]
|
13
|
+
# @!attribute [r] in_reply_to_id
|
14
|
+
# @return [String]
|
15
|
+
# @!attribute [r] in_reply_to_account_id
|
16
|
+
# @return [String]
|
17
|
+
# @!attribute [r] spoiler_text
|
18
|
+
# @return [String]
|
19
|
+
# @!attribute [r] content
|
20
|
+
# @return [String]
|
21
|
+
# @!attribute [r] url
|
22
|
+
# @return [String]
|
23
|
+
# @!attribute [r] uri
|
24
|
+
# @return [String]
|
25
|
+
# @!attribute [r] created_at
|
26
|
+
# @return [String]
|
27
|
+
# @!attribute [r] reblogs_count
|
28
|
+
# @return [Integer]
|
29
|
+
# @!attribute [r] favourites_count
|
30
|
+
# @return [Integer]
|
31
|
+
# @!attribute [r] visibility
|
32
|
+
# @return [String]
|
33
|
+
# @!attribute [r] language
|
34
|
+
# @return [String]
|
35
|
+
# @!attribute [r] account
|
36
|
+
# @return [Mastodon::Account]
|
37
|
+
# @!attribute [r] reblog
|
38
|
+
# @return [Mastodon::Status]
|
39
|
+
# @!attribute [r] application
|
40
|
+
# @return [Mastodon::Entities::App]
|
41
|
+
# @!attribute [r] favourited?
|
42
|
+
# @return [Boolean]
|
43
|
+
# @!attribute [r] reblogged?
|
44
|
+
# @return [Boolean]
|
45
|
+
# @!attribute [r] sensitive?
|
46
|
+
# @return [Boolean]
|
47
|
+
# @!attribute [r] muted?
|
48
|
+
# @return [Boolean]
|
49
|
+
# @!attribute [r] pinned?
|
50
|
+
# @return [Boolean]
|
51
|
+
# @!attribute [r] media_attachments
|
52
|
+
# @return [Mastodon::Collection<Mastodon::Entities::Media>]
|
53
|
+
# @!attribute [r] mentions
|
54
|
+
# @return [Mastodon::Collection<Mastodon::Entities::Mention>]
|
55
|
+
# @!attribute [r] tags
|
56
|
+
# @return [Mastodon::Collection<Mastodon::Entities::Hashtag>]
|
57
|
+
# @!attribute [r] emojis
|
58
|
+
# @return [Mastodon::Collection<Mastodon::Emoji>]
|
59
|
+
# @!attribute [r] card
|
60
|
+
# @return [Mastodon::Card]
|
61
|
+
|
62
|
+
normal_attr_reader :id,
|
63
|
+
:content,
|
64
|
+
:in_reply_to_id,
|
65
|
+
:in_reply_to_account_id,
|
66
|
+
:url,
|
67
|
+
:uri,
|
68
|
+
:created_at,
|
69
|
+
:reblogs_count,
|
70
|
+
:favourites_count,
|
71
|
+
:visibility,
|
72
|
+
:spoiler_text,
|
73
|
+
:language
|
74
|
+
|
75
|
+
predicate_attr_reader :favourited,
|
76
|
+
:reblogged,
|
77
|
+
:sensitive,
|
78
|
+
:muted,
|
79
|
+
:pinned
|
80
|
+
|
81
|
+
object_attr_reader :account, Mastodon::Account
|
82
|
+
object_attr_reader :reblog, Mastodon::Status
|
83
|
+
object_attr_reader :application, Mastodon::Entities::App
|
84
|
+
object_attr_reader :card, Mastodon::Card
|
85
|
+
|
86
|
+
collection_attr_reader :media_attachments, Mastodon::Entities::Media
|
87
|
+
collection_attr_reader :mentions, Mastodon::Entities::Mention
|
88
|
+
collection_attr_reader :emojis, Mastodon::Emoji
|
89
|
+
collection_attr_reader :tags, Mastodon::Entities::Hashtag
|
90
|
+
|
91
|
+
def initialize(attributes = {})
|
92
|
+
attributes.fetch('id')
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'http/request'
|
2
|
+
require 'mastodon/client'
|
3
|
+
require 'mastodon/streaming/connection'
|
4
|
+
require 'mastodon/streaming/message_parser'
|
5
|
+
require 'mastodon/streaming/response'
|
6
|
+
|
7
|
+
module Mastodon
|
8
|
+
module Streaming
|
9
|
+
class Client < Mastodon::Client
|
10
|
+
attr_writer :connection
|
11
|
+
|
12
|
+
# Initializes a new Client object
|
13
|
+
#
|
14
|
+
# @param options [Hash] A customizable set of options.
|
15
|
+
# @option options [String] :tcp_socket_class A class that Connection will use to create a new TCP socket.
|
16
|
+
# @option options [String] :ssl_socket_class A class that Connection will use to create a new SSL socket.
|
17
|
+
# @return [Mastodon::Streaming::Client]
|
18
|
+
def initialize(options = {})
|
19
|
+
super
|
20
|
+
options[:using_ssl] ||= base_url =~ /^https/
|
21
|
+
@connection = Streaming::Connection.new(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Streams messages for a single user
|
25
|
+
#
|
26
|
+
# @yield [Mastodon::Status, Mastodon::Notification, Mastodon::Streaming::Events::StatusDelete, Mastodon::Streaming::Events::FiltersChange] A stream of Mastodon objects.
|
27
|
+
def user(**options, &block)
|
28
|
+
stream('user', **options, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns statuses that contain the specified hashtag
|
32
|
+
#
|
33
|
+
# @yield [Mastodon::Status, Mastodon::Streaming::Events::StatusDelete] A stream of Mastodon objects.
|
34
|
+
def hashtag(tag, **options, &block)
|
35
|
+
stream('hashtag', **{ tag: tag, **options}, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns all public statuses
|
39
|
+
#
|
40
|
+
# @yield [Mastodon::Status, Mastodon::Streaming::Events::StatusDelete] A stream of Mastodon objects.
|
41
|
+
def public(**options, &block)
|
42
|
+
stream('public', **options, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns conversations for a single user
|
46
|
+
#
|
47
|
+
# @yield [Mastodon::Conversation] A stream of Mastodon objects.
|
48
|
+
def direct(**options, &block)
|
49
|
+
stream('direct', options, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Calls an arbitrary streaming endpoint and returns the results
|
54
|
+
# @yield [Mastodon::Status, Mastodon::Notification, Mastodon::Streaming::DeletedStatus] A stream of Mastodon objects.
|
55
|
+
def stream(path, **options, &block)
|
56
|
+
request(:get, "/api/v1/streaming/#{path}", **options, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set a Proc to be run when connection established.
|
60
|
+
def before_request(&block)
|
61
|
+
if block_given?
|
62
|
+
@before_request = block
|
63
|
+
self
|
64
|
+
elsif instance_variable_defined?(:@before_request)
|
65
|
+
@before_request
|
66
|
+
else
|
67
|
+
proc {}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
|
74
|
+
def request(method, path, **params)
|
75
|
+
before_request.call
|
76
|
+
|
77
|
+
uri = Addressable::URI.parse(base_url + path)
|
78
|
+
headers = Mastodon::Headers.new(self).request_headers
|
79
|
+
request = HTTP::Request.new(verb: method, uri: uri + '?' + to_url_params(params), headers: headers)
|
80
|
+
|
81
|
+
response = Streaming::Response.new do |type, data|
|
82
|
+
if item = Streaming::MessageParser.parse(type, data) # rubocop:disable AssignmentInCondition
|
83
|
+
yield(item)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
@connection.stream(request, response)
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_url_params(params)
|
91
|
+
uri = Addressable::URI.new
|
92
|
+
uri.query_values = params
|
93
|
+
uri.query
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'resolv'
|
3
|
+
|
4
|
+
module Mastodon
|
5
|
+
module Streaming
|
6
|
+
class Connection
|
7
|
+
attr_reader :tcp_socket_class, :ssl_socket_class
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@tcp_socket_class = options.fetch(:tcp_socket_class) { TCPSocket }
|
11
|
+
@ssl_socket_class = options.fetch(:ssl_socket_class) { OpenSSL::SSL::SSLSocket }
|
12
|
+
@using_ssl = options.fetch(:using_ssl) { false }
|
13
|
+
end
|
14
|
+
|
15
|
+
def stream(request, response)
|
16
|
+
client = connect(request)
|
17
|
+
|
18
|
+
request.stream(client)
|
19
|
+
|
20
|
+
while body = client.readpartial(1024) # rubocop:disable AssignmentInCondition
|
21
|
+
response << body
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def connect(request)
|
26
|
+
client = new_tcp_socket(request.socket_host, request.socket_port)
|
27
|
+
|
28
|
+
return client if !@using_ssl || (!@using_ssl && request.using_proxy?)
|
29
|
+
|
30
|
+
client_context = OpenSSL::SSL::SSLContext.new
|
31
|
+
ssl_client = @ssl_socket_class.new(client, client_context)
|
32
|
+
ssl_client.hostname = request.socket_host
|
33
|
+
|
34
|
+
ssl_client.connect
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def new_tcp_socket(host, port)
|
40
|
+
@tcp_socket_class.new(Resolv.getaddress(host), port)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|