twitchrb 1.3.0 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6774429fbfacd30d1308f5240f54d31bddfc9e5511ca11a5318317d8ecd426fe
4
- data.tar.gz: 8483a2e2a75269d40a6fcc56e1206dfc59a4033ef6d4d8bb679aaca6ab1e72dc
3
+ metadata.gz: 901a6fa2ce68163b04be8e9ac4827311ba51ebbf10ebd1b2ac22431093200625
4
+ data.tar.gz: d72fb9133fa476489a4378abceec8e4b8456394bf0706dbb02a3f1a97c2a4ad5
5
5
  SHA512:
6
- metadata.gz: 36c6bea9d2c2e8e1ff5eab8d3daf2edc0b2edc1047bb65f5d38c77b78b9fcba7333dc628593c5d5e9aa6cc2a0543115738f7a437200867a4d7186c0edd5e01c6
7
- data.tar.gz: f775ef2e85b39651f8c4fcea07791badce94086b3129f52dab6d44bf08456a1083d2b805bb3b6ef2c3eb965ae1178190623af7f243109042dc7ae0b10b0dd1a9
6
+ metadata.gz: 6cc69cb4c54daa8ceb639c0e2c73541b2f6091ba43b94bad887858d178bb9a259b3095fb243d95428224ea855bdaf92a3f36381aa908883882ce002638f9187b
7
+ data.tar.gz: 486829ca4f786fbdb4141ff8ae5da79420f6438a1af959f8604818e0a29778e62ec2fcc452868046739bbb37a45649ae8eadd1995213537edef49da339511ddc
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ open-pull-requests-limit: 10
8
+ - package-ecosystem: github-actions
9
+ directory: "/"
10
+ schedule:
11
+ interval: monthly
@@ -1,15 +1,21 @@
1
1
  name: CI
2
- on: push
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ branches:
8
+ - main
3
9
  jobs:
4
10
  lint:
5
11
  runs-on: ubuntu-latest
6
12
  steps:
7
13
  - name: Checkout code
8
- uses: actions/checkout@v4
14
+ uses: actions/checkout@v5
9
15
  - name: Set up Ruby
10
16
  uses: ruby/setup-ruby@v1
11
17
  with:
12
- ruby-version: '3.3'
18
+ ruby-version: '3.4'
13
19
  bundler-cache: true
14
20
  - name: Lint code for consistent style
15
21
  run: bundle exec rubocop -f github
@@ -21,11 +27,11 @@ jobs:
21
27
  fail-fast: false
22
28
  matrix:
23
29
  ruby_version:
24
- - '3.1'
25
30
  - '3.2'
26
31
  - '3.3'
32
+ - '3.4'
27
33
  steps:
28
- - uses: actions/checkout@v4
34
+ - uses: actions/checkout@v5
29
35
  - uses: ruby/setup-ruby@v1
30
36
  with:
31
37
  ruby-version: ${{ matrix.ruby_version }}
data/.rubocop.yml CHANGED
@@ -6,3 +6,6 @@ inherit_gem: { rubocop-rails-omakase: rubocop.yml }
6
6
  # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
7
  # Layout/SpaceInsideArrayLiteralBrackets:
8
8
  # Enabled: false
9
+
10
+ Rails/RefuteMethods:
11
+ Enabled: false
data/Gemfile CHANGED
@@ -8,3 +8,4 @@ gem "minitest", "~> 5.0"
8
8
  gem "dotenv"
9
9
  gem "vcr"
10
10
  gem "rubocop-rails-omakase", require: false
11
+ gem "activesupport", ">= 4.2.0", "< 8.0"
data/Gemfile.lock CHANGED
@@ -1,93 +1,103 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- twitchrb (1.3.0)
5
- faraday (~> 2.0)
4
+ twitchrb (1.5.0)
5
+ faraday (~> 2.11)
6
+ ostruct (~> 0.6.0)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- activesupport (7.1.3.4)
11
+ activesupport (7.2.2.2)
11
12
  base64
13
+ benchmark (>= 0.3)
12
14
  bigdecimal
13
- concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ concurrent-ruby (~> 1.0, >= 1.3.1)
14
16
  connection_pool (>= 2.2.5)
15
17
  drb
16
18
  i18n (>= 1.6, < 2)
19
+ logger (>= 1.4.2)
17
20
  minitest (>= 5.1)
18
- mutex_m
19
- tzinfo (~> 2.0)
20
- ast (2.4.2)
21
- base64 (0.2.0)
22
- bigdecimal (3.1.8)
23
- concurrent-ruby (1.3.3)
24
- connection_pool (2.4.1)
25
- dotenv (2.7.6)
26
- drb (2.2.1)
27
- faraday (2.9.2)
28
- faraday-net_http (>= 2.0, < 3.2)
29
- faraday-net_http (3.1.0)
30
- net-http
31
- i18n (1.14.5)
21
+ securerandom (>= 0.3)
22
+ tzinfo (~> 2.0, >= 2.0.5)
23
+ ast (2.4.3)
24
+ base64 (0.3.0)
25
+ benchmark (0.4.1)
26
+ bigdecimal (3.2.3)
27
+ concurrent-ruby (1.3.5)
28
+ connection_pool (2.5.4)
29
+ dotenv (3.1.8)
30
+ drb (2.2.3)
31
+ faraday (2.13.4)
32
+ faraday-net_http (>= 2.0, < 3.5)
33
+ json
34
+ logger
35
+ faraday-net_http (3.4.1)
36
+ net-http (>= 0.5.0)
37
+ i18n (1.14.7)
32
38
  concurrent-ruby (~> 1.0)
33
- json (2.7.2)
34
- language_server-protocol (3.17.0.3)
35
- minitest (5.15.0)
36
- mutex_m (0.2.0)
37
- net-http (0.4.1)
39
+ json (2.13.2)
40
+ language_server-protocol (3.17.0.5)
41
+ lint_roller (1.1.0)
42
+ logger (1.7.0)
43
+ minitest (5.25.5)
44
+ net-http (0.6.0)
38
45
  uri
39
- parallel (1.25.1)
40
- parser (3.3.3.0)
46
+ ostruct (0.6.3)
47
+ parallel (1.27.0)
48
+ parser (3.3.9.0)
41
49
  ast (~> 2.4.1)
42
50
  racc
43
- racc (1.8.0)
44
- rack (3.1.3)
51
+ prism (1.5.0)
52
+ racc (1.8.1)
53
+ rack (3.2.1)
45
54
  rainbow (3.1.1)
46
55
  rake (12.3.3)
47
- regexp_parser (2.9.2)
48
- rexml (3.3.0)
49
- strscan
50
- rubocop (1.64.1)
56
+ regexp_parser (2.11.2)
57
+ rubocop (1.80.2)
51
58
  json (~> 2.3)
52
- language_server-protocol (>= 3.17.0)
59
+ language_server-protocol (~> 3.17.0.2)
60
+ lint_roller (~> 1.1.0)
53
61
  parallel (~> 1.10)
54
62
  parser (>= 3.3.0.2)
55
63
  rainbow (>= 2.2.2, < 4.0)
56
- regexp_parser (>= 1.8, < 3.0)
57
- rexml (>= 3.2.5, < 4.0)
58
- rubocop-ast (>= 1.31.1, < 2.0)
64
+ regexp_parser (>= 2.9.3, < 3.0)
65
+ rubocop-ast (>= 1.46.0, < 2.0)
59
66
  ruby-progressbar (~> 1.7)
60
- unicode-display_width (>= 2.4.0, < 3.0)
61
- rubocop-ast (1.31.3)
62
- parser (>= 3.3.1.0)
63
- rubocop-minitest (0.35.0)
64
- rubocop (>= 1.61, < 2.0)
65
- rubocop-ast (>= 1.31.1, < 2.0)
66
- rubocop-performance (1.21.0)
67
- rubocop (>= 1.48.1, < 2.0)
68
- rubocop-ast (>= 1.31.1, < 2.0)
69
- rubocop-rails (2.25.0)
67
+ unicode-display_width (>= 2.4.0, < 4.0)
68
+ rubocop-ast (1.46.0)
69
+ parser (>= 3.3.7.2)
70
+ prism (~> 1.4)
71
+ rubocop-performance (1.26.0)
72
+ lint_roller (~> 1.1)
73
+ rubocop (>= 1.75.0, < 2.0)
74
+ rubocop-ast (>= 1.44.0, < 2.0)
75
+ rubocop-rails (2.33.3)
70
76
  activesupport (>= 4.2.0)
77
+ lint_roller (~> 1.1)
71
78
  rack (>= 1.1)
72
- rubocop (>= 1.33.0, < 2.0)
73
- rubocop-ast (>= 1.31.1, < 2.0)
74
- rubocop-rails-omakase (1.0.0)
75
- rubocop
76
- rubocop-minitest
77
- rubocop-performance
78
- rubocop-rails
79
+ rubocop (>= 1.75.0, < 2.0)
80
+ rubocop-ast (>= 1.44.0, < 2.0)
81
+ rubocop-rails-omakase (1.1.0)
82
+ rubocop (>= 1.72)
83
+ rubocop-performance (>= 1.24)
84
+ rubocop-rails (>= 2.30)
79
85
  ruby-progressbar (1.13.0)
80
- strscan (3.1.0)
86
+ securerandom (0.4.1)
81
87
  tzinfo (2.0.6)
82
88
  concurrent-ruby (~> 1.0)
83
- unicode-display_width (2.5.0)
84
- uri (0.13.0)
85
- vcr (6.2.0)
89
+ unicode-display_width (3.2.0)
90
+ unicode-emoji (~> 4.1)
91
+ unicode-emoji (4.1.0)
92
+ uri (1.0.3)
93
+ vcr (6.3.1)
94
+ base64
86
95
 
87
96
  PLATFORMS
88
97
  ruby
89
98
 
90
99
  DEPENDENCIES
100
+ activesupport (>= 4.2.0, < 8.0)
91
101
  dotenv
92
102
  minitest (~> 5.0)
93
103
  rake (~> 12.0)
@@ -96,4 +106,4 @@ DEPENDENCIES
96
106
  vcr
97
107
 
98
108
  BUNDLED WITH
99
- 2.3.21
109
+ 2.5.17
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # TwitchRB
2
2
 
3
+ [![CI](https://github.com/deanpcmad/twitchrb/actions/workflows/ci.yml/badge.svg)](https://github.com/deanpcmad/twitchrb/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/twitchrb.svg)](https://badge.fury.io/rb/twitchrb)
5
+ [![Downloads](https://img.shields.io/gem/dt/twitchrb.svg)](https://rubygems.org/gems/twitchrb)
6
+
3
7
  TwitchRB is the easiest and most complete Ruby library for the [Twitch Helix API](https://dev.twitch.tv/docs/api).
4
8
 
5
9
  ## Installation
@@ -275,6 +279,44 @@ These require an application OAuth access token.
275
279
  @client.eventsub_subscriptions.delete(id: "abc12-abc12-abc12")
276
280
  ```
277
281
 
282
+ ### EventSub Conduits
283
+
284
+ Conduits provide a way to receive events over multiple transports. These require an application OAuth access token.
285
+
286
+ ```ruby
287
+ # List all conduits for your application
288
+ @client.eventsub_conduits.list
289
+
290
+ # Create a conduit with a specified number of shards
291
+ # shard_count must be between 1 and 100
292
+ @client.eventsub_conduits.create(shard_count: 10)
293
+
294
+ # Update a conduit's shard count
295
+ @client.eventsub_conduits.update(id: "abc123-def456", shard_count: 20)
296
+
297
+ # Delete a conduit
298
+ @client.eventsub_conduits.delete(id: "abc123-def456")
299
+
300
+ # List shards for a conduit
301
+ # Optional parameters: status, after
302
+ @client.eventsub_conduits.shards(id: "abc123-def456")
303
+ @client.eventsub_conduits.shards(id: "abc123-def456", status: "enabled")
304
+
305
+ # Update shards for a conduit
306
+ # shards is an array of shard objects with id and transport properties
307
+ shards = [
308
+ {
309
+ id: "0",
310
+ transport: {
311
+ method: "webhook",
312
+ callback: "https://example.com/webhooks/callback",
313
+ secret: "your-secret"
314
+ }
315
+ }
316
+ ]
317
+ @client.eventsub_conduits.update_shards(id: "abc123-def456", shards: shards)
318
+ ```
319
+
278
320
  ### Banned Events
279
321
 
280
322
  ```ruby
@@ -564,6 +606,180 @@ messages = [{msg_id: "abc1", msg_text: "is this allowed?"}, {msg_id: "abc2", msg
564
606
  @client.warnings.create broadcaster_id: 123, moderator_id: 123, user_id: 321, reason: "dont do that"
565
607
  ```
566
608
 
609
+ ### Streams
610
+
611
+ ```ruby
612
+ # List live streams
613
+ # Available parameters: user_id, user_login, game_id, type, language, first, before, after
614
+ @client.streams.list
615
+ @client.streams.list(game_id: "509658")
616
+ @client.streams.list(user_login: "twitchdev")
617
+
618
+ # Get followed streams for a user
619
+ # Required scope: user:read:follows
620
+ # user_id must match the currently authenticated user
621
+ @client.streams.followed(user_id: 123)
622
+ ```
623
+
624
+ ### Polls
625
+
626
+ ```ruby
627
+ # List polls for a broadcaster
628
+ # broadcaster_id must match the currently authenticated user
629
+ @client.polls.list(broadcaster_id: 123)
630
+
631
+ # Create a poll
632
+ # broadcaster_id must match the currently authenticated user
633
+ # duration is in seconds (15-1800)
634
+ choices = [
635
+ { title: "Choice 1" },
636
+ { title: "Choice 2" }
637
+ ]
638
+ @client.polls.create(broadcaster_id: 123, title: "What should I play?", choices: choices, duration: 300)
639
+
640
+ # End a poll
641
+ # broadcaster_id must match the currently authenticated user
642
+ # status can be "TERMINATED" or "ARCHIVED"
643
+ @client.polls.end(broadcaster_id: 123, id: "poll-id", status: "terminated")
644
+ ```
645
+
646
+ ### Predictions
647
+
648
+ ```ruby
649
+ # List predictions for a broadcaster
650
+ # broadcaster_id must match the currently authenticated user
651
+ @client.predictions.list(broadcaster_id: 123)
652
+
653
+ # Create a prediction
654
+ # broadcaster_id must match the currently authenticated user
655
+ # duration is in seconds (30-1800)
656
+ outcomes = [
657
+ { title: "Outcome 1" },
658
+ { title: "Outcome 2" }
659
+ ]
660
+ @client.predictions.create(broadcaster_id: 123, title: "Will I win?", outcomes: outcomes, duration: 600)
661
+
662
+ # End a prediction
663
+ # broadcaster_id must match the currently authenticated user
664
+ # status can be "RESOLVED", "CANCELED", or "LOCKED"
665
+ # winning_outcome_id is required when status is "RESOLVED"
666
+ @client.predictions.end(broadcaster_id: 123, id: "prediction-id", status: "resolved", winning_outcome_id: "outcome-id")
667
+ ```
668
+
669
+ ### Subscriptions
670
+
671
+ ```ruby
672
+ # Get all subscriptions for a broadcaster
673
+ # Required scope: channel:read:subscriptions
674
+ # broadcaster_id must match the currently authenticated user
675
+ @client.subscriptions.list(broadcaster_id: 123)
676
+
677
+ # Check if a user is subscribed to a broadcaster
678
+ # Required scope: user:read:subscriptions
679
+ # user_id must match the currently authenticated user
680
+ @client.subscriptions.is_subscribed(broadcaster_id: 123, user_id: 456)
681
+
682
+ # Get subscription counts and points for a broadcaster
683
+ # Required scope: channel:read:subscriptions
684
+ # broadcaster_id must match the currently authenticated user
685
+ @client.subscriptions.counts(broadcaster_id: 123)
686
+ ```
687
+
688
+ ### Search
689
+
690
+ ```ruby
691
+ # Search for categories/games
692
+ @client.search.categories(query: "Just Chatting")
693
+
694
+ # Search for channels
695
+ @client.search.channels(query: "twitchdev")
696
+ ```
697
+
698
+ ### Stream Schedule
699
+
700
+ ```ruby
701
+ # Get stream schedule for a broadcaster
702
+ # broadcaster_id must match the currently authenticated user
703
+ @client.stream_schedule.list(broadcaster_id: 123)
704
+
705
+ # Get iCalendar format of stream schedule
706
+ # broadcaster_id must match the currently authenticated user
707
+ @client.stream_schedule.icalendar(broadcaster_id: 123)
708
+
709
+ # Update stream schedule settings
710
+ # broadcaster_id must match the currently authenticated user
711
+ @client.stream_schedule.update(broadcaster_id: 123, is_vacation_enabled: true)
712
+
713
+ # Create a schedule segment
714
+ # broadcaster_id must match the currently authenticated user
715
+ @client.stream_schedule.create_segment(
716
+ broadcaster_id: 123,
717
+ start_time: "2023-08-01T16:00:00Z",
718
+ timezone: "America/New_York",
719
+ duration: "240",
720
+ is_recurring: false,
721
+ category_id: "509658",
722
+ title: "Special Stream"
723
+ )
724
+
725
+ # Update a schedule segment
726
+ # broadcaster_id must match the currently authenticated user
727
+ @client.stream_schedule.update_segment(broadcaster_id: 123, id: "segment-id", title: "Updated Title")
728
+
729
+ # Delete a schedule segment
730
+ # broadcaster_id must match the currently authenticated user
731
+ @client.stream_schedule.delete_segment(broadcaster_id: 123, id: "segment-id")
732
+ ```
733
+
734
+ ### Stream Markers
735
+
736
+ ```ruby
737
+ # Create a stream marker
738
+ # Required scope: channel:manage:broadcast
739
+ # user_id must match the currently authenticated user
740
+ @client.stream_markers.create(user_id: 123, description: "Important moment")
741
+
742
+ # Get stream markers for a user or video
743
+ # Required scope: user:read:broadcast
744
+ # user_id must match the currently authenticated user
745
+ @client.stream_markers.list(user_id: 123)
746
+ @client.stream_markers.list(video_id: "video-id")
747
+ ```
748
+
749
+ ### Tags
750
+
751
+ ```ruby
752
+ # Get all stream tags
753
+ @client.tags.list
754
+
755
+ # Get stream tags for a specific broadcaster
756
+ @client.tags.stream(broadcaster_id: 123)
757
+
758
+ # Replace stream tags for a broadcaster
759
+ # Required scope: channel:manage:broadcast
760
+ # broadcaster_id must match the currently authenticated user
761
+ tag_ids = ["tag-id-1", "tag-id-2"]
762
+ @client.tags.replace(broadcaster_id: 123, tag_ids: tag_ids)
763
+ ```
764
+
765
+ ### Hype Train Events
766
+
767
+ ```ruby
768
+ # Get hype train events for a broadcaster
769
+ # Required scope: channel:read:hype_train
770
+ # broadcaster_id must match the currently authenticated user
771
+ @client.hype_train_events.list(broadcaster_id: 123)
772
+ ```
773
+
774
+ ### Moderator Events
775
+
776
+ ```ruby
777
+ # Get moderator events for a broadcaster
778
+ # Required scope: moderation:read
779
+ # broadcaster_id must match the currently authenticated user
780
+ @client.moderator_events.list(broadcaster_id: 123)
781
+ ```
782
+
567
783
 
568
784
  ## Contributing
569
785
 
@@ -0,0 +1,128 @@
1
+ module Twitch
2
+ class ErrorGenerator < StandardError
3
+ attr_reader :http_status_code
4
+ attr_reader :twitch_error_code
5
+ attr_reader :twitch_error_message
6
+
7
+ def initialize(response_body, http_status_code)
8
+ @response_body = response_body
9
+ @http_status_code = http_status_code
10
+ set_twitch_error_values
11
+ super(build_message)
12
+ end
13
+
14
+ private
15
+
16
+ def set_twitch_error_values
17
+ @twitch_error_code = @response_body.dig("error")
18
+ @twitch_error_message = @response_body.dig("message")
19
+ end
20
+
21
+ def error_message
22
+ @twitch_error_message || @response_body.dig("error")
23
+ rescue NoMethodError
24
+ "An unknown error occurred."
25
+ end
26
+
27
+ def build_message
28
+ if twitch_error_code.nil?
29
+ return "Error #{@http_status_code}: #{error_message}"
30
+ end
31
+ "Error #{@http_status_code}: #{error_message} '#{twitch_error_message}'"
32
+ end
33
+ end
34
+
35
+ module Errors
36
+ class BadRequestError < ErrorGenerator
37
+ private
38
+
39
+ def error_message
40
+ "Your request was malformed."
41
+ end
42
+ end
43
+
44
+ class AuthenticationMissingError < ErrorGenerator
45
+ private
46
+
47
+ def error_message
48
+ "You did not supply valid authentication credentials."
49
+ end
50
+ end
51
+
52
+ class ForbiddenError < ErrorGenerator
53
+ private
54
+
55
+ def error_message
56
+ "You are not allowed to perform that action."
57
+ end
58
+ end
59
+
60
+ class EntityNotFoundError < ErrorGenerator
61
+ private
62
+
63
+ def error_message
64
+ "No results were found for your request."
65
+ end
66
+ end
67
+
68
+ class ConflictError < ErrorGenerator
69
+ private
70
+
71
+ def error_message
72
+ "Your request was a conflict."
73
+ end
74
+ end
75
+
76
+ class TooManyRequestsError < ErrorGenerator
77
+ private
78
+
79
+ def error_message
80
+ "Your request exceeded the API rate limit."
81
+ end
82
+ end
83
+
84
+ class InternalError < ErrorGenerator
85
+ private
86
+
87
+ def error_message
88
+ "We were unable to perform the request due to server-side problems."
89
+ end
90
+ end
91
+
92
+ class ServiceUnavailableError < ErrorGenerator
93
+ private
94
+
95
+ def error_message
96
+ "You have been rate limited for sending more than 20 requests per second."
97
+ end
98
+ end
99
+
100
+ class NotImplementedError < ErrorGenerator
101
+ private
102
+
103
+ def error_message
104
+ "This resource has not been implemented."
105
+ end
106
+ end
107
+ end
108
+
109
+ class ErrorFactory
110
+ HTTP_ERROR_MAP = {
111
+ 400 => Errors::BadRequestError,
112
+ 401 => Errors::AuthenticationMissingError,
113
+ 403 => Errors::ForbiddenError,
114
+ 404 => Errors::EntityNotFoundError,
115
+ 409 => Errors::ConflictError,
116
+ 429 => Errors::TooManyRequestsError,
117
+ 500 => Errors::InternalError,
118
+ 503 => Errors::ServiceUnavailableError,
119
+ 501 => Errors::NotImplementedError
120
+ }.freeze
121
+
122
+ def self.create(response_body, http_status_code)
123
+ status = http_status_code
124
+ error_class = HTTP_ERROR_MAP[status] || ErrorGenerator
125
+ error_class.new(response_body, http_status_code) if error_class
126
+ end
127
+ end
128
+ end
@@ -29,31 +29,20 @@ module Twitch
29
29
  end
30
30
 
31
31
  def handle_response(response)
32
- case response.status
33
- when 400
34
- raise Error, "Error 400: Your request was malformed. '#{response.body["message"]}'"
35
- when 401
36
- raise Error, "Error 401: You did not supply valid authentication credentials. '#{response.body["error"]}'"
37
- when 403
38
- raise Error, "Error 403: You are not allowed to perform that action. '#{response.body["error"]}'"
39
- when 404
40
- raise Error, "Error 404: No results were found for your request. '#{response.body["error"]}'"
41
- when 409
42
- raise Error, "Error 409: Your request was a conflict. '#{response.body["message"]}'"
43
- when 422
44
- raise Error, "Error 422: Unprocessable Entity. '#{response.body["message"]}"
45
- when 429
46
- raise Error, "Error 429: Your request exceeded the API rate limit. '#{response.body["error"]}'"
47
- when 500
48
- raise Error, "Error 500: We were unable to perform the request due to server-side problems. '#{response.body["error"]}'"
49
- when 503
50
- raise Error, "Error 503: You have been rate limited for sending more than 20 requests per second. '#{response.body["error"]}'"
51
- when 204
52
- # 204 is a response for success on Twitch's API
53
- return true
54
- end
55
-
56
- response
32
+ return true if response.status == 204
33
+ return response unless error?(response)
34
+
35
+ raise_error(response)
36
+ end
37
+
38
+ def error?(response)
39
+ [ 400, 401, 403, 404, 409, 429, 500, 501, 503 ].include?(response.status) ||
40
+ response.body&.key?("error")
41
+ end
42
+
43
+ def raise_error(response)
44
+ error = Twitch::ErrorFactory.create(response.body, response.status)
45
+ raise error if error
57
46
  end
58
47
  end
59
48
  end
@@ -1,3 +1,3 @@
1
1
  module Twitch
2
- VERSION = "1.3.0"
2
+ VERSION = "1.5.0"
3
3
  end
data/lib/twitch.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  require "faraday"
2
2
  require "json"
3
+ require "ostruct"
3
4
  require "twitch/version"
4
5
 
5
6
  module Twitch
7
+ autoload :Error, "twitch/error"
8
+ autoload :Errors, "twitch/error_generator"
9
+ autoload :ErrorGenerator, "twitch/error_generator"
10
+ autoload :ErrorFactory, "twitch/error_generator"
11
+
6
12
  autoload :Client, "twitch/client"
7
13
  autoload :Collection, "twitch/collection"
8
- autoload :Error, "twitch/error"
9
14
  autoload :Resource, "twitch/resource"
10
15
  autoload :Object, "twitch/object"
11
16
 
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4"
data/twitchrb.gemspec CHANGED
@@ -24,5 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = [ "lib" ]
26
26
 
27
- spec.add_dependency "faraday", "~> 2.0"
27
+ spec.add_dependency "faraday", "~> 2.11"
28
+ spec.add_dependency "ostruct", "~> 0.6.0"
28
29
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitchrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-06-28 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: faraday
@@ -16,15 +15,28 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '2.0'
18
+ version: '2.11'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '2.0'
27
- description:
25
+ version: '2.11'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ostruct
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.6.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.6.0
28
40
  email:
29
41
  - dean@deanpcmad.com
30
42
  executables: []
@@ -33,6 +45,7 @@ extra_rdoc_files: []
33
45
  files:
34
46
  - ".env.example"
35
47
  - ".github/FUNDING.yml"
48
+ - ".github/dependabot.yml"
36
49
  - ".github/workflows/ci.yml"
37
50
  - ".gitignore"
38
51
  - ".rubocop.yml"
@@ -47,6 +60,7 @@ files:
47
60
  - lib/twitch/client.rb
48
61
  - lib/twitch/collection.rb
49
62
  - lib/twitch/error.rb
63
+ - lib/twitch/error_generator.rb
50
64
  - lib/twitch/oauth.rb
51
65
  - lib/twitch/object.rb
52
66
  - lib/twitch/objects/automod_setting.rb
@@ -106,7 +120,6 @@ files:
106
120
  - lib/twitch/resources/custom_reward_redemptions.rb
107
121
  - lib/twitch/resources/custom_rewards.rb
108
122
  - lib/twitch/resources/emotes.rb
109
- - lib/twitch/resources/event_sub_conduit.rb
110
123
  - lib/twitch/resources/eventsub_conduits.rb
111
124
  - lib/twitch/resources/eventsub_subscriptions.rb
112
125
  - lib/twitch/resources/games.rb
@@ -132,6 +145,7 @@ files:
132
145
  - lib/twitch/resources/whispers.rb
133
146
  - lib/twitch/version.rb
134
147
  - lib/twitchrb.rb
148
+ - mise.toml
135
149
  - twitchrb.gemspec
136
150
  homepage: https://deanpcmad.com
137
151
  licenses:
@@ -139,7 +153,6 @@ licenses:
139
153
  metadata:
140
154
  homepage_uri: https://deanpcmad.com
141
155
  source_code_uri: https://github.com/deanpcmad/twitchrb
142
- post_install_message:
143
156
  rdoc_options: []
144
157
  require_paths:
145
158
  - lib
@@ -154,8 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
167
  - !ruby/object:Gem::Version
155
168
  version: '0'
156
169
  requirements: []
157
- rubygems_version: 3.5.9
158
- signing_key:
170
+ rubygems_version: 3.6.7
159
171
  specification_version: 4
160
172
  summary: A Ruby library for interacting with the Twitch Helix API
161
173
  test_files: []
@@ -1,19 +0,0 @@
1
- module Twitch
2
- class EventSubSubscriptionsResource < Resource
3
- def list(**params)
4
- response = get_request("eventsub/subscriptions", params: params)
5
- Collection.from_response(response, type: EventSubSubscription)
6
- end
7
-
8
- def create(type:, version:, condition:, transport:, **params)
9
- attributes = { type: type, version: version, condition: condition, transport: transport }.merge(params)
10
- response = post_request("eventsub/subscriptions", body: attributes)
11
-
12
- EventSubSubscription.new(response.body.dig("data")[0]) if response.success?
13
- end
14
-
15
- def delete(id:)
16
- delete_request("eventsub/subscriptions", params: { id: id })
17
- end
18
- end
19
- end