Added play-store update script

This commit is contained in:
renaud gaudin 2015-06-08 12:01:32 +02:00
parent efe76fa3bb
commit e49081594f
3 changed files with 304 additions and 0 deletions

42
customapp-json/wpbm.json Normal file
View File

@ -0,0 +1,42 @@
{
"ic_launcher": "ic_launcher_512_bm.png",
"app_name": "Wikipedia BM",
"package": "org.kiwix.kiwixcustomwpbm",
"zim_file": "/Users/reg/Downloads/wikipedia_bm.zim",
"play_store": {
"images": {
"featureGraphic": ["/Users/reg/Desktop/feature-bm.png"],
"tvScreenshots": [],
"tenInchScreenshots": [],
"promoGraphic": [],
"tvBanner": [],
"sevenInchScreenshots": [],
"phoneScreenshots": [],
"icon": ""
},
"listings": {
"en-US": {
"video": null,
"shortDescription": "Offline version of the Bamanakan Wikipedia",
"fullDescription": "Wikipedia is a free-access, free-content Internet encyclopedia, supported and hosted by the non-profit Wikimedia Foundation. Those who can access the site can edit most of its articles. Editors are expected to follow the website's rules. Wikipedia is ranked among the ten most popular websites and constitutes the Internet's largest and most popular general reference work.\n\nThis application is a read-only archive of the Bamanakan language Wikipedia.",
"title": "Bamanankan Wikipedia"
},
"fr-FR": {
"video": null,
"shortDescription": "Version hors-ligne de l'encyclop\u00e9die Wikip\u00e9dia Bambara",
"fullDescription": "Wikip\u00e9dia est un projet d'encyclop\u00e9die universelle, multilingue (287 langues mi-2013), sous licence CC-BY-SA 3.0, cr\u00e9\u00e9e par Jimmy Wales et Larry Sanger le 15 janvier 20011 en wiki sous le nom de domaine wikipedia.org.\n\nLe wiki est h\u00e9berg\u00e9 sur Internet gr\u00e2ce aux serveurs financ\u00e9s par la Wikimedia Foundation, organisation \u00e0 but non lucratif am\u00e9ricaine et d\u00e9positaire de la marque Wikip\u00e9dia.\n\nN'importe qui pouvant acc\u00e9der au site peut modifier la quasi-totalit\u00e9 de ses articles. Wikip\u00e9dia est le sixi\u00e8me site le plus fr\u00e9quent\u00e9, et constitue le plus grand et le plus populaire des ouvrages de r\u00e9f\u00e9rences g\u00e9n\u00e9rales d'Internet. En f\u00e9vrier 2014, il y avait presque 500 millions de visiteurs chaque mois. Wikip\u00e9dia dispose de 22 millions de comptes, dont plus de 73000 sont consid\u00e9r\u00e9s \u00e9diteurs actifs, et ce \u00e0 l'\u00e9chelle mondiale au mois de mai 2014.\n\nCette Application est une version hors-ligne de Wikip\u00e9dia en Bamabra",
"title": "Wikip\u00e9dia Bambara"
}
},
"details": {
"contactEmail": "contact+android@kiwix.org",
"contactPhone": null,
"contactWebsite": "http://kiwix.org",
"defaultLanguage": "en-US"
}
},
"version_code": "4",
"embed_zim": false,
"enforced_lang": "bm",
"version_name": "2015-06"
}

262
update-play-store.py Executable file
View File

@ -0,0 +1,262 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4 nu
from __future__ import (unicode_literals, absolute_import,
division, print_function)
import logging
import sys
import os
import json
import requests
import tempfile
import shutil
from subprocess import call
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
# check for python version as google client api is broken on py2
if sys.version_info.major < 3:
print("You must run this script with python3 as "
"Google API Client is broken python2")
sys.exit(1)
try:
import httplib2
from apiclient.discovery import build
from oauth2client import client
except ImportError:
print("Missing Google API Client dependency.\n"
"Please install with: \n"
"apt-get install libffi-dev libssl-devel\n"
"pip install google-api-python-client PyOpenSSL\n"
"Install from github in case of oauth http errors.")
sys.exit(1)
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
for handler in logging.root.handlers:
handler.addFilter(logging.Filter('__main__'))
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
def usage(arg0, exit=None):
print("Usage: {} <json_file>".format(arg0))
if exit is not None:
sys.exit(exit)
def syscall(args, shell=False, with_print=True):
''' execute an external command. Use shell=True if using bash specifics '''
args = args.split()
if with_print:
print(u"-----------\n" + u" ".join(args) + u"\n-----------")
if shell:
args = ' '.join(args)
call(args, shell=shell)
def get_remote_content(url):
''' file descriptor from remote file using GET '''
req = requests.get(url)
try:
req.raise_for_status()
except Exception as e:
logger.error("Failed to load data at `{}`".format(url))
logger.exception(e)
sys.exit(1)
return StringIO.StringIO(req.text)
def get_local_content(path):
''' file descriptor from local file '''
if not os.path.exists(path) or not os.path.isfile(path):
logger.error("Unable to find JSON file `{}`".format(path))
sys.exit(1)
try:
fd = open(path, 'r')
except Exception as e:
logger.error("Unable to open file `{}`".format(path))
logger.exception(e)
sys.exit(1)
return fd
def is_remote_path(path):
return path.startswith('http:')
def get_local_remote_fd(path):
''' file descriptor for a path (either local or remote) '''
if is_remote_path(path):
return get_remote_content(path)
else:
return get_local_content(path)
def copy_to(src, dst):
''' copy source content (local or remote) to local file '''
local = None
if is_remote_path(src):
local = tempfile.NamedTemporaryFile(delete=False)
download_remote_file(src, local.name)
src = local.name
shutil.copy(src, dst)
if local is not None:
os.remove(local.name)
def download_remote_file(url, path):
''' download url to path '''
syscall('wget -c -O {path} {url}'.format(path=path, url=url))
def main(json_path, *args):
jsdata = json.load(get_local_remote_fd(json_path))
logger.info("Updating Play Store Content for {}".format(jsdata['package']))
if not jsdata.get('play_store'):
logger.error("You have no data in the play_store container")
sys.exit(1)
if 'GOOGLE_API_KEY' not in os.environ:
logger.error("You need to set the GOOGLE_API_KEY environment variable "
"to use the Google API (using path to google-api.p12)")
return
GOOGLE_CLIENT_ID = '107823297044-nhoqv99cpr86vlfcronskirgib2g7tq' \
'9@developer.gserviceaccount.com'
service = build('androidpublisher', 'v2')
key = open(os.environ['GOOGLE_API_KEY'], 'rb').read()
credentials = client.SignedJwtAssertionCredentials(
GOOGLE_CLIENT_ID,
key,
scope='https://www.googleapis.com/auth/androidpublisher')
http = httplib2.Http()
http = credentials.authorize(http)
service = build('androidpublisher', 'v2', http=http)
package_name = jsdata['package']
ps = jsdata.get('play_store')
default_lang = None # for images
files_to_delete = []
try:
# another edit request
edit_request = service.edits().insert(body={},
packageName=package_name)
result = edit_request.execute()
edit_id = result['id']
logger.info("Starting Edit #{} for all updates…".format(edit_id))
if 'details' in ps:
logger.debug("Updating details")
details_fields = ['contactEmail', 'contactPhone',
'contactWebsite', 'defaultLanguage']
details_body = {k: v for k, v in ps['details'].items()
if k in details_fields and v is not None}
details_upd = service.edits().details().update(
editId=edit_id,
packageName=package_name,
body=details_body).execute()
logger.debug("updated with {} items.".format(len(details_upd)))
# update default_lang with the value we just submitted
default_lang = details_body.get('defaultLanguage', None)
if 'listings' in ps:
logger.debug("Updating listings (main texts)")
for lang in ps['listings']:
details_fields = ['fullDescription', 'shortDescription',
'title', 'video']
details_body = {k: v for k, v in ps['listings'][lang].items()
if k in details_fields and v is not None}
listing_upd = service.edits().listings().update(
editId=edit_id,
packageName=package_name,
language=lang,
body=details_body).execute()
logger.debug("updated {} with {} items"
.format(lang, len(listing_upd)))
if 'images' in ps:
logger.debug("Updating images")
# retrieve default language as important for images
if default_lang is None:
details_data = service.edits().details().get(
editId=edit_id, packageName=package_name,).execute()
default_lang = details_data['defaultLanguage']
# upload images to default lang
for image_type, images in ps['images'].items():
if not images:
continue
# delete images for that type
delete_upd = service.edits().images().deleteall(
editId=edit_id,
packageName=package_name,
imageType=image_type,
language=default_lang).execute()
logger.debug("Cleared {} images: {}".format(
image_type,
",".join([d['sha1'] for d in delete_upd['deleted']])))
for image in images:
img_file = tempfile.NamedTemporaryFile(suffix='.png').name
copy_to(image, img_file)
files_to_delete.append(img_file)
img_upd = service.edits().images().upload(
editId=edit_id,
packageName=package_name,
imageType=image_type,
language=default_lang,
media_body=img_file).execute()
logger.debug("Uploaded image for {}. sha1: {}"
.format(image_type, img_upd['image']['sha1']))
# commit *all* the changes on the Play Store
commit_request = service.edits().commit(
editId=edit_id, packageName=package_name).execute()
logger.debug("Edit `{}` has been committed. done."
.format(commit_request['id']))
except client.AccessTokenRefreshError:
logger.error("The credentials have been revoked or expired, "
"please re-run the application to re-authorize")
finally:
for f in files_to_delete:
os.remove(f)
if __name__ == '__main__':
# ensure we were provided a JSON file as first argument
if len(sys.argv) < 2:
usage(sys.argv[0], 1)
else:
jspath = sys.argv[1]
args = sys.argv[2:]
main(jspath, *args)