From 8c4bef86df9ac2d9bc6e1d38a4a679a80ae831b7 Mon Sep 17 00:00:00 2001 From: Jared-02 <78630856+Jared-02@users.noreply.github.com> Date: Tue, 19 Oct 2021 13:25:05 +0800 Subject: [PATCH] Performance improvements --- helpers/Muxer.py | 24 ++--- .../__pycache__/MSLClient.cpython-39.pyc | Bin 12691 -> 12726 bytes .../__pycache__/get_keys.cpython-39.pyc | Bin 4229 -> 4217 bytes .../__pycache__/get_manifest.cpython-39.pyc | Bin 13727 -> 13939 bytes helpers/Parsers/Netflix/get_keys.py | 26 +++--- helpers/Parsers/Netflix/get_manifest.py | 26 ++++-- helpers/aria2.py | 83 ++++++++++++++---- helpers/ripprocess.py | 26 +++--- services/__pycache__/netflix.cpython-39.pyc | Bin 22617 -> 22076 bytes services/netflix.py | 62 +++++++------ 10 files changed, 159 insertions(+), 88 deletions(-) diff --git a/helpers/Muxer.py b/helpers/Muxer.py index 9c288c5..a7c3d09 100644 --- a/helpers/Muxer.py +++ b/helpers/Muxer.py @@ -318,10 +318,15 @@ class Muxer(object): def LanguageList(self): LanguageList = [ - ["Hindi", "hin", "hin", "Hindi"], - ["Tamil", "tam", "tam", "Tamil"], - ["Telugu", "tel", "tel", "Telugu"], + ["Simplified Chinese", "zhoS", "chi", "Simplified Chinese"], + ["Traditional Chinese", "zhoT", "chi", "Traditional Chinese"], + ["Mandarin (Putonghua)", "zho", "zh-cmn", "Mandarin"], + ["Mandarin (Guoyu)", "zho", "chi", "Chinese"], + ["Cantonese", "zho", "zh-yue", "Cantonese"], + ["Taiwanese", "zho", "zh-nan", "Minnan"], + ["Chinese", "zho", "chi", "Chinese"], ["English", "eng", "eng", "English"], + ["British English", "enGB", "eng", "British English"], ["Afrikaans", "af", "afr", "Afrikaans"], ["Arabic", "ara", "ara", "Arabic"], ["Arabic (Syria)", "araSy", "ara", "Arabic Syria"], @@ -348,16 +353,15 @@ class Muxer(object): ["Assamese", "asm", "asm", "Assamese"], ["Bengali", "ben", "ben", "Bengali"], ["Basque", "eus", "baq", "Basque"], - ["British English", "enGB", "eng", "British English"], ["Bulgarian", "bul", "bul", "Bulgarian"], - ["Cantonese", "None", "chi", "Cantonese"], ["Catalan", "cat", "cat", "Catalan"], - ["Simplified Chinese", "zhoS", "chi", "Chinese Simplified"], - ["Traditional Chinese", "zhoT", "chi", "Chinese Traditional"], ["Croatian", "hrv", "hrv", "Croatian"], ["Czech", "ces", "cze", "Czech"], ["Danish", "dan", "dan", "Danish"], ["Dutch", "nld", "dut", "Dutch"], + ["Hindi", "hin", "hin", "Hindi"], + ["Tamil", "tam", "tam", "Tamil"], + ["Telugu", "tel", "tel", "Telugu"], ["Estonian", "est", "est", "Estonian"], ["Filipino", "fil", "fil", "Filipino"], ["Finnish", "fin", "fin", "Finnish"], @@ -496,8 +500,6 @@ class Muxer(object): self.mkvmerge, "--output", outputVideo, - "--title", - 'RAB', "(", inputVideo, ")", @@ -585,7 +587,7 @@ class Muxer(object): "--language", f"0:{language_id}", "--track-name", - f"0:Forced", + f"0:{language_name} Forced", "--forced-track", "0:yes", "--default-track", @@ -604,7 +606,7 @@ class Muxer(object): "--language", f"0:{language_id}", "--track-name", - f"0:SDH", + f"0:{language_name} SDH", "--forced-track", "0:no", "--default-track", diff --git a/helpers/Parsers/Netflix/__pycache__/MSLClient.cpython-39.pyc b/helpers/Parsers/Netflix/__pycache__/MSLClient.cpython-39.pyc index 30ab1995c07735dd69af1fdb076d58e7276067d6..171230028c3ae98269ba9836a947afadb2282629 100644 GIT binary patch delta 1057 zcmZ9K-EYfL7{@*I1=W&BH)ht+Qe%}j1eLvjYU$OuG&MJcKy})RoAH+5()F3 zlWktZWQezm`7w7yh%7^h%eldo3;%%x=X)9=eixs7pXd9W-}9Uo5gUn3i#nZCC&+JQ z$GYh7v;lkb&h@LpZ3g2;cuSPCcz6RdQaL>v-o|o!)5*f3d@{~-V^Li1%B1yZobgDL zY1;jE3W=|-5~a+J=?|?`5-xWGWyNy$YAOoDU7UGHHW|0DLNceh_y!s9lAwyTtjSdP zsN3wT_)ayQ$OnLD9CW0{yPd$*y~19SmCpa`HFKMf2> zj8D%-xxpfdXeMqXqAAAvVD$qBB{XY!q88NJIop4L89Ckqdk)b07aPq@vo8~6&97Be zH03Vpsf*tc*6Pibm`t;j|MUPWvcP?lRbL{yDSpj8?p712p_jp{1rCWzHM=W^rPQ3| z#j5d5c#nk3(@YOUi>HomnF-G`qI;s=o3xF3|UadChqw{(HLWX5PY3*P~9Q8zCMkFN$ye zHFQ|`7LT?ZK|)y!ssk7XZUK*hXTTHSJ@6V(O+P|?7J)#b>I~#spa%E=tONSQqrjKn D=AQ@s delta 990 zcmZ9K?Mu^96vsQcxoS=YnKqLRpZ%#!ry^kwP^e)<;d*$nvbE+f9nEdtna;<2AStcT zE?8g%DUPTN>{n(K6=In5Kq2*Fz4Cqi3(@`FQ7`(v`0%~wd+t5wp5I;ca&MByWZJe# ze39s=dm-tjA+@Tu=G5VOr!N#znZ3eZu6;My4HV=0lz#GSBPsKG8sH9d5w&xdc^CEZ zDRXaHzc?YLQzO0(C7IQV1smXb>3)$jnO;CW+EV&YvIY<@2ZoWZuX8$&IN24U6=H*Y zdAris4I@zvc!SLjUheE_R<6Wi@1=qN0oUJdZ8yz#~57NYkdXMu}#5j`fmRR+9}? z!_Ni!`77(`j3+`WruYGa2+sl|i|jEXKd;R# zO- zV9oFWrNW32vP58lzf|($9U0>twew%fA@N{piVskiHe9SHy2>w?IE-V+Zvw{oN=Zcv zuE7%IA;6?S%pe{D>kf6qFD?I+K_2TewuSxfuo@2gf&q3{sovHg3t^osAg(AAD0{zu2mxuSP-g%__y+nKcNElC;$Ke diff --git a/helpers/Parsers/Netflix/__pycache__/get_keys.cpython-39.pyc b/helpers/Parsers/Netflix/__pycache__/get_keys.cpython-39.pyc index b586ef11cbf0babddf505f3f9c67ed010cf1f589..40c5c61819462d010b4a303cdc7e1e0df97846bd 100644 GIT binary patch delta 194 zcmZow{Heg3$ji&c00jFMIVEy$VqG%Xl}%Yvq97-+ nvM4n%rBXM;$jl@cZr0>3wiHIr&F|TQI2aQ*JMlX)GTH$EvWYzG delta 179 zcmeyV(5lFr$ji&c00e9T9r3$2^1fjdFm|zu@pB8xEGS4V(lgRCn5@ingO@d((VU@{ zsfH<-L6dtj2lIBu+{p)+MH#s#Ut|0$XQUKOe#as<*@;aVh=uu)H0l-gE4ut8NU-FqXPhf&slMbt0(Je&C!{)erv013&5;((*3Io zE?Rrn`~lEn4fz}bD7bUo8PM>_x>JzFna&0@8~%bA9&eoXuBPcM95nQz)#!g0rg)Mv zxjCuAm1R>t!sYpCUQZdE;V}iZ$C~am*skWBAML}&V zd)4-`({#?c42R*FdTXanLgBA+ME4Zz>X(}mg?B1A+C%fax_d@nx&Wx8-Ng7si#n2wb(E36r%K5_+ddLi= zl<_gPrOREUG?pvaAEm+Ek?jAJN_#YYvS8Rna(bv=^B9IkS|w7T9pU}vLvRD5!68_U zlfeUZBfinBHk!|5sX?YhGUK!-{3RIh6oKA|37W$3_$D|IcI*QY1YQ6Ed{r<1r%>bL zC0+uF-sn_IjSFt#p^iH+g6)wo+{3}hV|Zw_ZKwtK7OwI zclE+|_@b)|_F-LYfVPp24cA|0+6xpG-8uck5*gK0TIr|Q_Npo{gOT{|Dnh)uQr3!Z zfO&ix?}ndIPWa&xMiK|%2mB-vg>Ue3Vp#l|S)9ke6VK|I5t(OT_idYB#oyoQYgu6A zbp~Myi{4!d(Y5y{)m&-sk4=~zu+H;o?_ZYO( flh^t?=<*y5-ABRAyWP?;x9skB58=xm3mX3c(!M!b delta 901 zcmZXQUr19?9LMkP?(Xiob?T$X>~zgG^fSp^~#T<;R2Ja6t0x^LTNZt9QA2j1Pb1$?iof$g;Ja{8> zAT^cT-A<;4Oqo*Lmi^EL(o&R)>l0LrkMhk_h#mlWNfct*s5Y*PXd;FvBU&xgRSgUu>>_0^?SH6_BOSg0{93sJJrS5{S2ZdUX} zl|tktq&9+1vlNg!+9D-_dRGX_LRlaZ2}ns@O-Sl^CHowVsM=*ydfMf{QHfEQ@Ze-8`Fa(+6% z11z$hp??FOFE|AwI77&w+1UaH>~i*GnrPCuq&6?A7*a7xfRk<)`$*kA##&bfyLZip zf-@7lU4D3o&s|P9ic78vQq=3NHa%6nBLs_FP%dwmngXIUii7SW8&aSbSKPH51a>MJ zd(D#%qd4L5!VG@)SYQlSJazB{PZk!yeY{*)&E8W>4CA}PPbRg{TA%A}uN9xd*WMEQ zxOy_J!a=Z@daOZ`1En2eu>C|wqdcM5i~2P%kI#G#!= int(dict(HighVideoList[-1])["vmaf"]) and int(dict(VideoList[-1])["Bitrate"]) >= int(dict(HighVideoList[-1])["Bitrate"]): + check_high_or_main = "MAIN" + else: check_high_or_main = "HIGH" + + checkerinfo = "\nNetflix Profile Checker v1.1\n2021-10-19 Jared_mod\n\nMain Rate: {}kbps | Vamf: {} | Profile: {}\nHigh Rate: {}kbps | Vamf: {} | Profile: {}\n\nResult: {} is Better!\n" checkerinfo = checkerinfo.format( str(dict(VideoList[-1])["Bitrate"]), + str(dict(VideoList[-1])["vmaf"]), str(dict(VideoList[-1])["Profile"]), str(dict(HighVideoList[-1])["Bitrate"]), + str(dict(HighVideoList[-1])["vmaf"]), str(dict(HighVideoList[-1])["Profile"]), - "result: MAIN is Better" - if int(dict(VideoList[-1])["Bitrate"]) - >= int(dict(HighVideoList[-1])["Bitrate"]) - else "result: HIGH is Better", + check_high_or_main, ) - - VideoList += HighVideoList self.logger.debug("HighVideoList: {}".format(HighVideoList)) + if check_high_or_main == "MAIN": + # 合并main和high解析列表 + VideoList += HighVideoList + elif check_high_or_main == "HIGH": + VideoList = HighVideoList + VideoList = sorted(VideoList, key=lambda k: int(k["Bitrate"])) return VideoList, checkerinfo diff --git a/helpers/aria2.py b/helpers/aria2.py index 1e3d012..02e36a0 100644 --- a/helpers/aria2.py +++ b/helpers/aria2.py @@ -163,15 +163,11 @@ class aria2: def aria2Options( self, allow_overwrite=True, - file_allocation=None, auto_file_renaming=False, async_dns=False, retry_wait=5, - summary_interval=0, - enable_color=False, - connection=16, - concurrent_downloads=16, - split=16, + enable_color=True, + concurrent_downloads=5, header="skip", user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36", uri_selector="inorder", @@ -179,51 +175,106 @@ class aria2: download_result="hide", quiet="false", extra_commands=[], + + # 单服务器最大连接线程数 + connection=64, + # 单任务最大连接线程数 + split=64, + # 代理地址,根据需要修改 + http_proxy_aria2c="http://127.0.0.1:7890", + https_proxy_aria2c="http://127.0.0.1:7890", + # 保存会话进度,用于断点续传 + save_session_interval=1, + auto_save_interval=30, + force_save="false", + # 文件最小分段大小 + min_split_size="4M", + # 磁盘缓存 + max_tries="0", + # HTTP/FTP下载分片大小 + piece_length="1M", + # 下载进度摘要输出间隔时间 + summary_interval=0, + # 断点续传 + continue_aria2c="true", + # 文件预分配方式 可选:none, prealloc, trunc, falloc + # 机械硬盘:falloc + # 固态硬盘:none + # prealloc 分配速度慢, trunc 无实际作用,不推荐使用。 + file_allocation="none", + # 磁盘缓存 + disk_cache="64M", ): options = [] + extra_commands allow_overwrite = self.convert_args(allow_overwrite) quiet = self.convert_args(quiet) - file_allocation = self.convert_args(file_allocation) auto_file_renaming = self.convert_args(auto_file_renaming) async_dns = self.convert_args(async_dns) retry_wait = self.convert_args(retry_wait) enable_color = self.convert_args(enable_color) - connection = self.convert_args(connection) concurrent_downloads = self.convert_args(concurrent_downloads) - split = self.convert_args(split) header = self.convert_args(header) + user_agent = self.convert_args(user_agent) uri_selector = self.convert_args(uri_selector) console_log_level = self.convert_args(console_log_level) download_result = self.convert_args(download_result) + connection = self.convert_args(connection) + split = self.convert_args(split) + http_proxy_aria2c = self.convert_args(http_proxy_aria2c) + https_proxy_aria2c = self.convert_args(https_proxy_aria2c) + save_session_interval = self.convert_args(save_session_interval) + auto_save_interval = self.convert_args(auto_save_interval) + force_save = self.convert_args(force_save) + min_split_size = self.convert_args(min_split_size) + max_tries = self.convert_args(max_tries) + piece_length = self.convert_args(piece_length) + summary_interval = self.convert_args(summary_interval) + continue_aria2c = self.convert_args(continue_aria2c) + file_allocation = self.convert_args(file_allocation) + disk_cache = self.convert_args(disk_cache) + ############################################################################## options += self.append_commands(options, "--allow-overwrite=", allow_overwrite) options += self.append_commands(options, "--quiet=", quiet) - options += self.append_commands(options, "--file-allocation=", file_allocation) + options += self.append_commands( options, "--auto-file-renaming=", auto_file_renaming ) options += self.append_commands(options, "--async-dns=", async_dns) options += self.append_commands(options, "--retry-wait=", retry_wait) options += self.append_commands(options, "--enable-color=", enable_color) - - options += self.append_commands( - options, "--max-connection-per-server=", connection - ) - options += self.append_commands( options, "--max-concurrent-downloads=", concurrent_downloads ) - options += self.append_commands(options, "--split=", split) + options += self.append_commands(options, "--header=", header) + options += self.append_commands(options, "--user-agent=", user_agent) options += self.append_commands(options, "--uri-selector=", uri_selector) options += self.append_commands( options, "--console-log-level=", console_log_level ) options += self.append_commands(options, "--download-result=", download_result) + options += self.append_commands( + options, "--max-connection-per-server=", connection + ) + options += self.append_commands(options, "--split=", split) + options += self.append_commands(options, "--http-proxy=", http_proxy_aria2c) + options += self.append_commands(options, "--https-proxy=", https_proxy_aria2c) + options += self.append_commands(options, "--save-session-interval=", save_session_interval) + options += self.append_commands(options, "--auto-save-interval=", auto_save_interval) + options += self.append_commands(options, "--force-save=", force_save) + options += self.append_commands(options, "--min-split-size=", min_split_size) + options += self.append_commands(options, "--max-tries=", max_tries) + options += self.append_commands(options, "--piece-length=", piece_length) + options += self.append_commands(options, "--summary-interval=", summary_interval) + options += self.append_commands(options, "--continue=", continue_aria2c) + options += self.append_commands(options, "--file-allocation=", file_allocation) + options += self.append_commands(options, "--disk-cache=", disk_cache) + return options def aria2DisableProxies(self): diff --git a/helpers/ripprocess.py b/helpers/ripprocess.py index 8439c0f..be4b090 100644 --- a/helpers/ripprocess.py +++ b/helpers/ripprocess.py @@ -386,6 +386,10 @@ class ripprocess(object): return "Mandarin Chinese (Simplified)", "zh-Hans" elif code == "cmn-Hant": return "Mandarin Chinese (Traditional)", "zh-Hant" + elif code == "zh-TW": + return "Chinese", "zho" + elif code == "zh-CN": + return "Chinese", "zho" elif code == "es-419": return "Spanish", "spa" elif code == "es-ES": @@ -674,16 +678,18 @@ class ripprocess(object): outputName = inputName.replace(replace_str, ext) self.logger.info(("{} -> {}").format(inputName, outputName)) - ff = ffmpy.FFmpeg( - executable=self.bin["ffmpeg"], - inputs={inputName: None}, - outputs={outputName: "-c:a copy"}, - global_options="-vn -sn -y -hide_banner -loglevel panic", - ) - ff.run() - time.sleep(0.05) - if os.path.isfile(outputName) and os.path.getsize(outputName) > 1024 * 1024: - os.remove(inputName) + #直接重命名到目标格式,移除ffmpeg混流过程 + os.rename(inputName, outputName) + #ff = ffmpy.FFmpeg( + # executable=self.bin["ffmpeg"], + # inputs={inputName: None}, + # outputs={outputName: "-c:a copy"}, + # global_options="-vn -sn -y -hide_banner -loglevel panic", + #) + #ff.run() + #time.sleep(0.05) + #if os.path.isfile(outputName) and os.path.getsize(outputName) > 1024 * 1024: + # os.remove(inputName) self.logger.info("Done!") return diff --git a/services/__pycache__/netflix.cpython-39.pyc b/services/__pycache__/netflix.cpython-39.pyc index b703372ab19643e951c75b76a60f36820f245a3d..37295b7aa525c9774ce83ae13377923b9c3ff420 100644 GIT binary patch delta 3087 zcmaJ@dr(x@8Q*hv_wKT=y9lC!APd2U%bQ3>7kcBmuzKCZS}*0xo})RA)wHZ8|!s1!aXM-nU5tkrL^S1uN-JJnm{Gq?`RP-GITijCY6_fRpJk z%kvx%hfwThk9t}*_M_-W7yvMBvKlgI5XV~)_92AWN1ob-9uOrLy$?0r2qOTd5E?hd zkfu$j3O$GlM@WkrO4JBg$90V!z=gp?pO*+^8}qNa-qjA8Id5wyq{NKMj%Y}e)#w=A zfm(N4FcelQ+u#7IP15b4Gi_a(ZUn?$8XSuRX(t}nfzXzi&Du{q58)ay7No(54jz4& zZIA#PTD|))8b{Y7>_R}}xz%R6ZUl|EJ^~jjG#Awq2z>yiT{oy2Gwlkc8s&u0I-DFs zs781gKyoBW*n)~F1hj%q1DH0d=rNNRiISYKK-$>S+G*0o?CTyQUt~|NTOvnUUhY1! zlj*rFRot-Msr@Mv=>qDwX^)^JAoQ{KbGMO2R+RUExEB?N6GM4t2^{Fk@7($oswXRz@ZY1nBtT|)zMkW zP9MOFSE8^9hZ+D(@nk{@&9qUlcO)8&KpL?#g_{LiCc9Bs;qt&_8~o{WtiZRu*DgC` zr<}H685hQ#w13PJb%LBGyK*gZ`clTC4MyU)Yk@2X3pOy>DrYR&KQq$ZV-nXur)kqC z)Ywfs97+j0@2eph>|@_p&T2^9P@Gc8-BelW?6IN_GR58~DkD#^TSbv<9`Dm=v8aQ^ zkg2b*K5sUAqS!5NCSYd`d#<=7O%U&hg7Z^xRpPDUWCmV7RgN3#m=O_I+#O3K8i za6FcXm-GX<>)q}7Fg7eF3A%7fAQp7>q*W%T2)H2t*VZ2T9au9U*?3BtB3O*H@zCOF zl8xOel~{@7bBHjsxHA&_rF=p@f2?{PJ62YC-y$gK6@-!$Y((k%04Kl+`UCbs*_CcQ z%yjATgE6Xw6kRuMq2S~sMGNWM2v|8%8jqssQlqiBu~(H9js6%X-vThL6RJ$Fu}{i- z$+N7rB1$q7XDh5E%kZ4^LWr#Bq3i~)yzF0d?EJJ}~yfeqZ(_fnfu>#rt#4ObVG{1RpZ-Uu`W zc|=x1bT(!vG$2N`5%l03%u1PTxJJt7@!~R6awVy9{2q8#j7$wE|7;x+gJJ6=~zZnATARhhpg18Fr_kh5UiFG**z`u}I_Qvj6Mifa#1( zOhJZ@DRhusZEW&DDq8}gUyIWas&bo(4r5A7#gx0j+bw4o_=oh<2(dC=jqU|d!;&QKt`4Z6D$GVWp8s?i(lLes%OGagY7AgxYzr{_`e zSA<&#kgpbMMf+WTuxua<%}%B%{{vYoWdL~;iO(o9{WosB$!40{$wl^B^Mk~l_;YiM zeQh$)VG{ECbzH;K{|uHXttu`}rTzb`)hqC6fLeXAT`IT^`=PUiwdpyhe^@T>fIkXm zLcgFV*r)A>y|XX~IJT?sd56@#%pUFVdH;sD-UgUcTL;^_*{Y6ecD-YlaL2;RJN-?+ z!Tk;jUH)DQ=5Q1D=^rTl6SrsHeTd-uq24#YNS|QKosHy6>~^Ol{t?%GnccsmypWd< z57s4A@`%-s{PCEYU6zmhx_*45Wp ziCmQ_mkquK)y@b)V}o6;5z(hy{tPS>Ns>4s`dDxtV;Xc5STclsMD z8E$z7AqNk}VDkc%ygXh|VG0}(?lzPNZDdXU&7_pY{aaQ)hqpMCn6Ba*?s?o+#4h@M zq%iS;f0hh4qbB)sMTt{$1SRex=i&t%zJzcdf#>3zD7}sFbA%fRyysvJaVKawVV-?! z*qehJ-RZ6k&OGNj=PGBetC8IqEN$mm&fkk`aBDRJrZT(~!f`{Lq(4Os(r4NXHKGLU aqoa}7Y#=Q*8`9$Nl9;8t65+jnBL4xaqbNrJ delta 3647 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