itch_client 0.2.0 → 0.4.1

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: 9e207ec3ac07a0a26dd3315a9e0cf1a9e0e6440559b07dffbc2f673aaac24231
4
- data.tar.gz: f2165aebc46c8486531bf679d03efbd2c0c5104b6854369031f69375088b9cf4
3
+ metadata.gz: e78c3d091abc57746fe57324e61e6328fa7194e8b50c3fde4d89426cbff9c9c4
4
+ data.tar.gz: 3b2a35f25b8dc886330a3d5b7211accc8f52d75c316fe5b827e23a0f6bf20e8c
5
5
  SHA512:
6
- metadata.gz: feb4a98fcfd03fee02025981aa54a242cec85d4122fb74eede970d3b189c580c0898b5fea59c795e63beefb36aaf6bd5714ca8fb56406f5ed2c7812c9bdf452f
7
- data.tar.gz: 48b5f07013f2e6b8435d8dafb0c708ff3b97f93d4fa4273f30024a838299c2b5c9532f669b6d6025c94b425bcdf99faaada80fcf30856c38c427e6b32cda0e33
6
+ metadata.gz: d6aec1b9bf214ec8db6584eba3503273dfaf8b7c629c7db6214b5acfcf20b3be605b1d9bf3a125652bd919e2e9d5e55f7576967b0ae3e29986168690e686f7cf
7
+ data.tar.gz: dacd4cfc500a02169a96eb984ae283bb972057f618f2b239e1a5daf45bd17d405235831fbfaaa63aa37339966c706f689a4ad2ac0091d9d6f5b21affab688dc6
data/.gitignore CHANGED
@@ -10,3 +10,6 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  .env
13
+ cookies.yml
14
+ *.gem
15
+ .tool-versions
data/CHANGELOG.md CHANGED
@@ -1,4 +1,14 @@
1
- ## [Unreleased]
1
+ ## [0.4.0] - 2022-04-03
2
+
3
+ - Added review list
4
+
5
+ ## [0.3.0] - 2021-10-13
6
+
7
+ - Added bundle list
8
+
9
+ ## [0.2.0] - 2021-05-27
10
+
11
+ - Improved error responses
2
12
 
3
13
  ## [0.1.0] - 2021-05-22
4
14
 
data/Gemfile CHANGED
@@ -12,3 +12,5 @@ gem "rspec", "~> 3.0"
12
12
  gem "rubocop", "~> 1.7"
13
13
 
14
14
  gem "irb", "~> 1.3"
15
+
16
+ gem "pry"
data/Gemfile.lock CHANGED
@@ -1,26 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- itch_client (0.2.0)
4
+ itch_client (0.4.1)
5
5
  mechanize (~> 2.8)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.7.0)
10
+ addressable (2.8.0)
11
11
  public_suffix (>= 2.0.2, < 5.0)
12
12
  ast (2.4.2)
13
+ coderay (1.1.3)
13
14
  connection_pool (2.2.5)
14
- diff-lcs (1.4.4)
15
+ diff-lcs (1.5.0)
15
16
  domain_name (0.5.20190701)
16
17
  unf (>= 0.0.5, < 1.0.0)
17
- http-cookie (1.0.3)
18
+ http-cookie (1.0.4)
18
19
  domain_name (~> 0.5)
19
- io-console (0.5.9)
20
- irb (1.3.5)
21
- reline (>= 0.1.5)
22
- mechanize (2.8.1)
23
- addressable (~> 2.7)
20
+ io-console (0.5.11)
21
+ irb (1.4.1)
22
+ reline (>= 0.3.0)
23
+ mechanize (2.8.4)
24
+ addressable (~> 2.8)
24
25
  domain_name (~> 0.5, >= 0.5.20190701)
25
26
  http-cookie (~> 1.0, >= 1.0.3)
26
27
  mime-types (~> 3.0)
@@ -30,64 +31,72 @@ GEM
30
31
  rubyntlm (~> 0.6, >= 0.6.3)
31
32
  webrick (~> 1.7)
32
33
  webrobots (~> 0.1.2)
33
- mime-types (3.3.1)
34
+ method_source (1.0.0)
35
+ mime-types (3.4.1)
34
36
  mime-types-data (~> 3.2015)
35
- mime-types-data (3.2021.0225)
37
+ mime-types-data (3.2022.0105)
38
+ mini_portile2 (2.8.0)
36
39
  net-http-digest_auth (1.4.1)
37
40
  net-http-persistent (4.0.1)
38
41
  connection_pool (~> 2.2)
39
- nokogiri (1.11.5-x86_64-linux)
42
+ nokogiri (1.13.6)
43
+ mini_portile2 (~> 2.8.0)
40
44
  racc (~> 1.4)
41
- parallel (1.20.1)
42
- parser (3.0.1.1)
45
+ parallel (1.22.1)
46
+ parser (3.1.1.0)
43
47
  ast (~> 2.4.1)
44
- public_suffix (4.0.6)
45
- racc (1.5.2)
46
- rainbow (3.0.0)
47
- rake (13.0.3)
48
- regexp_parser (2.1.1)
49
- reline (0.2.5)
48
+ pry (0.14.1)
49
+ coderay (~> 1.1)
50
+ method_source (~> 1.0)
51
+ public_suffix (4.0.7)
52
+ racc (1.6.0)
53
+ rainbow (3.1.1)
54
+ rake (13.0.6)
55
+ regexp_parser (2.2.1)
56
+ reline (0.3.1)
50
57
  io-console (~> 0.5)
51
58
  rexml (3.2.5)
52
- rspec (3.10.0)
53
- rspec-core (~> 3.10.0)
54
- rspec-expectations (~> 3.10.0)
55
- rspec-mocks (~> 3.10.0)
56
- rspec-core (3.10.1)
57
- rspec-support (~> 3.10.0)
58
- rspec-expectations (3.10.1)
59
+ rspec (3.11.0)
60
+ rspec-core (~> 3.11.0)
61
+ rspec-expectations (~> 3.11.0)
62
+ rspec-mocks (~> 3.11.0)
63
+ rspec-core (3.11.0)
64
+ rspec-support (~> 3.11.0)
65
+ rspec-expectations (3.11.0)
59
66
  diff-lcs (>= 1.2.0, < 2.0)
60
- rspec-support (~> 3.10.0)
61
- rspec-mocks (3.10.2)
67
+ rspec-support (~> 3.11.0)
68
+ rspec-mocks (3.11.1)
62
69
  diff-lcs (>= 1.2.0, < 2.0)
63
- rspec-support (~> 3.10.0)
64
- rspec-support (3.10.2)
65
- rubocop (1.15.0)
70
+ rspec-support (~> 3.11.0)
71
+ rspec-support (3.11.0)
72
+ rubocop (1.26.1)
66
73
  parallel (~> 1.10)
67
- parser (>= 3.0.0.0)
74
+ parser (>= 3.1.0.0)
68
75
  rainbow (>= 2.2.2, < 4.0)
69
76
  regexp_parser (>= 1.8, < 3.0)
70
77
  rexml
71
- rubocop-ast (>= 1.5.0, < 2.0)
78
+ rubocop-ast (>= 1.16.0, < 2.0)
72
79
  ruby-progressbar (~> 1.7)
73
80
  unicode-display_width (>= 1.4.0, < 3.0)
74
- rubocop-ast (1.5.0)
75
- parser (>= 3.0.1.1)
81
+ rubocop-ast (1.16.0)
82
+ parser (>= 3.1.1.0)
76
83
  ruby-progressbar (1.11.0)
77
84
  rubyntlm (0.6.3)
78
85
  unf (0.1.4)
79
86
  unf_ext
80
- unf_ext (0.0.7.7)
81
- unicode-display_width (2.0.0)
87
+ unf_ext (0.0.8.1)
88
+ unicode-display_width (2.1.0)
82
89
  webrick (1.7.0)
83
90
  webrobots (0.1.2)
84
91
 
85
92
  PLATFORMS
93
+ ruby
86
94
  x86_64-linux
87
95
 
88
96
  DEPENDENCIES
89
97
  irb (~> 1.3)
90
98
  itch_client!
99
+ pry
91
100
  rake (~> 13.0)
92
101
  rspec (~> 3.0)
93
102
  rubocop (~> 1.7)
data/README.md CHANGED
@@ -171,6 +171,27 @@ client.game(12345).css
171
171
  client.game(12345).css = "body { background-color: green; }"
172
172
  ```
173
173
 
174
+ ### Reviews
175
+
176
+ Fetch current reviews
177
+
178
+ ```ruby
179
+ reviews = client.game(12345).reviews.list
180
+ #=>
181
+ [
182
+ #<Itch::Review:0x0000557aa98c7930
183
+ @id="123456789",
184
+ @user_name="Billiam",
185
+ @user_id="billiam",
186
+ @date=<DateTime: 2022-04-03T10:02:00+00:00>,
187
+ @stars=4,
188
+ @review=[
189
+ "I really like this game",
190
+ "So much that I've added a second paragraph"
191
+ ],
192
+ ]
193
+ ```
194
+
174
195
  ### Rewards
175
196
 
176
197
  Fetch reward CSV data
@@ -253,6 +274,24 @@ end
253
274
  client.game(12345).rewards.save(filtered_rewards)
254
275
  ```
255
276
 
277
+ ## Bundles
278
+
279
+ Fetch current bundles
280
+
281
+ ```ruby
282
+ client.bundles.list
283
+
284
+ #=>
285
+ [
286
+ #<Itch::Bundle:0x0000557aa98c7930
287
+ @id="123",
288
+ @earnings=BigDecimal(123.00),
289
+ @price=BigDecimal(10.00),
290
+ @purchases=10,
291
+ @title="My Bundle!"
292
+ ]
293
+ ```
294
+
256
295
  ## Development
257
296
 
258
297
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/itch_client.gemspec CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.metadata["homepage_uri"] = spec.homepage
17
17
  spec.metadata["source_code_uri"] = spec.homepage
18
18
  spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
19
+ spec.metadata["rubygems_mfa_required"] = "true"
19
20
 
20
21
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "simple_inspect"
4
+
5
+ module Itch
6
+ # Data container for single bundle
7
+ class Bundle
8
+ include SimpleInspect
9
+
10
+ attr_accessor :id, :title, :games, :purchases, :price, :earnings
11
+
12
+ def initialize(id, title, purchases, price, earnings)
13
+ @id = id
14
+ @title = title
15
+ @purchases = purchases
16
+ @price = price
17
+ @earnings = earnings
18
+ end
19
+
20
+ def url
21
+ format(Itch::URL::BUNDLE, id: @id)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+
5
+ require_relative "simple_inspect"
6
+ require_relative "bundle"
7
+ require_relative "request"
8
+ require_relative "require_auth"
9
+
10
+ module Itch
11
+ # Fetch bundles
12
+ class Bundles
13
+ include RequireAuth
14
+ include SimpleInspect
15
+ include Request
16
+
17
+ def initialize(agent)
18
+ @agent = agent
19
+ end
20
+
21
+ def list
22
+ page = with_login do
23
+ @agent.get(bundles_url)
24
+ end
25
+
26
+ page.css(".bundle_list table > tr").map do |row|
27
+ parse_row(row)
28
+ end
29
+ end
30
+
31
+ def parse_row(row)
32
+ id = row.at_xpath("td[2]/a/@href").value.match(%r{^/b/(\d+)/})[1]
33
+ vals = row.css("td").map(&:text)
34
+ price = BigDecimal(vals[5].gsub(/[^\d.-]/, ""))
35
+ earnings = BigDecimal(vals[6].gsub(/[\D-]/, ""))
36
+
37
+ Bundle.new(id, vals[1], vals[4].to_i, price, earnings)
38
+ end
39
+
40
+ def bundles_url
41
+ Itch::URL::BUNDLES
42
+ end
43
+ end
44
+ end
data/lib/itch/client.rb CHANGED
@@ -4,6 +4,7 @@ require "forwardable"
4
4
  require "mechanize"
5
5
 
6
6
  require_relative "auth"
7
+ require_relative "bundles"
7
8
  require_relative "game"
8
9
  require_relative "game_map"
9
10
  require_relative "purchases"
@@ -35,6 +36,10 @@ module Itch
35
36
  @purchases ||= Purchases.new(@agent)
36
37
  end
37
38
 
39
+ def bundles
40
+ @bundles ||= Bundles.new(@agent)
41
+ end
42
+
38
43
  def game_map
39
44
  @game_map ||= GameMap.new(@agent)
40
45
  end
data/lib/itch/game.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "reviews"
3
4
  require_relative "rewards"
4
5
  require_relative "reward"
5
6
  require_relative "require_auth"
@@ -48,6 +49,10 @@ module Itch
48
49
  Rewards.new(@agent, @id)
49
50
  end
50
51
 
52
+ def reviews
53
+ Reviews.new(@agent, @id)
54
+ end
55
+
51
56
  def reward(id)
52
57
  rewards.find { |reward| reward.id == id }
53
58
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "simple_inspect"
4
+
5
+ module Itch
6
+ # Data container for single review
7
+ class Review
8
+ include SimpleInspect
9
+
10
+ attr_reader :id, :user_name, :user_id, :stars, :date, :review
11
+
12
+ # rubocop:disable Metrics/ParameterLists
13
+ def initialize(user_name:, user_id:, stars:, date:, review:, id: nil)
14
+ @id = id
15
+ @user_name = user_name
16
+ @user_id = user_id
17
+ @stars = stars
18
+ @date = date
19
+ @review = review
20
+ end
21
+ # rubocop:enable Metrics/ParameterLists
22
+ end
23
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ require_relative "require_auth"
6
+ require_relative "simple_inspect"
7
+ require_relative "review"
8
+ require_relative "request"
9
+
10
+ module Itch
11
+ # Fetch reviews
12
+ class Reviews
13
+ include SimpleInspect
14
+ include RequireAuth
15
+ include Request
16
+
17
+ def initialize(agent, game_id)
18
+ @agent = agent
19
+ @game_id = game_id
20
+ end
21
+
22
+ def list
23
+ all_reviews = []
24
+
25
+ page_number = 1
26
+ loop do
27
+ page_reviews = parse_page_reviews(page_number)
28
+
29
+ break if page_reviews.empty?
30
+
31
+ all_reviews += page_reviews
32
+ page_number += 1
33
+ sleep 0.5
34
+ end
35
+
36
+ all_reviews
37
+ end
38
+
39
+ protected
40
+
41
+ def parse_page_reviews(page_number)
42
+ page = with_login do
43
+ @agent.get(review_url(page_number))
44
+ end
45
+
46
+ raise Error, "Could not find game id #{@game_id} rewards" unless page.code == "200"
47
+
48
+ page.css(".content_column .rating").map do |row|
49
+ parse_row row
50
+ end
51
+ end
52
+
53
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
54
+ def parse_row(row)
55
+ id = row.at_css("button[data-lightbox_url]")["data-lightbox_url"].split("/").last
56
+ stars = row.css(".star_picker .icon-star").length
57
+ header = row.at_css(".row_header")
58
+ date = DateTime.parse header.at_css("abbr")["title"].strip
59
+
60
+ user_link = header.at_css(".user_link")
61
+ user_name = user_link.search("./text()").text.strip
62
+ user_id = user_link["href"].split("/").last
63
+
64
+ text = row.css(".blurb p").map(&:text)
65
+
66
+ Review.new(
67
+ id: id,
68
+ user_name: user_name,
69
+ user_id: user_id,
70
+ stars: stars,
71
+ date: date,
72
+ review: text
73
+ )
74
+ end
75
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
76
+
77
+ def review_url(page = 1)
78
+ format(Itch::URL::REVIEWS, id: @game_id, page: page)
79
+ end
80
+ end
81
+ end
data/lib/itch/rewards.rb CHANGED
@@ -15,7 +15,7 @@ module Itch
15
15
  include RequireAuth
16
16
  include Request
17
17
 
18
- REWARD_DATA = /GameEdit\.EditRewards\(.*?(?:"rewards":(\[.*\]),)?"reward_noun":"(.*(?<!\\))"}\)/.freeze
18
+ REWARD_DATA = /GameEdit\.EditRewards\(.*?(?:"rewards":(\[.*?\]),)?"reward_noun":"(.*?)(?<!\\)"/.freeze
19
19
 
20
20
  def initialize(agent, game_id)
21
21
  @agent = agent
@@ -106,9 +106,9 @@ module Itch
106
106
  input.name.match(/^rewards\[(\d+)\]\[id\]/)
107
107
  end.value
108
108
 
109
- attributes = %w[title description amount price].map do |name|
109
+ attributes = %w[title description amount price].to_h do |name|
110
110
  [name.to_sym, row.css_at(".reward_#{name}_input").value]
111
- end.to_h
111
+ end
112
112
  attributes[:claimed] = row.css_at(".claimed_count").text
113
113
 
114
114
  Reward.new(@agent, @game_id, id, attributes)
data/lib/itch/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Itch
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.1"
5
5
  end
data/lib/itch_client.rb CHANGED
@@ -28,11 +28,14 @@ module Itch
28
28
 
29
29
  module URL
30
30
  DASHBOARD = "https://itch.io/dashboard"
31
+ BUNDLES = "https://itch.io/dashboard/bundles"
32
+ BUNDLE = "https://itch.io/bundle/%<id>d"
31
33
  EDIT_GAME = "https://itch.io/game/edit/%<id>d"
32
34
  GAME = "https://%<username>s.itch.io/%<slug>s"
33
35
  LOGIN = "https://itch.io/login"
34
36
  MONTH_PURCHASES_CSV = "https://itch.io/export-purchases/by-date/%<month>d-%<year>d"
35
37
  PURCHASES_CSV = "https://itch.io/export-purchases/all"
38
+ REVIEWS = "https://itch.io/game/ratings/%<id>d?page=%<page>d"
36
39
  REWARD_CSV = "https://itch.io/game/rewards/%<id>d/claimed?format=csv"
37
40
  REWARDS = "https://itch.io/game/rewards/%<id>d"
38
41
  TOTP_FRAGMENT = "https://itch.io/totp/verify/"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itch_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Billiam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-27 00:00:00.000000000 Z
11
+ date: 2022-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mechanize
@@ -45,12 +45,16 @@ files:
45
45
  - bin/setup
46
46
  - itch_client.gemspec
47
47
  - lib/itch/auth.rb
48
+ - lib/itch/bundle.rb
49
+ - lib/itch/bundles.rb
48
50
  - lib/itch/client.rb
49
51
  - lib/itch/game.rb
50
52
  - lib/itch/game_map.rb
51
53
  - lib/itch/purchases.rb
52
54
  - lib/itch/request.rb
53
55
  - lib/itch/require_auth.rb
56
+ - lib/itch/review.rb
57
+ - lib/itch/reviews.rb
54
58
  - lib/itch/reward.rb
55
59
  - lib/itch/rewards.rb
56
60
  - lib/itch/simple_inspect.rb
@@ -63,6 +67,7 @@ metadata:
63
67
  homepage_uri: https://github.com/Billiam/itch-client
64
68
  source_code_uri: https://github.com/Billiam/itch-client
65
69
  changelog_uri: https://github.com/Billiam/itch-client/CHANGELOG.md
70
+ rubygems_mfa_required: 'true'
66
71
  post_install_message:
67
72
  rdoc_options: []
68
73
  require_paths:
@@ -78,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
83
  - !ruby/object:Gem::Version
79
84
  version: '0'
80
85
  requirements: []
81
- rubygems_version: 3.2.15
86
+ rubygems_version: 3.1.6
82
87
  signing_key:
83
88
  specification_version: 4
84
89
  summary: Itch.io screen scraping utility