googlepub 0.0.3

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MGRlN2I3ZjJhZDEzZWYwODRmOTdjMjI5ZjlkNWEyNzAzYjQyMWY2ZA==
5
+ data.tar.gz: !binary |-
6
+ MjdkNGE3NTVlZmJkZTg1NTUyM2I5MWJjZjFmMGRiNmQ2MTk5ZjFhZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YWI2YjY0NWZjYTI5OTE3YjRhOGEyYjZiYjVhMzM2ZmY2ZTI3ZGJjNThmMDg5
10
+ NmE4YjQxMjczZTEzZTM4ZDQ2ZWE0NzFjNjMzOWJlOTI0ZGY2NzZiZWJjYTU4
11
+ Mjk5YTZjOGJjMDk3M2QzZjhjZjE0NWQyNjRlNGU2MGZhYjU2YWU=
12
+ data.tar.gz: !binary |-
13
+ YmE2ZWVkMzYwMGExYjAxNjIxMTllNzdlOTI5NGQ3M2VjNzQ1ZTUxYTZhOGZl
14
+ OGU1MmFjMGE2MTA1MDFmMTY1ZGE1M2JlMzY4ZjYxYTBkNmIyOWNjODBiYzg2
15
+ NmMzNmY1MmY2ZWUwN2E3ZmRhN2M2MzI0MmEwMDkwOWE5NTMzNjI=
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Keshav Goel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # googlepub
2
+
3
+ ## The gem to automate everything for GooglePlay Developer Console with a Single Command i.e. googlepub
4
+ This gem uses the Google Publishing API.Go for it. A single command for everything. Have issues/problems/Feature requests/advices Please add them as Issues. I'll get back to you ASAP.
5
+ ## Set up Googlepub
6
+ In your terminal:
7
+ `[sudo] gem install googlepub`
8
+
9
+ For updates:
10
+ `[sudo] gem update googlepub`
11
+
12
+ **This gem is OS independent.**
13
+
14
+ ## Google Play Access
15
+
16
+ To enable googlepub to access Google Play you have to follow these steps:
17
+
18
+ * Open the Google Play Console
19
+ * Open Settings => API-Access
20
+ * Create a new Service Account - follow the link of the dialog
21
+ * Create new Client ID
22
+ * Select Service Account
23
+ * Click Generate new P12 key and store the downloaded file
24
+ * The Email address underneath Service account is the email address you have to enter as the Issuer
25
+ * Back on the Google Play developer console, click on Grant Access for the newly added service account
26
+ * Choose Release Manager from the dropdown and confirm
27
+
28
+ ## Issuer
29
+ Copy and paste the email address which looks like *9083982039lnwdnlwk-23929ojkn@developer.gserviceaccount.com* and pass it as the -i or --iss option with the command or paste it when asked for or set as ENV['ISS']
30
+
31
+
32
+ ## Keyfile
33
+ Store your p12 file in a secure place, for ease open it in any editor and copy and pass the key as -k or --key option with the command or paste it when asked for or set as ENV['KEY']
34
+
35
+ ## Package
36
+ The SKU of you App eg. "com.keshav.goel". Pass is as -p or --package option with the command or when asked for or set as ENV['PACKAGE']
37
+
38
+ ##Main commands
39
+ apk
40
+ metadata
41
+
42
+ ## Options
43
+
44
+ ### With sub command metadata:
45
+ -k, --key [KEY] Key for the Account from Google Developer Console (ENV['KEY'])
46
+ -i, --iss [KEY] ISS for the Account from Google Developer Console (ENV['ISS'])
47
+ -p, --package [PACKAGE] Package to update on the Google Developer Console (ENV['PACKAGE'])
48
+ --store Specify that Store Listing details are to be Updated.
49
+ -t, --title [TITLE] Name for your App
50
+ -f, --full [FULLDESCRIPTION] Full Description for your App
51
+ -s, --short [SHORTDESCRIPTION] Short Description for your App
52
+ -v, --video [VIDEO] Youtube Video URL
53
+ --details Specify that the details are to be updated (Website, Email and Phone)
54
+ -w, --website [WEBSITE] Website for Contact
55
+ -e, --email [EMAIL] Email for Contact
56
+ --phone [PHONE] Phone for Contact
57
+ --screenshots Specify that Screenshots are to be updated for Contact
58
+ --featureGraphic [FEATUREGRAPHIC]
59
+ featureGraphic for your App eg: "path/to/file"
60
+ --icon [ICON] icon for your App eg: "path/to/file"
61
+ --phoneScreenshots [PHONE SCREENSHOTS]
62
+ phoneScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
63
+ --promoGraphic [PROMOGRAPHIC]
64
+ promoGraphic for your App eg: "path/to/file"
65
+ --sevenInchScreenshots [SEVENINCHSCREENS]
66
+ sevenInchScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
67
+ --tenInchScreenshots [TENINCHSCREENS]
68
+ tenInchScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
69
+ --tvBanner [TVBANNER] tvBanner for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
70
+ --tvScreenshots [TVSCREENS] tvScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
71
+ --wearScreenshots [WEARSCREENS]
72
+ wearScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."
73
+ --version display googlepub version
74
+ -h, --help display this help message
75
+
76
+ ### With sub command apk:
77
+ --file [FILE] APK file to upload eg: "path/to/file"
78
+ --track [TRACK] Track to which APK file is to be uploaded eg: "beta"
79
+ --version display googlepub version
80
+ -h, --help display this help message
81
+
82
+ #Example:
83
+ googlepub metadata -l "en-US" -p "com.keshav.goel" --store -t "Title" -s "Short Description" -f "fullDescription" --icon "icon.png"
84
+
85
+ googlepub apk -p "com.keshav.goel" --file "file.apk" --track "beta"
86
+
87
+ * **If ENV['KEY'] or -k/--key is not passed, the command will ask for key pass it as "-----KEY---"**
88
+ * **If ENV['ISS'] or -i/-iss is not passed, the command will ask for iss pass it as"iss@account.com"**
89
+ * **If ENV['PACKAGE'] or -p/--package is not passed, the command will ask for package pass it as "com.keshav.goel"**
90
+
91
+ ### In-App purchase support coming in a few days.
92
+
93
+ ##### For any issues/problems please add an Issue to the repo.
data/bin/googlepub ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "#{File.dirname(__FILE__)}/../lib/googlepub/options.rb"
4
+
5
+ Googlepub::Options.new
data/googlepub.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/lib/googlepub.rb')
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'googlepub'
5
+ s.version = Googlepub::VERSION
6
+ s.date = '2015-10-25'
7
+ s.summary = "GooglePlay App Publisher!"
8
+ s.description = "Automate everything related to Google App Publishing, APK, Stor Listing and In-App Purchses."
9
+ s.authors = ["Keshav Goel"]
10
+ s.email = 'keshu_gl@yahoo.com'
11
+ s.require_paths = ['lib']
12
+ s.executables = ['googlepub']
13
+
14
+ s.files = Dir['lib/**/*', 'bin/*','googlepub.gemspec'] + %w( README.md LICENSE )
15
+ s.homepage = 'https://github.com/thekeshavgoel/googlepub'
16
+ s.license = 'MIT'
17
+ s.required_ruby_version = '>= 1.9.2'
18
+ s.add_runtime_dependency 'base64url', '~> 1.0'
19
+ s.add_runtime_dependency 'jwt', '~> 1.5'
20
+ s.add_runtime_dependency 'json-jwt', '~> 1'
21
+ s.add_runtime_dependency 'httparty', '~> 0'
22
+ s.add_runtime_dependency 'httmultiparty', '~> 0'
23
+ s.add_runtime_dependency 'colorize', '~> 0'
24
+ end
data/lib/googlepub.rb ADDED
@@ -0,0 +1,78 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/googlepub/metadata.rb')
2
+ require File.expand_path(File.dirname(__FILE__) + '/googlepub/apk.rb')
3
+
4
+ module Googlepub
5
+
6
+ ROOT = File.expand_path(File.dirname(__FILE__) + '/..')
7
+
8
+ VERSION = "0.0.3"
9
+
10
+ def self.call_metadata(options = {})
11
+ @pack = Googlepub::Metadata.new(options["language"])
12
+ if options["store"]
13
+ p "Going to edit Store Listing"
14
+ @pack.edit_listings(options["title"], options["fullDescription"], options["shortDescription"], options["video"])
15
+ end
16
+ if options["icon"]
17
+ p "Going to Upload Icon on GooglePlay Store:"
18
+ @pack.imagefile("icon", options["icon"])
19
+ end
20
+
21
+ if options["details"]
22
+ p "Going to edit Details"
23
+ @pack.edit_details(options["website"], options["email"], options["phone"])
24
+ end
25
+
26
+ if options["screenshots"]
27
+ p "Going to Update Screenshots"
28
+ types = ["featureGraphic", "phoneScreenshots", "promoGraphic", "sevenInchScreenshots", "tenInchScreenshots", "tvBanner", "tvScreenshots", "wearScreenshots"]
29
+ types.each do |t|
30
+ if options[t]
31
+ screens = options[t].split(",")
32
+ screens.each do |sc|
33
+ @pack.imagefile(t, sc)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ def self.call_apk(options = {})
42
+ if !options["file"]
43
+ p "Please provide the file to input: "
44
+ @file = gets.chomp
45
+ if !@file
46
+ p "No APK file provided".red
47
+ end
48
+ else
49
+ @file = options["file"]
50
+ end
51
+
52
+ if !options["track"]
53
+ p "Please provide the Track for the APK [alpha, beta, prod] (for ease use --track)"
54
+ @track = gets.chomp
55
+ if !@track
56
+ p "No track provided".red
57
+ end
58
+ else
59
+ @track = options["track"]
60
+ end
61
+
62
+ if !options["version"]
63
+ p "Please provide the Version (Code) for the APK"
64
+ @version = gets.chomp
65
+ else
66
+ @version = options["version"]
67
+ end
68
+ if !@version
69
+ p "Invalid request, Please provide a Version!".red
70
+ exit (1)
71
+ end
72
+ @apk = Googlepub::APK.new(@file, @track)
73
+ @apk.upload_apk
74
+ @apk.select_version(@version)
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,62 @@
1
+ require "base64"
2
+ require 'jwt'
3
+ require 'jwt/json'
4
+ require 'httparty'
5
+ require 'httmultiparty'
6
+ require 'colorize'
7
+
8
+ module Googlepub
9
+
10
+ class APK
11
+
12
+ def initialize(file, track)
13
+ @track = track
14
+ @file = file
15
+ @edit_id = ENV['EDIT_ID']
16
+ @access_token = ENV['ACCESS_TOKEN']
17
+ @package = ENV['PACKAGE']
18
+ if !@edit_id || !@access_token || @package
19
+ p "Invalid call".red
20
+ end
21
+ if !File.new(@file)
22
+ p "File read error, Maybe file not found at #{@file}"
23
+ exit (1)
24
+ end
25
+ end
26
+
27
+ def list_apks
28
+ apks = HTTParty.get("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/apks?access_token=#{@access_token}")
29
+ end
30
+
31
+ def upload_apk
32
+ puts "Uploading the APK".green
33
+ resp = HTTMultiParty.post("https://www.googleapis.com/upload/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/apks?access_token=#{@access_token}",
34
+ :body =>{:somefile => File.new(@file)})
35
+ p "Uploaded the APK file".green
36
+ end
37
+
38
+ def select_version(version)
39
+ @version = version
40
+ if !@version
41
+ p "Please provide a version with call!".red
42
+ exit (1)
43
+ end
44
+ track_resp = HTTParty.get("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/tracks/#{@track}?access_token=#{@access_token}").parsed_response
45
+ if (track_resp["versionCodes"][0]).to_i >= @version.to_i
46
+ puts "Please bump the Version. \nAPK with Version: #{@version} already exists!".red
47
+ exit 0
48
+ end
49
+
50
+ track_resp["versionCodes"][0] = @version
51
+ response_track = HTTParty.put("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/tracks/#{@track}?access_token=#{@access_token}", :headers => { 'Content-Type' => 'application/json' }, :body => track_resp.to_json).parsed_response
52
+ if (response_track["versionCodes"][0]).to_i != @version.to_i
53
+ puts "Unsuccessfull upload, Please check!".red
54
+ else
55
+ puts "Successfully put the #{@version} build to #{@track}".green
56
+ end
57
+ end
58
+
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,121 @@
1
+ require "base64"
2
+ require 'jwt'
3
+ require 'jwt/json'
4
+ require 'httparty'
5
+ require 'httmultiparty'
6
+ require 'colorize'
7
+
8
+ module Googlepub
9
+
10
+ class Auth
11
+
12
+ def initialize(options = {})
13
+ if !options["key"] && !ENV['KEY']
14
+ puts "Please provide the key for the Account on Google Developer Console (use option -k or --key for ease): "
15
+ key = gets.chomp
16
+ key = eval %Q{#{key}}
17
+ else
18
+ key = options["key"] || ENV['KEY']
19
+ end
20
+ if !options["iss"] && !ENV['ISS']
21
+ puts "Please provide the ISS for the account on Google Developer Console (use -i or -iss for ease): "
22
+ iss = gets.chomp
23
+ iss = eval %Q{#{iss}}
24
+ else
25
+ iss = options["iss"] || ENV['ISS']
26
+ end
27
+ if !options["package"] && !ENV['PACKAGE']
28
+ puts "Please provide the package you want to EDIT on (Use option -p or --package for ease): "
29
+ package = gets.chomp
30
+ package = eval %Q{#{package}}
31
+ else
32
+ package = options["package"] || ENV['PACKAGE']
33
+ end
34
+ if (!key || !iss || !package)
35
+ puts "Invalid Arguments!".red
36
+ end
37
+ @key = key
38
+ @iss = iss
39
+ @package = package
40
+ ENV['KEY'] = key
41
+ ENV['ISS'] = iss
42
+ ENV['PACKAGE'] = package
43
+ header = {"alg" => "RS256","typ" => "JWT"}
44
+ claim_set = {
45
+ "iss"=>@iss,
46
+ "scope"=> 'https://www.googleapis.com/auth/androidpublisher',
47
+ "aud"=>"https://www.googleapis.com/oauth2/v3/token",
48
+ "exp" => Time.now.to_i + 3600,
49
+ "iat" => Time.now.to_i
50
+ }
51
+ private_key = @key.to_s
52
+ @key = OpenSSL::PKey.read(private_key)
53
+ if !@key
54
+ puts "Invlaid OPENSLL Key, please check!".red
55
+ exit 1
56
+ end
57
+ jwt = JWT.encode(claim_set, @key, "RS256", header)
58
+ if !jwt
59
+ puts "Invlaid JWT, please check!".red
60
+ exit 1
61
+ end
62
+ data = {"grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion" => "#{jwt}"}
63
+ response = HTTParty.post("https://www.googleapis.com/oauth2/v3/token", :body => data)
64
+ if !response.parsed_response["access_token"]
65
+ puts "Invlaid or Not generated Access Token, please try again!".red
66
+ puts response.parsed_response
67
+ exit 1
68
+ end
69
+ access_token = response.parsed_response["access_token"] #Access Token valid for 60 minutes
70
+ ENV['ACCESS_TOKEN'] = access_token
71
+ @access_token = access_token
72
+ puts "Access Token: #{access_token}".green
73
+ if @package
74
+ self.edit()
75
+ end
76
+ end
77
+
78
+ ################# A new EDIT ##########################
79
+ def edit
80
+ puts "Generating Edit for package: #{@package}"
81
+ headers = {"Authorization" => "Bearer #{@access_token}"}
82
+
83
+ edit_response = HTTParty.post("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits", :headers => headers, :body => {}).parsed_response
84
+
85
+ if !edit_response["id"]
86
+ puts "Invlaid Edit, No id returned, please check!".red
87
+ p edit_response
88
+ exit 1
89
+ end
90
+ ENV['EDIT_ID'] = edit_response["id"]
91
+ @edit_id = edit_response["id"]
92
+ puts "Edit ID generated: #{ENV['EDIT_ID']}".green
93
+ end
94
+
95
+ ##################### Validate Edit ##########################
96
+ def validate
97
+ response_validate = HTTParty.post("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}:validate?access_token=#{@access_token}", :body =>{}).parsed_response
98
+ if response_validate["id"] == @edit_id
99
+ puts "Validated: Good to Go".green
100
+ else
101
+ puts "Invalid Edit, please check!".red
102
+ puts response_validate
103
+ exit 1
104
+ end
105
+ end
106
+
107
+ ###################### Commit the Edit ##########################
108
+ def commit
109
+ response_commit = HTTParty.post("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}:commit?access_token=#{@access_token}", :body =>{}).parsed_response
110
+ if response_commit["id"] == @edit_id
111
+ puts "Committed!".green
112
+ else
113
+ puts "Commit Error! please check!".red
114
+ puts response_commit
115
+ exit 1
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,91 @@
1
+ require "base64"
2
+ require 'jwt'
3
+ require 'jwt/json'
4
+ require 'httparty'
5
+ require 'getoptlong'
6
+ require 'httmultiparty'
7
+ require 'yaml'
8
+ require 'auth'
9
+ require 'colorize'
10
+
11
+ class inapps
12
+ def initialize(sku, price, title, description, type = "managedUser", currency = "USD", language = "en-US", status = "active", trial = nil)
13
+ @sku = sku
14
+ @price = price
15
+ @title = title
16
+ @description = description
17
+ @type = type
18
+ @currency = currency
19
+ @language = language
20
+ @status = status
21
+ @package = ENV['PACKAGE']
22
+ @access_token = ENV['ACCESS_TOKEN']
23
+ @edit_id = ENV['EDIT_ID']
24
+ @trial = trail
25
+ end
26
+
27
+ def newinapp
28
+ if type == "managedUser"
29
+ new_iap = {"packageName"=>@package, "sku"=>@sku, "status"=>@status, "purchaseType"=>"#{@type}",
30
+ "defaultPrice"=>{"priceMicros"=>@price, "currency"=>"#{@currency}"}, "listings"=>{"#{@language}"=>{"title"=>@title,
31
+ "description"=>@description }}, "defaultLanguage"=>"#{@language}"}
32
+ elsif type == "subscription"
33
+ new_iap = {"packageName"=>@package, "sku"=>@sku, "status"=>@status, "purchaseType"=>"#{@type}",
34
+ "defaultPrice"=>{"priceMicros"=>@price, "currency"=>"#{@currency}"}, "listings"=>{"#{@language}"=>{"title"=>@title,
35
+ "description"=>@description }}, "defaultLanguage"=>"#{@language}", "subscriptionPeriod" => "#{@period}", "trialPeriod" => "#{@trial}"}
36
+ end
37
+
38
+ resp = HTTParty.post("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/inappproducts?autoConvertMissingPrices=true&access_token=#{@access_token}", :headers => { 'Content-Type' => 'application/json' },
39
+ :body => new_iap.to_json).parsed_response
40
+
41
+ if !resp["listings"]["en-US"]["title"]
42
+ puts "Unable to create: Response -> #{resp}".red
43
+ else
44
+ puts "Made IAP #{i}".green
45
+ end
46
+ puts "Successfully Done: New IAP Creation".green
47
+ end
48
+
49
+ def find_inapp
50
+ @inapps = HTTParty.get("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/inappproducts/#{@sku}?access_token=#{@access_token}").parsed_response
51
+ if !@inapps || !inapps["listings"]["#{@language}"]["title"]
52
+ puts "In-app: #{@sku} Not Found!".red
53
+ exit 1
54
+ else
55
+ puts "Inapp: #{@sku} found, Name:#{@inapps["listings"]["#{@language}"]["title"]}, Price: #{@inapps["defaultPrice"]["priceMicros"]}".green
56
+ end
57
+ end
58
+
59
+ def edit_inapp(action)
60
+ if action = "name"
61
+ ####### Change the Ttitle ##########
62
+ @inapps["listings"]["#{@language}"]["title"] = name
63
+
64
+ ############# Put the request ###########
65
+ changed_response = HTTParty.put("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/inappproducts/#{@sku}?access_token=#{@access_token}",
66
+ :headers => { 'Content-Type' => 'application/json' }, :body => @inapps.to_json).parsed_response
67
+ if changed_response["listings"]["#{@language}"]["title"] != name
68
+ puts "Unable to Change name, Response -> #{changed_response}".red
69
+ exit 3
70
+ end
71
+ puts "Done: Name Change".green
72
+ end
73
+
74
+ if action = "price"
75
+ ################# Changing the price ######################
76
+ new_iap = {"packageName"=>@package, "sku"=>@sku, "status"=>@status, "purchaseType"=>@type,
77
+ "defaultPrice"=>{"priceMicros"=>@price, "currency"=>@currency}, "listings"=>{"#{@language}"=>{"title"=>@inapps["listings"]["#{@language}"]["title"],
78
+ "description"=>@inapps["listings"]["#{@language}"]["description"] }}, "defaultLanguage"=>"#{@language}"}
79
+
80
+ ##################### Putting the the request back ###############
81
+
82
+ resp = HTTParty.put("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/inappproducts/#{@sku}?autoConvertMissingPrices=true&access_token=#{@access_token}", :headers => { 'Content-Type' => 'application/json' },
83
+ :body => new_iap.to_json).parsed_response
84
+
85
+ if resp["defaultPrice"]["priceMicros"] != price
86
+ puts "Unable to change price, Response -> #{resp}".red
87
+ exit 3
88
+ end
89
+ puts "Done: Price Change".green
90
+ end
91
+ end
@@ -0,0 +1,95 @@
1
+ require "base64"
2
+ require 'jwt'
3
+ require 'jwt/json'
4
+ require 'httparty'
5
+ require 'httmultiparty'
6
+ require 'colorize'
7
+
8
+ module Googlepub
9
+
10
+ class Metadata
11
+
12
+ def initialize(language)
13
+ @language = language
14
+ @edit_id = ENV['EDIT_ID']
15
+ @access_token = ENV['ACCESS_TOKEN']
16
+ @package = ENV['PACKAGE']
17
+ if !@edit_id || !@access_token || !@package
18
+ p "Missing Something, Invalid call".red
19
+ end
20
+ get_listing
21
+ get_details
22
+ end
23
+
24
+ def get_listing
25
+ @listing = HTTParty.get("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/listings/#{@language}?access_token=#{@access_token}", :body =>{}).parsed_response
26
+ if @listing["language"] != @language
27
+ puts "Unable to find Listing"
28
+ exit
29
+ end
30
+ end
31
+
32
+ def get_details
33
+ @details = HTTParty.get("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/details?access_token=#{@access_token}", :body =>{}).parsed_response
34
+ end
35
+
36
+ def edit_listings (title, fullDescription, shortDescription, video)
37
+ app_listing = {
38
+ "language"=> @language,
39
+ "title"=> title || @listing["title"],
40
+ "fullDescription"=> fullDescription || @listing["fullDescription"],
41
+ "shortDescription"=> shortDescription || @listing["shortDescription"],
42
+ "video"=> video || @listing["video"]
43
+ }
44
+ listings = HTTParty.put("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/listings/#{@language}?access_token=#{@access_token}", :headers => { 'Content-Type' => 'application/json' }, :body =>app_listing.to_json).parsed_response
45
+
46
+ if listings["language"] == @language && listings["title"] == title
47
+ puts "Done Listing"
48
+ else
49
+ puts "Error in Listings"
50
+ exit
51
+ end
52
+ end
53
+
54
+ def edit_details (website, email, phone)
55
+ details = {
56
+ "defaultLanguage"=> @language,
57
+ "contactWebsite" => website || @details["contactWebsite"],
58
+ "contactEmail" => email || @details["contactEmail"],
59
+ "contactPhone" => phone || @details["contactPhone"]
60
+ }
61
+
62
+ details_resp = HTTParty.put("https://www.googleapis.com/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/details?access_token=#{@access_token}", :headers => { 'Content-Type' => 'application/json' }, :body =>details.to_json).parsed_response
63
+ if details_resp["defaultLanguage"] == @language
64
+ puts "Details entered"
65
+ else
66
+ puts "Error in Details"
67
+ puts details_resp
68
+ exit
69
+ end
70
+ end
71
+
72
+ def imagefile(typefile, filename)
73
+ @types = ["featureGraphic","icon", "phoneScreenshots", "promoGraphic", "sevenInchScreenshots", "tenInchScreenshots", "tvBanner", "tvScreenshots", "wearScreenshots"]
74
+ if !@types.include?(typefile)
75
+ puts "Please provide a type out of: #{@types}"
76
+ exit (1)
77
+ end
78
+ file = File.new(filename)
79
+ if !file
80
+ puts "File read error, Maybe file Not found."
81
+ exit (1)
82
+ end
83
+ puts "Uploading #{typefile}"
84
+ resp = HTTMultiParty.post("https://www.googleapis.com/upload/androidpublisher/v2/applications/#{@package}/edits/#{@edit_id}/listings/#{@language}/#{typefile}?access_token=#{@access_token}",
85
+ :body =>{:somepngfile => file}, :detect_mime_type => true).parsed_response
86
+ if !resp["image"]
87
+ puts "Error Uploading #{typefile}: #{resp}"
88
+ exit
89
+ else
90
+ puts "Done Uploading #{@language}-#{typefile}"
91
+ end
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,157 @@
1
+ require 'optparse'
2
+
3
+ require "#{File.dirname(__FILE__)}/auth.rb"
4
+ require File.expand_path(File.dirname(__FILE__) + '/../googlepub')
5
+
6
+
7
+ module Googlepub
8
+
9
+ class Options
10
+
11
+ BANNER = <<-EOS
12
+ Googlepub it gem for Google Android Publisheing API.
13
+ Abilities:
14
+ 1) Store Listing
15
+ 2) APK - All tracks
16
+ 3) In-App Purchases (Managed and Subscriptions) (Coming Soon)
17
+
18
+ Usage:
19
+ googlepub COMMAND [OPTIONS]
20
+ Main commands:
21
+ apk. metadata
22
+ Example:
23
+ googlepub metadata -l "en-US" -p "com.keshav.goel" --store -t "Title" -s "Short Description" -f "fullDescription" --icon "icon.png"
24
+ googlepub apk -p "com.keshav.goel" --file "file.apk" --track "beta"
25
+ Dependencies:
26
+ Ruby, HTTP
27
+
28
+ Author: @thekeshavgoel
29
+ Email: keshu_gl@yahoo.com
30
+ EOS
31
+
32
+ # Creating a CommandLine runs off of the contents of ARGV.
33
+ def initialize
34
+ parse_options
35
+ cmd = ARGV.shift
36
+ @command = cmd && cmd.to_sym
37
+ @auth = Googlepub::Auth.new(@options)
38
+ run
39
+ @auth.validate
40
+ @auth.commit
41
+ end
42
+
43
+ def run
44
+ begin
45
+ case @command
46
+ when :apk then puts Googlepub.call_apk(@options)
47
+ when :metadata then puts Googlepub.call_metadata(@options)
48
+ else
49
+ puts "Please provide command to Excute - 'apk' or 'metadata'"
50
+ exit (1)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Print out the usage help message.
56
+ def usage
57
+ puts "\n#{@option_parser}\n"
58
+ exit
59
+ end
60
+
61
+
62
+ private
63
+ def parse_options
64
+ @options = {"language" => "en-US"}
65
+ @option_parser = OptionParser.new do |opts|
66
+ opts.on('-k', '--key [KEY]', "Key for the Account from Google Developer Console (ENV['KEY'])") do |l|
67
+ @options["language"] = l
68
+ end
69
+ opts.on('-i', '--iss [ISSUER]', "ISS for the Account from Google Developer Console (ENV['ISS'])") do |l|
70
+ @options["language"] = l
71
+ end
72
+ opts.on('-p', '--package [PACKAGE]', "Package to update on the Google Developer Console (ENV['PACKAGE'])") do |pa|
73
+ @options["package"] = pa
74
+ end
75
+ opts.on('--store', 'Specify that Store Listing details are to be Updated.') do |s|
76
+ @options["store"] = s
77
+ end
78
+ opts.on('-t', '--title [TITLE]', 'Name for your App') do |k|
79
+ @options["title"] = k
80
+ end
81
+ opts.on('-f', '--full [FULLDESCRIPTION]', 'Full Description for your App') do |t|
82
+ @options["fullDescription"] = t
83
+ end
84
+ opts.on('-s', '--short [SHORTDESCRIPTION]', 'Short Description for your App') do |d|
85
+ @options["shortDescription"] = d
86
+ end
87
+ opts.on('-v', '--video [VIDEO]', 'Youtube Video URL') do |o|
88
+ @options["video"] = o
89
+ end
90
+ opts.on('--details', 'Specify that the details are to be updated (Website, Email and Phone)') do |c|
91
+ @options["details"] = true
92
+ end
93
+ opts.on('-w', '--website [WEBSITE]', 'Website for Contact') do |l|
94
+ @options["website"] = l
95
+ end
96
+ opts.on('-e', '--email [EMAIL]', 'Email for Contact') do |n|
97
+ @options["email"] = n
98
+ end
99
+ opts.on('--phone [PHONE]', 'Phone for Contact') do |r|
100
+ @options["phone"] = r
101
+ end
102
+ opts.on('--screenshots', 'Specify that Screenshots are to be updated for Contact') do |r|
103
+ @options["screenshots"] = r
104
+ end
105
+ opts.on('--featureGraphic [FEATUREGRAPHIC]', 'featureGraphic for your App eg: "path/to/file"') do |r|
106
+ @options["featureGraphic"] = r
107
+ end
108
+ opts.on('--icon [ICON]', 'icon for your App eg: "path/to/file"') do |z|
109
+ @options["icon"] = z
110
+ end
111
+ opts.on('--phoneScreenshots [PHONE SCREENSHOTS]', 'phoneScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
112
+ @options["phoneScreenshots"] = r
113
+ end
114
+ opts.on('--promoGraphic [PROMOGRAPHIC]', 'promoGraphic for your App eg: "path/to/file"') do |r|
115
+ @options["promoGraphic"] = r
116
+ end
117
+ opts.on('--sevenInchScreenshots [SEVENINCHSCREENS]', 'sevenInchScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
118
+ @options["sevenInchScreenshots"] = r
119
+ end
120
+ opts.on('--tenInchScreenshots [TENINCHSCREENS]', 'tenInchScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
121
+ @options["tenInchScreenshots"] = r
122
+ end
123
+ opts.on('--tvBanner [TVBANNER]', 'tvBanner for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
124
+ @options["tvBanner"] = r
125
+ end
126
+ opts.on('--tvScreenshots [TVSCREENS]', 'tvScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
127
+ @options["tvScreenshots"] = r
128
+ end
129
+ opts.on('--wearScreenshots [WEARSCREENS]', 'wearScreenshots for your App (comma separated) eg: "path/to/file1,path/to/file1,.."') do |r|
130
+ @options["wearScreenshots"] = r
131
+ end
132
+ opts.on('--file [FILE]', 'APK file to upload eg: "path/to/file"') do |r|
133
+ @options["file"] = r
134
+ end
135
+ opts.on('--track [TRACK]', ' Track to which APK file is to be uploaded eg: "beta"') do |r|
136
+ @options["file"] = r
137
+ end
138
+ opts.on_tail('-v', '--version', 'display googlepub version') do
139
+ puts "Googlepub version #{Googlepub::VERSION}"
140
+ exit
141
+ end
142
+ opts.on_tail('-h', '--help', 'display this help message') do
143
+ usage
144
+ end
145
+ end
146
+ @option_parser.banner = BANNER
147
+ begin
148
+ @option_parser.parse!(ARGV)
149
+ rescue OptionParser::InvalidOption => e
150
+ puts e.message
151
+ exit(1)
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: googlepub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Keshav Goel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64url
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jwt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json-jwt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: httparty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: httmultiparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colorize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Automate everything related to Google App Publishing, APK, Stor Listing
98
+ and In-App Purchses.
99
+ email: keshu_gl@yahoo.com
100
+ executables:
101
+ - googlepub
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - LICENSE
106
+ - README.md
107
+ - bin/googlepub
108
+ - googlepub.gemspec
109
+ - lib/googlepub.rb
110
+ - lib/googlepub/apk.rb
111
+ - lib/googlepub/auth.rb
112
+ - lib/googlepub/inapps.rb
113
+ - lib/googlepub/metadata.rb
114
+ - lib/googlepub/options.rb
115
+ homepage: https://github.com/thekeshavgoel/googlepub
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: 1.9.2
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.4.8
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: GooglePlay App Publisher!
139
+ test_files: []