mirror of
				https://github.com/iiab/iiab.git
				synced 2025-03-09 15:40:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			208 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| '''
 | |
| Common functions for IIAB
 | |
| Admin Console functions are in adm_lib.py
 | |
| '''
 | |
| import os
 | |
| import json
 | |
| import subprocess
 | |
| import shlex
 | |
| import xml.etree.ElementTree as ET
 | |
| import iiab.iiab_const as CONST
 | |
| 
 | |
| lang_codes = {}
 | |
| lang_iso2_codes = {}
 | |
| 
 | |
| def get_zim_list(path):
 | |
|     '''
 | |
|     Get a list of installed zims in the passed path
 | |
| 
 | |
|     Args:
 | |
|       path (str): The path to search
 | |
| 
 | |
|     Returns:
 | |
|       files_processed (dict): A dict all zims found and any index directory (now obsolete)
 | |
|       zim_versions (dict): A dict that translates generic zim names to physically installed
 | |
|     '''
 | |
| 
 | |
|     files_processed = {}
 | |
|     zim_versions = {} # we don't need this unless adm cons is installed, but easier to compute now
 | |
|     content = path + "/content/"
 | |
|     index = path + "/index/"
 | |
|     flist = os.listdir(content)
 | |
|     flist.sort()
 | |
|     for filename in flist:
 | |
|         zimpos = filename.find(".zim")
 | |
|         if zimpos != -1:
 | |
|             zim_info = {}
 | |
|             filename = filename[:zimpos]
 | |
|             zimname = "content/" + filename + ".zim"
 | |
|             zimidx = "index/" + filename + ".zim.idx"
 | |
|             if zimname not in files_processed:
 | |
|                 if not os.path.isdir(path + "/" + zimidx): # only declare index if exists (could be embedded)
 | |
|                     zimidx = None
 | |
|                 files_processed[zimname] = zimidx
 | |
|                 zimname = content + filename + ".zim"
 | |
|                 zimidx = index + filename + ".zim.idx"
 | |
|                 if filename in CONST.old_zim_map: # handle old names that don't parse
 | |
|                     perma_ref = CONST.old_zim_map[filename]
 | |
|                 else:
 | |
|                     ulpos = filename.rfind("_")
 | |
|                     # but old gutenberg and some other names are not canonical
 | |
|                     if filename.rfind("-") < 0: # non-canonical name
 | |
|                         ulpos = filename[:ulpos].rfind("_")
 | |
|                     perma_ref = filename[:ulpos]
 | |
|                 zim_info['file_name'] = filename
 | |
|                 zim_versions[perma_ref] = zim_info # if there are multiples, last should win
 | |
|     return files_processed, zim_versions
 | |
| 
 | |
| def read_library_xml(lib_xml_file, kiwix_exclude_attr=["favicon"]): # duplicated from iiab-cmdsrv but changed
 | |
|     '''
 | |
|     Read zim properties from library.xml
 | |
|     Returns dict of library.xml and map of zim id to zim file name (under <dev>/library/zims)
 | |
| 
 | |
|     Args:
 | |
|       lib_xml_file (str): Path to file to read. Can be on removable device
 | |
|       kiwix_exclude_attr (list): Zim properties to exclude from return
 | |
| 
 | |
|     Returns:
 | |
|       zims_installed (dict): A dictionary holding all installed zims and their attributes
 | |
|       path_to_id_map (dict): A dictionary that translates zim ids to physical names
 | |
|     '''
 | |
| 
 | |
|     kiwix_exclude_attr.append("id") # don't include id because is key
 | |
|     zims_installed = {}
 | |
|     path_to_id_map = {}
 | |
|     try:
 | |
|         tree = ET.parse(lib_xml_file)
 | |
|         root = tree.getroot()
 | |
|         for child in root:
 | |
|             attributes = {}
 | |
|             if 'id' not in child.attrib: # is this necessary? implies there are records with no book id which would break index for removal
 | |
|                 print("xml record missing Book Id")
 | |
|             zim_id = child.attrib['id']
 | |
|             for attr in child.attrib:
 | |
|                 if attr not in kiwix_exclude_attr:
 | |
|                     attributes[attr] = child.attrib[attr] # copy if not id or in exclusion list
 | |
|             zims_installed[zim_id] = attributes
 | |
|             path_to_id_map[child.attrib['path']] = zim_id
 | |
|     except IOError:
 | |
|         zims_installed = {}
 | |
|     return zims_installed, path_to_id_map
 | |
| 
 | |
| def rem_libr_xml(zim_id, kiwix_library_xml):
 | |
|     '''
 | |
|     Remove a zim from library.xml
 | |
| 
 | |
|     Args:
 | |
|       zim_id (uuid): Id of the zim to remove
 | |
|       lib_xml_file (str): Path to file to read. Can be on removable device
 | |
|     '''
 | |
| 
 | |
|     command = CONST.kiwix_manage + " " + kiwix_library_xml + " remove " + zim_id
 | |
|     #print command
 | |
|     args = shlex.split(command)
 | |
|     try:
 | |
|         outp = subprocess.check_output(args)
 | |
|     except subprocess.CalledProcessError as e:
 | |
|         if e.returncode != 2: # skip bogus file open error in kiwix-manage
 | |
|             print(outp)
 | |
| 
 | |
| def add_libr_xml(kiwix_library_xml, zim_path, zimname, zimidx=None):
 | |
|     '''
 | |
|     Add a zim to library.xml
 | |
| 
 | |
|     Args:
 | |
|       kiwix_library_xml (str): Name (path) of library.xml file
 | |
|       zim_path (str): Path to zim file to add
 | |
|       zimname (str): Name of zim file to add
 | |
|       zimidx (str): Path to separate idx directory (obsolete)
 | |
| 
 | |
|     '''
 | |
|     command = CONST.kiwix_manage + " " + kiwix_library_xml + " add " + zim_path + "/" + zimname
 | |
|     if zimidx:
 | |
|         command += " -i " + zim_path + "/" + zimidx
 | |
|     #print command
 | |
|     args = shlex.split(command)
 | |
|     try:
 | |
|         outp = subprocess.check_output(args)
 | |
| 
 | |
|     except: #skip things that don't work
 | |
|         #print 'skipping ' + zimname
 | |
|         pass
 | |
| 
 | |
| def read_lang_codes():
 | |
|     '''Populate the global lang_codes dictionary from CONST.lang_codes_path json file'''
 | |
| 
 | |
|     global lang_codes
 | |
|     with open(CONST.lang_codes_path, "r") as f:
 | |
|         reads = f.read()
 | |
|         #print("menu.json:%s"%reads)
 | |
|         lang_codes = json.loads(reads)
 | |
| 
 | |
|     # create iso2 index
 | |
|     for lang in lang_codes:
 | |
|         lang_iso2_codes[lang_codes[lang]['iso2']  ] = lang
 | |
| 
 | |
| # there is a different algorithm in get_zim_list above
 | |
| def calc_perma_ref(uri):
 | |
|     '''Given a path or url return the generic zim name'''
 | |
|     url_slash = uri.split('/')
 | |
|     url_end = url_slash[-1] # last element
 | |
|     file_ref = url_end.split('.zim')[0] # true for both internal and external index
 | |
|     perma_ref_parts = file_ref.split('_')
 | |
|     perma_ref = perma_ref_parts[0]
 | |
|     if len(perma_ref_parts) > 1:
 | |
|         perma_ref_parts = perma_ref_parts[0:len(perma_ref_parts) - 1] # all but last, which should be date
 | |
|         for part in perma_ref_parts[1:]: # start with 2nd
 | |
|             if not part.isdigit():
 | |
|                 perma_ref += "_" + part
 | |
|     return perma_ref
 | |
| 
 | |
| def kiwix_lang_to_iso2(zim_lang_code):
 | |
|     '''Lookup the iso2 equivalent of a zim language code'''
 | |
|     return lang_codes[zim_lang_code]['iso2']
 | |
| 
 | |
| def human_readable(num):
 | |
|     '''Convert a number to a human readable string'''
 | |
|     # return 3 significant digits and unit specifier
 | |
|     # TFM 7/15/2019 change to factor of 1024, not 1000 to match similar calcs elsewhere
 | |
|     num = float(num)
 | |
|     units = ['', 'K', 'M', 'G']
 | |
|     for i in range(4):
 | |
|         if num < 10.0:
 | |
|             return "%.2f%s"%(num, units[i])
 | |
|         if num < 100.0:
 | |
|             return "%.1f%s"%(num, units[i])
 | |
|         if num < 1000.0:
 | |
|             return "%.0f%s"%(num, units[i])
 | |
|         num /= 1024.0
 | |
| 
 | |
| # Environment Functions
 | |
| 
 | |
| def get_iiab_env(name):
 | |
|     ''' read iiab.env file for a value, return "" if does not exist. return all value for *'''
 | |
|     iiab_env = {}
 | |
|     iiab_env_var = ''
 | |
|     try:
 | |
|         fd = open("/etc/iiab/iiab.env", "r")
 | |
|         for line in fd:
 | |
|             line = line.lstrip()
 | |
|             line = line.rstrip('\n')
 | |
|             if len(line) == 0:
 | |
|                 continue
 | |
|             if line[0] == "#":
 | |
|                 continue
 | |
|             if line.find("=") == -1:
 | |
|                 continue
 | |
|             chunks = line.split('=')
 | |
|             iiab_env[chunks[0]] = chunks[1]
 | |
|             if chunks[0] == name:
 | |
|                 iiab_env_var = chunks[1]
 | |
|     except:
 | |
|         pass
 | |
|     finally:
 | |
|         fd.close()
 | |
|     if name == '*':
 | |
|         return iiab_env
 | |
|     else:
 | |
|         return iiab_env_var
 |