class Plugin(Plugin_Base): name = "teedoc-plugin-google-analytics" desc = "google analytics support for teedoc" defautl_config = {"id": None} def on_init(self, config, doc_src_path, site_config, logger=None, multiprocess=True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format( self.name, self.config)) self.html_header_items = [] # set site_root_url env value if not "id" in config: self.logger.e('can not find config["id"] in plugin {}'.format( self.name)) return code_raw = ''' <script async src="https://www.googletagmanager.com/gtag/js?id={}"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){{dataLayer.push(arguments);}} gtag('js', new Date()); gtag('config', '{}'); </script>'''.format(config["id"], config["id"]) self.html_header_items = [code_raw] def on_add_html_header_items(self, type_name): return self.html_header_items
class Plugin(Plugin_Base): name = "teedoc-plugin-baidu-tongji" desc = "baidu tongji support for teedoc" defautl_config = { } def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config)) # set site_root_url env value if not "code" in config: self.logger.e('can not find config["code"] in plugin {}'.format(self.name)) return baidu_tongji_code = '''<script> var _hmt = _hmt || []; (function() {{ var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?{}"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); }})(); </script>'''.format(config["code"]) self.html_header_items = [baidu_tongji_code] def on_add_html_header_items(self, type_name): return self.html_header_items
class Plugin(Plugin_Base): name = "teedoc-plugin-comments-gitalk" desc = "gitalk comment support for teedoc" defautl_config = { "contrainer": "comments-container", "env": { "clientID": 'GitHub Application Client ID', "clientSecret": 'GitHub Application Client Secret', "repo": 'GitHub repo', "owner": 'GitHub repo owner', "admin": [ 'GitHub repo owner and collaborators, only these guys can initialize github issues' ], # "id": location.pathname, // Ensure uniqueness and length less than 50 # "distractionFreeMode": false // Facebook-like distraction free mode # "main_color": "#4caf7d", # "second_color": "#0a7d43" }, } def on_init(self, config, doc_src_path, site_config, logger=None, multiprocess=True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config # check config for key in self.config["env"]: if not key in config["env"]: self.logger.e( 'you MUST set env var "{}" for gitalk plugin in site_config' .format(key)) self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format( self.name, self.config)) self.assets_abs_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "assets") self.files_to_copy = { "/static/js/gitalk/gitalk.min.js": os.path.join(self.assets_abs_path, "gitalk.min.js"), "/static/js/gitalk/main.js": os.path.join(self.assets_abs_path, "main.js"), "/static/css/gitalk/gitalk.css": os.path.join(self.assets_abs_path, "gitalk.css") } self.html_header_items = [ '<link rel="stylesheet" href="{}" type="text/css"/>'.format( "/static/css/gitalk/gitalk.css"), ] self.html_js_items = [ '<script src="{}"></script>'.format( "/static/js/gitalk/gitalk.min.js"), '<script src="{}"></script>'.format("/static/js/gitalk/main.js") ] self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_comments_gitalk") if os.path.exists(self.temp_dir): shutil.rmtree(self.temp_dir) os.makedirs(self.temp_dir) # custom main color custom_color_vars = {} if "main_color" in self.config["env"]: self.logger.i("-- plugin <{}> get main_color {}".format( self.name, self.config["env"]["main_color"])) self.html_header_items.append( '<link rel="stylesheet" href="{}" type="text/css"/>'.format( "/static/css/gitalk/custom_gitalk.css")) self.files_to_copy[ "/static/css/gitalk/custom_gitalk.css"] = os.path.join( self.assets_abs_path, "custom_gitalk.css") # remove color vars from env, for env used by js if not "second_color" in self.config["env"]: self.config["env"]["second_color"] = self.config["env"][ "main_color"] custom_color_vars["main_color"] = self.config["env"]["main_color"] custom_color_vars["second_color"] = self.config["env"][ "second_color"] self.config["env"].pop("main_color") self.config["env"].pop("second_color") else: self.logger.i("-- plugin <{}> use default color") vars = { "comment_contrainer_id": self.config["contrainer"], "config": json.dumps(self.config["env"]) } vars.update(custom_color_vars) self.files_to_copy = self._update_file_var(self.files_to_copy, vars, self.temp_dir) def on_add_html_header_items(self, type_name): return self.html_header_items def on_add_html_footer_js_items(self, type_name): return self.html_js_items def on_copy_files(self): res = self.files_to_copy self.files_to_copy = {} return res def on_del(self): if os.path.exists(self.temp_dir): try: shutil.rmtree(self.temp_dir) except Exception: pass def _update_file_var(self, files, vars, temp_dir): for url, path in files.items(): with open(path, encoding='utf-8') as f: content = f.read() for k, v in vars.items(): content = content.replace( "${}{}{}".format("{", k.strip(), "}"), str(v)) temp_path = os.path.join(temp_dir, os.path.basename(path)) with open(temp_path, "w", encoding='utf-8') as fw: fw.write(content) files[url] = temp_path return files
class Plugin(Plugin_Base): name = "teedoc-plugin-assets" desc = "add assets(css js) support for teedoc" defautl_config = { "header_items": [], "footer_items": [], "env":{} } def on_init(self, config, doc_src_path, site_config, logger = None, multiprocess = True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config # check config for key in self.config["env"]: if not key in config["env"]: self.logger.e('you MUST set env var "{}" for gitalk plugin in site_config'.format(key)) self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format(self.name, self.config)) self.files_to_copy = {} self.html_header_items = [] self.html_footer_items = [] for item in self.config["header_items"]: if item.startswith("/"): path = os.path.join(self.doc_src_path, item[1:]) if os.path.exists(path): if path.endswith(".js"): self.html_header_items.append(f'<script src="{item}"></script>') self.files_to_copy[item] = path elif path.endswith(".css"): self.html_header_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>') self.files_to_copy[item] = path else: self.logger.e(f"config: url {item} not support! you can use html tag instead") else: self.logger.e(f"config: url {item} wrong, file {path} no found ") else: self.html_header_items.append(item) for item in self.config["footer_items"]: if item.startswith("/"): path = os.path.join(self.doc_src_path, item[1:]) if os.path.exists(path): if path.endswith(".js"): self.html_footer_items.append(f'<script src="{item}"></script>') self.files_to_copy[item] = path elif path.endswith(".css"): self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>') self.files_to_copy[item] = path else: self.logger.e(f"config: url {item} not support! you can use html tag instead") else: self.logger.e(f"config: url {item} wrong, file {path} no found ") elif item.startswith("http"): if item.endswith(".js"): self.html_footer_items.append(f'<script src="{item}"></script>') elif item.endswith(".css"): self.html_footer_items.append(f'<link rel="stylesheet" href="{item}" type="text/css"/>') else: self.logger.e(f"config: url {item} not support! you can use html tag instead") else: self.html_footer_items.append(item) self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_assets") if os.path.exists(self.temp_dir): shutil.rmtree(self.temp_dir) os.makedirs(self.temp_dir) self.files_to_copy = self._update_file_var(self.files_to_copy, self.config["env"], self.temp_dir) def on_add_html_header_items(self, type_name): return self.html_header_items def on_add_html_footer_js_items(self, type_name): return self.html_footer_items def on_copy_files(self): res = self.files_to_copy self.files_to_copy = {} return res def on_del(self): if os.path.exists(self.temp_dir): try: shutil.rmtree(self.temp_dir) except Exception: pass def _update_file_var(self, files, vars, temp_dir): for url, path in files.items(): with open(path, encoding='utf-8') as f: content = f.read() for k, v in vars.items(): content = content.replace("${}{}{}".format("{", k.strip(), "}"), str(v)) temp_path = os.path.join(temp_dir, os.path.basename(path)) with open(temp_path, "w", encoding='utf-8') as fw: fw.write(content) files[url] = temp_path return files
class Plugin(Plugin_Base): name = "teedoc-plugin-search" desc = "search support for teedoc" defautl_config = { "content_type": "raw", # supported_content_type "search_hint": "Search", "input_hint": "Keywords separated by space", "loading_hint": "Loading, wait please ...", "download_err_hint": "Download error, please check network and refresh again", "other_docs_result_hint": "Result from other docs", "curr_doc_result_hint": "Result from current doc", "env": { "main_color": "#4caf7d", "main_color_dark": "#1b4c33", "hint_shadow_color": "rgba(76, 175, 125, 0.38)" } } supported_content_type = ["raw", "html"] def on_init(self, config, doc_src_path, site_config, logger=None, multiprocess=True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format( self.name, self.config)) if not self.config["content_type"] in self.supported_content_type: self.logger.e( "-- plugin <{}> config content_type error: {}, should be in {}" .format(self.name, self.config["content_type"], self.supported_content_type)) if self.config["content_type"] == "raw": self.content_from = "raw" else: self.content_from = "body" self.module_path = os.path.abspath( os.path.dirname(os.path.abspath(__file__))) self.assets_abs_path = os.path.join(self.module_path, "assets") self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_search") if os.path.exists(self.temp_dir): shutil.rmtree(self.temp_dir) os.makedirs(self.temp_dir) self.css = { "/static/css/search/style.css": os.path.join(self.assets_abs_path, "style.css"), } self.footer_js = { "/static/js/search/search_main.js": os.path.join(self.assets_abs_path, "search_main.js") } self.images = { "/static/image/search/close.svg": os.path.join(self.assets_abs_path, "close.svg"), "/static/image/search/search.svg": os.path.join(self.assets_abs_path, "search.svg"), } # set site_root_url env value if not "env" in self.config: self.config['env'] = {} self.config['env']["site_root_url"] = self.site_config["site_root_url"] # replace variable in css with value vars = self.config["env"] self.css = self._update_file_var(self.css, vars, self.temp_dir) self.footer_js = self._update_file_var(self.footer_js, vars, self.temp_dir) # files to copy self.html_header_items = self._generate_html_header_items() self.files_to_copy = {} self.files_to_copy.update(self.css) self.files_to_copy.update(self.footer_js) self.files_to_copy.update(self.images) self.html_js_items = self._generate_html_js_items() self.content = {"articles": {}, "pages": {}} self.docs_name = {} def on_del(self): if os.path.exists(self.temp_dir): try: shutil.rmtree(self.temp_dir) except Exception: pass def _generate_html_header_items(self): items = [] # css for url in self.css: item = '<link rel="stylesheet" href="{}" type="text/css"/>'.format( url) items.append(item) return items def _generate_html_js_items(self): items = [] for url in self.footer_js: item = '<script src="{}"></script>'.format(url) items.append(item) return items def _update_file_var(self, files, vars, temp_dir): for url, path in files.items(): with open(path, encoding='utf-8') as f: content = f.read() for k, v in vars.items(): content = content.replace( "${}{}{}".format("{", k.strip(), "}"), v) temp_path = os.path.join(temp_dir, os.path.basename(path)) with open(temp_path, "w", encoding='utf-8') as fw: fw.write(content) files[url] = temp_path return files def _get_conf(self, config, new_config, conf_name): if conf_name in new_config: return True, new_config[conf_name] return False, config[conf_name] def on_parse_start(self, type_name, url, dirs, doc_config, new_config): if not "name" in doc_config: self.logger.w(f'doc dir "{dirs[0]}"\'s config no "name" keyword') self.docs_name[url] = url else: self.docs_name[url] = doc_config["name"] self.doc_locale = doc_config[ "locale"] if "locale" in doc_config else None # self.new_config = copy.deepcopy(self.config) # self.new_config = update_config(self.new_config, new_config) self.new_config = new_config def on_add_html_header_items(self, type_name): return self.html_header_items def on_add_html_footer_js_items(self, type_name): return self.html_js_items def on_add_navbar_items(self): ''' @config config cover self.config ''' # i18n # set default or custom settings names = [ "search_hint", "input_hint", "loading_hint", "download_err_hint", "other_docs_result_hint", "curr_doc_result_hint" ] flags = [False] * len(names) # flags have costum settings configs = [""] * len(names) for i, conf in enumerate(names): flags[i], configs[i] = self._get_conf(self.config, self.new_config, conf) # get translation if don't have custom setting if False in flags and self.doc_locale: import gettext try: lang = gettext.translation('messages', localedir=os.path.join( self.module_path, 'locales'), languages=[self.doc_locale]) lang.install() _ = lang.gettext if not flags[0]: configs[0] = _("search_hint") if not flags[1]: configs[1] = _("search_input_hint") if not flags[2]: configs[2] = _("search_loading_hint") if not flags[3]: configs[3] = _("search_download_err_hint") if not flags[4]: configs[4] = _("search_other_docs_result_hint") if not flags[5]: configs[5] = _("search_curr_doc_result_hint") except Exception as e: pass configs = tuple(configs) search_btn = '''<a id="search"><span class="icon"></span><span class="placeholder">%s</span> <div id="search_hints"> <span id="search_input_hint">%s</span> <span id="search_loading_hint">%s</span> <span id="search_download_err_hint">%s</span> <span id="search_other_docs_result_hint">%s</span> <span id="search_curr_doc_result_hint">%s</span> </div></a>''' % configs items = [search_btn] return items def on_copy_files(self): res = self.files_to_copy self.files_to_copy = {} return res def on_htmls(self, htmls_files, htmls_pages, htmls_blog=None): ''' update htmls, may not all html, just partially htmls_files: { "/get_started/zh":{ "url":{ "title": "", "desc": "", "keywords": [], "body": html, "url": "", "raw": "" } } } ''' # for file, html in htmls_files.items(): # self.content["articles"][html["url"]] = html["raw"] # for file, html in htmls_pages.items(): # self.content["pages"][html["url"]] = html["raw"] self.logger.i("generate search index") if htmls_blog: htmls_pages.update(copy.deepcopy(htmls_blog)) docs_url = list(htmls_files.keys()) pages_url = list(htmls_pages.keys()) index_content = {} sub_index_path = [] generated_index_json = {} for i, url in enumerate(docs_url): index_content[url] = [ self.docs_name[url], "{}static/search_index/index_{}.json".format( self.site_config["site_root_url"], i) ] path = os.path.join(self.temp_dir, "index_{}.json".format(i)) sub_index_path.append(path) # write content to sub index file content = {} for page_url in htmls_files[url]: content[page_url] = { "title": htmls_files[url][page_url]["title"], "content": htmls_files[url][page_url][self.content_from] } with open(path, "w", encoding="utf-8") as f: json.dump(content, f, ensure_ascii=False) for i, url in enumerate(pages_url, len(docs_url)): index_content[url] = [ self.docs_name[url], "{}static/search_index/index_{}.json".format( self.site_config["site_root_url"], i) ] path = os.path.join(self.temp_dir, "index_{}.json".format(i)) sub_index_path.append(path) # write content to sub index file content = {} for page_url in htmls_pages[url]: content[page_url] = { "title": htmls_pages[url][page_url]["title"], "content": htmls_pages[url][page_url][self.content_from] } with open(path, "w", encoding="utf-8") as f: json.dump(content, f, ensure_ascii=False) # write content to files # index file index_path = os.path.join(self.temp_dir, "index.json") with open(index_path, "w", encoding="utf-8") as f: json.dump(index_content, f, ensure_ascii=False) # add to copy file list generated_index_json["/static/search_index/index.json"] = index_path for i, path in enumerate(sub_index_path): generated_index_json["/static/search_index/index_{}.json".format( i)] = path self.files_to_copy.update(generated_index_json) return True
class Plugin(Plugin_Base): name = "teedoc-plugin-blog" desc = "markdown parser plugin for teedoc" defautl_config = {"parse_files": ["md"]} def on_init(self, config, doc_src_path, site_config, logger=None, multiprocess=True, **kw_args): ''' @config a dict object @logger teedoc.logger.Logger object ''' self.multiprocess = multiprocess self.logger = Fake_Logger() if not logger else logger self.doc_src_path = doc_src_path self.site_config = site_config self.config = Plugin.defautl_config self.config.update(config) self.logger.i("-- plugin <{}> init".format(self.name)) self.logger.i("-- plugin <{}> config: {}".format( self.name, self.config)) self.temp_dir = os.path.join(tempfile.gettempdir(), "teedoc_plugin_blog") if os.path.exists(self.temp_dir): shutil.rmtree(self.temp_dir) os.makedirs(self.temp_dir) self.assets_abs_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "assets") self.assets = { "/static/js/plugin_blog/main.js": os.path.join(self.assets_abs_path, "main.js"), } vars = {"site_root_url": self.site_config["site_root_url"]} self.assets = self._update_file_var(self.assets, vars, self.temp_dir) self.files_to_copy = self.assets.copy() # must use copy blog_url = list(self.site_config["route"]["blog"].keys()) if len(blog_url) > 1: self.logger.e("only support one blog url path") raise Exception("only support one blog url path") self.blog_url = blog_url[0] self.blog_dir = os.path.join( self.doc_src_path, self.site_config["route"]["blog"][self.blog_url]).replace( "\\", "/") self.index_content = {"items": {}} def on_new_process_init(self): ''' for multiple processing, for below func, will be called in new process, every time create a new process, this func will be invoke ''' self.md_parser = create_markdown_parser() self.meta_parser = Meta_Parser() def on_new_process_del(self): ''' for multiple processing, for below func, will be called in new process, every time exit a new process, this func will be invoke ''' del self.md_parser del self.meta_parser def on_parse_blog(self, files): # result, format must be this result = {"ok": False, "msg": "", "htmls": OrderedDict()} # function parse md file is disabled if not "md" in self.config["parse_files"]: result[ "msg"] = "disabled markdown parse, but only support markdown" return result self.logger.d("-- plugin <{}> parse {} files".format( self.name, len(files))) # self.logger.d("files: {}".format(files)) for file in files: ext = os.path.splitext(file)[1].lower() if ext.endswith("md"): with open(file, encoding="utf-8") as f: content = f.read().strip() content = self._update_link(content) blog_index_file_path = os.path.join( self.blog_dir, "readme.md").replace("\\", "/").lower() is_blog_index = file.lower() == blog_index_file_path if is_blog_index: content += '\n<div id="blog_list"></div>' if not self.multiprocess: md_parser = create_markdown_parser() meta_parser = Meta_Parser() else: md_parser = self.md_parser meta_parser = self.meta_parser metadata, content_no_meta = meta_parser.parse_meta(content) html = md_parser(content_no_meta) if "<!-- more -->" in html: brief = html[:html.find("<!-- more -->")].strip() else: brief = html[:500].strip() if "title" in metadata: title = metadata["title"] else: title = "" if "keywords" in metadata and not metadata[ "keywords"].strip() == "": keywords = metadata["keywords"].split(",") else: keywords = [] if "tags" in metadata and not metadata["tags"].strip( ) == "": tags = metadata["tags"].split(",") else: tags = [] if "desc" in metadata: desc = metadata["desc"] else: desc = "" html_str = '<span id="blog_start"></span>' + html # date default last edit time ts = int(os.stat(file).st_mtime) date_file_edit = time.strftime("%Y-%m-%d", time.localtime(ts)) if "date" in metadata: date = metadata["date"].strip().lower() # set date to false to disable date display if date and (date == "false" or date == "none"): date = "" else: GMT_FORMAT = '%Y-%m-%d' try: date_obj = datetime.strptime(date, GMT_FORMAT) ts = int(date_obj.timestamp()) except Exception as e: date = date_file_edit else: date = date_file_edit if "author" in metadata: author = metadata["author"] else: author = "" result["htmls"][file] = { "title": title, "desc": desc, "keywords": keywords, "tags": tags, "body": html_str, # "toc": html.toc_html if html.toc_html else "", "toc": "", # just empty, toc generated by js but not python "metadata": metadata, "raw": content, "date": date, "ts": ts, "author": author, "brief": brief } else: result["htmls"][file] = None result['ok'] = True return result def on_add_html_header_items(self, type_name): items = [] items.append( '<meta name="blog-generator" content="teedoc-plugin-blog">') return items def _update_link(self, content): def re_del(c): ret = c[0] links = re.findall('\((.*?)\)', c[0]) if len(links) > 0: for link in links: if link.startswith(".") or os.path.isabs(link): ret = re.sub("README.md", "index.html", c[0], flags=re.I) ret = re.sub(r".md", ".html", ret, re.I) return ret return ret def re_del_ipynb(c): ret = c[0] links = re.findall('\((.*?)\)', c[0]) if len(links) > 0: for link in links: if link.startswith(".") or os.path.isabs(link): ret = re.sub("README.ipynb", "index.html", c[0], flags=re.I) ret = re.sub(r".ipynb", ".html", ret, re.I) return ret return ret # <a class="anchor-link" href="#链接"> </a></h2><p><a href="./syntax_markdown.md">markdown 语法</a> content = re.sub(r'\[.*?\]\(.*?\.md\)', re_del, content, flags=re.I) content = re.sub(r'\[.*?\]\(.*?\.ipynb\)', re_del_ipynb, content, flags=re.I) return content def on_htmls(self, htmls_files, htmls_pages, htmls_blog=None): ''' update htmls, may not all html, just partially htmls_blog: { "/blog/":{ "url":{ "title": "", "desc": "", "keywords": [], "body": html, "tags": [], "url": "", "raw": "", "date": date, "ts": 12344566, "author": author, "brief": "", "metadata": {} } } } ''' if not htmls_blog: return True blog_url = list(htmls_blog.keys()) if len(blog_url) == 0: return True index_url = "" blog_url = blog_url[0] index_url = "{}static/blog_index/index.json".format( self.site_config["site_root_url"]) index_path = os.path.join(self.temp_dir, "index.json") for url, item in htmls_blog[blog_url].items(): # except blog index.html if url == os.path.join(blog_url, "index.html"): continue new_item = { "title": item["title"], "desc": item["desc"], "keywords": item["keywords"], "tags": item["tags"], "url": url, "date": item["date"], "ts": item["ts"], "author": item["author"], "brief": item["brief"], } self.index_content["items"][url] = new_item # sort by date self.index_content["items"] = OrderedDict( sorted(self.index_content["items"].items(), key=lambda v: v[1]["ts"], reverse=True)) # write content to sub index file with open(index_path, "w", encoding="utf-8") as f: json.dump(self.index_content, f, ensure_ascii=False) # add to copy file list generated_index_json = {"/static/blog_index/index.json": index_path} self.files_to_copy.update(generated_index_json) return True def on_copy_files(self): res = self.files_to_copy self.files_to_copy = {} return res def on_add_html_footer_js_items(self, type_name): for url in self.assets: html_js_items = ['<script src="{}"></script>'.format(url)] return html_js_items def _update_file_var(self, files, vars, temp_dir): for url, path in files.items(): with open(path, encoding='utf-8') as f: content = f.read() for k, v in vars.items(): content = content.replace( "${}{}{}".format("{", k.strip(), "}"), v) temp_path = os.path.join(temp_dir, os.path.basename(path)) with open(temp_path, "w", encoding='utf-8') as fw: fw.write(content) files[url] = temp_path return files