moostodon 0.1.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/lib/mastodon.rb +8 -0
  3. data/lib/mastodon/account.rb +62 -0
  4. data/lib/mastodon/app.rb +19 -0
  5. data/lib/mastodon/base.rb +52 -0
  6. data/lib/mastodon/card.rb +43 -0
  7. data/lib/mastodon/client.rb +32 -0
  8. data/lib/mastodon/collection.rb +30 -0
  9. data/lib/mastodon/emoji.rb +14 -0
  10. data/lib/mastodon/entities/app.rb +15 -0
  11. data/lib/mastodon/entities/hashtag.rb +15 -0
  12. data/lib/mastodon/entities/media.rb +31 -0
  13. data/lib/mastodon/entities/mention.rb +17 -0
  14. data/lib/mastodon/error.rb +37 -0
  15. data/lib/mastodon/headers.rb +20 -0
  16. data/lib/mastodon/instance.rb +25 -0
  17. data/lib/mastodon/list.rb +17 -0
  18. data/lib/mastodon/media.rb +37 -0
  19. data/lib/mastodon/notification.rb +32 -0
  20. data/lib/mastodon/relationship.rb +38 -0
  21. data/lib/mastodon/rest/accounts.rb +71 -0
  22. data/lib/mastodon/rest/api.rb +29 -0
  23. data/lib/mastodon/rest/apps.rb +28 -0
  24. data/lib/mastodon/rest/client.rb +13 -0
  25. data/lib/mastodon/rest/instances.rb +19 -0
  26. data/lib/mastodon/rest/media.rb +42 -0
  27. data/lib/mastodon/rest/notifications.rb +19 -0
  28. data/lib/mastodon/rest/relationships.rb +77 -0
  29. data/lib/mastodon/rest/request.rb +54 -0
  30. data/lib/mastodon/rest/search.rb +28 -0
  31. data/lib/mastodon/rest/statuses.rb +130 -0
  32. data/lib/mastodon/rest/suggestions.rb +19 -0
  33. data/lib/mastodon/rest/timelines.rb +47 -0
  34. data/lib/mastodon/rest/utils.rb +42 -0
  35. data/lib/mastodon/results.rb +19 -0
  36. data/lib/mastodon/status.rb +94 -0
  37. data/lib/mastodon/streaming/client.rb +103 -0
  38. data/lib/mastodon/streaming/connection.rb +47 -0
  39. data/lib/mastodon/streaming/deleted_status.rb +17 -0
  40. data/lib/mastodon/streaming/message_parser.rb +21 -0
  41. data/lib/mastodon/streaming/response.rb +45 -0
  42. data/lib/mastodon/version.rb +32 -0
  43. data/moostodon.gemspec +25 -0
  44. metadata +156 -0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/rest/utils'
4
+ require 'mastodon/status'
5
+
6
+ module Mastodon
7
+ module REST
8
+ module Search
9
+ include Mastodon::REST::Utils
10
+
11
+ # Search for content
12
+ # @param options [Hash]
13
+ # @option options :q [String] The search query
14
+ # @option options :resolve [Boolean] Whether to resolve non-local accounts
15
+ # @return [Mastodon::Results] If q is a URL, Mastodon will
16
+ # attempt to fetch the provided account or status. Otherwise, it
17
+ # will do a local account and hashtag search.
18
+ def search(query, options = {})
19
+ opts = {
20
+ q: query
21
+ }.merge(options)
22
+
23
+ perform_request_with_object(:get, '/api/v1/search', opts,
24
+ Mastodon::Results)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/rest/utils'
4
+ require 'mastodon/status'
5
+
6
+ module Mastodon
7
+ module REST
8
+ module Statuses
9
+ include Mastodon::REST::Utils
10
+
11
+ # @overload create_status(text, in_reply_to_id, media_ids, visibility)
12
+ # Create new status
13
+ # @param text [String]
14
+ # @param in_reply_to_id [Integer]
15
+ # @param media_ids [Array<Integer>]
16
+ # @param visibility [String]
17
+ # @return [Mastodon::Status]
18
+ # @overload create_status(text, args)
19
+ # Create new status
20
+ # @param text [String]
21
+ # @param options [Hash]
22
+ # @option options :in_reply_to_id [Integer]
23
+ # @option options :media_ids [Array<Integer>]
24
+ # @option options :visibility [String]
25
+ # @return <Mastodon::Status>
26
+ def create_status(text, *args)
27
+ params = normalize_status_params(*args)
28
+ params[:status] = text
29
+ params['media_ids[]'] ||= params.delete(:media_ids)
30
+
31
+ perform_request_with_object(:post, '/api/v1/statuses',
32
+ params, Mastodon::Status)
33
+ end
34
+
35
+ # Retrieve status
36
+ # @param id [Integer]
37
+ # @return [Mastodon::Status]
38
+ def status(id)
39
+ perform_request_with_object(:get, "/api/v1/statuses/#{id}",
40
+ {}, Mastodon::Status)
41
+ end
42
+
43
+ # Destroy status
44
+ # @param id [Integer]
45
+ # @return [Boolean]
46
+ def destroy_status(id)
47
+ !perform_request(:delete, "/api/v1/statuses/#{id}").nil?
48
+ end
49
+
50
+ # Reblog a status
51
+ # @param id [Integer]
52
+ # @return [Mastodon::Status]
53
+ def reblog(id)
54
+ perform_request_with_object(:post, "/api/v1/statuses/#{id}/reblog",
55
+ {}, Mastodon::Status)
56
+ end
57
+
58
+ # Undo a reblog of a status
59
+ # @param id [Integer]
60
+ # @return [Mastodon::Status]
61
+ def unreblog(id)
62
+ perform_request_with_object(:post, "/api/v1/statuses/#{id}/unreblog",
63
+ {}, Mastodon::Status)
64
+ end
65
+
66
+ # Favourite a status
67
+ # @param id [Integer]
68
+ # @return [Mastodon::Status]
69
+ def favourite(id)
70
+ perform_request_with_object(:post, "/api/v1/statuses/#{id}/favourite",
71
+ {}, Mastodon::Status)
72
+ end
73
+
74
+ # Undo a favourite of a status
75
+ # @param id [Integer]
76
+ # @return [Mastodon::Status]
77
+ def unfavourite(id)
78
+ perform_request_with_object(:post,
79
+ "/api/v1/statuses/#{id}/unfavourite",
80
+ {}, Mastodon::Status)
81
+ end
82
+
83
+ # Get a list of accounts that reblogged a toot
84
+ # @param id [Integer]
85
+ # @param options [Hash]
86
+ # @return [Mastodon::Collection<Mastodon::Account>]
87
+ def reblogged_by(id, options = {})
88
+ perform_request_with_collection(:get,
89
+ "/api/v1/statuses/#{id}/reblogged_by",
90
+ options, Mastodon::Account)
91
+ end
92
+
93
+ # Get a list of accounts that favourited a toot
94
+ # @param id [Integer]
95
+ # @param options [Hash]
96
+ # @return [Mastodon::Collection<Mastodon::Account>]
97
+ def favourited_by(id, options = {})
98
+ perform_request_with_collection(:get,
99
+ "/api/v1/statuses/#{id}/favourited_by",
100
+ options, Mastodon::Account)
101
+ end
102
+
103
+ # Get a list of statuses by a user
104
+ # @param account_id [Integer]
105
+ # @param options [Hash]
106
+ # @option options :max_id [Integer]
107
+ # @option options :since_id [Integer]
108
+ # @option options :limit [Integer]
109
+ # @return [Mastodon::Collection<Mastodon::Status>]
110
+ def statuses(account_id, options = {})
111
+ url = "/api/v1/accounts/#{account_id}/statuses"
112
+ perform_request_with_collection(:get, url, options, Mastodon::Status)
113
+ end
114
+
115
+ private
116
+
117
+ def normalize_status_params(*args)
118
+ if args.length == 1 && args.first.is_a?(Hash)
119
+ args.shift
120
+ else
121
+ {
122
+ in_reply_to_id: args.shift,
123
+ 'media_ids[]' => args.shift,
124
+ visibility: args.shift
125
+ }
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/rest/utils'
4
+ require 'mastodon/account'
5
+
6
+ module Mastodon
7
+ module REST
8
+ module Suggestions
9
+ include Mastodon::REST::Utils
10
+
11
+ # Get "who to follow" suggestions for authenticated user
12
+ # @return [Mastodon::Collection<Mastodon::Account>]
13
+ def suggestions
14
+ perform_request_with_collection(:get, '/api/v1/accounts/suggestions',
15
+ {}, Mastodon::Account)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/rest/utils'
4
+ require 'mastodon/status'
5
+
6
+ module Mastodon
7
+ module REST
8
+ module Timelines
9
+ include Mastodon::REST::Utils
10
+
11
+ # Retrieve statuses from the home timeline
12
+ # @param options [Hash]
13
+ # @option options :max_id [Integer]
14
+ # @option options :since_id [Integer]
15
+ # @option options :limit [Integer]
16
+ # @return [Mastodon::Collection<Mastodon::Status>]
17
+ def home_timeline(options = {})
18
+ perform_request_with_collection(:get, '/api/v1/timelines/home',
19
+ options, Mastodon::Status)
20
+ end
21
+
22
+ # Retrieve statuses from the public timeline
23
+ # @param options [Hash]
24
+ # @option options :max_id [Integer]
25
+ # @option options :since_id [Integer]
26
+ # @option options :limit [Integer]
27
+ # @return [Mastodon::Collection<Mastodon::Status>]
28
+ def public_timeline(options = {})
29
+ perform_request_with_collection(:get, '/api/v1/timelines/public',
30
+ 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 :limit [Integer]
39
+ # @return [Mastodon::Collection<Mastodon::Status>]
40
+ def hashtag_timeline(hashtag, options = {})
41
+ perform_request_with_collection(:get,
42
+ "/api/v1/timelines/tag/#{hashtag}",
43
+ options, Mastodon::Status)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/rest/request'
4
+
5
+ module Mastodon
6
+ module REST
7
+ module Utils
8
+ # @param request_method [Symbol]
9
+ # @param path [String]
10
+ # @param options [Hash]
11
+ def perform_request(request_method, path, options = {})
12
+ Mastodon::REST::Request.new(self, request_method, path, options).perform
13
+ end
14
+
15
+ # @param request_method [Symbol]
16
+ # @param path [String]
17
+ # @param options [Hash]
18
+ # @param klass [Class]
19
+ def perform_request_with_object(request_method, path, options, klass)
20
+ response = perform_request(request_method, path, options)
21
+ klass.new(response)
22
+ end
23
+
24
+ # @param request_method [Symbol]
25
+ # @param path [String]
26
+ # @param options [Hash]
27
+ # @param klass [Class]
28
+ def perform_request_with_collection(request_method, path, options, klass)
29
+ response = perform_request(request_method, path, options)
30
+ Mastodon::Collection.new(response, klass)
31
+ end
32
+
33
+ # Format an array of values into a query param
34
+ # @param key [Symbol]
35
+ # @param values [Enumerable]
36
+ # @return [Array]
37
+ def array_param(key, values)
38
+ values.map.with_index { |value, _i| ["#{key}[]", value] }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/account'
4
+ require 'mastodon/status'
5
+
6
+ module Mastodon
7
+ class Results < Mastodon::Base
8
+ # @!attribute [r] accounts
9
+ # @return [Mastodon::Collection<Mastodon::Account>]
10
+ # @!attribute [r] statuses
11
+ # @return [Mastodon::Collection<Mastodon::Status>]
12
+ # @!attribute [r] hashtags
13
+ # @return [Mastodon::Collection<String>]
14
+
15
+ collection_attr_reader :accounts, Mastodon::Account
16
+ collection_attr_reader :statuses, Mastodon::Status
17
+ collection_attr_reader :hashtags, String
18
+ end
19
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mastodon/account'
4
+ require 'mastodon/entities/media'
5
+ require 'mastodon/entities/mention'
6
+ require 'mastodon/entities/app'
7
+ require 'mastodon/entities/hashtag'
8
+ require 'mastodon/emoji'
9
+
10
+ module Mastodon
11
+ class Status < Mastodon::Base
12
+ # @!attribute [r] id
13
+ # @return [String]
14
+ # @!attribute [r] in_reply_to_id
15
+ # @return [String]
16
+ # @!attribute [r] in_reply_to_account_id
17
+ # @return [String]
18
+ # @!attribute [r] spoiler_text
19
+ # @return [String]
20
+ # @!attribute [r] content
21
+ # @return [String]
22
+ # @!attribute [r] url
23
+ # @return [String]
24
+ # @!attribute [r] uri
25
+ # @return [String]
26
+ # @!attribute [r] created_at
27
+ # @return [String]
28
+ # @!attribute [r] reblogs_count
29
+ # @return [Integer]
30
+ # @!attribute [r] favourites_count
31
+ # @return [Integer]
32
+ # @!attribute [r] visibility
33
+ # @return [String]
34
+ # @!attribute [r] language
35
+ # @return [String]
36
+ # @!attribute [r] account
37
+ # @return [Mastodon::Account]
38
+ # @!attribute [r] reblog
39
+ # @return [Mastodon::Status]
40
+ # @!attribute [r] application
41
+ # @return [Mastodon::Entities::App]
42
+ # @!attribute [r] favourited?
43
+ # @return [Boolean]
44
+ # @!attribute [r] reblogged?
45
+ # @return [Boolean]
46
+ # @!attribute [r] sensitive?
47
+ # @return [Boolean]
48
+ # @!attribute [r] muted?
49
+ # @return [Boolean]
50
+ # @!attribute [r] pinned?
51
+ # @return [Boolean]
52
+ # @!attribute [r] media_attachments
53
+ # @return [Mastodon::Collection<Mastodon::Entities::Media>]
54
+ # @!attribute [r] mentions
55
+ # @return [Mastodon::Collection<Mastodon::Entities::Mention>]
56
+ # @!attribute [r] tags
57
+ # @return [Mastodon::Collection<Mastodon::Entities::Hashtag>]
58
+ # @!attribute [r] emojis
59
+ # @return [Mastodon::Collection<Mastodon::Emoji>]
60
+
61
+ normal_attr_reader :id,
62
+ :content,
63
+ :in_reply_to_id,
64
+ :in_reply_to_account_id,
65
+ :url,
66
+ :uri,
67
+ :created_at,
68
+ :reblogs_count,
69
+ :favourites_count,
70
+ :visibility,
71
+ :spoiler_text,
72
+ :language
73
+
74
+ predicate_attr_reader :favourited,
75
+ :reblogged,
76
+ :sensitive,
77
+ :muted,
78
+ :pinned
79
+
80
+ object_attr_reader :account, Mastodon::Account
81
+ object_attr_reader :reblog, Mastodon::Status
82
+ object_attr_reader :application, Mastodon::Entities::App
83
+
84
+ collection_attr_reader :media_attachments, Mastodon::Entities::Media
85
+ collection_attr_reader :mentions, Mastodon::Entities::Mention
86
+ collection_attr_reader :emojis, Mastodon::Emoji
87
+ collection_attr_reader :tags, Mastodon::Entities::Hashtag
88
+
89
+ def initialize(attributes = {})
90
+ attributes.fetch('id')
91
+ super
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http/request'
4
+ require 'mastodon/client'
5
+ require 'mastodon/streaming/connection'
6
+ require 'mastodon/streaming/deleted_status'
7
+ require 'mastodon/streaming/message_parser'
8
+ require 'mastodon/streaming/response'
9
+
10
+ module Mastodon
11
+ module Streaming
12
+ # Streaming client class, to handle all streaming purposes.
13
+ class Client < Mastodon::Client
14
+ attr_writer :connection
15
+
16
+ # Initializes a new Client object
17
+ #
18
+ # @param options [Hash] A customizable set of options.
19
+ # @option options [String] :tcp_socket_class A class that Connection will
20
+ # use to create a new TCP socket.
21
+ # @option options [String] :ssl_socket_class A class that Connection will
22
+ # use to create a new SSL socket.
23
+ # @return [Mastodon::Streaming::Client]
24
+ def initialize(options = {})
25
+ super
26
+ options[:using_ssl] ||= base_url =~ /^https/
27
+ @connection = Streaming::Connection.new(options)
28
+ end
29
+
30
+ # Streams messages for a single user
31
+ #
32
+ # @yield [Mastodon::Status, Mastodon::Notification,
33
+ # Mastodon::Streaming::DeletedStatus] A stream of Mastodon objects.
34
+ def user(options = {}, &block)
35
+ stream('user', options, &block)
36
+ end
37
+
38
+ # Returns statuses that contain the specified hashtag
39
+ #
40
+ # @yield [Mastodon::Status, Mastodon::Notification,
41
+ # Mastodon::Streaming::DeletedStatus] A stream of Mastodon objects.
42
+ def hashtag(tag, options = {}, &block)
43
+ options['tag'] = tag
44
+ stream('hashtag', options, &block)
45
+ end
46
+
47
+ # Returns all public statuses
48
+ #
49
+ # @yield [Mastodon::Status, Mastodon::Notification,
50
+ # Mastodon::Streaming::DeletedStatus] A stream of Mastodon objects.
51
+ def firehose(options = {}, &block)
52
+ stream('public', options, &block)
53
+ end
54
+
55
+ #
56
+ # Calls an arbitrary streaming endpoint and returns the results
57
+ # @yield [Mastodon::Status, Mastodon::Notification,
58
+ # Mastodon::Streaming::DeletedStatus] A stream of Mastodon objects.
59
+ def stream(path, options = {}, &block)
60
+ request(:get, "/api/v1/streaming/#{path}", options, &block)
61
+ end
62
+
63
+ # Set a Proc to be run when connection established.
64
+ def before_request(&block)
65
+ if block_given?
66
+ @before_request = block
67
+ self
68
+ elsif instance_variable_defined?(:@before_request)
69
+ @before_request
70
+ else
71
+ proc {}
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def request(method, path, params)
78
+ before_request.call
79
+ uri = Addressable::URI.parse(base_url + path)
80
+
81
+ headers = Mastodon::Headers.new(self).request_headers
82
+
83
+ request = HTTP::Request.new(verb: method,
84
+ uri: "#{uri}?#{to_url_params(params)}",
85
+ headers: headers)
86
+ response = Streaming::Response.new do |type, data|
87
+ # rubocop:disable AssignmentInCondition
88
+ if item = Streaming::MessageParser.parse(type, data)
89
+ yield(item)
90
+ end
91
+ # rubocop:enable AssignmentInCondition
92
+ end
93
+ @connection.stream(request, response)
94
+ end
95
+
96
+ def to_url_params(params)
97
+ uri = Addressable::URI.new
98
+ uri.query_values = params
99
+ uri.query
100
+ end
101
+ end
102
+ end
103
+ end