itch_client 0.2.0 → 0.4.1

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: 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