├── README.md ├── cheat_server.py ├── config.json └── scripts └── vendors~xgplayer_encrypt.b05f677a.chunk.js /README.md: -------------------------------------------------------------------------------- 1 | # cheat_server 2 | 3 | 推荐使用另一种更灵活方便的方式 4 | 5 | **https://blog.weimo.info/archives/598/** 6 | 7 | ## 关于 8 | 9 | 本脚本/软件是为方便调试网页中的js所写,需要配合Gooreplacer插件使用(或者其他一类重定向请求的插件)。 10 | 11 | ## 使用 12 | 13 | - 将js文件放在config.json配置中`scripts_path`对应的相对目录中,默认`scripts` 14 | - 在配置文件中配置你所需要的返回头 15 | - 配置好你需要的端口和地址,默认地址`127.0.0.1`,默认端口`22222` 16 | - 运行exe或脚本 17 | - 在Gooreplacer插件中重定向网页中的js到`http://127.0.0.1:22222/js文件名`,并使规则生效 18 | 19 | 好了,现在你可以在本地实时修改js了,在浏览器中刷新就能生效了。 20 | 注意在Network一栏选中Disable Cache或者给本地的js配置中设定不缓存,~~但也需要强制刷新一遍才能生效~~。 21 | 22 | ## 其他 23 | 24 | 示例参考:https://blog.weimo.info/archives/441 25 | -------------------------------------------------------------------------------- /cheat_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.7 2 | # coding=utf-8 3 | ''' 4 | # 作者: weimo 5 | # 创建日期: 2020-01-18 01:01:09 6 | # 上次编辑时间: 2020-02-22 18:35:25 7 | # 一个人的命运啊,当然要靠自我奋斗,但是... 8 | ''' 9 | import os 10 | import sys 11 | import json 12 | import chardet 13 | import datetime 14 | import email.utils 15 | import urllib.parse 16 | from http import HTTPStatus 17 | from functools import partial 18 | from http.server import HTTPServer, SimpleHTTPRequestHandler 19 | 20 | def load_config(): 21 | config = {} 22 | config_path = "config.json" 23 | if os.path.isfile(config_path): 24 | with open(config_path, "rb") as f: 25 | # 只读256是为了避免读取文件太大,虽然一般不会太大 26 | _encoding = chardet.detect(f.read(256))["encoding"] 27 | with open(config_path, "r", encoding=_encoding) as f: 28 | config = json.loads(f.read()) 29 | return config 30 | 31 | class MyHandler(SimpleHTTPRequestHandler): 32 | 33 | def __init__(self, *args, config: dict = {}, **kwargs): 34 | self.config = config 35 | kwargs["directory"] = os.path.join(os.getcwd(), config["scripts_path"]) 36 | super().__init__(*args, **kwargs) 37 | 38 | def send_head(self): 39 | path = self.translate_path(self.path) 40 | f = None 41 | if os.path.isdir(path): 42 | parts = urllib.parse.urlsplit(self.path) 43 | if not parts.path.endswith('/'): 44 | # redirect browser - doing basically what apache does 45 | self.send_response(HTTPStatus.MOVED_PERMANENTLY) 46 | new_parts = (parts[0], parts[1], parts[2] + '/', 47 | parts[3], parts[4]) 48 | new_url = urllib.parse.urlunsplit(new_parts) 49 | self.send_header("Location", new_url) 50 | self.end_headers() 51 | return None 52 | for index in "index.html", "index.htm": 53 | index = os.path.join(path, index) 54 | if os.path.exists(index): 55 | path = index 56 | break 57 | else: 58 | return self.list_directory(path) 59 | ctype = self.guess_type(path) 60 | try: 61 | f = open(path, 'rb') 62 | except OSError: 63 | self.send_error(HTTPStatus.NOT_FOUND, "File not found") 64 | return None 65 | 66 | try: 67 | fs = os.fstat(f.fileno()) 68 | # Use browser cache if possible 69 | if ("If-Modified-Since" in self.headers 70 | and "If-None-Match" not in self.headers): 71 | # compare If-Modified-Since and time of last file modification 72 | try: 73 | ims = email.utils.parsedate_to_datetime( 74 | self.headers["If-Modified-Since"]) 75 | except (TypeError, IndexError, OverflowError, ValueError): 76 | # ignore ill-formed values 77 | pass 78 | else: 79 | if ims.tzinfo is None: 80 | # obsolete format with no timezone, cf. 81 | # https://tools.ietf.org/html/rfc7231#section-7.1.1.1 82 | ims = ims.replace(tzinfo=datetime.timezone.utc) 83 | if ims.tzinfo is datetime.timezone.utc: 84 | # compare to UTC datetime of last modification 85 | last_modif = datetime.datetime.fromtimestamp( 86 | fs.st_mtime, datetime.timezone.utc) 87 | # remove microseconds, like in If-Modified-Since 88 | last_modif = last_modif.replace(microsecond=0) 89 | 90 | if last_modif <= ims: 91 | self.send_response(HTTPStatus.NOT_MODIFIED) 92 | self.end_headers() 93 | f.close() 94 | return None 95 | 96 | self.send_response(HTTPStatus.OK) 97 | # self.send_header("Content-type", ctype) 98 | # self.send_header("Content-Length", str(fs[6])) 99 | # self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 100 | self.send_custom_header() 101 | self.end_headers() 102 | return f 103 | except: 104 | f.close() 105 | raise 106 | 107 | def send_custom_header(self): 108 | if self.path.startswith("/"): 109 | js_path = self.path.lstrip("/") 110 | else: 111 | js_path = self.path 112 | if self.config.get(js_path) is None: 113 | return 114 | headers = self.config[js_path] 115 | for key, value in headers.items(): 116 | self.send_header(key, value) 117 | 118 | def send_response(self, code, message=None): 119 | self.log_request(code) 120 | self.send_response_only(code, message) 121 | # self.send_header('Server', self.version_string()) 122 | # self.send_header('Date', self.date_time_string()) 123 | 124 | def send_header(self, keyword, value): 125 | if self.request_version != 'HTTP/0.9': 126 | if not hasattr(self, '_headers_buffer'): 127 | self._headers_buffer = [] 128 | self._headers_buffer.append( 129 | ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict')) 130 | 131 | if keyword.lower() == 'connection': 132 | if value.lower() == 'close': 133 | self.close_connection = True 134 | elif value.lower() == 'keep-alive': 135 | self.close_connection = False 136 | 137 | def main(): 138 | config = load_config() 139 | Handler = partial(MyHandler, config=config) 140 | server = HTTPServer((config["host"], config["port"]), Handler) 141 | print("Starting server, listen at: http://{host}:{port}".format(**config)) 142 | server.serve_forever() 143 | 144 | if __name__ == '__main__': 145 | main() -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "127.0.0.1", 3 | "port": 22222, 4 | "scripts_path": "scripts", 5 | "vendors~xgplayer_encrypt.b05f677a.chunk.js": { 6 | "access-control-allow-origin": "*", 7 | "timing-allow-origin": "*" 8 | } 9 | } --------------------------------------------------------------------------------