steam-trade 0.0.4 → 0.0.5

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
  SHA1:
3
- metadata.gz: d174f053f0d7882ecbb2ec1af0cf9c56e8399d94
4
- data.tar.gz: 07d6eefabd7144cc36467186835c7d58d3bff31b
3
+ metadata.gz: 34bdbd304683a4b23f616f4b8ebfb86f05c6a5f5
4
+ data.tar.gz: 0af0c76c9407399eaec724220221219bba88382b
5
5
  SHA512:
6
- metadata.gz: 3337852cc85e4fcf85c65f22b263927c3cb470456b19fbdf285ea7bdb7448c6e6e109e6f7c6de366f603fa53c1bc4118dccfc2879f61b12e185efe1e45c8aa3a
7
- data.tar.gz: 3ded4edd8fb64a7c9d097c207670e4744d9e6d913929e1699f7271ec50ac8e6d81fd266f29ab7909063642d40f4f9efa19d64687d69dc3117f8339ec233c6349
6
+ metadata.gz: c44ba8afd2b5441d8b52b039ef7260473e11a6a23116021073dbd6c260132c8bfe0b856efce97ccc1446bb874c30666c9acd04df9ddba804c7c27b0b790d082f
7
+ data.tar.gz: f8f65ea446d9a23a221aad67baa992ea0d5805df846ad1ff5920eb972128d7f094d54650637290ad82b6937b2fbf352e70f36494a0534b506ebeeb2a1ba7cb8d
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # steam-trade
2
2
 
3
- This gem simplifes/allows sending steam trade offers programmatically
3
+ This gem simplifes/allows sending steam trade offers programmatically.
4
4
 
5
+ this gem is primarly for trading cards, tho can be used to CS:GO and other games inventories
5
6
  ## Installation
6
7
  in your commandline :
7
8
 
@@ -12,7 +13,7 @@ First you need to require the gem:
12
13
  ```ruby
13
14
  require 'steam-trade'
14
15
  ```
15
-
16
+ ## Logging-in
16
17
  then you need to login and optionally set your shared_secret and identity_secret:
17
18
  - `shared_secret` is used to generate steam authentication codes so you won't have to write them manually each time you login.
18
19
  - `identity_secret` is used to confirm trade offers automatically.
@@ -24,14 +25,42 @@ account = Handler.new('username','password','shared_secret') # share secret is o
24
25
 
25
26
 
26
27
  account.mobile_info('identity_secret')
27
- #identity_secret is requred
28
+ #identity_secret is required
28
29
 
29
30
  ```
31
+ ## Getting someone's inventory
32
+ #### `normal_get_inventory('steamid','inventoryappid','contextid')`
33
+ - `steamid` is the target's steamid
34
+ - `inventoryappid` is the inventory type you want to load, ex : normal inventory(the one which holds trading cards), it's is 753
35
+ - `contextid` required to make a correct request to steam servers, ex:for normal inventory(the one which holds trading cards), it's is 6
36
+ - if you call `normal_get_inventory()` with no params, it will be default use the current logged-in account `steamid`, `inventoryappid = 753` and `contextid = 6`
37
+
38
+ ```ruby
39
+ require 'steam-trade'
40
+
41
+ account = Handler.new('username','password','shared_secret')
42
+ account.mobile_info('identity_secret')
43
+
44
+ my_inventory = normal_get_inventory() #if you are logged in you can call this command with no parameters to get the logged account's inventory
45
+
46
+ partner_inventory = normal_get_inventory('76561198044170935')
47
+ ```
48
+ the returned items from `normal_get_inventory()` are in the form of an array example : `[item1,item2,item3...itemN]`.
49
+
50
+ each item is a hash which contains information about the item in the form of `{"appid"=>'xxx',"contextid"=>'xxx',"assetid" => 'xxx',"classid"=> 'xxx',......"name"=> 'xxxx',"market_fee_app" => 'xxx',....}`.
51
+
52
+ `market_fee_app` key gives you the appid of the game's app ( for trading cards), for other items technically `inventoryappid` is the games appid.
53
+
54
+ `name` key gives you the item name.
55
+ ####
30
56
 
31
- then you can send your offer
57
+ **IMPORTANT**: `normal_get_inventory()` will load the whole target inventory, for each **5k** of items, you are adding **~40MB** to your memory and of course will affect performance of the code and the computer
58
+ ## Sending a trade offer
59
+ then you can send your offer
32
60
  - `Myarray` is an array which contains hashes of selected items to send in the offer. (currently you must get this alone)
33
61
  - `Theirarray` is an array which contains hashes of selected items to receive in the offer. (currently you must get this alone)
34
62
  - `trade_offer_link` is the trade link of you partner `ex: https://steamcommunity.com/tradeoffer/new/?partner=410155236&token=H-yK-GFt`
63
+ - `trade_offer_link` can also be a steamID, however using a steamID requires you and your partner to be friends on steam
35
64
  - `message` is the comment you want to include in the trade offer
36
65
 
37
66
  - `Myarray`, `Theirarray`, `trade_offer_link` are required, `message` is optional
@@ -0,0 +1,133 @@
1
+ module BadgeCommands
2
+
3
+ def sets_count(steamid = @steamid, use_nonmarketable = true)
4
+
5
+
6
+ if steamid == nil
7
+ output "no steamid specified"
8
+ return
9
+ end
10
+
11
+ thread = Thread.new(steamid) { |steamid| ##getting name
12
+ targetname = ''
13
+ begin
14
+ data = get_player_summaries(steamid)
15
+ data.each { |acc|
16
+ if id["steamid"].to_s == steamid.to_s
17
+ targetname = id["personaname"]
18
+ end
19
+ }
20
+ rescue
21
+ targetname = ''
22
+ end
23
+ }
24
+
25
+ items = normal_get_inventory(steamid)
26
+ sorted = {}
27
+ items.each { |asset|
28
+ if use_nonmarketable == false
29
+ if asset["marketable"] == 0 || asset["tags"][-1]["localized_tag_name"] != "Trading Card" || asset["tags"][-2]["localized_tag_name"] == "Foil"
30
+ next
31
+ end
32
+ else
33
+ if asset["tags"][-1]["localized_tag_name"] != "Trading Card" || asset["tags"][-2]["localized_tag_name"] == "Foil"
34
+ next
35
+ end
36
+ end
37
+
38
+ name = asset["name"].sub(" (Trading Card)", "")
39
+ appid = asset["market_fee_app"].to_s
40
+ if sorted.has_key?(appid) == true
41
+ if sorted[appid].has_key?(name) == true
42
+ sorted[appid][name] = sorted[appid][name] + 1
43
+ elsif sorted[appid].has_key?(name) == false
44
+ sorted[appid][name] = 1
45
+ end
46
+ elsif sorted.has_key?(appid) == false
47
+ sorted[appid] = {}
48
+ sorted[appid][name] = 1
49
+ end
50
+ }
51
+
52
+ bigdata = JSON.parse(File.read("#{@libdir}/blueprints/byappid.json",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
53
+ counted = {}
54
+
55
+ sorted.each { |appid,cards|
56
+
57
+
58
+ counted[appid] = bigdata[appid].merge(cards)
59
+ }
60
+
61
+ setsowned = {}
62
+ numberofsets = 0
63
+ total_non_foil = 0
64
+
65
+ counted.each { |appid,cards|
66
+ lowest = 9999
67
+ cards.each { |cardname, amount|
68
+ if amount < lowest then lowest = amount end
69
+ total_non_foil = total_non_foil + amount
70
+ }
71
+ setsowned[appid] = lowest
72
+ numberofsets = numberofsets + lowest
73
+ }
74
+
75
+ persona = thread.value
76
+ write_badges(counted,setsowned,numberofsets,total_non_foil, use_nonmarketable,persona,steamid)
77
+ if use_nonmarketable == false
78
+ return {'sets' => counted, 'appxsets' => setsowned, 'totalsets' => numberofsets, 'totalcards' => total_non_foil, 'marketable' => false}
79
+ else
80
+ return {'sets' => counted, 'appxsets' => setsowned, 'totalsets' => numberofsets, 'totalcards' => total_non_foil, 'marketable' => true}
81
+ end
82
+ end
83
+
84
+
85
+ private
86
+ def write_badges(hashofcards,eachappidsets,totalsets,total_non_foil,use_nonmarketable,persona,steamid)
87
+ if persona == ''
88
+ filename = steamid
89
+ else
90
+ filename = persona
91
+ end
92
+
93
+ "./#{filename}_badges.txt"
94
+ titles = JSON.parse(File.read("#{@libdir}/blueprints/appid_title.json",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
95
+ eachappidsets = eachappidsets.sort_by do |k,v|
96
+ v
97
+ end
98
+ eachappidsets.reverse!
99
+ begin
100
+ File.truncate("./#{filename}_badges.txt", 0)
101
+ rescue
102
+ end
103
+
104
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "for #{persona}(#{steamid})"}
105
+ if use_nonmarketable == false
106
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total non-foil trading cards #{total_non_foil}"}
107
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "only marketable cards are counted"}
108
+ else
109
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total non-foil trading cards #{total_non_foil}"}
110
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "all cards counted including non-marketable"}
111
+ end
112
+
113
+
114
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total sets in target account #{totalsets}"}
115
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
116
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
117
+
118
+
119
+ eachappidsets.each { |appid, sets|
120
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "#{titles[appid]}, sets = #{sets}, appid = #{appid}"}
121
+ hashofcards[appid].each { |cardname, owned|
122
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "#{cardname} xxx #{owned}"}
123
+ }
124
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
125
+ File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
126
+ }
127
+
128
+ output "badges.txt has been created"
129
+ end
130
+
131
+
132
+
133
+ end
@@ -1,8 +1,8 @@
1
- require 'Guard.rb'
1
+
2
2
 
3
3
 
4
4
  module ConfirmationCommands
5
- include GuardCommands
5
+
6
6
 
7
7
 
8
8
 
@@ -54,8 +54,7 @@ module ConfirmationCommands
54
54
  response = @session.get('https://steamcommunity.com/mobileconf/conf', params, no, headers)
55
55
  html = response.content
56
56
  if html.include?('Steam Guard Mobile Authenticator is providing incorrect Steam Guard codes.')
57
- puts "invalid steammguard"
58
- exit
57
+ raise("identity secret: #{@identity_secret} is incorrect")
59
58
  end
60
59
  return html
61
60
  end
@@ -71,8 +70,7 @@ module ConfirmationCommands
71
70
  return confirmhash
72
71
  end
73
72
  }
74
- puts "did not find a confirmation"
75
- exit
73
+ raise("Could not find the offer to confirm")
76
74
  end
77
75
 
78
76
  def fetch_confirmation_details_page(hash) ##eigth
@@ -4,13 +4,14 @@ module GuardCommands
4
4
 
5
5
 
6
6
 
7
- def fa()
7
+ def fa(shared_secret = @secret)
8
+ raise "No shared_secret given" if shared_secret == nil # cause upon initialization @secret = nil
8
9
  timestamp = Time.new.to_i
9
10
  math = timestamp / 30
10
11
  math = math.to_i
11
12
  time_buffer =[math].pack('Q>')
12
13
 
13
- hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(@secret), time_buffer)
14
+ hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(shared_secret), time_buffer)
14
15
 
15
16
  start = hmac[19].ord & 0xf
16
17
  last = start + 4
@@ -29,6 +30,7 @@ module GuardCommands
29
30
 
30
31
  end
31
32
 
33
+ private
32
34
  def generate_confirmation_key(tag_string, time_stamp)
33
35
  buffer = [time_stamp].pack('Q>') + tag_string.encode('ascii')
34
36
  return Base64.encode64(OpenSSL::HMAC.digest('sha1', Base64.decode64(@identity_secret), buffer))
@@ -0,0 +1,111 @@
1
+ module InventoryCommands
2
+
3
+
4
+
5
+
6
+
7
+ def normal_get_inventory(steamid = @steamid ,appid = 753,context = 6)
8
+ if steamid == nil
9
+ output "no steamid specified"
10
+ return
11
+ elsif steamid.to_i == 0 && steamid.include?("?partner=") ##supplied trade link
12
+ partner_raw = steamid.split('partner=',2)[1].split('&',2)[0]
13
+ steamid = partner_id_to_steam_id(partner_raw)
14
+ end
15
+
16
+
17
+ if @inventory_cache == true
18
+ verdict = verify_inventory_cache(steamid)
19
+ if verdict != false
20
+ return verdict
21
+ end
22
+ end
23
+
24
+
25
+ items = []
26
+ last_id = 0
27
+ until last_id == false
28
+ received = get_inventory_chunk_normal_way(appid,context,steamid,last_id)
29
+ last_id = received['new_last_id']
30
+ items = items + received['assets']
31
+ output "loaded #{items.length}"
32
+ sleep(2) if last_id != false
33
+ end
34
+
35
+ output "total loaded #{items.length} asset"
36
+ if @inventory_cache == true
37
+ File.open("./#{steamid}.inventory", 'w') {|f| f.puts items.to_json}
38
+ end
39
+
40
+ return items
41
+ end
42
+
43
+ private
44
+ def get_inventory_chunk_normal_way(appid,context,steamid,last_id)
45
+
46
+
47
+ html = open("https://steamcommunity.com/inventory/#{steamid}/#{appid}/#{context}?start_assetid=#{last_id}&count=5000").read
48
+
49
+ get = JSON.parse(html)
50
+
51
+ if get.keys[3].to_s == "last_assetid"
52
+
53
+ new_last_id = get.values[3].to_s
54
+
55
+ else
56
+ new_last_id = false
57
+
58
+ end
59
+
60
+ assets = get["assets"]
61
+ descriptions = get["descriptions"]
62
+
63
+
64
+ descriptions_classids = {} ###sorting descriptions by key value || key is classid of the item's description
65
+ descriptions.each {|description|
66
+ classidxinstance = description["classid"] + '_' + description["instanceid"] # some items has the same classid but different instane id
67
+ descriptions_classids[classidxinstance] = description
68
+ }
69
+
70
+ assets.each { |asset| ## merging assets with names
71
+ classidxinstane = asset["classid"] + '_' + asset["instanceid"]
72
+ asset.replace(asset.merge(descriptions_classids[classidxinstance]))
73
+ }
74
+
75
+
76
+ return {'assets' => assets, 'new_last_id' =>new_last_id}
77
+
78
+ end
79
+
80
+
81
+
82
+
83
+
84
+ def verify_inventory_cache(steamid)
85
+ if File.exists?("./#{steamid}.inventory") == false
86
+ return false
87
+ end
88
+ puts File.mtime("./#{steamid}.inventory").to_s
89
+ puts Time.now.to_s
90
+ file_last_time = Time.parse(File.mtime("./#{steamid}.inventory").to_s)
91
+ current_time = Time.parse(Time.now.to_s)
92
+ calcule = current_time - file_last_time
93
+ puts "difference #{calcule}"
94
+ if calcule.to_i > @inventory_validity
95
+ File.delete("./#{steamid}.inventory")
96
+ return false
97
+ else
98
+ output "gonna use cached inventory which is #{calcule} seconds old"
99
+ begin
100
+ return JSON.parse(File.read("./#{steamid}.inventory",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
101
+ rescue
102
+ File.delete("./#{steamid}.inventory")
103
+ return false
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+
110
+
111
+ end
@@ -1,7 +1,7 @@
1
1
  module LoginCommands
2
2
 
3
3
  ########################################################################################
4
- def login
4
+ def login()
5
5
  data = pass_stamp()
6
6
  encrypted_password = data["password"]
7
7
  timestamp = data["timestamp"]
@@ -30,13 +30,11 @@ module LoginCommands
30
30
 
31
31
  login = @session.post('https://store.steampowered.com/login/dologin', send )
32
32
  response = JSON::parse(login.body)
33
-
33
+ output "logging-in"
34
34
  if response["success"] == true
35
35
  repeater = true
36
36
  elsif repeater == 3
37
- puts "Could not login"
38
- puts "exiting"
39
- exit
37
+ raise "Login failed username: #{@username}, password: #{@password} tried 3 times"
40
38
  else
41
39
  puts "re-trying to login"
42
40
  puts "sleeping for 6 seconds"
@@ -71,7 +69,18 @@ module LoginCommands
71
69
 
72
70
  cookie = Mechanize::Cookie.new :domain => 'steamcommunity.com', :name =>'sessionid', :value =>steampowered_sessionid, :path => '/'
73
71
  @session.cookie_jar << cookie
74
- puts "logged-in with steamid: #{@steamid}"
72
+ @loggedin = true
73
+ @api_key = Nokogiri::HTML(@session.get("https://steamcommunity.com/dev/apikey").content).css('#bodyContents_ex').css('p').first.text.sub('Key: ','')
74
+
75
+ data = get_player_summaries(@steamid)
76
+ data.each { |element|
77
+ if element["steamid"].to_s == @steamid.to_s
78
+ @persona = element["personaname"]
79
+ end
80
+ }
81
+ output "logged in as #{@persona}"
82
+ output "your steamid is #{@steamid}"
83
+ output "loaded API_KEY : #{@api_key}"
75
84
  end
76
85
  ########################################################################################
77
86
 
@@ -1,5 +1,17 @@
1
- module Abilites
1
+
2
+ module MiscCommands
3
+
4
+
5
+
6
+
7
+
2
8
  ########################################################################################
9
+ def set_steamid(steamid)
10
+ @steamid = steamid
11
+ end
12
+
13
+
14
+
3
15
  def copy_session
4
16
  return @session
5
17
  end
@@ -37,6 +49,10 @@ module Abilites
37
49
 
38
50
 
39
51
 
52
+
53
+
54
+
55
+
40
56
  private
41
57
  def partner_id_to_steam_id(account_id)
42
58
  unknown_constant = 17825793 # or 0x1100001 idk wtf is this but ....
@@ -45,6 +61,26 @@ module Abilites
45
61
  collect = last_bytes + first_bytes
46
62
  return collect.unpack('Q>')[0].to_s
47
63
  end
64
+ def output(message)
65
+ time = Time.new
66
+ add = time.strftime("%d-%m-%Y %H:%M:%S")
67
+ puts "#{time} :: #{message}"
68
+ end
69
+
48
70
 
49
71
 
50
72
  end
73
+
74
+ module Util
75
+ def self.gem_libdir
76
+ require_relative 'meta/version.rb'
77
+ gem_name = 'steam-trade'
78
+ version = '0.0.5'
79
+ t = ["#{File.dirname(File.expand_path($0))}/#{Meta::GEM_NAME}.rb",
80
+ "#{Gem.dir}/gems/#{Meta::GEM_NAME}-#{Meta::VERSION}/lib/#{Meta::GEM_NAME}.rb"]
81
+ t.each {|i|
82
+ return i.gsub("#{Meta::GEM_NAME}.rb", '') if File.readable?(i)
83
+ }
84
+ raise "both paths are invalid: #{t}, while getting gemlib directory"
85
+ end
86
+ end