From 6f0d314897ad3006093624e120eef3299811d25a Mon Sep 17 00:00:00 2001 From: johndoe Date: Thu, 24 Oct 2019 18:31:47 +0300 Subject: [PATCH] Refactor build system, simplify templates and escape macros in code Refactor build system into several modules: - `settings.py`: to provide common settings (from `buildsettings.py` / `localbuildsettings.py`) - `build_plugin.py`: to build single plugin formats userscript metablock, preprocesses sources - makes templates substitutions, inlines dependencies js/css/img - and wraps into wrapper (from `pluginwrapper.py`) - `pluginwrapper_noinject.py` - alternative wrapper, useful for debugging scripts. Sample usage in `buildsettings.py`, for build name 'tmdev'. - `build_mobile.py`: to build android apk (embedding scripts from given directory) - `build.py`: to build all: main IITC script, all plugins, and (optionally) Android apk. - `--watch` mode (auto-rebuild on sources changes) Each module can be used independently as cli utility. Escape macros in code in order to keep js-validity, fix #50. Simplify userscripts source template, completely get rid of these ugly substitutions: - `@@METAINFO@@` - `@@PLUGINSTART@@` - `@@PLUGINEND@@` - `.@@DATETIMEVERSION@@` - `[@@BUILDNAME@@-@@BUILDDATE@@]` Close #150: use template from settings instead of url harcoding. Close #99: remove timestamp component from `version` of Release scripts. Rename plugin sources: `*.user.js` -> `*.js` Additional dev utilities: - `web_meta_gen.py` to generate meta.json for IITC-Button. Can be used as standalone cli, or as part of build process. - `web_server_local.py` to start local webserver for specified build name. --- .travis.yml | 41 +- build.py | 371 ++++++------------ build_mobile.py | 105 +++++ build_plugin.py | 231 +++++++++++ buildsettings.py | 116 ++++-- code/boot.js | 42 +- code/search.js | 2 +- code/smartphone.js | 7 +- code/utils_misc.js | 4 +- main.js | 27 +- mobile/plugins/user-location.user.js | 20 +- plugins/ap-stats.user.js | 18 +- plugins/basemap-bing.user.js | 22 +- plugins/basemap-blank.user.js | 23 +- plugins/basemap-gaode.user.js | 18 +- plugins/basemap-google-gray.user.js | 18 +- plugins/basemap-kartverket.user.js | 18 +- plugins/basemap-openstreetmap.user.js | 19 +- plugins/basemap-stamen.user.js | 19 +- plugins/basemap-yandex.user.js | 23 +- plugins/bookmarks.css | 2 +- plugins/bookmarks.user.js | 28 +- plugins/cache-portals-on-map.user.js | 19 +- plugins/cross-links.user.js | 21 +- plugins/debug-raw-portal-data.user.js | 19 +- plugins/deleted/basemap-opencyclemap.user.js | 19 +- plugins/deleted/default-intel-detail.user.js | 19 +- .../deleted/portal-highlighter-debug.user.js | 18 +- .../show-less-portals-zoomed-out.user.js | 19 +- plugins/deleted/update-check.user.js | 21 +- plugins/distance-to-portal.user.js | 23 +- plugins/done-links.user.js | 20 +- plugins/draw-tools.user.js | 37 +- .../marker-canvas-icon-data.user.js | 19 +- .../experimental/marker-divicon-svg.user.js | 19 +- plugins/farms-find.user.js | 22 +- plugins/fix-china-map-offset.user.js | 18 +- plugins/fly-links.user.js | 18 +- plugins/highlight-forgotten.user.js | 18 +- plugins/highlight-hide-team.user.js | 18 +- plugins/highlight-high-level.user.js | 18 +- plugins/highlight-infrastructure.user.js | 18 +- plugins/highlight-level-color.user.js | 18 +- plugins/highlight-missing-resonators.user.js | 18 +- plugins/highlight-needs-recharge.user.js | 18 +- plugins/highlight-ornaments.user.js | 18 +- plugins/highlight-portals-my-level.user.js | 18 +- plugins/highlight-weakness.user.js | 18 +- plugins/keys-on-map.user.js | 18 +- plugins/keys.user.js | 20 +- plugins/layer-count.user.js | 21 +- plugins/link-show-direction.user.js | 19 +- plugins/linked-portals-show.user.js | 20 +- plugins/minimap.user.js | 22 +- plugins/missions.user.js | 31 +- plugins/overlay-kml.user.js | 21 +- plugins/pan-control.user.js | 21 +- plugins/periodic-refresh.user.js | 16 +- plugins/player-activity-tracker.user.js | 27 +- plugins/player-level-guess.user.js | 18 +- plugins/portal-counts.user.js | 18 +- plugins/portal-level-numbers.user.js | 18 +- plugins/portal-names.user.js | 18 +- plugins/portals-list.user.js | 20 +- plugins/privacy-view.user.js | 18 +- plugins/regions.user.js | 25 +- .../reso-energy-pct-in-portal-detail.user.js | 18 +- plugins/scale-bar.user.js | 18 +- plugins/score-cycle-times.user.js | 22 +- plugins/scoreboard.user.js | 18 +- plugins/scroll-wheel-zoom-disable.user.js | 20 +- plugins/speech-search.user.js | 18 +- plugins/sync.user.js | 20 +- plugins/tidy-links.user.js | 20 +- plugins/uniques.user.js | 19 +- plugins/zaprange.user.js | 18 +- plugins/zoom-slider.user.js | 22 +- pluginwrapper.py | 12 +- pluginwrapper_noinject.py | 14 + settings.py | 67 ++++ 80 files changed, 1007 insertions(+), 1355 deletions(-) create mode 100755 build_mobile.py create mode 100755 build_plugin.py create mode 100644 pluginwrapper_noinject.py create mode 100755 settings.py diff --git a/.travis.yml b/.travis.yml index abf6e14a8..0f67efc18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ addons: apt: packages: - python3 - ssh_known_hosts: modos189.ru + ssh_known_hosts: ssh.modos189.ru notifications: email: on_success: change @@ -37,24 +37,27 @@ before_script: - chmod 600 /tmp/deploy_rsa - eval "$(ssh-agent -s)" - ssh-add /tmp/deploy_rsa +- wget https://iitc.modos189.ru/deploy/localbuildsettings.py +- wget https://iitc.modos189.ru/deploy/deploy.sh -script: -- wget https://iitc.modos189.ru/deploy/$BUILD_TYPE/localbuildsettings.py -- ./build.py $BUILD_TYPE -- ./build.py mobile +script: ./build.py $BUILD_TYPE deploy: - provider: releases - name: $TRAVIS_TAG - skip_cleanup: true - api_key: - secure: KoJXTxCoatpFbQgbW1VBIh1ndtQIEmj68sANI+zOs54vi9XMCG3RM4cFn4y7YsSI/kz6XcoSC30SNnqedxHMPJyjrIWvVLKDTlbJswZmGhsslrZmClw3sFROKodVI5DoI0520mAfwzQ5PInPpSEfsPZQhA9ufv1wTZ/98q2efcRPu3J6riSdOZmqJ2A+veWpID3t3P57Lcjew+P3PdmUpwC9t6Yp4oQaYX4DZvMMpqK6s8E4EfOVQptaFAxYDIlAIWxNsfIJkx3jwmLdyaSwQL/fyesQ3fZRECKZTN7RM8/2nImuBZsq4uKS3nrKpLEXFTId45ET5N0fa23KXMLMM8NW0LlATLLWju+N7dP2HCeV5w2wxh+ToAR58XciiZLIsxI1IfF8WXloPax6DmJYksEKOenMYB/y/VASi5xbEhl89kdkxAaO6hAoVqKYo+xt7y3nPGSDUf+zfJnno5lPXgF3ctVAjmRBTWUSQQ5VhAeOp2LGg8ennzSkaLKxqyIxJ7F+n7Y0/QmG0uQzmerOjEEjVBsyVawRWjZGrDlog3Pq2S0n4vnbvbtUchwp/Fapjtg1f1pWy9Bzi1tnnE4ALJEmM894izxWH4vtDQu1+nkjKtLrkxgjk5yEuPj3n95ab64UO1To/x4YlyApmLkDeZIEMd+5siBTeGlB1V05Mr4= - file_glob: true - file: - - ./build/mobile/IITC_Mobile-release.apk - - ./build/release/* - on: - repo: IITC-CE/ingress-intel-total-conversion - tags: true - all_branches: true - condition: $TRAVIS_BRANCH != test-builds \ No newline at end of file + - provider: script + script: bash deploy.sh $BUILD_TYPE + skip_cleanup: true + on: + branch: + - master + - test-builds + - provider: releases + name: $TRAVIS_TAG + api_key: + secure: KoJXTxCoatpFbQgbW1VBIh1ndtQIEmj68sANI+zOs54vi9XMCG3RM4cFn4y7YsSI/kz6XcoSC30SNnqedxHMPJyjrIWvVLKDTlbJswZmGhsslrZmClw3sFROKodVI5DoI0520mAfwzQ5PInPpSEfsPZQhA9ufv1wTZ/98q2efcRPu3J6riSdOZmqJ2A+veWpID3t3P57Lcjew+P3PdmUpwC9t6Yp4oQaYX4DZvMMpqK6s8E4EfOVQptaFAxYDIlAIWxNsfIJkx3jwmLdyaSwQL/fyesQ3fZRECKZTN7RM8/2nImuBZsq4uKS3nrKpLEXFTId45ET5N0fa23KXMLMM8NW0LlATLLWju+N7dP2HCeV5w2wxh+ToAR58XciiZLIsxI1IfF8WXloPax6DmJYksEKOenMYB/y/VASi5xbEhl89kdkxAaO6hAoVqKYo+xt7y3nPGSDUf+zfJnno5lPXgF3ctVAjmRBTWUSQQ5VhAeOp2LGg8ennzSkaLKxqyIxJ7F+n7Y0/QmG0uQzmerOjEEjVBsyVawRWjZGrDlog3Pq2S0n4vnbvbtUchwp/Fapjtg1f1pWy9Bzi1tnnE4ALJEmM894izxWH4vtDQu1+nkjKtLrkxgjk5yEuPj3n95ab64UO1To/x4YlyApmLkDeZIEMd+5siBTeGlB1V05Mr4= + file_glob: true + file: + - ./build/release/IITC_Mobile-release.apk + - ./build/release/* + on: + tags: true + condition: $TRAVIS_BRANCH != test-builds diff --git a/build.py b/build.py index 8ac76275b..45e0f9fdf 100755 --- a/build.py +++ b/build.py @@ -1,272 +1,159 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 + +"""IITC main build script.""" import glob -import time -import re -import io -import base64 -import sys import os import shutil -import json -import shelve -import hashlib -from importlib import import_module # Python >= 2.7 +from runpy import run_path -try: - import urllib2 -except ImportError: - import urllib.request as urllib2 +import build_plugin +import settings -# load settings file -from buildsettings import buildSettings -defaultBuild = None -if os.path.isfile('./localbuildsettings.py'): - # load optional local settings file - from localbuildsettings import buildSettings as localBuildSettings +def run_python(cmd): + if not os.path.isfile(cmd) and not os.path.abs(cmd): + path = os.path.dirname(__file__) # try script path instead cwd + if not os.path.samefile(os.curdir, path): + fullpath = os.path.join(path, cmd) + if os.path.isfile(fullpath): + cmd = fullpath + if not os.path.isfile(cmd): + raise UserWarning('no such file: {}'.format(cmd)) + return run_path(cmd) - buildSettings.update(localBuildSettings) - # load default build +def run_system(cmd): + status = os.system(cmd) try: - from localbuildsettings import defaultBuild - except ImportError: - pass - -buildName = defaultBuild - -# build name from command line -if len(sys.argv) == 2: # argv[0] = program, argv[1] = buildname, len=2 - buildName = sys.argv[1] - -if buildName is None or buildName not in buildSettings: - print("Usage: build.py buildname") - print(" available build names: %s" % ', '.join(buildSettings.keys())) - sys.exit(1) - -settings = buildSettings[buildName] - -# set up vars used for replacements - -utcTime = time.gmtime() -buildDate = time.strftime('%Y-%m-%d-%H%M%S', utcTime) -# userscripts have specific specifications for version numbers - the above date format doesn't match -dateTimeVersion = time.strftime('%Y%m%d.', utcTime) + time.strftime('%H%M%S', utcTime).lstrip('0') - -# extract required values from the settings entry -resourceUrlBase = settings.get('resourceUrlBase') -distUrlBase = settings.get('distUrlBase') -buildMobile = settings.get('buildMobile') -gradleOptions = settings.get('gradleOptions', '') -gradleBuildFile = settings.get('gradleBuildFile', 'mobile/build.gradle') -pluginWrapper = import_module(settings.get('pluginWrapper','pluginwrapper')) -pluginWrapper.startUseStrict = pluginWrapper.start.replace("{\n", "{\n\"use strict\";\n", 1) - -pluginMetaBlock = """// @updateURL @@UPDATEURL@@ -// @downloadURL @@DOWNLOADURL@@ -// @namespace https://github.com/IITC-CE/ingress-intel-total-conversion -// @include https://intel.ingress.com/* -// @match https://intel.ingress.com/* -// @grant none""" - - -def readfile(fn): - with io.open(fn, 'r', encoding='utf8') as f: - return f.read() - - -def loaderRaw(var): - fn = var.group(1) - return readfile(fn) - - -def MultiLine(Str): - return Str.replace('\\', '\\\\').replace('\n', '\\\n').replace('\'', '\\\'') - - -def loaderString(var): - return MultiLine(loaderRaw(var)) - + exit_code = os.WEXITSTATUS(status) if os.WIFEXITED(status) else -1 + except AttributeError: # Windows + exit_code = status + if exit_code != 0: + raise UserWarning('execution failed: {}'.format(cmd)) + + +def run_cmds(cmds, source, target): + for cmd in (cmds or []): + if callable(cmd): + cmd(source, target) + elif os.path.splitext(cmd)[1] == '.py': + module = run_python(cmd) + if 'iitc_build' in module: + module['iitc_build'](source, target) + else: + run_system(cmd.format( + settings, + source=source, + target=target, + )) -def loaderCSS(var): - Str = re.sub('(?<=url\()["\']?([^)#]+?)["\']?(?=\))', loaderImage, loaderRaw(var)) - return MultiLine(Str) +def iitc_build(source, outdir): + run_cmds(settings.pre_build, source, outdir) -def loaderImage(var): - fn = var.group(1) - _, ext = os.path.splitext(fn) - return 'data:image/%s;base64,' % ('svg+xml' if ext == '.svg' else 'png') \ - + base64.b64encode(open(fn, 'rb').read()).decode('utf8') + iitc_script = 'main.js' + build_plugin.process_file(os.path.join(source, iitc_script), outdir, name='total-conversion-build') + plugins_outdir = os.path.join(outdir, 'plugins') + if not os.path.isdir(plugins_outdir): + os.mkdir(plugins_outdir) + for filename in glob.glob(os.path.join(source, 'plugins', '*.js')): + build_plugin.process_file(filename, plugins_outdir, dist_path='plugins') -def wrapInIIFE(fn): - module = readfile(fn) - name,_ = os.path.splitext(os.path.split(fn)[1]) - return '\n// *** module: ' + fn + ' ***\n' +\ - '(function () {\n' +\ - "var log = ulog('" + name + "');\n" +\ - module +\ - '\n})();\n' + run_cmds(settings.post_build, source, outdir) -def loadCode(ignore): - return '\n\n;\n\n'.join(map(wrapInIIFE, sorted(glob.glob('code/*.js')))) +def clean(directory): + if os.path.exists(directory): + shutil.rmtree(directory) -def extractUserScriptMeta(var): - m = re.search(r"//[ \t]*==UserScript==\n.*?//[ \t]*==/UserScript==\n", var, re.MULTILINE | re.DOTALL) - return m.group(0) +def backup(directory): + if os.path.exists(directory): + bak = directory + '~' + clean(bak) + os.rename(directory, bak) -def doReplacements(script, updateUrl, downloadUrl, pluginName=None): - script = re.sub('@@INJECTCODE@@', loadCode, script) +def backup_and_run(): + target_parent = os.path.join(settings.build_target_dir, os.pardir) + workdir = os.path.join(os.path.normpath(target_parent), '~') + clean(workdir) + os.makedirs(workdir) - script = script.replace('@@METAINFO@@', pluginMetaBlock) - script = script.replace('@@PLUGINSTART@@', pluginWrapper.start) - script = script.replace('@@PLUGINSTART-USE-STRICT@@', pluginWrapper.startUseStrict) - script = script.replace('@@PLUGINEND@@', - pluginWrapper.end if pluginName == 'total-conversion-build' - else pluginWrapper.setup + pluginWrapper.end) + iitc_build(settings.build_source_dir, workdir) - script = re.sub('@@INCLUDERAW:([0-9a-zA-Z_./-]+)@@', loaderRaw, script) - script = re.sub('@@INCLUDESTRING:([0-9a-zA-Z_./-]+)@@', loaderString, script) - script = re.sub('@@INCLUDECSS:([0-9a-zA-Z_./-]+)@@', loaderCSS, script) - script = re.sub('@@INCLUDEIMAGE:([0-9a-zA-Z_./-]+)@@', loaderImage, script) + outdir = settings.build_target_dir + backup(outdir) + os.rename(workdir, outdir) - script = script.replace('@@BUILDDATE@@', buildDate) - script = script.replace('@@DATETIMEVERSION@@', dateTimeVersion) - if resourceUrlBase: - script = script.replace('@@RESOURCEURLBASE@@', resourceUrlBase) +def on_event(cmd): + if not cmd: + return + elif callable(cmd): + cmd() else: - if '@@RESOURCEURLBASE@@' in script: - raise Exception("Error: '@@RESOURCEURLBASE@@' found in script, but no replacement defined") - - script = script.replace('@@BUILDNAME@@', buildName) - - script = script.replace('@@UPDATEURL@@', updateUrl) - script = script.replace('@@DOWNLOADURL@@', downloadUrl) - - if (pluginName): - script = script.replace('@@PLUGINNAME@@', pluginName) - - return script - - -def saveScriptAndMeta(script, ourDir, filename, oldDir=None): - # TODO: if oldDir is set, compare files. if only data/time-based version strings are different - # copy from there instead of saving a new file - - fn = os.path.join(outDir, filename) - with io.open(fn, 'w', encoding='utf8') as f: - f.write(script) - - metafn = fn.replace('.user.js', '.meta.js') - if metafn != fn: - with io.open(metafn, 'w', encoding='utf8') as f: - meta = extractUserScriptMeta(script) - f.write(meta) - - -outDir = os.path.join('build', buildName) - -# create the build output - -# first, delete any existing build - but keep it in a temporary folder for now -oldDir = None -if os.path.exists(outDir): - oldDir = outDir + '~' - if os.path.exists(oldDir): - shutil.rmtree(oldDir) - os.rename(outDir, oldDir) - -# copy the 'dist' folder, if it exists -if os.path.exists('dist'): - # this creates the target directory (and any missing parent dirs) - # FIXME? replace with manual copy, and any .css and .js files are parsed for replacement tokens? - shutil.copytree('dist', outDir) -else: - # no 'dist' folder - so create an empty target folder - os.makedirs(outDir) - -# run any preBuild commands -for cmd in settings.get('preBuild', []): - os.system(cmd) - -# load main.js, parse, and create main total-conversion-build.user.js -main = readfile('main.js') - -downloadUrl = distUrlBase and distUrlBase + '/total-conversion-build.user.js' or 'none' -updateUrl = distUrlBase and distUrlBase + '/total-conversion-build.meta.js' or 'none' -main = doReplacements(main, downloadUrl=downloadUrl, updateUrl=updateUrl, pluginName='total-conversion-build') - -saveScriptAndMeta(main, outDir, 'total-conversion-build.user.js', oldDir) - -with io.open(os.path.join(outDir, '.build-timestamp'), 'w') as f: - f.write(u"" + time.strftime('%Y-%m-%d %H:%M:%S UTC', utcTime)) - -# for each plugin, load, parse, and save output -os.mkdir(os.path.join(outDir, 'plugins')) - -for fn in glob.glob("plugins/*.user.js"): - script = readfile(fn) - - downloadUrl = distUrlBase and distUrlBase + '/' + fn.replace("\\", "/") or 'none' - updateUrl = distUrlBase and downloadUrl.replace('.user.js', '.meta.js') or 'none' - pluginName = os.path.splitext(os.path.splitext(os.path.basename(fn))[0])[0] - script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl, pluginName=pluginName) - - saveScriptAndMeta(script, outDir, fn, oldDir) - -# if we're building mobile too -if buildMobile: - if buildMobile not in ['debug', 'release', 'copyonly']: - raise Exception("Error: buildMobile must be 'debug' or 'release' or 'copyonly'") + os.system(cmd) + + +def watch(watch_list, run, interval): + from time import ctime, sleep + from traceback import print_exc + + last_modified = 0 + while 1: + timestamp = max(map(os.path.getmtime, watch_list)) + if timestamp == last_modified: + try: + sleep(interval) + except KeyboardInterrupt: + print('Keyboard interrupt received, exiting.') + break + else: + continue + last_modified = timestamp + print('\nrebuild started [{}]'.format(ctime(last_modified))) + try: + run() + except Exception as err: + print_exc() + on_event(settings.on_fail) + else: + on_event(settings.on_success) - # compile the user location script - fn = "user-location.user.js" - script = readfile("mobile/plugins/" + fn) - downloadUrl = distUrlBase and distUrlBase + '/' + fn.replace("\\", "/") or 'none' - updateUrl = distUrlBase and downloadUrl.replace('.user.js', '.meta.js') or 'none' - script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl, pluginName='user-location') - saveScriptAndMeta(script, outDir, fn) +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('build', type=str, nargs='?', + help='Specify build name') + parser.add_argument('--watch', action='store_true', + help='auto-rebuild on sources changes') + args = parser.parse_args() - # copy the IITC script into the mobile folder. create the folder if needed - try: - os.makedirs("mobile/assets") - except: - pass - shutil.copy(os.path.join(outDir, "total-conversion-build.user.js"), "mobile/assets/total-conversion-build.user.js") - # copy the user location script into the mobile folder. - shutil.copy(os.path.join(outDir, "user-location.user.js"), "mobile/assets/user-location.user.js") - # also copy plugins try: - shutil.rmtree("mobile/assets/plugins") - except: - pass - ignore_patterns = settings.get('ignore_patterns') or [] - ignore_patterns.append('*.meta.js') - shutil.copytree(os.path.join(outDir, "plugins"), "mobile/assets/plugins", - # do not include desktop-only plugins to mobile assets - ignore=shutil.ignore_patterns(*ignore_patterns)) - - if buildMobile != 'copyonly': - # now launch 'ant' to build the mobile project - buildAction = "assemble" + buildMobile.capitalize() - retcode = os.system("mobile/gradlew %s -b %s %s" % (gradleOptions, gradleBuildFile, buildAction)) - - if retcode != 0: - print("Error: mobile app failed to build. gradlew returned %d" % retcode) - exit(1) # ant may return 256, but python seems to allow only values <256 - else: - shutil.copy("mobile/app/build/outputs/apk/%s/app-%s.apk" % (buildMobile, buildMobile), - os.path.join(outDir, "IITC_Mobile-%s.apk" % buildMobile)) - -# run any postBuild commands -for cmd in settings.get('postBuild', []): - os.system(cmd) - -# vim: ai si ts=4 sw=4 sts=4 et + settings.load(args.build) + except ValueError as err: + parser.error(err) + + if args.watch or settings.watch_mode: + sources_root = os.path.abspath(settings.build_source_dir) + watch_list = {sources_root} + watch_list.update([os.path.join(sources_root, path) for path in settings.sources]) + + target_root = os.path.abspath(settings.build_target_dir) + target_parent = os.path.normpath(os.path.join(target_root, os.pardir)) + if {target_root, target_parent}.intersection(watch_list): + # !!this check is not perfect: it does not consider case-insensitive file system + parser.error('specified target location would cause endless cycle: {}'.format(target_root)) + + print('IITC build: {} (watch mode)'.format(settings.build_name)) + watch(watch_list, backup_and_run, settings.watch_interval) + else: + print('IITC build: {}'.format(settings.build_name)) + try: + backup_and_run() + except UserWarning as err: + parser.error(err) diff --git a/build_mobile.py b/build_mobile.py new file mode 100755 index 000000000..313637a2f --- /dev/null +++ b/build_mobile.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +"""Utility to build IITC-Mobile apk.""" + +import os +import shutil + +import build_plugin +import settings + +defaults = { + 'mobile_source' : None, # default: '/mobile' + 'gradle_buildtype': 'debug', + 'gradle_options' : '', + 'gradle_buildfile': None, # default: '/build.gradle' + 'ignore_patterns' : [ # exclude desktop-only plugins from mobile assets + 'scroll-wheel-zoom-disable*', '*.meta.js', + ], +} +iitc_script = 'total-conversion-build.user.js' +buildtypes = {'debug', 'release'} + + +def add_default_settings(build_source): + for attr, default in defaults.items(): + if not hasattr(settings, attr): + setattr(settings, attr, default) + if not settings.mobile_source: + assert build_source, 'Either mobile_source or build_source required' + settings.mobile_source = os.path.join(build_source, 'mobile') + + +def exec_gradle(source): + gradlew = os.path.join(source, 'gradlew') + options = settings.gradle_options + buildfile = settings.gradle_buildfile or os.path.join(source, 'build.gradle') + buildtype = settings.gradle_buildtype + if buildtype not in buildtypes: + raise UserWarning('gradle_buildtype value must be in: {}'.format(', '.join(buildtypes))) + build_action = 'assemble' + buildtype.capitalize() + status = os.system('{} {} -b {} {}'.format(gradlew, options, buildfile, build_action)) + try: + if not os.WIFEXITED(status): + raise UserWarning('gradlew exited abnormally') + except AttributeError: # Windows + exit_code = status + else: # Unix + exit_code = os.WEXITSTATUS(status) + + if exit_code != 0: + raise UserWarning('gradlew returned {}'.format(exit_code)) + + return os.path.join(source, 'app', 'build', 'outputs', 'apk', buildtype, 'app-{}.apk'.format(buildtype)) + + +def build_mobile(source, scripts_dir, out_dir=None, out_name='IITC_Mobile.apk'): + """Build IITC-Mobile apk file, embedding scripts from given directory.""" + assets_dir = os.path.join(source, 'assets') + if os.path.exists(assets_dir): + shutil.rmtree(assets_dir) + os.makedirs(assets_dir) + + user_location_plug = os.path.join(source, 'plugins', 'user-location.user.js') + build_plugin.process_file(user_location_plug, assets_dir) + shutil.copy(os.path.join(scripts_dir, iitc_script), assets_dir) + shutil.copytree( + os.path.join(scripts_dir, 'plugins'), + os.path.join(assets_dir, 'plugins'), + ignore=shutil.ignore_patterns(*settings.ignore_patterns), + ) + shutil.copy( + exec_gradle(source), + os.path.join(out_dir or scripts_dir, out_name), + ) + + +def iitc_build(iitc_source, build_outdir): + add_default_settings(iitc_source) + build_mobile(settings.mobile_source, build_outdir) + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('build', type=str, nargs='?', + help='Specify build name') + args = parser.parse_args() + + try: + settings.load(args.build) + except ValueError as err: + parser.error(err) + + directory = settings.build_target_dir + if not os.path.isdir(directory): + parser.error('Directory not found: {}'.format(directory)) + script_path = os.path.join(directory, iitc_script) + if not os.path.isfile(script_path): + parser.error('Main script not found: {}'.format(script_path)) + + add_default_settings(settings.build_source_dir) + try: + build_mobile(settings.mobile_source, directory) + except UserWarning as err: + parser.error('mobile app failed to build\n{}'.format(err)) diff --git a/build_plugin.py b/build_plugin.py new file mode 100755 index 000000000..625b0a90d --- /dev/null +++ b/build_plugin.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python + +"""Utility to build iitc plugin for given source file name.""" + +import base64 +import glob +import io +import os +import re +import sys +from importlib import import_module # Python >= 2.7 +from mimetypes import guess_type + +import settings + + +def get_module(name): + sys.path.insert(0, '') # temporary include cwd in modules search paths + module = import_module(name) + sys.path.pop(0) + return module + + +def fill_meta(source, plugin_name, dist_path): + meta = ['// ==UserScript=='] + keys = set() + + def append_line(key, value): + if key not in keys: + meta.append('// @{:<14} {}'.format(key, value)) + + is_main = False + for line in source.splitlines(): + text = line.lstrip() + rem = text[:2] + if rem != '//': + raise UserWarning('{}: wrong line in metablock: {}'.format(plugin_name, line)) + text = text[2:].strip() + try: + key, value = text.split(None, 1) + except ValueError: + if text == '==UserScript==': + raise UserWarning('{}: wrong metablock detected'.format(plugin_name)) + else: + key = key[1:] + keys.add(key) + if key == 'version': + if settings.version_timestamp and not re.search(r'[^\d.]', value): + line = line.replace(value, '{ver}.{.build_timestamp}'.format(settings, ver=value)) + elif key == 'name': + if value == 'IITC: Ingress intel map total conversion': + is_main = True + else: + line = line.replace(value, 'IITC plugin: ' + value) + meta.append(line) + + append_line('id', plugin_name) + append_line('namespace', settings.namespace) + + if settings.url_dist_base: + path = [settings.url_dist_base] + if dist_path: + path.append(dist_path) + path.append(plugin_name) + path = '/'.join(path) + if settings.update_file in {'.user.js', '.meta.js'}: + append_line('updateURL', path + settings.update_file) + append_line('downloadURL', path + '.user.js') + + if keys.isdisjoint({'match', 'include'}): + append_line('match', settings.match) + + append_line('grant', 'none') + meta.append('// ==/UserScript==\n') + return '\n'.join(meta), is_main + + +def readfile(fullname): + with io.open(fullname, 'r', encoding='utf-8-sig') as src: + return src.read() + + +def multi_line(text): + return ('\n' + text).replace('\\', r'\\').replace('\n', '\\\n').replace("'", r"\'") + + +def load_image(fullname): + mtype, _ = guess_type(fullname) + assert mtype, 'Failed to guess mimetype: {}'.format(fullname) + with io.open(fullname, 'rb') as img: + return 'data:{};base64,{}'.format( + mtype, + base64.b64encode(img.read()).decode('utf8'), + ) + + +def wrap_iife(fullname): + filename = os.path.basename(fullname) + name, _ = os.path.splitext(filename) + return u""" +// *** module: {filename} *** +(function () {{ +var log = ulog('{name}'); +{content} + +}})(); +""".format(filename=filename, name=name, content=readfile(fullname)) + + +current_path = None + + +def bundle_code(_): + files = os.path.join(current_path, 'code', '*.js') + return '\n'.join(map(wrap_iife, sorted(glob.glob(files)))) + + +def getabs(filename, base): + if os.path.isabs(filename): + return filename + return os.path.join(base, filename) + + +def imgrepl(match): + fullname = getabs(match.group('filename'), current_path) + return load_image(fullname) + + +def expand_template(match): + quote = "'%s'" + kw, filename = match.groups() + if not filename: + return quote % getattr(settings, kw) + + fullname = getabs(filename, current_path) + if kw == 'include_raw': + return u"""// *** included: {filename} *** +{content} + +""".format(filename=filename, content=readfile(fullname)) + elif kw == 'include_string': + return quote % multi_line(readfile(fullname)) + elif kw == 'include_img': + return quote % load_image(fullname) + elif kw == 'include_css': + pattern = r'(?<=url\()["\']?(?P[^)#]+?)["\']?(?=\))' + css = re.sub(pattern, imgrepl, readfile(fullname)) + return quote % multi_line(css) + + +def split_filename(path): + filename = os.path.basename(path) + return filename.split('.')[0] + + +def write_userscript(data, plugin_name, ext, directory=None): + filename = plugin_name + ext + filename = os.path.join(directory, filename) if directory else filename + with io.open(filename, 'w', encoding='utf8') as userscript: + userscript.write(data) + + +def process_file(source, out_dir, dist_path=None): + """Generate .user.js (and optionally .meta.js) from given source file. + + Resulted file(s) put into out_dir (if specified, otherwise - use current). + + dist_path component is for adding to @downloadURL/@updateURL. + """ + global current_path # to pass value to repl-functions + current_path = settings.build_source_dir # used as root for all (relative) paths + # todo: evaluate relatively to processed file (with os.path.dirname) + try: + meta, script = readfile(source).split('\n\n', 1) + except ValueError: + raise Exception('{}: wrong input: empty line expected after metablock'.format(source)) + plugin_name = split_filename(source) + meta, is_main = fill_meta(meta, plugin_name, dist_path) + settings.plugin_id = plugin_name + + script = re.sub(r"'@bundle_code@';", bundle_code, script) + wrapper = get_module(settings.plugin_wrapper) + template = r"'@(\w+)(?::([\w./-]+))?@'" # to find '@keyword[:path]@' patterns + data = [ + meta, + re.sub(template, expand_template, wrapper.start), + re.sub(template, expand_template, script), + wrapper.setup, + wrapper.end, + ] + if is_main: + data.pop(3) # remove wrapper.setup (it's for plugins only) + write_userscript(''.join(data), plugin_name, '.user.js', out_dir) + + if settings.url_dist_base and settings.update_file == '.meta.js': + write_userscript(meta, plugin_name, '.meta.js', out_dir) + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('build', type=str, nargs='?', + help='Specify build name') + parser.add_argument('source', type=str, + help='Specify source file name') + parser.add_argument('--out-dir', type=str, nargs='?', + help='Specify out directory') + args = parser.parse_args() + + try: + settings.load(args.build) + except ValueError as err: + parser.error(err) + + if not os.path.isfile(args.source): + parser.error('Source file not found: {.source}'.format(args)) + + out_dir = args.out_dir or settings.build_target_dir + if not os.path.isdir(out_dir): + parser.error('Out directory not found: {}'.format(out_dir)) + + target = os.path.join(out_dir, split_filename(args.source) + '.user.js') + if os.path.isfile(target) and os.path.samefile(args.source, target): + parser.error('Target cannot be same as source: {.source}'.format(args)) + + try: + process_file(args.source, out_dir) + except UserWarning as err: + parser.error(err) + + print(target) diff --git a/buildsettings.py b/buildsettings.py index a0a41b1e8..13154c41d 100644 --- a/buildsettings.py +++ b/buildsettings.py @@ -1,55 +1,91 @@ -# settings file for builds. +"""Config file for builds. -# if you want to have custom builds, copy this file to "localbuildsettings.py" and make changes there. +if you want to have custom builds, copy this file to "localbuildsettings.py" and make changes there. +""" -# possible fields: -# resourceBaseUrl - optional - the URL base for external resources (all resources embedded in standard IITC) -# distUrlBase - optional - the base URL to use for update checks -# buildMobile - optional - if set, mobile builds are built with 'gradle'. requires the Android SDK and appropriate mobile/local.properties file configured -# preBuild - optional - an array of strings to run as commands, via os.system, before building the scripts -# postBuild - optional - an array of string to run as commands, via os.system, after all builds are complete -# pluginWrapper - optional - name of module to import custom plugin wrapper from +from __future__ import print_function +localfile = 'localbuildsettings.py' -buildSettings = { - # local: use this build if you're not modifying external resources - # no external resources allowed - they're not needed any more - 'local': { - 'resourceUrlBase': None, - 'distUrlBase': None, +defaults = { # common for all build targets + + 'url_dist_base': None, # network location, used for @updateURL and @downloadURL fields + 'update_file': None, # how to use @updateURL + # - '.meta.js': generate .meta.js + # - '.user.js': use main script + # - None: do not use the field + + 'version_timestamp': False, # add extra component to version field (to force update) + + # these settings should be modified when developing own fork of this project + 'namespace': 'https://github.com/IITC-CE/ingress-intel-total-conversion', + 'url_homepage': 'https://iitc.modos189.ru/', + 'url_tg': 'https://t.me/iitc_news', + + # these settings should not be touched unless intel url(s) changed + 'url_intel_base': 'https://intel.ingress.com/', + 'match': 'https://intel.ingress.com/*', + + 'plugin_wrapper': 'pluginwrapper', # use wrapper from pluginwrapper.py + + 'pre_build': [], # list of commands to execute before build run + 'post_build': [], # ... after build succeed + + # watch mode settings: + 'watch_mode': False, # otherwise can be activated with --watch commandline argument + 'watch_interval': 1, # (seconds) + 'sources': ( # list of source directories to watch for changes, + 'code', # relative to 'build_source_dir' (and including it) + 'external', + 'images', + 'plugins', + ), + 'on_fail': lambda: print('\a'), # function (or string for os.system) + 'on_success': lambda: print('Build successed'), + + # other: + # runtime settings set in settings.py also can be overriden + # - 'build_source_dir' + # - 'build_target_dir' + # - ... +} + +builds = { # every build entry extends common defaults + + # default settings + 'local': {}, + + # specify localhost as base for scripts (auto)updating + # useful for developers + 'dev': { + 'url_dist_base': 'http://localhost:8000', + 'update_file': '.user.js', + 'version_timestamp': True, }, - # local8000: if you need to modify external resources, this build will load them from - # the web server at http://0.0.0.0:8000/dist - # (This shouldn't be required any more - all resources are embedded. but, it remains just in case some new feature - # needs external resources) - 'local8000': { - 'resourceUrlBase': 'http://0.0.0.0:8000/dist', - 'distUrlBase': None, + # use no-inject wrapper for easy breakpoints (Tampermonkey only!) + 'tmdev': { + 'url_dist_base': 'http://localhost:8000', + 'update_file': '.user.js', + 'version_timestamp': True, + 'plugin_wrapper': 'pluginwrapper_noinject', }, - # mobile: default entry that also builds the mobile .apk - # you will need to have the android-sdk installed, and the file mobile/local.properties created as required + # default entry that also builds the mobile .apk + # requires: Java JDK, android-sdk 'mobile': { - 'resourceUrlBase': None, - 'distUrlBase': None, - 'buildMobile': 'debug', - 'ignore_patterns': ['speech-search*', 'scroll-wheel-zoom-disable*'], + 'post_build': ['build_mobile.py'], }, - # if you want to publish your own fork of the project, and host it on your own web site - # create a localbuildsettings.py file containing something similar to this - # note: Firefox+Greasemonkey require the distUrlBase to be "https" - they won't check for updates on regular "http" URLs - # 'example': { - # 'resourceBaseUrl': 'http://www.example.com/iitc/dist', - # 'distUrlBase': 'https://secure.example.com/iitc/dist', + # publish your own fork of the project, and host it on your own web site + # 'myfork': { + # 'url_homepage': 'https://www.example.com/iitc', + # 'url_dist_base': 'https://download.example.com/iitc', + # 'update_file': '.meta.js', # }, - - } - -# defaultBuild - the name of the default build to use if none is specified on the build.py command line -# (in here as an example - it only works in localbuildsettings.py) -#defaultBuild = 'local' +# default_build - the name of the build settings to use if none is specified on the build.py command line +# (change it in localbuildsettings.py) +default_build = None diff --git a/code/boot.js b/code/boot.js index fb11f96d7..504a24041 100644 --- a/code/boot.js +++ b/code/boot.js @@ -575,9 +575,9 @@ window.setupLayerChooserApi = function() { window.extendLeaflet = function() { L.Icon.Default.mergeOptions({ - iconUrl: '@@INCLUDEIMAGE:images/marker-ingress.png@@', - iconRetinaUrl: '@@INCLUDEIMAGE:images/marker-ingress-2x.png@@', - shadowUrl: '@@INCLUDEIMAGE:images/marker-shadow.png@@' + iconUrl: '@include_img:images/marker-ingress.png@', + iconRetinaUrl: '@include_img:images/marker-ingress-2x.png@', + shadowUrl: '@include_img:images/marker-shadow.png@' }); L.Icon.Default.imagePath = ' '; // in order to suppress _detectIconPath (it fails with data-urls) @@ -730,7 +730,7 @@ function boot() { if(!isSmartphone()) // TODO remove completely? window.debug.console.overwriteNativeIfRequired(); - log.log('loading done, booting. Built: @@BUILDDATE@@'); + log.log('loading done, booting. Built: '+'@build_date@'); if (window.deviceID) { log.log('Your device ID: ' + window.deviceID); } @@ -832,23 +832,23 @@ window.registerMarkerForOMS = function(marker) { } try { -@@INCLUDERAW:external/autolink-min.js@@ - -window.L_NO_TOUCH = navigator.maxTouchPoints===0; // prevent mobile style on desktop https://github.com/IITC-CE/ingress-intel-total-conversion/pull/189 -@@INCLUDERAW:external/leaflet-src.js@@ -@@INCLUDERAW:external/L.Geodesic.js@@ -@@INCLUDERAW:external/Leaflet.GoogleMutant.js@@ -@@INCLUDERAW:external/oms.min.js@@ -L.CanvasIconLayer = (function (module) { - @@INCLUDERAW:external/rbush.min.js@@ - @@INCLUDERAW:external/leaflet.canvas-markers.js@@ - return module; -}({})).exports(L); - -@@INCLUDERAW:external/jquery-3.4.1.min.js@@ -@@INCLUDERAW:external/jquery-ui-1.12.1.min.js@@ -@@INCLUDERAW:external/taphold.js@@ -@@INCLUDERAW:external/jquery.qrcode.min.js@@ + '@include_raw:external/autolink-min.js@'; + + window.L_NO_TOUCH = navigator.maxTouchPoints===0; // prevent mobile style on desktop https://github.com/IITC-CE/ingress-intel-total-conversion/pull/189 + '@include_raw:external/leaflet-src.js@'; + '@include_raw:external/L.Geodesic.js@'; + '@include_raw:external/Leaflet.GoogleMutant.js@'; + '@include_raw:external/oms.min.js@'; + L.CanvasIconLayer = (function (module) { + '@include_raw:external/rbush.min.js@'; + '@include_raw:external/leaflet.canvas-markers.js@'; + return module; + }({})).exports(L); + + '@include_raw:external/jquery-3.4.1.min.js@'; + '@include_raw:external/jquery-ui-1.12.1.min.js@'; + '@include_raw:external/taphold.js@'; + '@include_raw:external/jquery.qrcode.min.js@'; } catch (e) { log.error("External's js loading failed"); diff --git a/code/search.js b/code/search.js index b82286871..d0b27d6a4 100644 --- a/code/search.js +++ b/code/search.js @@ -276,7 +276,7 @@ addHook('search', function(query) { title: data.title, description: teams[team] + ', L' + data.level + ', ' + data.health + '%, ' + data.resCount + ' Resonators', position: portal.getLatLng(), - icon: 'data:image/svg+xml;base64,'+btoa('@@INCLUDESTRING:images/icon-portal.svg@@'.replace(/%COLOR%/g, color)), + icon: 'data:image/svg+xml;base64,'+btoa('@include_string:images/icon-portal.svg@'.replace(/%COLOR%/g, color)), onSelected: function(result, event) { if(event.type == 'dblclick') { zoomToAndShowPortal(guid, portal.getLatLng()); diff --git a/code/smartphone.js b/code/smartphone.js index e27057378..31539d938 100644 --- a/code/smartphone.js +++ b/code/smartphone.js @@ -22,9 +22,10 @@ window.runOnSmartphonesBeforeBoot = function() { log.warn('running smartphone pre boot stuff'); // add smartphone stylesheet - headHTML = document.getElementsByTagName('head')[0].innerHTML; - headHTML += ''; - document.getElementsByTagName('head')[0].innerHTML = headHTML; + var style = document.createElement('style'); + style.type = 'text/css'; + style.appendChild(document.createTextNode('@include_string:mobile/smartphone.css@')); + document.head.appendChild(style); // don’t need many of those window.setupStyles = function() { diff --git a/code/utils_misc.js b/code/utils_misc.js index dea8dcb8b..3cb1d1e89 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -77,8 +77,8 @@ window.aboutIITC = function () { + '
Ingress Intel Total Conversion
' + '
' + '
' - + ' IITC Homepage |' + - ' Telegram channel
' + + ' IITC Homepage |' + + ' Telegram channel
' + ' On the script’s homepage you can:' + '
    ' + '
  • Find Updates
  • ' diff --git a/main.js b/main.js index 102798fab..874c52e4e 100644 --- a/main.js +++ b/main.js @@ -1,20 +1,17 @@ -// ==UserScript== -// @id ingress-intel-total-conversion@jonatkins +// @author jonatkins // @name IITC: Ingress intel map total conversion -// @version 0.29.1.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Total conversion for the ingress intel map. -@@METAINFO@@ +// @version 0.29.1 +// @description Total conversion for the ingress intel map. // @run-at document-end -// ==/UserScript== -@@PLUGINSTART@@ + window.script_info = plugin_info; // REPLACE ORIG SITE /////////////////////////////////////////////////// if (document.documentElement.getAttribute('itemscope') !== null) { throw new Error('Ingress Intel Website is down, not a userscript issue.'); } -window.iitcBuildDate = '@@BUILDDATE@@'; +window.iitcBuildDate = '@build_date@'; // disable vanilla JS window.onload = function() {}; @@ -38,7 +35,7 @@ if (!window.PLAYER || !PLAYER.nickname) { // add login form stylesheet var style = document.createElement('style'); style.type = 'text/css'; - style.appendChild(document.createTextNode('@@INCLUDESTRING:login.css@@')); + style.appendChild(document.createTextNode('@include_string:login.css@')); document.head.appendChild(style); throw new Error("Couldn't retrieve player data. Are you logged in?"); @@ -52,8 +49,8 @@ if (!window.PLAYER || !PLAYER.nickname) { // possible without requiring scripts. document.head.innerHTML = '' + 'Ingress Intel Map' - + '' - + '' + + '' + + '' //note: smartphone.css injection moved into code/smartphone.js + ''; @@ -83,7 +80,7 @@ document.body.innerHTML = '' + '
    t
    ' + '
     loading global control stats
    ' + '
    ' - + ' ' + + ' ' + ' ' + '
    ' + '
    ' @@ -191,13 +188,11 @@ window.overlayStatus = {}; if(typeof window.plugin !== 'function') window.plugin = function() {}; var ulog = (function (module) { - @@INCLUDERAW:external/ulog.min.js@@ + '@include_raw:external/ulog.min.js@'; return module; }({})).exports; -@@INJECTCODE@@ +'@bundle_code@'; // fixed Addons RegionScoreboard.setup(); - -@@PLUGINEND@@ diff --git a/mobile/plugins/user-location.user.js b/mobile/plugins/user-location.user.js index 62aad18d7..22d9b316c 100644 --- a/mobile/plugins/user-location.user.js +++ b/mobile/plugins/user-location.user.js @@ -1,15 +1,9 @@ -// ==UserScript== -// @id iitc-plugin-user-location@cradle -// @name IITC plugin: User Location +// @author cradle +// @name User Location // @category Tweaks -// @version 0.2.1.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Show user location marker on map -@@METAINFO@@ -// ==/UserScript== +// @version 0.2.1 +// @description Show user location marker on map -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// window.plugin.userLocation = function() {}; @@ -19,7 +13,7 @@ window.plugin.userLocation.user = { latlng:null, direction:null }; window.plugin.userLocation.setup = function() { window.pluginCreateHook('pluginUserLocation'); - $(''); } - - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/deleted/basemap-opencyclemap.user.js b/plugins/deleted/basemap-opencyclemap.user.js index f4913041c..a5ce9c3a2 100644 --- a/plugins/deleted/basemap-opencyclemap.user.js +++ b/plugins/deleted/basemap-opencyclemap.user.js @@ -1,15 +1,8 @@ -// ==UserScript== -// @id iitc-plugin-basemap-opencyclepam@jonatkins -// @name IITC plugin: OpenCycleMap.org map tiles +// @author jonatkins +// @name OpenCycleMap.org map tiles // @category Map Tiles -// @version 0.2.0.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Add the OpenCycleMap.org map tiles as an optional layer. -@@METAINFO@@ -// ==/UserScript== - -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// +// @version 0.2.0 +// @description Add the OpenCycleMap.org map tiles as an optional layer. // use own namespace for plugin @@ -39,7 +32,3 @@ window.plugin.mapTileOpenCycleMap = { }; var setup = window.plugin.mapTileOpenCycleMap.addLayer; - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/deleted/default-intel-detail.user.js b/plugins/deleted/default-intel-detail.user.js index a76cb4dc9..c94590095 100644 --- a/plugins/deleted/default-intel-detail.user.js +++ b/plugins/deleted/default-intel-detail.user.js @@ -1,15 +1,8 @@ -// ==UserScript== -// @id iitc-plugin-default-intel-detail@jonatkins -// @name IITC plugin: Default intel detail level +// @author jonatkins +// @name Default intel detail level // @category Tweaks -// @version 0.2.0.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Use the portal level detail levels from the standard intel site. By default, IITC shows less detail when zoomed out, as this is enough for general use, is more friendly to the niantic servers, and loads much faster. This plugin restores the default zoom level to portal level mapping. Note: using this plugin causes a larger number of requests to the intel server, and at high resolutions can cause excessive requests to be made (yes: the default intel site also has this problem!), so it is not recommended except for low resolution screens. -@@METAINFO@@ -// ==/UserScript== - -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// +// @version 0.2.0 +// @description Use the portal level detail levels from the standard intel site. By default, IITC shows less detail when zoomed out, as this is enough for general use, is more friendly to the niantic servers, and loads much faster. This plugin restores the default zoom level to portal level mapping. Note: using this plugin causes a larger number of requests to the intel server, and at high resolutions can cause excessive requests to be made (yes: the default intel site also has this problem!), so it is not recommended except for low resolution screens. // use own namespace for plugin @@ -24,7 +17,3 @@ window.plugin.defaultIntelDetail.setup = function() { }; var setup = window.plugin.defaultIntelDetail.setup; - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/deleted/portal-highlighter-debug.user.js b/plugins/deleted/portal-highlighter-debug.user.js index 6319da725..322e21915 100644 --- a/plugins/deleted/portal-highlighter-debug.user.js +++ b/plugins/deleted/portal-highlighter-debug.user.js @@ -1,15 +1,9 @@ -// ==UserScript== -// @id iitc-plugin-highlight-portals-debug -// @name IITC plugin: Debug: Highlighers +// @author jonatkins +// @name Debug: Highlighers // @category Debug -// @version 0.1.0.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Various debug and/or temporary highlighters. Will change over time as needed. -@@METAINFO@@ -// ==/UserScript== +// @version 0.1.0 +// @description Various debug and/or temporary highlighters. Will change over time as needed. -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.portalHighlighterDebug = function() {}; @@ -30,7 +24,3 @@ window.plugin.portalHighlighterDebug = function() {}; var setup = function() { // window.addPortalHighlighter('DEBUG: Unknoen_11', window.plugin.portalHighlighterDebug.unknown11); } - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/deleted/show-less-portals-zoomed-out.user.js b/plugins/deleted/show-less-portals-zoomed-out.user.js index 5c9ce7b7d..c955d08df 100644 --- a/plugins/deleted/show-less-portals-zoomed-out.user.js +++ b/plugins/deleted/show-less-portals-zoomed-out.user.js @@ -1,15 +1,8 @@ -// ==UserScript== -// @id iitc-plugin-show-less-portals@jonatkins -// @name IITC plugin: Show less portals when zoomed out +// @author jonatkins +// @name Show less portals when zoomed out // @category Tweaks -// @version 0.3.0.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Vastly reduce the detail level when zoomed out to level 11 or less (L4+ portals), to significantly reduce data usage when viewing large areas. -@@METAINFO@@ -// ==/UserScript== - -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// +// @version 0.3.0 +// @description Vastly reduce the detail level when zoomed out to level 11 or less (L4+ portals), to significantly reduce data usage when viewing large areas. // use own namespace for plugin @@ -24,7 +17,3 @@ window.plugin.showLessPortalsZoomedOut.setup = function() { }; var setup = window.plugin.showLessPortalsZoomedOut.setup; - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/deleted/update-check.user.js b/plugins/deleted/update-check.user.js index 46c1d4103..8d2eb4fa9 100644 --- a/plugins/deleted/update-check.user.js +++ b/plugins/deleted/update-check.user.js @@ -1,15 +1,8 @@ -// ==UserScript== -// @id iitc-plugin-update-check@jonatkins -// @name IITC plugin: Check for updates +// @author jonatkins +// @name Check for updates // @category Misc -// @version 0.1.1.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] **WORK IN PROGRESS** Check for updates for IITC and plugins against http://iitc.jonatkins.com/. Can also report status messages for known IITC issues. -@@METAINFO@@ -// ==/UserScript== - -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// +// @version 0.1.1 +// @description **WORK IN PROGRESS** Check for updates for IITC and plugins against http://iitc.jonatkins.com/. Can also report status messages for known IITC issues. // use own namespace for plugin @@ -21,7 +14,7 @@ window.plugin.updateCheck.versionDataLoading = false; window.plugin.updateCheck.getUrl = function(callback) { var base = window.location.protocol == 'https:' ? 'https://secure.jonatkins.com/iitc' : 'http://iitc.jonatkins.com'; var url = base+'/versioncheck.php' - + '?build=@@BUILDNAME@@' + + '?build='+'@build_name@' + '&mobile='+((typeof android !== 'undefined' && android)?'1':'0') + '&ts='+Date.now(); // append timestamp - ensures no caching of old data, even on mobile with the aggressive cache code @@ -302,7 +295,3 @@ window.plugin.updateCheck.setup = function() { }; var setup = window.plugin.updateCheck.setup; - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/distance-to-portal.user.js b/plugins/distance-to-portal.user.js index 26270540e..ee41fe5cc 100644 --- a/plugins/distance-to-portal.user.js +++ b/plugins/distance-to-portal.user.js @@ -1,15 +1,8 @@ -// ==UserScript== -// @id iitc-plugin-distance-to-portal@jonatkins -// @name IITC plugin: Distance to portal +// @author jonatkins +// @name Distance to portal // @category Portal Info -// @version 0.1.1.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Allows your current location to be set manually, then shows the distance to the selected portal. Useful when managing portal keys. -@@METAINFO@@ -// ==/UserScript== - -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// +// @version 0.1.1 +// @description Allows your current location to be set manually, then shows the distance to the selected portal. Useful when managing portal keys. // use own namespace for plugin @@ -115,7 +108,7 @@ window.plugin.distanceToPortal.setupPortalsList = function() { window.plugin.distanceToPortal.setup = function() { // https://github.com/gregallensworth/Leaflet/ - @@INCLUDERAW:external/LatLng_Bearings.js@@ + '@include_raw:external/LatLng_Bearings.js@'; try { window.plugin.distanceToPortal.currentLoc = L.latLng(JSON.parse(localStorage['plugin-distance-to-portal'])); @@ -125,7 +118,7 @@ window.plugin.distanceToPortal.setup = function() { window.plugin.distanceToPortal.currentLocMarker = null; - $(''); } - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/portal-level-numbers.user.js b/plugins/portal-level-numbers.user.js index 6617c0dd0..f24631a35 100644 --- a/plugins/portal-level-numbers.user.js +++ b/plugins/portal-level-numbers.user.js @@ -1,15 +1,9 @@ -// ==UserScript== -// @id iitc-plugin-portal-level-numbers@rongou -// @name IITC plugin: Portal Level Numbers +// @author rongou +// @name Portal Level Numbers // @category Layer -// @version 0.1.5.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Show portal level numbers on map. -@@METAINFO@@ -// ==/UserScript== +// @version 0.1.5 +// @description Show portal level numbers on map. -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.portalLevelNumbers = function() { @@ -170,7 +164,3 @@ var setup = function() { window.map.on('overlayadd overlayremove', function() { setTimeout(function(){window.plugin.portalLevelNumbers.delayedUpdatePortalLabels(1.0);},1); }); } - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/portal-names.user.js b/plugins/portal-names.user.js index 670830736..d71517612 100644 --- a/plugins/portal-names.user.js +++ b/plugins/portal-names.user.js @@ -1,15 +1,9 @@ -// ==UserScript== -// @id iitc-plugin-portal-names@zaso -// @name IITC plugin: Portal Names +// @author ZasoGD +// @name Portal Names // @category Layer -// @version 0.1.6.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Show portal names on the map. -@@METAINFO@@ -// ==/UserScript== +// @version 0.1.6 +// @description Show portal names on the map. -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.portalNames = function() {}; @@ -181,7 +175,3 @@ var setup = function() { window.map.on('zoomend', window.plugin.portalNames.clearAllPortalLabels ); } - -// PLUGIN END ////////////////////////////////////////////////////////// - -@@PLUGINEND@@ diff --git a/plugins/portals-list.user.js b/plugins/portals-list.user.js index b78eda9f3..b27a58a02 100644 --- a/plugins/portals-list.user.js +++ b/plugins/portals-list.user.js @@ -1,15 +1,9 @@ -// ==UserScript== -// @id iitc-plugin-portals-list@teo96 -// @name IITC plugin: Portals list +// @author teo96 +// @name Portals list // @category Info -// @version 0.2.1.@@DATETIMEVERSION@@ -// @description [@@BUILDNAME@@-@@BUILDDATE@@] Display a sortable list of all visible portals with full details about the team, resonators, links, etc. -@@METAINFO@@ -// ==/UserScript== +// @version 0.2.1 +// @description Display a sortable list of all visible portals with full details about the team, resonators, links, etc. -@@PLUGINSTART@@ - -// PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin window.plugin.portalslist = function() {}; @@ -400,11 +394,7 @@ var setup = function() { $("