Fix mutable params + compact names json
This commit is contained in:
@@ -33,6 +33,16 @@ def enum_genres(bundle_id):
|
|||||||
yield lang, gid, name
|
yield lang, gid, name
|
||||||
|
|
||||||
|
|
||||||
|
def choose_lang(obj):
|
||||||
|
''' expects dict with {'us': ..., 'de': ...} '''
|
||||||
|
for lang in AVAILABLE_LANGS:
|
||||||
|
try:
|
||||||
|
return obj[lang]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def download_info(bundle_id, lang, force=False):
|
def download_info(bundle_id, lang, force=False):
|
||||||
fname = fname_for(bundle_id, lang)
|
fname = fname_for(bundle_id, lang)
|
||||||
if force or not mylib.file_exists(fname):
|
if force or not mylib.file_exists(fname):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def process(affected=None, per_page=60):
|
|||||||
print(' {} ({})'.format(cat, a))
|
print(' {} ({})'.format(cat, a))
|
||||||
|
|
||||||
print(' .. {} categories'.format(len(arr)))
|
print(' .. {} categories'.format(len(arr)))
|
||||||
src = ''.join([HTML.a(n, '{}/'.format(cid)) for cid, n in arr])
|
src = ''.join([HTML.a_category(cid, n) for cid, n in arr])
|
||||||
HTML.write(base, '''
|
HTML.write(base, '''
|
||||||
<h2>{}</h2>
|
<h2>{}</h2>
|
||||||
<div class="tags large center">
|
<div class="tags large center">
|
||||||
|
|||||||
@@ -4,67 +4,58 @@ import sys
|
|||||||
import lib_common as mylib
|
import lib_common as mylib
|
||||||
import download_itunes # app_names
|
import download_itunes # app_names
|
||||||
|
|
||||||
_bundle_name_dict = None
|
_app_names_dict = None
|
||||||
|
|
||||||
|
|
||||||
def index_fname():
|
def fname_apps_all():
|
||||||
return mylib.path_data_index('app_names.json')
|
return mylib.path_data_index('app_names_all.json')
|
||||||
|
|
||||||
|
|
||||||
def missing():
|
def fname_apps_compact():
|
||||||
return not mylib.file_exists(index_fname())
|
return mylib.path_data_index('app_names_compact.json')
|
||||||
|
|
||||||
|
|
||||||
def load_json_if_not_already():
|
def get_name(bundle_id, fallback='< App-Name >'):
|
||||||
global _bundle_name_dict
|
global _app_names_dict
|
||||||
if not _bundle_name_dict:
|
if not _app_names_dict:
|
||||||
index_file = index_fname()
|
_app_names_dict = mylib.json_safe_read(fname_apps_compact(), {})
|
||||||
if mylib.file_exists(index_file):
|
try:
|
||||||
_bundle_name_dict = mylib.json_read(index_file)
|
return _app_names_dict[bundle_id]
|
||||||
else:
|
except KeyError:
|
||||||
_bundle_name_dict = {}
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
def write_json_to_disk():
|
|
||||||
mylib.json_write(index_fname(), _bundle_name_dict, pretty=False)
|
|
||||||
|
|
||||||
|
|
||||||
def get_name(bundle_id, langs=['us', 'de'], fallback='< App-Name >'):
|
|
||||||
load_json_if_not_already()
|
|
||||||
for lang in langs:
|
|
||||||
try:
|
|
||||||
return _bundle_name_dict[bundle_id][lang]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
return fallback # None
|
|
||||||
|
|
||||||
|
|
||||||
def process(bundle_ids, deleteOnly=False):
|
def process(bundle_ids, deleteOnly=False):
|
||||||
|
global _app_names_dict
|
||||||
print('writing index: app names ...')
|
print('writing index: app names ...')
|
||||||
if bundle_ids == ['*']:
|
if bundle_ids == ['*']:
|
||||||
print(' full reset')
|
print(' full reset')
|
||||||
mylib.rm_file(index_fname()) # rebuild from ground up
|
mylib.rm_file(fname_apps_all()) # rebuild from ground up
|
||||||
|
mylib.rm_file(fname_apps_compact())
|
||||||
|
|
||||||
load_json_if_not_already()
|
index = mylib.json_safe_read(fname_apps_all(), {})
|
||||||
did_change = False
|
did_change = False
|
||||||
for bid in mylib.appids_in_data(bundle_ids):
|
for bid in mylib.appids_in_data(bundle_ids):
|
||||||
if deleteOnly:
|
if deleteOnly:
|
||||||
did_change |= mylib.try_del(_bundle_name_dict, [bid])
|
did_change |= mylib.try_del(index, [bid])
|
||||||
continue
|
continue
|
||||||
names = download_itunes.get_app_names(bid)
|
names = download_itunes.get_app_names(bid)
|
||||||
if not names:
|
if not names:
|
||||||
mylib.err('index-app-names', 'could not load: {}'.format(bid))
|
mylib.err('index-app-names', 'could not load: {}'.format(bid))
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
if _bundle_name_dict[bid] == names:
|
if index[bid] == names:
|
||||||
continue
|
continue
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
_bundle_name_dict[bid] = names
|
index[bid] = names
|
||||||
did_change = True
|
did_change = True
|
||||||
if did_change:
|
if did_change:
|
||||||
print(' writing')
|
print(' writing')
|
||||||
write_json_to_disk()
|
mylib.json_write(fname_apps_all(), index, pretty=False)
|
||||||
|
_app_names_dict = {bid: download_itunes.choose_lang(names)
|
||||||
|
for bid, names in index.items()}
|
||||||
|
mylib.json_write(fname_apps_compact(), _app_names_dict, pretty=False)
|
||||||
else:
|
else:
|
||||||
print(' no change')
|
print(' no change')
|
||||||
print('')
|
print('')
|
||||||
|
|||||||
@@ -12,50 +12,53 @@ def fname_app_categories():
|
|||||||
return mylib.path_data_index('app_categories.json')
|
return mylib.path_data_index('app_categories.json')
|
||||||
|
|
||||||
|
|
||||||
def fname_category_names():
|
def fname_cat_name_all():
|
||||||
return mylib.path_data_index('category_names.json')
|
return mylib.path_data_index('category_names_all.json')
|
||||||
|
|
||||||
|
|
||||||
def load_json_if_not_already():
|
def fname_cat_name_compact():
|
||||||
def load_json_from_disk(fname):
|
return mylib.path_data_index('category_names_compact.json')
|
||||||
return mylib.json_read(fname) if mylib.file_exists(fname) else {}
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_json_if_not_already(noNames=False):
|
||||||
global _dict_apps, _dict_names
|
global _dict_apps, _dict_names
|
||||||
if not _dict_apps:
|
if not _dict_apps:
|
||||||
_dict_apps = load_json_from_disk(fname_app_categories())
|
_dict_apps = mylib.json_safe_read(fname_app_categories(), {})
|
||||||
if not _dict_names:
|
if not _dict_names and not noNames:
|
||||||
_dict_names = load_json_from_disk(fname_category_names())
|
_dict_names = mylib.json_safe_read(fname_cat_name_compact(), {})
|
||||||
|
|
||||||
|
|
||||||
def try_update_app(bid, genre_ids):
|
def try_update_app(index, bid, genre_ids):
|
||||||
try:
|
try:
|
||||||
if _dict_apps[bid] == genre_ids:
|
if index[bid] == genre_ids:
|
||||||
return False
|
return False
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
_dict_apps[bid] = genre_ids
|
index[bid] = genre_ids
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def try_update_name(gid, lang, name):
|
def try_update_name_all(index, cid, lang, name):
|
||||||
try:
|
try:
|
||||||
_dict_names[gid]
|
index[cid]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
_dict_names[gid] = {}
|
index[cid] = {}
|
||||||
try:
|
try:
|
||||||
if _dict_names[gid][lang]:
|
if index[cid][lang]:
|
||||||
return False # key already exists
|
return False # key already exists
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
_dict_names[gid][lang] = name
|
index[cid][lang] = name
|
||||||
return True # updated, need to persist changes
|
return True # updated, need to persist changes
|
||||||
|
|
||||||
|
|
||||||
def reset_index():
|
def reset_index():
|
||||||
global _dict_apps
|
global _dict_apps, _dict_names
|
||||||
print(' full reset')
|
|
||||||
mylib.rm_file(fname_app_categories()) # rebuild from ground up
|
mylib.rm_file(fname_app_categories()) # rebuild from ground up
|
||||||
|
mylib.rm_file(fname_cat_name_all())
|
||||||
|
mylib.rm_file(fname_cat_name_compact())
|
||||||
_dict_apps = None
|
_dict_apps = None
|
||||||
|
_dict_names = None
|
||||||
|
|
||||||
|
|
||||||
def get_categories(bundle_id):
|
def get_categories(bundle_id):
|
||||||
@@ -66,13 +69,7 @@ def get_categories(bundle_id):
|
|||||||
return []
|
return []
|
||||||
res = []
|
res = []
|
||||||
for gid in genres:
|
for gid in genres:
|
||||||
for lang in ['us', 'de']:
|
res.append((gid, _dict_names[gid]))
|
||||||
try:
|
|
||||||
name = _dict_names[gid][lang]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
res.append((gid, name))
|
|
||||||
break
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@@ -85,40 +82,40 @@ def enum_all_categories():
|
|||||||
reverse_index[gid].append(bid)
|
reverse_index[gid].append(bid)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
reverse_index[gid] = [bid]
|
reverse_index[gid] = [bid]
|
||||||
for gid, lang_dict in _dict_names.items():
|
for gid, name in _dict_names.items():
|
||||||
for lang in ['us', 'de']:
|
yield gid, name, reverse_index[gid]
|
||||||
try:
|
|
||||||
name = lang_dict[lang]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
yield gid, name, reverse_index[gid]
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def process(bundle_ids, force=False):
|
def process(bundle_ids, force=False):
|
||||||
|
global _dict_apps, _dict_names
|
||||||
print('writing index: categories ...')
|
print('writing index: categories ...')
|
||||||
if force and bundle_ids == ['*']:
|
if force and bundle_ids == ['*']:
|
||||||
|
print(' full reset')
|
||||||
reset_index()
|
reset_index()
|
||||||
|
|
||||||
load_json_if_not_already()
|
load_json_if_not_already(noNames=False)
|
||||||
|
name_index = mylib.json_safe_read(fname_cat_name_all(), {})
|
||||||
write_name_index = False
|
write_name_index = False
|
||||||
write_app_index = False
|
write_app_index = False
|
||||||
for bid in mylib.appids_in_data(bundle_ids):
|
for bid in mylib.appids_in_data(bundle_ids):
|
||||||
genre_ids = []
|
cateogory_ids = []
|
||||||
for lang, gid, gname in download_itunes.enum_genres(bid):
|
for lang, cid, gname in download_itunes.enum_genres(bid):
|
||||||
if gid not in genre_ids:
|
if cid not in cateogory_ids:
|
||||||
genre_ids.append(gid)
|
cateogory_ids.append(cid)
|
||||||
if try_update_name(gid, lang, gname):
|
if try_update_name_all(name_index, cid, lang, gname):
|
||||||
write_name_index = True
|
write_name_index = True
|
||||||
if try_update_app(bid, genre_ids):
|
if try_update_app(_dict_apps, bid, cateogory_ids):
|
||||||
write_app_index = True
|
write_app_index = True
|
||||||
|
|
||||||
if write_name_index:
|
|
||||||
print(' write name-index')
|
|
||||||
mylib.json_write(fname_category_names(), _dict_names, pretty=False)
|
|
||||||
if write_app_index:
|
if write_app_index:
|
||||||
print(' write app-index')
|
print(' write app-index')
|
||||||
mylib.json_write(fname_app_categories(), _dict_apps, pretty=False)
|
mylib.json_write(fname_app_categories(), _dict_apps, pretty=False)
|
||||||
|
if write_name_index:
|
||||||
|
print(' write name-index')
|
||||||
|
mylib.json_write(fname_cat_name_all(), name_index, pretty=False)
|
||||||
|
_dict_names = {cid: download_itunes.choose_lang(names)
|
||||||
|
for cid, names in name_index.items()}
|
||||||
|
mylib.json_write(fname_cat_name_compact(), _dict_names, pretty=False)
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ def fname_tracker():
|
|||||||
|
|
||||||
|
|
||||||
def load_json_from_disk(index_file):
|
def load_json_from_disk(index_file):
|
||||||
if mylib.file_exists(index_file):
|
return mylib.json_safe_read(
|
||||||
return mylib.json_read(index_file)
|
index_file, fallback={'bundle': [], 'pardom': {}, 'subdom': {}})
|
||||||
else:
|
|
||||||
return {'bundle': [], 'pardom': {}, 'subdom': {}}
|
|
||||||
|
|
||||||
|
|
||||||
def delete_from_index(index, bundle_ids, deleteOnly=False):
|
def delete_from_index(index, bundle_ids, deleteOnly=False):
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ def fname_app_rank():
|
|||||||
return mylib.path_data_index('app_rank.json')
|
return mylib.path_data_index('app_rank.json')
|
||||||
|
|
||||||
|
|
||||||
def load_json_from_disk(fname):
|
|
||||||
return mylib.json_read(fname) if mylib.file_exists(fname) else {}
|
|
||||||
|
|
||||||
|
|
||||||
def json_to_list(json):
|
def json_to_list(json):
|
||||||
return [
|
return [
|
||||||
json['sum_rec'],
|
json['sum_rec'],
|
||||||
@@ -100,7 +96,7 @@ def write_rank_index(index):
|
|||||||
|
|
||||||
def get_total_counts():
|
def get_total_counts():
|
||||||
try:
|
try:
|
||||||
return load_json_from_disk(fname_app_summary())['_sum']
|
return mylib.json_safe_read(fname_app_summary(), {})['_sum']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return [0, 0]
|
return [0, 0]
|
||||||
|
|
||||||
@@ -112,7 +108,7 @@ def process(bundle_ids, deleteOnly=False):
|
|||||||
print(' full reset')
|
print(' full reset')
|
||||||
mylib.rm_file(fname) # rebuild from ground up
|
mylib.rm_file(fname) # rebuild from ground up
|
||||||
|
|
||||||
index = load_json_from_disk(fname)
|
index = mylib.json_safe_read(fname, {})
|
||||||
ids = mylib.appids_in_data(bundle_ids)
|
ids = mylib.appids_in_data(bundle_ids)
|
||||||
write_summary_index(index, ids, deleteOnly=deleteOnly)
|
write_summary_index(index, ids, deleteOnly=deleteOnly)
|
||||||
write_rank_index(index)
|
write_rank_index(index)
|
||||||
|
|||||||
@@ -249,14 +249,14 @@ def enum_jsons(bundle_id):
|
|||||||
yield fname, json.load(fp)
|
yield fname, json.load(fp)
|
||||||
|
|
||||||
|
|
||||||
def appids_in_out(selection=['*']):
|
def appids_in_out(selection=None):
|
||||||
if selection != ['*']:
|
if selection and selection != ['*']:
|
||||||
return selection
|
return selection
|
||||||
return [os.path.basename(x) for x in glob.glob(path_out_app('*'))]
|
return [os.path.basename(x) for x in glob.glob(path_out_app('*'))]
|
||||||
|
|
||||||
|
|
||||||
def appids_in_data(selection=['*']):
|
def appids_in_data(selection=None):
|
||||||
if selection != ['*']:
|
if selection and selection != ['*']:
|
||||||
return selection
|
return selection
|
||||||
global _all_data_bundle_ids
|
global _all_data_bundle_ids
|
||||||
if not _all_data_bundle_ids:
|
if not _all_data_bundle_ids:
|
||||||
@@ -287,6 +287,10 @@ def json_read(path):
|
|||||||
return json.load(fp)
|
return json.load(fp)
|
||||||
|
|
||||||
|
|
||||||
|
def json_safe_read(path, fallback=None):
|
||||||
|
return json_read(path) if file_exists(path) else fallback
|
||||||
|
|
||||||
|
|
||||||
def json_write(path, obj, pretty=False):
|
def json_write(path, obj, pretty=False):
|
||||||
with open(path, 'w') as fp:
|
with open(path, 'w') as fp:
|
||||||
json.dump(obj, fp, indent=2 if pretty else None, sort_keys=pretty)
|
json.dump(obj, fp, indent=2 if pretty else None, sort_keys=pretty)
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ def percent_bar(percent):
|
|||||||
return '<div class="pcbar"><i style="left: {}%"></i></div>'.format(round(percent * 100))
|
return '<div class="pcbar"><i style="left: {}%"></i></div>'.format(round(percent * 100))
|
||||||
|
|
||||||
|
|
||||||
def rank_tile(title, value, additional=None, attr={},
|
def rank_tile(title, value, additional=None, attr=None,
|
||||||
percent=0.5, rank='?', best='?', worst='?'):
|
percent=0.5, rank='?', best='?', worst='?'):
|
||||||
if additional:
|
if additional:
|
||||||
value += '<i class="snd mg_lr">({})</i>'.format(additional)
|
value += '<i class="snd mg_lr">({})</i>'.format(additional)
|
||||||
attr = HTML.attr_and(attr, {'class': 'rank'})
|
attr = HTML.attr_and(attr or {}, {'class': 'rank'})
|
||||||
return HTML.div('''
|
return HTML.div('''
|
||||||
<h4>{}</h4>
|
<h4>{}</h4>
|
||||||
{} <b class="mg_lr">{}</b>
|
{} <b class="mg_lr">{}</b>
|
||||||
|
|||||||
@@ -46,29 +46,27 @@ def attr_and(a, b):
|
|||||||
|
|
||||||
# Basic building blocks
|
# Basic building blocks
|
||||||
|
|
||||||
def xml(tag, inner, attr={}):
|
def xml(tag, inner, attr=None):
|
||||||
src = ''
|
src = ''
|
||||||
for key, val in attr.items():
|
if attr:
|
||||||
if val:
|
for key, val in attr.items():
|
||||||
src += ' {}="{}"'.format(key, val)
|
if val:
|
||||||
|
src += ' {}="{}"'.format(key, val)
|
||||||
return '<{0}{1}>{2}</{0}>'.format(tag, src, inner)
|
return '<{0}{1}>{2}</{0}>'.format(tag, src, inner)
|
||||||
|
|
||||||
|
|
||||||
def div(inner, attr={}):
|
def div(inner, attr=None):
|
||||||
return xml('div', inner, attr)
|
return xml('div', inner, attr)
|
||||||
|
|
||||||
|
|
||||||
def h2(inner, attr={}):
|
def h2(inner, attr=None):
|
||||||
return xml('h2', inner, attr)
|
return xml('h2', inner, attr)
|
||||||
|
|
||||||
|
|
||||||
def a(inner, href, attr={}):
|
|
||||||
return xml('a', inner, attr_and(attr, {'href': href}))
|
|
||||||
|
|
||||||
|
|
||||||
def a_path(parts, suffix):
|
def a_path(parts, suffix):
|
||||||
''' expects (name, url) tuples '''
|
''' expects (name, url) tuples '''
|
||||||
return ' / '.join([a(*x) for x in parts] + [suffix])
|
return ' / '.join(['<a href="{}/">{}</a>'.format(url, title)
|
||||||
|
for title, url in parts] + [suffix])
|
||||||
|
|
||||||
|
|
||||||
# Simple constructs
|
# Simple constructs
|
||||||
@@ -137,8 +135,8 @@ def app_tile_template():
|
|||||||
</div></a>'''
|
</div></a>'''
|
||||||
|
|
||||||
|
|
||||||
def app_tiles_all(bundle_ids, per_page=60, attr={}):
|
def app_tiles_all(bundle_ids, per_page=60):
|
||||||
attr = attr_and(attr, {'id': 'app-toc', 'class': 'no-ul-all'})
|
attr = {'id': 'app-toc', 'class': 'no-ul-all'}
|
||||||
c_apps = len(bundle_ids)
|
c_apps = len(bundle_ids)
|
||||||
c_pages = int(math.ceil(c_apps / per_page))
|
c_pages = int(math.ceil(c_apps / per_page))
|
||||||
for i, apps in apps_sorted_batch(bundle_ids, batch_size=per_page):
|
for i, apps in apps_sorted_batch(bundle_ids, batch_size=per_page):
|
||||||
@@ -170,11 +168,11 @@ def write(path, content, title=None, fname='index.html'):
|
|||||||
fp.write(base_template(content, title=title))
|
fp.write(base_template(content, title=title))
|
||||||
|
|
||||||
|
|
||||||
def write_app_pages(base, bundle_ids, title, per_page=60, attr={}, pre=''):
|
def write_app_pages(base, bundle_ids, title, per_page=60, pre=''):
|
||||||
pages = 0
|
pages = 0
|
||||||
entries = 0
|
entries = 0
|
||||||
mylib.rm_dir(base)
|
mylib.rm_dir(base)
|
||||||
for i, count, src in app_tiles_all(bundle_ids, per_page, attr):
|
for i, count, src in app_tiles_all(bundle_ids, per_page):
|
||||||
pages += 1
|
pages += 1
|
||||||
entries += count
|
entries += count
|
||||||
pth = base if i == 1 else mylib.path_add(base, str(i))
|
pth = base if i == 1 else mylib.path_add(base, str(i))
|
||||||
|
|||||||
Reference in New Issue
Block a user