diff --git a/README.md b/README.md index c8586b1..5f2a37b 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,23 @@ The downside is that equations are not rendered for team members without the Mat ## How do I install it? -Download and run the script. Restart the Slack client. You're done! +Get and run the script. Restart the Slack client. You're done! +### Getting the script ### Mac and Linux Run the following in a terminal: ```shell -curl -OL https://github.com/fsavje/math-with-slack/releases/download/v0.2.5/math-with-slack.sh -sudo bash math-with-slack.sh +curl -OL https://raw.githubusercontent.com/psg-mit/math-with-slack/v3/math-with-slack.py +sudo python math-with-slack.py ``` - ### Windows +!!! Current support for windows is unknown + [Download the script](https://github.com/fsavje/math-with-slack/releases/download/v0.2.5/math-with-slack.bat) and double-click to run. Alternatively, run it in the command prompt with: ```shell diff --git a/math-with-slack.py b/math-with-slack.py old mode 100755 new mode 100644 index 71383a9..a93533d --- a/math-with-slack.py +++ b/math-with-slack.py @@ -15,7 +15,7 @@ # ################################################################################ -# Python 2.7 +# Python 2.7 and 3 from __future__ import print_function @@ -28,6 +28,17 @@ import shutil import struct import sys +from distutils.version import LooseVersion + +try: + # Python 3 + import urllib.request as urllib_request +except: + # Python 2 + import urllib as urllib_request + +import tarfile +import tempfile # Math with Slack version @@ -39,7 +50,9 @@ parser = argparse.ArgumentParser(prog='math-with-slack', description='Inject Slack with MathJax.') parser.add_argument('-a', '--app-file', help='Path to Slack\'s \'app.asar\' file.') -parser.add_argument('-s', '--settings-file', help='Path to Slack\'s \'local-settings.json\' file.') +parser.add_argument('--mathjax-url', + help='Url to download mathjax release.', + default='https://registry.npmjs.org/mathjax/-/mathjax-3.0.1.tgz') parser.add_argument('-u', '--uninstall', action='store_true', help='Removes injected MathJax code.') parser.add_argument('--version', action='version', version='%(prog)s ' + mws_version) args = parser.parse_args() @@ -58,7 +71,7 @@ def exprint(*args, **kwargs): app_path = args.app_file elif sys.platform == 'darwin': app_path = '/Applications/Slack.app/Contents/Resources/app.asar' -elif sys.platform == 'linux': +elif sys.platform.startswith('linux'): for test_app_file in [ '/usr/lib/slack/resources/app.asar', '/usr/local/lib/slack/resources/app.asar', @@ -80,59 +93,10 @@ def exprint(*args, **kwargs): exprint('Could not find Slack\'s app.asar file. Please provide path.') -# Find path to local-settings.json - -if args.settings_file is not None: - settings_path = args.settings_file -elif sys.platform == 'darwin': - for test_settings_file in [ - os.path.expandvars('${HOME}/Library/Application Support/Slack/local-settings.json'), - os.path.expandvars('${HOME}/Library/Containers/com.tinyspeck.slackmacgap/Data/Library/Application Support/Slack/local-settings.json') - ]: - if os.path.isfile(test_settings_file): - settings_path = test_settings_file - break -elif sys.platform == 'linux': - exprint('Not implemented') -elif sys.platform == 'win32': - settings_path = os.path.expandvars('%AppData%\\Slack\\local-settings.json') - - -# Check so local-settings.json file exists - -try: - if not os.path.isfile(settings_path): - exprint('Cannot find settings file at: ' + settings_path) -except NameError: - exprint('Could not find local-settings.json. Please provide path.') - # Print info print('Using Slack installation at: ' + app_path) -print('Using local settings file at: ' + settings_path) - - -# Update local settings file - -with open(settings_path, mode='r') as settings_file: - settings_json = json.load(settings_file) - -if args.uninstall: - if 'bootSonic.mwsbak' in settings_json: - settings_json['bootSonic'] = settings_json['bootSonic.mwsbak'] - del settings_json['bootSonic.mwsbak'] -else: - if 'bootSonic.mwsbak' not in settings_json: - settings_json['bootSonic.mwsbak'] = settings_json['bootSonic'] - settings_json['bootSonic'] = 'never' - -try: - with open(settings_path, mode='w') as settings_file: - json.dump(settings_json, settings_file, separators=(',', ':')) -except Exception as e: - print(e) - exprint('Cannot update settings file. Make sure the script has write permissions.') # Remove previously injected code if it exists @@ -146,12 +110,14 @@ def exprint(*args, **kwargs): assert json_binary_size == json_data_size + 4 json_check = json.loads(json_binary[8:(json_string_size + 8)].decode('utf-8')) +app_backup_path = app_path + '.mwsbak' + if 'MWSINJECT' in json_check['files']: - if not os.path.isfile(app_path + '.mwsbak'): + if not os.path.isfile(app_backup_path): exprint('Found injected code without backup. Please re-install Slack.') try: os.remove(app_path) - shutil.move(app_path + '.mwsbak', app_path) + shutil.move(app_backup_path, app_path) except Exception as e: print(e) exprint('Cannot remove previously injected code. Make sure the script has write permissions.') @@ -159,9 +125,9 @@ def exprint(*args, **kwargs): # Remove old backup if it exists -if os.path.isfile(app_path + '.mwsbak'): +if os.path.isfile(app_backup_path): try: - os.remove(app_path + '.mwsbak') + os.remove(app_backup_path) except Exception as e: print(e) exprint('Cannot remove old backup. Make sure the script has write permissions.') @@ -179,45 +145,76 @@ def exprint(*args, **kwargs): # Code to be injected inject_code = ('\n\n// math-with-slack ' + mws_version + ''' -// https://github.com/fsavje/math-with-slack +// Inject MathJax 3. +// Credit to initial implementation: https://github.com/fsavje/math-with-slack document.addEventListener('DOMContentLoaded', function() { - var mathjax_config = document.createElement('script'); - mathjax_config.type = 'text/x-mathjax-config'; - mathjax_config.text = ` - MathJax.Hub.Config({ - messageStyle: 'none', - extensions: ['tex2jax.js'], - jax: ['input/TeX', 'output/HTML-CSS'], - tex2jax: { - displayMath: [['$$', '$$']], - element: 'msgs_div', - ignoreClass: 'ql-editor', - inlineMath: [['$', '$']], - processEscapes: true, - skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'] - }, - TeX: { - extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js'] + + function typeset(element) { + const MathJax = window.MathJax; + MathJax.startup.promise = MathJax.startup.promise + .then(() => {console.log(element); return MathJax.typesetPromise(element);}) + .catch((err) => console.log('Typeset failed: ' + err.message)); + return MathJax.startup.promise; + } + + window.MathJax = { + options: { + skipHtmlTags: [ + 'script', 'noscript', 'style', 'textarea', 'pre', + 'code', 'annotation', 'annotation-xml' + ], + }, + loader: { + paths: {mathjax: 'mathjax/es5'}, + source: {}, + require: require, + load: [ + 'input/tex-full', + 'output/svg', + '[tex]/noerrors', + '[tex]/noundefined', + '[tex]/boldsymbol' + ] + }, + tex: { + packages: {'[+]': ['ams', 'color', 'noerrors', 'noundefined', 'boldsymbol']}, + inlineMath: [['$', '$']], + displayMath: [['$$', '$$']], + }, + startup: { + ready: () => { + MathJax = window.MathJax; + MathJax.startup.defaultReady(); + var entry_observer = new IntersectionObserver( + (entries, observer) => { + var appearedEntries = entries.filter((entry) => entry.intersectionRatio > 0); + if(appearedEntries.length) { + console.log(appearedEntries); + typeset(appearedEntries.map((entry) => entry.target)); + } + }, + { root: document.body } + ); + var target = document.body.addEventListener("DOMNodeInserted", + function(event) { + var target = event.relatedNode; + if(target && typeof target.getElementsByClassName === 'function') { + // span.c-message_kit__text for messages in the Threads View + // span.c-message__body for messages in the chats (i.e. direct messages) + var messages = target.querySelectorAll('span.c-message__body, span.c-message_kit__text, div.p-rich_text_block'); + for (var i = 0; i < messages.length; i++) { + msg = messages[i]; + entry_observer.observe(msg); + } + } + } + ); } - }); - `; - - var mathjax_observer = document.createElement('script'); - mathjax_observer.type = 'text/x-mathjax-config'; - mathjax_observer.text = ` - var target = document.querySelector('#messages_container'); - var options = { attributes: false, childList: true, characterData: true, subtree: true }; - var observer = new MutationObserver(function (r, o) { MathJax.Hub.Queue(['Typeset', MathJax.Hub]); }); - observer.observe(target, options); - `; - - var mathjax_script = document.createElement('script'); - mathjax_script.type = 'text/javascript'; - mathjax_script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js'; - - document.head.appendChild(mathjax_config); - document.head.appendChild(mathjax_observer); - document.head.appendChild(mathjax_script); + }, + }; + + // Import mathjax + $MATH_JAX_STUB$ }); ''').encode('utf-8') @@ -225,7 +222,7 @@ def exprint(*args, **kwargs): # Make backup try: - shutil.move(app_path, app_path + '.mwsbak') + shutil.copy(app_path, app_backup_path) except Exception as e: print(e) exprint('Cannot make backup. Make sure the script has write permissions.') @@ -233,7 +230,7 @@ def exprint(*args, **kwargs): # Get file info -with open(app_path + '.mwsbak', mode='rb') as ori_app_fp: +with open(app_backup_path, mode='rb') as ori_app_fp: (header_data_size, json_binary_size) = struct.unpack('