#! /usr/bin/env python3 # source from https://gist.github.com/bwiernik/45f514da37af92491893f2f7212710f9 zotxform v0.612 # AUTHORS: Ian-Mathew Hornburg ‹imhornburg@gmail.com› # Optima Language Analytics LLC # LICENSE: [TBD] # Copyright (c) 2014–2015, the authors. # All rights reserved. # --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- # # update zotero.jar : add a custom plugin to tinymce and modify some files. # should be run as admin from shutil import copytree, rmtree, copy2 import logging import os import os.path as path import zipfile as z from win10toast import ToastNotifier from subprocess import Popen import time #custom var icon_start =r"C:\custom_path\MyIcons\start.ico" #★ icon_end =r"C:\custom_path\MyIcons\done.ico" #★ customplug_original_path=r"C:\custom_path\Zotero\custom_plugin_folder" #★ TEMPDIR_PATH = r"C:\custom_path\Zotero\temp_dir"#★ # other vars manifest_path = r"C:\Program Files (x86)\Zotero\chrome.manifest" manifest_edit = '\n\nEdits added + custom_plugin' # + date_time zotero_exe = r"C:\Program Files (x86)\Zotero\zotero.exe" archive_path = r"C:\Program Files (x86)\Zotero\zotero.jar" replace_list= [ {'path':path.join('resource', 'tinymce', 'css', 'note-ui.css'), 'replacement_table': { '.mce-window {\n width: auto !important;\n background: none !important;\n}':'.mce-window {\n width: 300px; /* xedit was set to : auto !important; */\n background: none !important;\n position: fixed; /* xedit*/\n top: 0; /* xedit*/\n right: 0; /* xedit*/\n}', '.mce-window:not([role=alertdialog]) {\n left: 0 !important;\n}':'/*.mce-window:not([role=alertdialog]) {\n left: 0 !important;\n} */', '.mce-window-head {\n background: #fff !important;\n}':'.mce-window-head {\n background: #fff !important;\nopacity: 0.8;\n}', '.mce-window-body {\n background: #fff !important;\n}':'.mce-window-body {\n background: #fff !important;\nopacity: 0.8;\n}' } }, {'path':path.join('resource', 'tinymce', 'note.html'), 'replacement_table': { 'plugins: "autolink,code,contextmenu,directionality,link,lists,paste,searchreplace,textcolor",': ' /********** START of xEDIT ********* \n\n plugin custom_plug added to plugins\n\n fontsizeselect in toolbar1 \n\n fontsize_formats: "8px 10px 12px 14px 16px 18px"\n\n *********/\n\n\n\n plugins: "autolink,code,custom_plug, contextmenu,directionality,link,lists,paste,searchreplace,textcolor",\n\n fontsize_formats: "8px 10px 12px 14px 16px 18px",' }, }, {'path':path.join('resource', 'tinymce', 'tinymce.min.js'), 'replacement_table': { 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins':'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,h1, h2, h3, h4, h5, h6', 'subscript:{inline:"sub"},superscript:{inline:"sup"}':'subscript:{inline:"sub", styles: {fontSize: \'70%\'}},superscript:{inline:"sup", styles: {fontSize: \'70%\'}}' } } ] date_time = time.strftime("%Y_%m_%d_") + time.strftime("_%H_%M_%S") logging.basicConfig(format="[Zotero Edits] {levelname} :: {message}", style='{') logger = logging.getLogger('Zotero Edits') logger.setLevel('INFO') logger.info("Zotero Edits") toaster = ToastNotifier() toaster.show_toast("Starting updating Zotero", "zotero_updating.py", icon_path=icon_start, duration=3) #close zotero before update os.system("TASKKILL /F /IM zotero.exe") time.sleep(10) # apply the modification stored in replacement to the file cf line 143 def modify_file(file, replacement): logger.info(f"start modifying {file}...") with open(file, encoding='utf_8', mode='r') as f: properties = f.read() for target in replacement.keys(): properties = properties.replace(target, replacement.get(target)) with open(file, encoding='utf_8', mode='w') as f: f.write(properties) logger.info(f"end modifying {file}!") zotero_archive_path = path.abspath(archive_path) chrome_manifeste_path = path.abspath(manifest_path) try: if os.path.isfile(chrome_manifeste_path): logger.info("Manifest found.") else: raise FileNotFoundError("chrome.manifest file not found.") with z.ZipFile(zotero_archive_path, mode='r') as archive: os.mkdir(TEMPDIR_PATH) os.chdir(TEMPDIR_PATH) #changes current working directory to tempdit # We wanna preserve the exact order of the files in the archive, # since for some applications, order matters (e.g., needing to have # the chrome.manifest first). So everything that’s going into the # archive needs to be explicitly enumerated in this list, starting # with the existing contents. file_list = archive.namelist() # Extract and end scope, closing archive logger.info('extracting zotero.jar... ') archive.extractall() logger.info('finish extracting zotero.jar!') # Add edits to chrome_manifeste with open(chrome_manifeste_path, encoding='utf_8', mode='r') as manifest: s = manifest.read() if manifest_edit in s: raise ValueError("Manifest already patched.") s = s.join([s, manifest_edit]) logger.info("Writing patched manifest.") with open(chrome_manifeste_path, encoding='utf_8', mode='w') as manifest: manifest.write(s) # copy the contents of custom_plug to local dir and save the content in file_list logger.info("start copying custom_plug...") custom_plug_new=path.join('resource', 'tinymce', 'plugins', 'custom_plug') copytree(customplug_original_path, custom_plug_new) file_list.append(custom_plug_new) for e in [path.join(dirpath, f) for dirpath, dirname, filename in os.walk(custom_plug_new) for f in filename]: file_list.append(e) logger.info("end copying custom_plug!") # modify the files according to its replacement_table for item in replace_list: modify_file(item["path"],item["replacement_table"]) #backup old zotero.jar bkp_zotero_archive_path= zotero_archive_path[:-4]+date_time+".jar" #remove .jar, add date, add .jar copy2(zotero_archive_path, bkp_zotero_archive_path) logger.info("backup old zotero.jar") # Truncate and write new archive with z.ZipFile(zotero_archive_path, compression=z.ZIP_DEFLATED, mode='w') as archive: #should be for e in file_list: archive.write(e) logger.info("Done.") finally: os.chdir(os.pardir) rmtree(TEMPDIR_PATH) #reopen zotero Popen([zotero_exe]) #notification end toaster = ToastNotifier() toaster.show_toast("Finish updating Zotero", "zotero_updating.py", icon_path=icon_end, duration=3)