Youtube-filter(channel、comment、video)

block and highlight youtube video/comment by keyword、channel

  1. // ==UserScript==
  2. // @name Youtube-filter(channel、comment、video)
  3. // @namespace smallsupo
  4. // @version 2.5
  5. // @description block and highlight youtube video/comment by keyword、channel
  6. // @description:zh-TW 屏蔽/高亮 youtube影片/留評 (依頻道、關鍵字)
  7. // @author smallsupo (smallsupo@gmail.com)
  8. // @match https://www.youtube.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  10. // @grant none
  11. // @noframes
  12. // @license Copyright smallsupo
  13. // ==/UserScript==
  14.  
  15. let languages=[
  16. {language:"en",restore:'restore',backup:'backup',setting:'setting',show:'show',hide:'hide',copytoclipboard:'copy text',membersonly:"Members only",
  17. block:'block',channel:'channel',video:'video',keyword:'keyword',comment:'comment',dot:'popup menu dot',
  18. user:'user',highlight:'highlight',color:'color',curvature:'curvature',border:'border',needrefresh:'(page refresh needed)',
  19. regex:'regex',posttime:'post time',regex_post_time:'minute ,hour,^1\sday',noselecttextpup:'no use popup (select keyword)'},
  20. {language:"zh",restore:'還原',backup:'備份',setting:'設定',show:'顯示',hide:'隱藏',copytoclipboard:'複製文字',membersonly:"頻道會員專屬",
  21. block:'屏蔽',channel:'頻道',video:'影片',keyword:'關鍵字',comment:'留言',dot:'選單點',needrefresh:'(頁面刷新生效)',
  22. user:'用戶',highlight:'高亮',color:'顏色',curvature:'弧度',border:'邊框',
  23. regex:'正規表示式',posttime:'發佈時間',regex_post_time:'分鐘,小時,^1\s天',noselecttextpup:'不使用浮窗(選取文字)'},
  24. ];
  25. let autoDectectSystemLanguage=true;//set true to auto detect system language or set false to assign specify language below
  26. let language="en";
  27. let currentlanguageindex=0;
  28. //---add language by yourself -------------------------------------------------
  29. const BLOCK_CHANNEL=0;const BLOCK_VIDEO_KEYWORD=1;const BLOCK_VIDEO=2;const BLOCK_COMMENT_USER=3;const BLOCK_COMMENT_KEYWORD=4;
  30. const HIGHLIGHT_CHANNEL=5;const HIGHLIGHT_VIDEO_KEYWORD=6;const HIGHLIGHT_VIDEO=7;const HIGHLIGHT_COMMENT_USER=8;
  31. let narrowwidth=150;
  32. let block="block";let highlight="highlight";let setting="setting";let show='show';let hide='hide';
  33. let needrefresh="(page refresh needed)";
  34. let parametersArray=[
  35. {title:"channel",value:[],uiwidth:200,filter:"true",storageid:"small_array0"},
  36. {title:"video keyword",value:[],uiwidth:narrowwidth-40,filter:"true",storageid:"small_array1"},
  37. {title:"video",value:[],uiwidth:narrowwidth-50,filter:"true",storageid:"small_array2"},
  38. {title:"comment user",value:[],uiwidth:200,filter:"true",storageid:"small_array3"},
  39. {title:"comment keyword",value:[],uiwidth:narrowwidth,filter:"true",storageid:"small_array4"},
  40. {title:"channel",value:[],uiwidth:200,filter:"true",storageid:"small_array5"},
  41. {title:"video keyword",value:[],uiwidth:narrowwidth-40,filter:"true",storageid:"small_array6"},
  42. {title:"video",value:[],uiwidth:narrowwidth-50,filter:"true",storageid:"small_array7"},
  43. {title:"comment user",value:[],uiwidth:200,filter:"true",storageid:"small_array8"},
  44. ];
  45. const HIGHLIGHT_CHANNEL_BACKGROUND=0;const HIGHLIGHT_VIDEO_KEYWORD_ARC=1;const HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND=2;
  46. const HIGHLIGHT_VIDEO_BACKGROUND=3;const HIGHLIGHT_COMMENT_USER_BACKGROUND=4;const HIGHTLIGHT_POSTTIME_BAKGROUND=5;
  47. const HIGHTLIGHT_POSTTIME_REGX=6;const HIGHTLIGHT_POSTTIME_TRUE=7;const HIDE_COMMENT=8;const DOT_COLOR=9;const DOT_COLOR_LEAVE=10;
  48. const BLOCK_MEMBERSONLY=11;const NOUSELECTTEXTPOPUP=12;
  49. let parametersSingle=[
  50. {title:"highlight channel color",type:"color",value:'#ffffe6',storageid:"small_single0"},
  51. //highlight keyword border:
  52. {title:"curvature",type:"string",value:'12',valuer:'px',storageid:"small_single1"},
  53. {title:"color",type:"color",value:'#ff0000',valuep:'4px solid ',storageid:"small_single2"},
  54. {title:"highlight video color",type:"color",value:'#e6fffd',storageid:"small_single3"},
  55. {title:"hightlight comment user color",type:"color",value:'#ffffe6',storageid:"small_single4"},
  56. //highlight post time
  57. {title:"color",type:"color",value:'#ffd2dc',storageid:"small_single5"},
  58. {title:"regex",type:"string",value:'minute,hour,^1\sday',storageid:"small_single6"},
  59. {title:"highlight post time",type:"boolean",value:'true',storageid:"small_single7"},
  60. {title:"hide comment",type:"boolean",value:'false',storageid:"small_single8"},
  61. {title:"dotcolor",type:"color",value:'#aaaaaa',storageid:"small_single9"},
  62. {title:"dotcolorleave",type:"color",value:'#eeeeee',storageid:"small_single10"},
  63. {title:"block 'Members only'",type:"boolean",value:'false',storageid:"small_single11"},
  64. {title:"no use popup(select keyword)",type:"boolean",value:'false',storageid:"small_single12"},
  65. ];
  66. //----------------------------------------------------------------------------
  67. let title_restorefile="restore";let title_savefile="backup";
  68. function setSVGIcon(targetElement, svgString) {
  69. const parser = new DOMParser();
  70. const svgDoc = parser.parseFromString(svgString, 'image/svg+xml');
  71. const svgElement = svgDoc.documentElement;
  72. targetElement.replaceChildren(svgElement);
  73. }
  74. class ParametersAgent{
  75. container;uniqueid;
  76. filename="parameters.txt";
  77. fontsize="14px";
  78. parametersUiHieght="200";
  79. splitmark=",";
  80. static checkid="_checked";
  81. static currentSelect=BLOCK_CHANNEL;
  82. constructor(container,filename,fontsize=this.fontsize){
  83. this.container=container;
  84. this.filename=filename;
  85. this.fontsize=fontsize;
  86. }
  87. static LT=0;static LB=1;static RT=2;static RB=3; //parameters ui position
  88. setPositionxy(mode){
  89. let edgex="left";let edgey="top";
  90. let edgegapx="2px",edgegapy="2px";
  91. if(mode==ParametersAgent.LT){edgex="left";edgey="top";}
  92. else if(mode==ParametersAgent.LB){edgex="left";edgey="bottom";edgegapy="20px";}
  93. else if(mode==ParametersAgent.RT){edgex="right";edgey="top";}
  94. else if(mode==ParametersAgent.RB){edgex="right";edgey="bottom";edgegapy="20px";}
  95. let xy=`${edgex}:${edgegapx};${edgey}:${edgegapy};`;
  96. return xy;
  97. }
  98. setPanel_Parameters(positionmode,dofunc_whenopen,dofunc_whenclose,lines=2){
  99. //let table=this.generateParametersArrayUI(lines);
  100. let table=this.generateParametersArrayUI_tabpane();
  101. this.createParametersControlPanel(positionmode,table,dofunc_whenopen,dofunc_whenclose);
  102. }
  103. static setTAshow(index){
  104. ParametersAgent.currentSelect=index;
  105. let backgroundcolor="#cce6ff";
  106. if(index==this.SETTING){
  107. let p=document.getElementById("smallsuposettings");
  108. let b=document.getElementById("smallbuttonsetting");
  109. if(p!=null&&b!=null){
  110. p.style.display="block";b.style.background = backgroundcolor;
  111. for(let i=0;i<parametersArray.length;i++){
  112. let p= parametersArray[i];
  113. let ta=document.getElementById(p.storageid);
  114. let button=document.getElementById("smallbutton"+p.storageid);
  115. ta.style.display="none";
  116. button.style.background = null;
  117. }
  118. }
  119. }else{
  120. for(let i=0;i<parametersArray.length;i++){
  121. let p= parametersArray[i];
  122. let ta=document.getElementById(p.storageid);
  123. STD.cursor_scrollToBottom(ta);
  124. let button=document.getElementById("smallbutton"+p.storageid);
  125. if(i==index){
  126. ta.style.display="block";
  127. STD.cursor_scrollToBottom(ta);
  128. button.style.background = backgroundcolor;
  129. }else{
  130. ta.style.display="none";
  131. button.style.background = null;
  132. }
  133. }
  134. let p=document.getElementById("smallsuposettings");let b=document.getElementById("smallbuttonsetting");
  135. if(p!=null&&b!=null){ p.style.display="none";b.style.background = null;}
  136. }
  137. }
  138. createParametersControlPanel(positionmode,mainpanel,dofunc_whenopen,dofunc_whenclose){
  139. const zindex=99999999999;const position="fixed";
  140. const others="";//"transform: translate(0%, -100%);";
  141. const ui_border_color="#888888";
  142. //const id_uniq="youtubeP";
  143. const bgcolor="rgb(241, 242, 243)";const fcolor="black";
  144. const id_button="smallsupo_id_parametersControlPanel_button_"+this.uniqueid;
  145. const id_divpanel="smallsupo_id_parametersControlPanel_divpanel_"+this.uniqueid;
  146. const button_width="32px";
  147. const button_opacity="0.2";
  148. const ICON_SETTING='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M13 2 L13 6 11 7 8 4 4 8 7 11 6 13 2 13 2 19 6 19 7 21 4 24 8 28 11 25 13 26 13 30 19 30 19 26 21 25 24 28 28 24 25 21 26 19 30 19 30 13 26 13 25 11 28 8 24 4 21 7 19 6 19 2 Z" /><circle cx="16" cy="16" r="4" /></svg>';
  149. const ICON_REFRESH='<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 26 24"><path d="M13.5 2c-5.629 0-10.212 4.436-10.475 10h-3.025l4.537 5.917 4.463-5.917h-2.975c.26-3.902 3.508-7 7.475-7 4.136 0 7.5 3.364 7.5 7.5s-3.364 7.5-7.5 7.5c-2.381 0-4.502-1.119-5.876-2.854l-1.847 2.449c1.919 2.088 4.664 3.405 7.723 3.405 5.798 0 10.5-4.702 10.5-10.5s-4.702-10.5-10.5-10.5z" fill="white" stroke="black" stroke-width="1"/></svg>'
  150. const button_openicon=ICON_REFRESH;
  151. let button_closeicon=ICON_SETTING;
  152. const button_fontsize="small";
  153. let SETTING=-1;
  154. let div=document.createElement("div");div.setAttribute("style","position:"+position+";z-Index:"+zindex+";"+this.setPositionxy(positionmode));
  155. let table=document.createElement("table");table.setAttribute("style","border:0px;");
  156. //---button--------------
  157. let tr0=document.createElement("tr");
  158. let td0=document.createElement("td");td0.setAttribute("style","vertical-align: top;");
  159. let button=document.createElement("div");button.setAttribute("id",id_button);
  160. button.setAttribute("style","text-align: center;cursor: pointer;width:"+button_width+";height:"+button_width+";background-color:"+bgcolor+";color:"+fcolor+";font-size: "+button_fontsize+";");
  161. setSVGIcon(button,button_closeicon);
  162. button.onmouseover= (e) => {
  163. let b=document.getElementById(id_button);let p=document.getElementById(id_divpanel);
  164. if(p.style.display=="none"){b.style.opacity=1;}
  165. };
  166. button.onmouseleave=(e) => {
  167. let b=document.getElementById(id_button);let p=document.getElementById(id_divpanel);
  168. if(p.style.display=="none"){b.style.opacity=button_opacity;}
  169. };
  170. button.onclick = ()=> {
  171. let b=document.getElementById(id_button);let p=document.getElementById(id_divpanel);
  172. if(p.style.display=="none"){
  173. setSVGIcon(b,button_openicon);
  174. b.style.opacity=1;button.style.border ="1px solid "+ui_border_color+";";
  175. p.style.display="block";
  176. this.openParametersUI(dofunc_whenopen);
  177. }else{
  178. setSVGIcon(b,button_closeicon);
  179. button.style.border ="none";p.style.display ="none";
  180. this.closeParametersUI(dofunc_whenclose);
  181. }
  182. };
  183. td0.appendChild(button);tr0.appendChild(td0);
  184. //-----
  185. let tr1=document.createElement("tr");let td1=document.createElement("td");td1.setAttribute("style","vertical-align: center;");
  186. let divpanel=document.createElement("div");divpanel.setAttribute("id",id_divpanel);
  187. divpanel.setAttribute("style","background-color:"+bgcolor+";color:"+fcolor+";display:none;");
  188. //-----main panel ui code here
  189. divpanel.appendChild(mainpanel);
  190. td1.appendChild(divpanel);tr1.appendChild(td1);
  191. //-----
  192. if(positionmode==ParametersAgent.LT||positionmode==ParametersAgent.RT){table.appendChild(tr0);table.appendChild(tr1);}
  193. else if(positionmode==ParametersAgent.LB||positionmode==ParametersAgent.RB){table.appendChild(tr1);table.appendChild(tr0);}
  194. div.appendChild(table);this.container.appendChild(div);
  195. //default hidden
  196. divpanel.style.display="none";
  197. setTimeout(()=>{
  198. if(document.getElementById(id_divpanel).style.display=="none")document.getElementById(id_button).style.opacity=button_opacity;
  199. },5000);
  200. }
  201. static setFilerValue(id,filter){
  202. for(let i=0;i<parametersArray.length;i++){
  203. if(parametersArray[i].storageid==id){
  204. parametersArray[i].filter=filter;
  205. ParametersAgent.saveLocalStorage1(parametersArray[i].storageid+ParametersAgent.checkid,parametersArray[i].filter);
  206. }
  207. }
  208. //console.log(id,filter);
  209. for(let i=0;i<parametersSingle.length;i++){
  210. if(parametersSingle[i].storageid==id){
  211. parametersSingle[i].value==filter;
  212. ParametersAgent.saveLocalStorage1(parametersSingle[i].storageid,filter);
  213. }
  214. }
  215. }
  216. generateSettingPanel(){
  217. let widthpx="100%;";
  218. let table=document.createElement("table");table.setAttribute("id","smallsuposettings");table.setAttribute("style","display:'none';");
  219. let tr=document.createElement("tr");
  220. let td=document.createElement("td");td.setAttribute("style","width:"+widthpx+"vertical-align: top;font-size:"+this.fontsize+";");
  221. //let td=document.createElement("td");td.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  222. td=this.generateParametersSingleUI(td);tr.appendChild(td);table.appendChild(tr);
  223. tr=document.createElement("tr");
  224. td=document.createElement("td");td.setAttribute("style","width:"+widthpx+"vertical-align: center;font-size:"+this.fontsize+";");
  225. td.innerText=" ";tr.appendChild(td);table.appendChild(tr);
  226. tr=document.createElement("tr");
  227. td=document.createElement("td");td.setAttribute("style","width:"+widthpx+"vertical-align: top;font-size:"+this.fontsize+";");
  228. let d=document.createElement("span");
  229. this.loadLocalFile(d,title_restorefile,"font-size:"+this.fontsize+";",this.doAfterLoadFile.bind(this));
  230. this.saveLocalFile(d,title_savefile,this.filename,"text","font-size:"+this.fontsize+";",this.doBeforeSaveFile.bind(this));
  231. td.appendChild(d);tr.appendChild(td);table.appendChild(tr);
  232. return table;
  233. }
  234. generateParametersArrayUI_tabpane(){
  235. let table=document.createElement("table");
  236. table.style.border="1px solid #888888;";table.style.boxShadow = "10px 20px 30px gray";
  237. let trtop=document.createElement("tr");
  238. let tdtop=document.createElement("td");tdtop.setAttribute("colspan",3);tdtop.setAttribute("style","text-align:center;");
  239. const h2 = document.createElement("h2");h2.textContent = "Youtube-filter by smallsupo@gmail.com 🐱";
  240. tdtop.replaceChildren(h2);
  241. trtop.appendChild(tdtop);table.appendChild(trtop);
  242. let tr=document.createElement("tr");
  243. let tdleft=document.createElement("td");tdleft.setAttribute("style",
  244. "width:200px;vertical-align: top;font-size:"+this.fontsize+";");
  245. let menutable=document.createElement("table");
  246. for(let i=0;i<parametersArray.length;i++){
  247. if(i==0||i==5){
  248. let type=block;if(i==5)type=highlight;
  249. if(i==5){
  250. let tr=document.createElement("tr");
  251. let td=document.createElement("td");td.setAttribute("style","visibility: hidden;");td.innerText=" ";tr.appendChild(td);
  252. td=document.createElement("td");
  253. tr.appendChild(td);
  254. menutable.appendChild(tr);
  255. }
  256. let tr=document.createElement("tr");
  257. let td=document.createElement("td");td.setAttribute("colspan",2);
  258. td.setAttribute("style","color: red;font-weight: bold;width:200px;vertical-align: top;text-align:left;font-size:"+this.fontsize+";");
  259. td.innerText=type;
  260. tr.appendChild(td);menutable.appendChild(tr);
  261. }
  262. let menutr=document.createElement("tr");
  263. let p=parametersArray[i];
  264. let td=document.createElement("td");td.setAttribute("style",
  265. "vertical-align: top;font-size:"+this.fontsize+";");
  266. //let dtable=document.createElement("table");
  267. let dtdc=document.createElement("td");
  268. let dtdtitle=document.createElement("td");
  269. let c=document.createElement("input");c.setAttribute("id",p.storageid+ParametersAgent.checkid);c.setAttribute("type", "checkbox");
  270. let title=document.createElement("button");title.setAttribute("id","smallbutton"+p.storageid);
  271. title.setAttribute("style","width:180px;cursor: pointer;");title.innerText=p.title;
  272. p.filter=this.loadLocalStorage(p.storageid+ParametersAgent.checkid,p.filter);
  273. if(p.filter=="true"){c.checked=true;}else{c.checked=false;}
  274. c.onclick = function () {if(!c.checked){
  275. ParametersAgent.setFilerValue(p.storageid,"false");}else {ParametersAgent.setFilerValue(p.storageid,"true");}
  276. filter("from checkbox");
  277. };
  278. title.onclick = function (){
  279. ParametersAgent.setTAshow(i);
  280. };
  281. dtdc.appendChild(c);dtdtitle.appendChild(title);menutr.appendChild(dtdc);menutr.appendChild(dtdtitle);
  282. menutable.appendChild(menutr);
  283.  
  284. }
  285. //----------------------------------------------
  286. let menutr=document.createElement("tr");
  287. let td=document.createElement("td");td.setAttribute("style","visibility: hidden;");td.innerText=" ";menutr.appendChild(td);
  288. td=document.createElement("td");
  289. menutr.appendChild(td);
  290. menutable.appendChild(menutr);
  291. menutr=document.createElement("tr");
  292. td=document.createElement("td");menutr.appendChild(td);
  293. td=document.createElement("td");
  294. let settingbutton=document.createElement("button");settingbutton.setAttribute("style","width:180px;cursor: pointer;");
  295. settingbutton.innerText=setting;settingbutton.setAttribute("id","smallbuttonsetting");
  296. settingbutton.onclick = function (){ParametersAgent.setTAshow(this.SETTING);};
  297. td.appendChild(settingbutton);menutr.appendChild(td);
  298. menutable.appendChild(menutr);
  299. tdleft.appendChild(menutable);
  300. //----------------------------------------------
  301.  
  302. let tdcenter=document.createElement("td");tdcenter.setAttribute("style","width:360px;vertical-align: top;font-size:"+this.fontsize+";");
  303. for(let i=0;i<parametersArray.length;i++){
  304. let p=parametersArray[i];
  305. let ta=document.createElement("textarea")
  306. ta.setAttribute("id",p.storageid);ta.setAttribute("rows",20);
  307. ta.setAttribute("style","display:'none';width:98%;height:100%;white-space:pre;overflow:scroll;resize: general;font-size:"+this.fontsize+";");
  308. tdcenter.appendChild(ta);
  309. }
  310. tdcenter.appendChild(this.generateSettingPanel());
  311. //let tdright=document.createElement("td");tdright.setAttribute("style","width:200px;vertical-align: top;font-size:"+this.fontsize+";");
  312.  
  313. tr.appendChild(tdleft);tr.appendChild(tdcenter);//tr.appendChild(this.generateParametersSingleUI(tdright));
  314. table.appendChild(tr);
  315. tr=document.createElement("tr");
  316. //let td=document.createElement("td");td.setAttribute("style","vertical-align: center;font-size:"+this.fontsize+";");td.setAttribute("colspan",2);
  317. //this.loadLocalFile(td,title_restorefile,"font-size:"+this.fontsize+";",this.doAfterLoadFile.bind(this));tr.appendChild(td);
  318. //this.saveLocalFile(td,title_savefile,this.filename,"text","font-size:"+this.fontsize+";",this.doBeforeSaveFile.bind(this));tr.appendChild(td);
  319. td=document.createElement("td");td.setAttribute("style","text-align: right;");td.setAttribute("colspan",2);this.generateQuestionLink(td);tr.appendChild(td);
  320. table.appendChild(tr);
  321. return table;
  322. //--------------------
  323.  
  324. }
  325. generateParametersArrayUI(lines){
  326. let table=document.createElement("table");
  327. table.style.border="1px solid #888888;";table.style.boxShadow = "10px 20px 30px gray";
  328. let startindex=0;
  329. let onelinecount=Math.ceil(parametersArray.length/lines);
  330. for(let j=0;j<lines;j++){
  331. let tr=document.createElement("tr");
  332. for(let i=0;i<onelinecount;i++){
  333. //console.log("index:"+(startindex+i));
  334. if((startindex+i)<parametersArray.length){
  335. let p=parametersArray[startindex+i];
  336. let w=p.uiwidth;
  337. let td=document.createElement("td");td.setAttribute("style","width:"+w+"px;word-wrap: break-word;vertical-align: bottom;font-size:"+
  338. this.fontsize+";");
  339. let d=document.createElement("div");d.innerText=p.title;//+'('+p.value.length+')';
  340. let c=document.createElement("input");c.setAttribute("id",p.storageid+ParametersAgent.checkid);c.setAttribute("type", "checkbox");
  341. p.filter=this.loadLocalStorage(p.storageid+ParametersAgent.checkid,p.filter);
  342. if(p.filter=="true"){c.checked=true;}else{c.checked=false;}
  343. c.onclick = function () {if(!c.checked){
  344. ParametersAgent.setFilerValue(p.storageid,"false");}else {ParametersAgent.setFilerValue(p.storageid,"true");}
  345. filter("from checkbox");
  346. };
  347. d.appendChild(c);td.appendChild(d);
  348. tr.appendChild(td);
  349. }
  350. }
  351. if(j==0){
  352. let td=document.createElement("td");td.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  353. td.setAttribute("rowspan",lines*2);
  354. tr.appendChild(this.generateParametersSingleUI(td));
  355. }
  356. table.appendChild(tr);
  357. tr=document.createElement("tr");
  358. for(let i=0;i<onelinecount;i++){
  359. if((startindex+i)<parametersArray.length){
  360. let p=parametersArray[startindex+i];
  361. if(Array.isArray(p.value)){
  362. let td=document.createElement("td");td.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  363. let w=p.uiwidth;
  364. let h=this.parametersUiHieght;
  365. let ta=document.createElement("textarea")
  366. ta.setAttribute("id",p.storageid);
  367. ta.setAttribute("style","width:"+w+"px;height:"+h+"px;white-space:pre;overflow:scroll;resize: general;font-size:"+this.fontsize+";");
  368. td.appendChild(ta);tr.appendChild(td);
  369. }
  370. }
  371. }
  372. table.appendChild(tr);
  373. startindex+=onelinecount;
  374. }
  375. //-------
  376. let tr=document.createElement("tr");
  377. let td=document.createElement("td");td.setAttribute("style","vertical-align: center;font-size:"+this.fontsize+";");td.setAttribute("colspan",onelinecount);
  378. this.loadLocalFile(td,title_restorefile,"font-size:"+this.fontsize+";",this.doAfterLoadFile.bind(this));tr.appendChild(td);
  379. //td=document.createElement("td");td.setAttribute("style","vertical-align: center;text-align:right;font-size:"+this.fontsize+";");
  380. this.saveLocalFile(td,title_savefile,this.filename,"text","font-size:"+this.fontsize+";",this.doBeforeSaveFile.bind(this));tr.appendChild(td);
  381. td=document.createElement("td");td.setAttribute("style","text-align: right;");this.generateQuestionLink(td);tr.appendChild(td);
  382. table.appendChild(tr);
  383. return table;
  384. }
  385.  
  386. generateParametersSingleUI(container){
  387. let bodersytle="border-style: ridge;border-width: 2px;margin:2px";
  388. let colorwidth="70px";
  389. let p=parametersSingle[HIGHLIGHT_CHANNEL_BACKGROUND];
  390. let div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  391. // 創建標籤 (highlight channel)
  392. let line=document.createElement("div");
  393. let label = document.createElement("b");label.textContent = languages[currentlanguageindex].highlight + " " + languages[currentlanguageindex].channel + ":";
  394. line.appendChild(label);
  395. let textNode = document.createTextNode(languages[currentlanguageindex].color);
  396. line.appendChild(textNode);
  397. let textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width = colorwidth;
  398. line.appendChild(textInput);
  399. let colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  400. line.appendChild(colorPicker);
  401. div.appendChild(line);
  402. container.appendChild(div);
  403. //highlihgt channer border
  404. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  405. line=document.createElement("div");
  406. let b = document.createElement("b");
  407. b.textContent = languages[currentlanguageindex].highlight+' '+languages[currentlanguageindex].channel+' '+languages[currentlanguageindex].border+':';
  408. line.appendChild(b);
  409. div.appendChild(line);
  410. p=parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC];
  411. line=document.createElement("div");
  412. textNode = document.createTextNode(p.title);
  413. line.appendChild(textNode);
  414. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width ="40px";
  415. line.appendChild(textInput);
  416. p=parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND];
  417. textNode = document.createTextNode(p.title);
  418. line.appendChild(textNode);
  419. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  420. line.appendChild(textInput);
  421. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  422. line.appendChild(colorPicker);
  423. div.appendChild(line);
  424. container.appendChild(div);
  425. //highlight video
  426. p=parametersSingle[HIGHLIGHT_VIDEO_BACKGROUND];
  427. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  428. line=document.createElement("div");
  429. b = document.createElement("b");
  430. b.textContent = languages[currentlanguageindex].highlight+' '+languages[currentlanguageindex].video+':';
  431. line.appendChild(b);
  432. textNode = document.createTextNode(languages[currentlanguageindex].color);
  433. line.appendChild(textNode);
  434. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  435. line.appendChild(textInput);
  436. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  437. line.appendChild(colorPicker);
  438. div.appendChild(line);
  439. container.appendChild(div);
  440. //highlight comment
  441. p=parametersSingle[HIGHLIGHT_COMMENT_USER_BACKGROUND];
  442. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  443. line=document.createElement("div");
  444. b = document.createElement("b");
  445. b.textContent = languages[currentlanguageindex].highlight+' '+languages[currentlanguageindex].comment+' '+languages[currentlanguageindex].user+':';
  446. line.appendChild(b);
  447. textNode = document.createTextNode(languages[currentlanguageindex].color);
  448. line.appendChild(textNode);
  449. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  450. line.appendChild(textInput);
  451. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  452. line.appendChild(colorPicker);
  453. div.appendChild(line);
  454. container.appendChild(div);
  455. //highlight post time
  456. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  457. line=document.createElement("div");
  458. b = document.createElement("b");
  459. b.textContent = languages[currentlanguageindex].highlight+' '+languages[currentlanguageindex].posttime+':';
  460. line.appendChild(b);
  461. p=parametersSingle[HIGHTLIGHT_POSTTIME_TRUE];
  462. let c = document.createElement("input");c.type = "checkbox";c.id = p.storageid;
  463. if((""+p.value).localeCompare("true")==0){c.checked=true;}else{c.checked=false;}
  464. c.onclick = function () {
  465. if(c.checked==false){
  466. p.value="false";//ParametersAgent.setFilerValue(p.storageid,"false");
  467. }else {p.value="true";//ParametersAgent.setFilerValue(p.storageid,"true");
  468. }
  469. filter("from checkbox post time");
  470. };
  471. line.appendChild(c);
  472. div.appendChild(line);
  473. line=document.createElement("div");
  474. textNode = document.createTextNode(languages[currentlanguageindex].color);
  475. line.appendChild(textNode);
  476. p=parametersSingle[HIGHTLIGHT_POSTTIME_BAKGROUND];
  477. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  478. line.appendChild(textInput);
  479. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  480. line.appendChild(colorPicker);
  481. div.appendChild(line);
  482. p=parametersSingle[HIGHTLIGHT_POSTTIME_REGX];
  483. line=document.createElement("div");
  484. textNode = document.createTextNode(languages[currentlanguageindex].regex);
  485. line.appendChild(textNode);
  486. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width ="98%";
  487. line.appendChild(textInput);
  488. div.appendChild(line);
  489. container.appendChild(div);
  490. //popupmenu color
  491. p=parametersSingle[DOT_COLOR];
  492. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";"+bodersytle);
  493. line=document.createElement("div");
  494. b = document.createElement("b");
  495. b.textContent = languages[currentlanguageindex].dot+':';
  496. line.appendChild(b);
  497. textNode = document.createTextNode(languages[currentlanguageindex].color);
  498. line.appendChild(textNode);
  499. div.appendChild(line);
  500. line=document.createElement("div");
  501. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  502. line.appendChild(textInput);
  503. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  504. line.appendChild(colorPicker);
  505. p=parametersSingle[DOT_COLOR_LEAVE];
  506. textInput = document.createElement("input");textInput.type = "text";textInput.id = p.storageid;textInput.style.width =colorwidth;
  507. line.appendChild(textInput);
  508. colorPicker = document.createElement("input");colorPicker.type = "color";colorPicker.value = p.value;colorPicker.id = "color-picker" + p.storageid;
  509. line.appendChild(colorPicker);
  510. div.appendChild(line);
  511. line=document.createElement("div");
  512. textNode = document.createTextNode(needrefresh);
  513. line.appendChild(textNode);
  514. div.appendChild(line);
  515. container.appendChild(div);
  516. //Members only
  517. p=parametersSingle[BLOCK_MEMBERSONLY];
  518. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-weight: bold;font-size:"+this.fontsize+";"+bodersytle);
  519. line=document.createElement("div");
  520. //textNode = document.createTextNode(p.title);
  521. b = document.createElement("b");
  522. b.textContent = p.title;
  523. line.appendChild(b);
  524. //line.appendChild(textNode);
  525. c = document.createElement("input");c.type = "checkbox";c.id = p.storageid;
  526. if((""+p.value).localeCompare("true")==0){c.checked=true;}else{c.checked=false;}
  527. c.onclick = function () {
  528. if(c.checked==false){
  529. p.value="false";//ParametersAgent.setFilerValue(p.storageid,"false");
  530. }else {p.value="true";//ParametersAgent.setFilerValue(p.storageid,"true");
  531. }
  532. filter("from checkbox members only");
  533. };
  534. line.appendChild(c);
  535. div.appendChild(line);
  536. container.appendChild(div);
  537. //no use popup(select keyword)
  538. p=parametersSingle[NOUSELECTTEXTPOPUP];
  539. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-weight: bold;font-size:"+this.fontsize+";"+bodersytle);
  540. line=document.createElement("div");
  541. //textNode = document.createTextNode(p.title);
  542. b = document.createElement("b");
  543. b.textContent = p.title;
  544. line.appendChild(b);
  545. //line.appendChild(textNode);
  546. c = document.createElement("input");c.type = "checkbox";c.id = p.storageid;
  547. if((""+p.value).localeCompare("true")==0){c.checked=true;}else{c.checked=false;}
  548. c.onclick = function () {
  549. if(c.checked==false){
  550. p.value="false";//ParametersAgent.setFilerValue(p.storageid,"false");
  551. }else {p.value="true";//ParametersAgent.setFilerValue(p.storageid,"true");
  552. }
  553. filter("from checkbox no use popup(select keyword)");
  554. };
  555. line.appendChild(c);
  556. div.appendChild(line);
  557. line=document.createElement("div");line.setAttribute("style","font-weight: normal;");
  558. textNode = document.createTextNode(needrefresh);
  559.  
  560. line.appendChild(textNode);
  561. div.appendChild(line);
  562. container.appendChild(div);
  563. //hide comment
  564. p=parametersSingle[HIDE_COMMENT];
  565. div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-weight: bold;font-size:"+this.fontsize+";"+bodersytle);
  566. line=document.createElement("div");
  567. //textNode = document.createTextNode(p.title);
  568. b = document.createElement("b");
  569. b.textContent = p.title;
  570. line.appendChild(b);
  571. //line.appendChild(textNode);
  572. c = document.createElement("input");c.type = "checkbox";c.id = p.storageid;
  573. if((""+p.value).localeCompare("true")==0){c.checked=true;}else{c.checked=false;}
  574. c.onclick = function () {
  575. if(c.checked==false){
  576. p.value="false";//ParametersAgent.setFilerValue(p.storageid,"false");
  577. }else {p.value="true";//ParametersAgent.setFilerValue(p.storageid,"true");
  578. }
  579. filter("from checkbox hide comment");
  580. };
  581. line.appendChild(c);
  582. div.appendChild(line);
  583. container.appendChild(div);
  584.  
  585.  
  586. return container;
  587. }
  588. // generateParametersSingleUIXXXX(container){
  589. // let innerhtml="";
  590. // for(let i=0;i<parametersSingle.length;i++){
  591. // let p=parametersSingle[i];
  592. // if(p.type.localeCompare("boolean")==0){
  593. // let div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  594. // let c=document.createElement("input");c.setAttribute("id",p.storageid);c.setAttribute("type", "checkbox");
  595. // if((""+p.value).localeCompare("true")==0){c.checked=true;}else{c.checked=false;}
  596. // c.onclick = function () {if(!c.checked){
  597. // p.value="false";}else {p.value="true";}
  598. // filter("from checkbox");
  599. // };
  600. // div.innerText=p.title;
  601. // div.appendChild(c);
  602. // container.appendChild(div);
  603. // }else if(p.type.localeCompare("color")==0){
  604. // let div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  605. // innerhtml='<div>'+p.title+':</div><div><input type="text" id="'+p.storageid+'" style="width:150px;">';
  606. // innerhtml+='<input type="color" value="'+p.value+'" id="color-picker'+p.storageid+'"/></div>';
  607. // div.innerHTML=innerhtml;
  608. // container.appendChild(div);
  609. //
  610. // }else{
  611. // let div=document.createElement("div");div.setAttribute("style","vertical-align: top;font-size:"+this.fontsize+";");
  612. // innerhtml='<div>'+p.title+':</div><div><input type="text" id="'+p.storageid+'" style="width:96%;"></div>';
  613. // div.innerHTML=innerhtml;
  614. // container.appendChild(div);
  615. // }
  616. // }
  617. // return container;
  618. // }
  619. generateQuestionLink(container){
  620. let icon='<svg width="30" height="30" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="none" /><text x="50%" y="50%" font-size="50" text-anchor="middle" fill="black" dy=".3em">?</text></svg>';
  621. let div=document.createElement("div");div.setAttribute("style","align:right;vertical-align: bottom;font-size:"+this.fontsize+";cursor: pointer;");
  622. div.onclick = function () {
  623. window.location.href = "https://greatest.deepsurf.us/scripts/500798";
  624. };
  625. //div.innerHTML=icon;
  626. setSVGIcon(div,icon);
  627. container.appendChild(div);
  628. }
  629. saveLocalFile(element,uistring,filename,filetype,style,doBeforeSave){
  630. const date = new Date().toISOString().split('T')[0]
  631. filename=filename+"-"+date+".txt";
  632. let div=document.createElement("span");
  633. //let l=document.createElement("label");l.innerText=uistring+": ";
  634. let b=document.createElement("button");b.setAttribute("style","margin:2px;border: 1px solid #888888;cursor: pointer;"+style);
  635. b.innerText=uistring;
  636. STD.setMouseEnterLeaveBgColor(b,'#e5e5e5','#f0f0f0');
  637. b.onclick = function () {
  638. let s="";
  639. s=doBeforeSave();
  640. ParametersAgent.download(s, filename, filetype);
  641. };
  642. //div.appendChild(l);
  643. div.appendChild(b);
  644. element.appendChild(div);
  645. }
  646. static download(data, filename, type) {
  647. var file = new Blob([data], {type: type});
  648. if (window.navigator.msSaveOrOpenBlob){
  649. window.navigator.msSaveOrOpenBlob(file, filename);
  650. }else {
  651. var a = document.createElement("a"),
  652. url = URL.createObjectURL(file);
  653. a.href = url;
  654. a.download = filename;
  655. document.body.appendChild(a);
  656. console.log(a);
  657. a.click();
  658. setTimeout(function() {
  659. document.body.removeChild(a);
  660. window.URL.revokeObjectURL(url);
  661. }, 0);
  662. }
  663. }
  664. loadLocalFile(element, uistring, style, doAfterLoad) {
  665. // 建立隱藏的 input
  666. let input = document.createElement("input");
  667. input.setAttribute("type", "file");
  668. input.style.display = "none";
  669.  
  670. // 建立自訂按鈕(label 元素)
  671. let button = document.createElement("button");
  672. //button.innerHTML = uistring;
  673. button.innerText=uistring;
  674. button.htmlFor = "jsonFileInput_" + Math.random().toString(36).substring(2); // 避免 ID 重複
  675. input.id = button.htmlFor;
  676.  
  677. // 設定自訂樣式
  678.  
  679. button.setAttribute("style","margin:2px;border: 1px solid #888888;cursor: pointer;"+style);
  680. STD.setMouseEnterLeaveBgColor(button,'#e5e5e5','#f0f0f0');
  681. button.addEventListener("click", () => input.click());
  682. // 處理選檔
  683. input.addEventListener('change', function () {
  684. if (this.files.length === 0) return;
  685. let fr = new FileReader();
  686. fr.onload = function () {
  687. doAfterLoad(fr.result);
  688. };
  689. fr.readAsText(this.files[0]);
  690. });
  691.  
  692. // 加入到指定容器
  693. element.appendChild(button);
  694. element.appendChild(input);
  695. }
  696. loadLocalFile1(element,uistring,style,doAfterLoad){
  697. let b=document.createElement("label");b.setAttribute("style",style);b.innerText=uistring+": ";element.appendChild(b);
  698. b=document.createElement("input");b.setAttribute("style",style);b.setAttribute("type", "file");
  699. b.addEventListener('change', function () {
  700. let fr = new FileReader();
  701. fr.onload = function () {
  702. doAfterLoad(fr.result);
  703. }
  704. fr.readAsText(this.files[0]);
  705. });
  706. element.appendChild(b);
  707. }
  708. doAfterLoadFile(s){
  709. let lines=s.split("\n");
  710. for(let i=0;i<lines.length;i++){
  711. if(lines[i].indexOf!=-1){
  712. let storageid=lines[i].substring(0,lines[i].indexOf(":"));
  713. let value=lines[i].substring(lines[i].indexOf(":")+1,lines[i].length);
  714. for(let j=0;j<parametersArray.length;j++){
  715. let p=parametersArray[j];
  716. if(p.storageid==storageid)p.value=JSON.parse(value);
  717. }
  718. for(let j=0;j<parametersSingle.length;j++){
  719. let p=parametersSingle[j];
  720. if(p.storageid==storageid)p.value=JSON.parse(value);
  721. }
  722. }
  723. }
  724. this.parametersToUi();
  725. this.save_parameters_toStorage();
  726. }
  727. doBeforeSaveFile(){
  728. this.uiToParameters();
  729. let s="";
  730. for(let i=0;i<parametersArray.length;i++){
  731. let p=parametersArray[i];
  732. s+=p.storageid+":"+JSON.stringify(p.value)+"\n";
  733. }
  734. for(let i=0;i<parametersSingle.length;i++){
  735. let p=parametersSingle[i];
  736. s+=p.storageid+":"+JSON.stringify(p.value)+"\n";
  737. }
  738. return s;
  739. }
  740. setColorPickerEvent(){
  741. for(let i=0;i<parametersSingle.length;i++){
  742. let p=parametersSingle[i];
  743. if(p.type.localeCompare("color")==0){
  744. let colorPicker = document.getElementById("color-picker"+p.storageid);
  745. let colortext = document.getElementById(p.storageid);
  746. if(colorPicker!=null&&colortext!=null){
  747. colorPicker.value=p.value;
  748. colorPicker.addEventListener("input", (event)=>{
  749. p.value=event.target.value;
  750. colortext.value=p.value;}, false);
  751. colorPicker.addEventListener("change",(event)=>{
  752. p.value=event.target.value;colortext.value=p.value;
  753. filterDelay(3000);}, false);
  754. }
  755. }
  756. }
  757. }
  758. openParametersUI(dofunc_whenopen){
  759. ParametersAgent.setTAshow(ParametersAgent.currentSelect);
  760. this.setColorPickerEvent();
  761. dofunc_whenopen();
  762. this.load_parameters_fromStorage();
  763. this.parametersToUi();
  764. }
  765. closeParametersUI(dofunc_whenclose){
  766. this.uiToParameters();
  767. this.save_parameters_toStorage();
  768. dofunc_whenclose("from parameter ui button closed");
  769. }
  770. load_parameters_fromStorage(){
  771. for(let i=0;i<parametersArray.length;i++){
  772. let p=parametersArray[i];
  773. p.value=JSON.parse(this.loadLocalStorage(p.storageid,JSON.stringify(p.value)));
  774. }
  775. for(let i=0;i<parametersSingle.length;i++){
  776. let p=parametersSingle[i];
  777. p.value=JSON.parse(this.loadLocalStorage(p.storageid,JSON.stringify(p.value)));
  778. }
  779. }
  780. save_parameters_toStorage(){
  781. for(let i=0;i<parametersArray.length;i++){
  782. let p=parametersArray[i];
  783. this.saveLocalStorage(p.storageid,JSON.stringify(p.value));
  784. }
  785. for(let i=0;i<parametersSingle.length;i++){
  786. let p=parametersSingle[i];
  787. this.saveLocalStorage(p.storageid,JSON.stringify(p.value));
  788. }
  789. }
  790. parametersToUi(){
  791. for(let i=0;i<parametersArray.length;i++){
  792. let p=parametersArray[i];
  793. let ta=document.getElementById(p.storageid);ta.value=p.value.join("\n")+"\n";
  794. let l=ta.value.length;ta.focus();ta.setSelectionRange(l, l);
  795. }
  796. for(let i=0;i<parametersSingle.length;i++){
  797. let p=parametersSingle[i];
  798. //console.log(i+" "+p.storageid+":"+p.value);
  799. document.getElementById(p.storageid).value=p.value;
  800. }
  801. }
  802. uiToParameters(){
  803. for(let i=0;i<parametersArray.length;i++){
  804. let p=parametersArray[i];
  805. p.value=document.getElementById(p.storageid).value.split('\n');
  806. p.value=p.value.filter((str) => str !=="");
  807. }
  808. for(let i=0;i<parametersSingle.length;i++){
  809. let p=parametersSingle[i];
  810. let d=document.getElementById(p.storageid);
  811. if(d.type=="checkbox"){
  812. p.value=d.checked;
  813. }else{
  814. p.value=document.getElementById(p.storageid).value;
  815. }
  816. }
  817. }
  818. static saveLocalStorage1(ls_id,value){
  819. localStorage.setItem(ls_id,value);
  820. }
  821. saveLocalStorage(ls_id,value){
  822. localStorage.setItem(ls_id, value);
  823. }
  824. loadLocalStorage(ls_id,parameter){
  825. if(!localStorage.getItem(ls_id))localStorage.setItem(ls_id, parameter);
  826. return localStorage.getItem(ls_id);
  827. }
  828. saveArrayLocalStorage(ls_id,ary){
  829. localStorage.setItem(ls_id, ary.toString());
  830. }
  831. loadArrayLocalStorage(ls_id,splitmark){
  832. let r=null;
  833. if(!localStorage.getItem(ls_id)){localStorage.setItem(ls_id, "");}
  834. r=localStorage.getItem(ls_id).split(splitmark);
  835. r=r.filter((str) => str !=="");
  836. return r;
  837. }
  838. }
  839. //----------------------------------------------------------------
  840. // STG -----------------------------------------------------------------------------
  841. class STG{ //smallsupo tools - general
  842. constructor(){}
  843. static delayRun(func,miliseconds=3000){setTimeout(function(){func();},miliseconds);}
  844. static COMPARE=0;static INDEXOF=1;static REGX=2;static INDEXOFREVERSE=3;
  845. static isEnglish(text){
  846. return /^[a-z]+$/i.test(text);
  847. }
  848. static stringToRegArray(s,splitmark){
  849. //s = s.replace("\\", "\\\\");
  850. let arr=s.split(splitmark);
  851. for(let i=0;i<arr.length;i++){
  852. arr[i]=new RegExp(arr[i]);
  853. }
  854. return arr;
  855. }
  856. static findInArray(text,ary,mode=this.COMPARE){
  857. let find=false;
  858. if(text==null)return false;
  859. ary.forEach((word) => {
  860. if(mode==this.COMPARE){if (text.localeCompare(word) == 0 ){find=true;}}
  861. else if(mode==this.INDEXOF){if(text.toLowerCase().indexOf(word.toLowerCase()) != -1 ){find=true;}}
  862. else if(mode==this.REGX){
  863. if(this.isEnglish(word)){
  864. if(new RegExp("\\b("+word+")\\b", "gi").test(text)){find=true;}
  865. }else{
  866. if(new RegExp(word,"g").test(text)){find=true;}
  867. }
  868.  
  869. }
  870. else if(mode==this.INDEXOFREVERSE){if(word.toLowerCase().indexOf(text.toLowerCase()) != -1 ){find=true;}}
  871. });
  872. return find;
  873. }
  874. static findInArrayText(text,ary,mode=this.COMPARE){
  875. let find=null;
  876. if(text==null)return null;
  877. ary.forEach((word) => {
  878. if(mode==this.COMPARE){if (text.localeCompare(word) == 0 ){find=word;}}
  879. else if(mode==this.INDEXOF){if(text.toLowerCase().indexOf(word.toLowerCase()) != -1 ){find=word;}}
  880. else if(mode==this.REGX){if(word.test(text)){find=word;}}
  881. else if(mode==this.INDEXOFREVERSE){if(word.toLowerCase().indexOf(text.toLowerCase()) != -1 ){find=word;}}
  882. });
  883. return find;
  884. }
  885. static removeInArray(value,ary,mode=this.COMPARE){
  886. if(mode==this.COMPARE){return ary.filter((str) => str !==value);}
  887. else if(mode==this.INDEXOF){return ary.filter((str) => value.toLowerCase().indexOf(str.toLowerCase()) == -1);}
  888. else if(mode==this.INDEXOFREVERSE){return ary.filter((str) => str.toLowerCase().indexOf(value.toLowerCase()) == -1);}
  889. }
  890. static addRemoveInArray(value,addvalue,ary,mode=this.COMPARE){
  891. if(STG.findInArray(value,ary,mode)){ary=STG.removeInArray(value,ary,mode);}else{ary.push(addvalue);}
  892. return ary;
  893. }
  894. }
  895. //end STG ----------------------------------------------------
  896. //----------------------------------------------------------------
  897. class STD{ //smallsupo tools - dom ui
  898. static DISPLAY_NONE=0;static VISIBILITY_HIDDEN=1;
  899. constructor(){}
  900. static createEL(htmltag,id,style){
  901. let e=document.createElement(htmltag);if(id!=null)e.setAttribute("id",id);if(style!=null)e.setAttribute("style",style);
  902. return e;
  903. }
  904. //--------------------------------------------------------------------------------------------------
  905. static isHiddenEL(element,mode=this.DISPLAY_NONE){
  906. if(mode==this.DISPLAY_NONE){if(element.style.display==="none")return true;else return false;}
  907. else if(mode==this.VISIBILITY_HIDDEN){if(element.style.visibility==="hidden")return true;else return false;}
  908. }
  909. static hiddenEL(element,mode=this.DISPLAY_NONE){
  910. if(mode==this.DISPLAY_NONE){element.style.display="none";}
  911. else if(mode==this.VISIBILITY_HIDDEN){element.style.width="0px";element.style.height="0px";element.style.visibility="hidden";}
  912. }
  913. static visibleEL(element,mode=this.DISPLAY_NONE){
  914. if(mode==this.DISPLAY_NONE){element.style.display="block";}
  915. else if(mode==this.VISIBILITY_HIDDEN){element.style.width="100%";element.style.height="100%";element.style.visibility="visible";}
  916. }
  917. //-------------------------------------------------------------------------------------------------
  918. static eventStopBubbling(e) {
  919. e = window.event || e;if (e.stopPropagation) {e.stopPropagation();} else {e.cancelBubble = true;}
  920. }
  921. static setMouseEnterLeaveBgColor(el,enterColor="#eee",leaveColor="white"){
  922. el.addEventListener("mouseenter", () => {el.style.backgroundColor=enterColor;});
  923. el.addEventListener("mouseleave", () => {el.style.backgroundColor=leaveColor;});
  924. }
  925. static setMouseEnterLeaveColor(el,enterColor="#aaa",leaveColor="#eee"){
  926. el.addEventListener("mouseenter", () => {el.style.color=enterColor;});
  927. el.addEventListener("mouseleave", () => {el.style.color=leaveColor;});
  928. }
  929. //-------------------------------------------------------------------------------------------------
  930. static arrayToTextarea(ary,ta){if(ta!=null){ta.value = ary.join("\n")+"\n";}}
  931. static textareaToArray(ta){
  932. let ary=[];ary=ta.value.split('\n');ary=ary.filter((str) => str !=="");
  933. return ary;
  934. }
  935. static cursor_scrollToBottom(element){
  936. let l=element.value.length;element.focus();element.setSelectionRange(l, l);
  937. }
  938.  
  939. static adjustELnotOutofScreen1(element, container,defaultTranslateX=0) {
  940. const containerRect = container.getBoundingClientRect();
  941. const elementRect = element.getBoundingClientRect();
  942.  
  943. const maxWidth = containerRect.width;
  944. let newWidth = elementRect.width;
  945.  
  946. // 若超過容器寬度,縮小至容器寬度
  947. if (elementRect.width > maxWidth) {
  948. newWidth = maxWidth;
  949. element.style.width = `${newWidth}px`;
  950. }
  951.  
  952. // 計算 element 的新位置(避免超出容器左右)
  953. const offsetLeft = elementRect.left - containerRect.left;
  954. let newLeft = offsetLeft;
  955.  
  956. if (offsetLeft + newWidth > maxWidth) {
  957. newLeft = maxWidth - newWidth;
  958. }
  959. if (newLeft < 0) {
  960. newLeft = 0;
  961. }
  962.  
  963. element.style.position = 'absolute'; // 確保可以調整位置
  964. element.style.left = `${newLeft}px`;
  965. }
  966. static adjustELnotOutofScreen(dome,useParent,defaultTranslateX=0,defaultTranslateY=0){
  967. let body=document.getElementsByTagName('body')[0];
  968. let sx=window.scrollX;let sy=window.scrollY;
  969. if(useParent){
  970. body=dome.parentElement;
  971. sx=0;sy=0;
  972. }
  973. let bodyRect = body.getBoundingClientRect();
  974. let domeRect = dome.getBoundingClientRect();
  975. //out right
  976. if(domeRect.right>bodyRect.right){
  977. //dome.style.transform=`translate(${defaultTranslateX+parseInt(bodyRect.right-domeRect.right)}px,${defaultTranslateY}px)`;
  978. dome.style.left=`${domeRect.left+ sx+defaultTranslateX+parseInt(bodyRect.right-domeRect.right)}px`;
  979. dome.style.top=`${domeRect.top+sy+defaultTranslateY}px`;
  980. }
  981. //out left、top、bottom...
  982. //TBD
  983.  
  984. }
  985. //-------------------------------------------------------------------------------------------------
  986. static getDomNode(root,queryArray){
  987. let node=root;
  988. if(node==null)return node;
  989. if(queryArray.length>0){
  990. node=root.querySelector(queryArray[0]);
  991. for(let i=1;i<queryArray.length;i++){if(node!=null){node=node.querySelector(queryArray[i]);}}
  992. }
  993. return node;
  994. }
  995. static getDomNodes(root,queryArray){
  996. let nodes=null;
  997. let endquery=queryArray.pop();
  998. let node=STD.getDomNode(root,queryArray);
  999. if(node!=null){nodes=node.querySelectorAll(endquery);}
  1000. return nodes;
  1001. }
  1002. static getDomAttribute(root,queryArray,attribute){
  1003. let value=null;let node=this.getDomNode(root,queryArray);
  1004. if(node!=null){if(node.hasAttribute(attribute))value=node.getAttribute(attribute);}
  1005. return value;
  1006. }
  1007. static getDomInnerText(root,queryArray){
  1008. let value=null;let node=this.getDomNode(root,queryArray);
  1009. if(node!=null){value=node.innerText;}
  1010. return value;
  1011. }
  1012. //-------------------------------------------------------------------------------------------------
  1013. static ABSOLUTE_RIGHT=0;static COVERALL=1;
  1014. static setELPosition(el,mode){
  1015. if(mode==STD.ABSOLUTE_RIGHT){
  1016. el.style.position="absolute";
  1017. el.style.left="100%";
  1018. el.style.transform="translateX(-100%)";
  1019. }
  1020. if(mode==STD.COVERALL){
  1021. el.style.position="absolute";
  1022. //el.width="100%";el.height="100%";
  1023. let parentnode=el.parentElement;let rect = parentnode.getBoundingClientRect();
  1024. el.style.width=parseInt(rect.right-rect.left)+"px";
  1025. el.style.height=parseInt(rect.bottom-rect.top)+"px";
  1026. el.style.textAlign="center";
  1027. el.style.left=parentnode.offsetLeft; el.style.top=parentnode.offsetTop;
  1028. }
  1029. }
  1030. //-------special---------------------------------------------------------------------------------------
  1031. static ISCOVER=true;static UNCOVER=false
  1032. static setCoverEL(becoverdEl,uniqueId,show,zindex=999,inner=SVGICON.CLOSERED,bgcolor="transparent"){ //show cover, hind cover
  1033. if(becoverdEl==null)return;
  1034. let id="smallsupo_coverel_id"+uniqueId;
  1035. let temp=becoverdEl.querySelectorAll('span[id="'+id+'"]');
  1036. if(temp.length>1){
  1037. for(let i=1;i<temp.length;i++)temp[i].remove();
  1038. }else if(temp.length==1){
  1039. }else{
  1040. let cover=STD.createEL("span",id,"zindex:"+zindex+";background-color:"+bgcolor+";");
  1041. //cover.style.backgroundColor="blue";
  1042. //cover.innerHTML=SVGICON.getIcon(inner,32,32);
  1043. setSVGIcon(cover,SVGICON.getIcon(inner,32,32));
  1044. becoverdEl.appendChild(cover);
  1045. STD.setELPosition(cover,STD.COVERALL);
  1046. STD.hiddenEL(cover);
  1047. }
  1048. let cover=document.getElementById(id);
  1049. if(cover!=null){
  1050. if(show)STD.visibleEL(cover);
  1051. else STD.hiddenEL(cover);
  1052. }
  1053. }
  1054. }
  1055. //--------------------------------------------------------------
  1056. class SVGICON{
  1057. constructor(){}
  1058. static SETTING='<svg id="i-settings" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="WWWWWW" height="HHHHHH" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M13 2 L13 6 11 7 8 4 4 8 7 11 6 13 2 13 2 19 6 19 7 21 4 24 8 28 11 25 13 26 13 30 19 30 19 26 21 25 24 28 28 24 25 21 26 19 30 19 30 13 26 13 25 11 28 8 24 4 21 7 19 6 19 2 Z" /><circle cx="16" cy="16" r="4" /></svg>';
  1059. static CLOSERED='<svg id="i-close" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="WWWWWW" height="HHHHHH" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"><path d="M2 30 L30 2 M30 30 L2 2" /></svg>';
  1060. static getIcon(icontype,width=32,height=32){
  1061. return icontype.replace("WWWWWW",width).replace("HHHHHH",height);
  1062. }
  1063. }
  1064. //--下拉選單--------------------------------------------------------------
  1065. let currentMenu=null;
  1066. function whenPopup(p){
  1067. if(currentMenu!=null){
  1068. STD.hiddenEL(currentMenu);
  1069. }
  1070. currentMenu=p;
  1071. }
  1072. class SFAC_DropDownMenu{
  1073. //lines[{title:"",func}]
  1074. static IDPRE="smallsupo_dropdown_id";
  1075. static removeUnFIndPopupMenu(containerEL,uniqueId,index){
  1076. let ns=containerEL.querySelectorAll('span[id^="'+SFAC_DropDownMenu.IDPRE+uniqueId+'"]');
  1077. if(ns!=null){
  1078. if(ns.length==1){
  1079. let x=containerEL.querySelector('span[id="'+SFAC_DropDownMenu.IDPRE+uniqueId+index+'"]');
  1080. if(x==null){
  1081. containerEL.removeChild(ns[0]);
  1082. }
  1083. }else{
  1084. for(let i=0;i<ns.length;i++){
  1085. containerEL.removeChild(ns[i]);
  1086. }
  1087. }
  1088. }
  1089. }
  1090. static setPopupMenu(containerEL,uniqueId,items,attributes,positionMode,whenPopup,endPopup,useParent,zindex=999999999){
  1091. if(containerEL==null)return;
  1092. let dropdown_id=SFAC_DropDownMenu.IDPRE+uniqueId;
  1093. let dropdown_button_id="smallsupo_dropdown_button_id"+uniqueId;
  1094. let dropdown_panel_id="smallsupo_dropdown_panel_id"+uniqueId;
  1095. //let temp=containerEL.querySelectorAll('span[id="'+dropdown_id+'"]');
  1096. let temp=document.body.querySelectorAll('span[id="'+dropdown_id+'"]');
  1097. if(temp.length>1){
  1098. for(let i=1;i<temp.length;i++)temp[i].remove();
  1099. }else if(temp.length==1){
  1100. }else{
  1101. let span=STD.createEL("span",dropdown_id,"z-index:"+zindex+";align:left;");
  1102. if(positionMode!=null)STD.setELPosition(span,positionMode);
  1103. let color=parametersSingle[DOT_COLOR_LEAVE].value;
  1104. let button=STD.createEL("button",dropdown_button_id,'color:'+color+';padding:0px 10px 4px 10px;background-color:transparent;border:none;cursor: pointer;');button.innerText="⁝";span.appendChild(button);
  1105. STD.setMouseEnterLeaveColor(button,parametersSingle[DOT_COLOR].value,color);
  1106. let panel=STD.createEL("div",dropdown_panel_id,"display: none;padding:6px;position: absolute;z-index:99999;background-color: #ffffff;box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);transform: translateX(-20px);");
  1107. for(let i=0;i<items.length;i++){
  1108. let item=STD.createEL("div",null,"cursor: pointer;padding:2px;white-space: nowrap;");
  1109. let hightext=items[i].highText(attributes);
  1110. //console.log(":"+items[i].highText(attributes)+":");
  1111. if(hightext.localeCompare('')==0){
  1112. item.textContent=items[i].title(attributes);
  1113.  
  1114. }else{
  1115. let span = document.createElement('span');span.style.color = "#ff0000";
  1116. span.textContent = " "+hightext;
  1117. item.appendChild(document.createTextNode(items[i].title(attributes)));
  1118. item.appendChild(span);
  1119. }
  1120. //item.innerText=items[i].title(attributes);
  1121. STD.setMouseEnterLeaveBgColor(item);
  1122. item.onclick=()=>{
  1123. let panel=document.getElementById(dropdown_panel_id);panel.style.display="none";
  1124. items[i].func(attributes);
  1125. STD.eventStopBubbling(event);
  1126. };
  1127. panel.appendChild(item);
  1128. }
  1129. //span.appendChild(panel);
  1130. document.body.appendChild(panel);
  1131. containerEL.appendChild(span);
  1132. //-------------------------------------------
  1133. button.onclick = ()=> {
  1134. let b=document.getElementById(dropdown_button_id);
  1135. let p=document.getElementById(dropdown_panel_id);
  1136. const rect = b.getBoundingClientRect();
  1137. p.style.left = `${rect.left + window.scrollX}px`;
  1138. p.style.top = `${rect.bottom + window.scrollY}px`;
  1139. if(STD.isHiddenEL(p)){
  1140. whenPopup(p);
  1141. STD.visibleEL(p);STD.adjustELnotOutofScreen(p,useParent,-2);
  1142. }else{
  1143. STD.hiddenEL(p);
  1144. }
  1145. STD.eventStopBubbling(event);
  1146. };
  1147. }
  1148. }
  1149. }
  1150.  
  1151. //----------------------------------------------------------------
  1152. //--- 文字選取popup選單 ---------------------------------------------------------
  1153. let selecttextpopupshow=false;
  1154. class SFAC_SelectTextPopup{
  1155. constructor(){}
  1156. static setPopupEvent(triggerEL,containerEL,lines,uniqueId,whenPopup,endPopup){
  1157. triggerEL.onmouseup = ()=>{
  1158. let selecttext = window.getSelection().toString();//document.execCommand('copy');
  1159. if(selecttext!=null&&selecttext.length>0){
  1160. //window.getSelection().empty();
  1161. let x=event.clientX;let y=event.clientY;
  1162. if(!selecttextpopupshow)SFAC_SelectTextPopup.setPopup(containerEL,x,y,uniqueId,selecttext,lines,whenPopup,endPopup);
  1163. }
  1164. STD.eventStopBubbling(event);
  1165. };
  1166. }
  1167. static setPopup(containerEL,x,y,uniqueId,selecttext,lines,whenPopup,endPopup,useParent=false){
  1168. let container=document.getElementsByTagName('body')[0];if(containerEL!=null)container=containerEL;
  1169. let left=0;if(x!=null)left=x;let top=0;if(y!=null)top=y;
  1170. let popup_id="smallsupo_selecttextpopup_id"+uniqueId;
  1171. let temp=container.querySelectorAll('div[id="'+popup_id+'"]');
  1172. if(temp.length>1){
  1173. for(let i=1;i<temp.length;i++)temp[i].remove();
  1174. }else if(temp.length==1){
  1175. }else{
  1176. let popup=STD.createEL("div",popup_id,'left:'+left+'px;top:'+top+'px;padding:6px;border:1px black;'+
  1177. 'position: fixed;z-index:999999;cursor: pointer;background-color: #ffffff;'+
  1178. 'box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);white-space: nowrap;'+
  1179. '');
  1180. //'transform: translate(-50px, -30px);');
  1181. for(let i=0;i<lines.length;i++){
  1182. let item=STD.createEL("div",popup_id+"_item"+i,"cursor: pointer;padding:2px;white-space: nowrap;");
  1183. STD.setMouseEnterLeaveBgColor(item);
  1184. popup.appendChild(item);
  1185. }
  1186. let item=STD.createEL("div",popup_id+"_item_copy","cursor: pointer;padding:2px;white-space: nowrap;");
  1187. item.innerText=languages[getCurrentLanguageIndex(language)].copytoclipboard;
  1188. STD.setMouseEnterLeaveBgColor(item);
  1189.  
  1190. popup.appendChild(item);
  1191.  
  1192. container.appendChild(popup);
  1193. popup.onmouseleave= (e) => {popup.style.display="none";};
  1194. }
  1195. //-- do --
  1196. let p=document.getElementById(popup_id);
  1197. //whenPopup(p);
  1198. p.style.left=(left-50)+"px";p.style.top=(top-10)+"px";
  1199. p.style.display="block";
  1200. //p.style.transform="translate(-30px,-20px)";
  1201. for(let i=0;i<lines.length;i++){
  1202. let item=document.getElementById(popup_id+"_item"+i);
  1203. //item.innerHTML=lines[i].title+"<font color=#ff0000>"+selecttext+"</font>";
  1204.  
  1205. item.textContent = "";item.appendChild(document.createTextNode(lines[i].title));
  1206. const highlight = document.createElement("font");highlight.color = "#ff0000";
  1207. highlight.textContent = selecttext;item.appendChild(highlight);
  1208.  
  1209. item.onclick = function () {
  1210. p.style.display="none";
  1211. lines[i].func(selecttext);
  1212. };
  1213. }
  1214. let item=document.getElementById(popup_id+"_item_copy");
  1215. item.onclick = function () {
  1216. p.style.display="none";
  1217. navigator.clipboard.writeText(selecttext);
  1218. };
  1219. //STD.visibleEL(p);
  1220. STD.adjustELnotOutofScreen(p,true,-32);
  1221.  
  1222. }
  1223. }
  1224.  
  1225. // end 文字選取popup選單 -------------------------------------------------
  1226. class YoutubeHandler{
  1227. static findNewDayNode(e){
  1228. let nodes=STD.getDomNodes(e,['div[id="content"]','div[id="details"]','div[id="meta"]','ytd-video-meta-block','div[id="metadata"]','div[id="metadata-line"]','span']);
  1229. let node=null;
  1230. if(nodes!=null&&nodes.length>=2)node=nodes[1];
  1231. return node;
  1232. }
  1233. static find_video_channel_id_youtube_homepage(e){
  1234. let id=null;
  1235. let node=STD.getDomNode(e,['div[id="content"]','div[id="details"]','a[id="avatar-link"]']);
  1236. if(node!=null){
  1237. id=node.getAttribute("href");
  1238. if(id!=null){id=id.substring(1,id.length)+"|"+node.getAttribute("title");}
  1239. //console.log(id);
  1240. }
  1241. return id;
  1242. }
  1243. static find_comment_channel_id_youtube_watchpage(e){
  1244. let r=null;let r1=null;
  1245. let as=['div[id="header-author"]','a[id="author-text"]'];
  1246. let as1=['div[id="header-author"]','a[id="author-text"]','span'];
  1247. r=STD.getDomAttribute(e,as,"href");
  1248. r1=STD.getDomInnerText(e,as1);
  1249. //if(r!=null)r=r.replace("/channel/","")+"|"+r.replace("/","");
  1250. if(r!=null){r=r.replace("/channel/","");r=r.replace("/","");}
  1251. return r;
  1252. }
  1253. static get_channel_id_in_comment_replay_watchpage(e,queryArray){
  1254. let id=null;
  1255. let node=STD.getDomNode(e,queryArray);
  1256. if(node!=null){
  1257. //id=node.getAttribute("href");id=id.replace("/channel/","")+"|"+id.replace("/","");
  1258. id=node.getAttribute("href");id=id.replace("/channel/","");id=id.replace("/","");
  1259. }
  1260. return id;
  1261. }
  1262. static find_video_channel_id_watchpage(e){
  1263. let id=null;
  1264. let node=STD.getDomNode(e,['div[id="upload-info"]','div[id="container"]','yt-formatted-string']);
  1265. if(node!=null){
  1266. let temp=node.querySelector('a');
  1267. if(temp!=null)id=temp.getAttribute("href");
  1268. if(id!=null)id=id.substring(1,id.length)+"|"+node.innerText;
  1269. //console.log(id);
  1270. }
  1271. return id;
  1272. }
  1273. static find_video_channel_id_youtube_searchpage(e){
  1274. let id=null;
  1275. let node=STD.getDomNode(e,['div[id="channel-info"]','ytd-channel-name','yt-formatted-string','a']);
  1276. if(node!=null){
  1277. id=node.getAttribute("href");
  1278. if(id!=null){id=id.substring(1,id.length)+"|"+node.innerText;}
  1279. //console.log(id);
  1280. }
  1281. return id;
  1282. }
  1283. static cutid(id){
  1284. let result=id;
  1285. if(id.indexOf("|")!=-1){result=id.substring(0,id.indexOf("|"));}
  1286. return result;
  1287. }
  1288. static setUnlink_HomePage(rootn){
  1289. function handleClick(event) {
  1290. return false;
  1291. }
  1292. let n=STD.getDomNode(rootn,['div[id="content"]','div[id="details"]','div[id="meta"]','h3']);
  1293. if(n!=null)n.style.cursor = "text";
  1294. YoutubeHandler.removeALink(rootn,['div[id="content"]','div[id="details"]','div[id="meta"]','h3','a[id="video-title-link"]']);
  1295. }
  1296. static setUnlinkSearchPage(rootn){
  1297. function handleClick(event) {
  1298. event.preventDefault();
  1299. event.stopPropagation();
  1300. return false;
  1301. }
  1302. let n=STD.getDomNode(rootn,['div[id="dismissible"]','div[class="text-wrapper style-scope ytd-video-renderer"]','div[id="meta"]','h3']);
  1303. if(n!=null)n.style.cursor = "default";
  1304. YoutubeHandler.removeALink(n,['a']);
  1305. }
  1306. static setUnlinkRightSideWatchPage(rootn,queryArray){
  1307. //let n=STD.getDomNode(rootn,queryArray);
  1308. //if(n!=null)n=STD.getDomNode(n,['h3']);
  1309. if(rootn!=null)rootn.style.cursor = "text";
  1310. YoutubeHandler.removeALink(rootn,queryArray);
  1311. }
  1312. static removeALink(rootn,queryArray){
  1313. function handleClick1(event) {
  1314. //event.preventDefault();
  1315. //event.stopPropagation();
  1316. return false;
  1317. }
  1318. let n1=STD.getDomNode(rootn,queryArray);
  1319. if(n1!=null){
  1320. n1.style.display = "inline-block";
  1321. n1.style.pointerEvents = "none";
  1322. n1.onclick=handleClick1;
  1323. }
  1324. }
  1325. static elementSetToDefault(e,newDayNode){
  1326. e.style.display="block";
  1327. e.style.background =null;
  1328. e.style.border = null;
  1329. if(newDayNode!=null){
  1330. newDayNode.style.background =null;
  1331. newDayNode.style.border = null;
  1332. }
  1333. }
  1334. static removeHighLightTag(e,uniqueid){
  1335. let id="smallsupo_"+uniqueid
  1336. let c=document.querySelectorAll('span[id^="'+id+'"]');
  1337. for(let i=0;i<c.length;i++){
  1338. if(e.contains(c[i])){
  1339. e.removeChild(c[i]);
  1340. }
  1341. }
  1342. }
  1343. static setHighLightTag(e,uniqueid,text,show,bordercolor,borderradius){
  1344. let id="smallsupo_"+uniqueid;
  1345. //console.log(id);
  1346. let n=document.getElementById(id);
  1347. if(n==null){
  1348. let x=STD.createEL("span",id,"position:absolute;right:0px;bottom:0px;padding:4px 4px 0px 4px;color:white;background-color:"+bordercolor+";");
  1349. x.style.transform="translateXY(-96%,-96%)";
  1350. x.style.borderRadius=borderradius+" 0px 2px 0px";x.innerText=text;
  1351. e.appendChild(x);
  1352. }else{
  1353. if(show){n.style.display="block";n.innerText=text;
  1354. }else {n.style.display="none";}
  1355. }
  1356. }
  1357. static setHighLightTagforWatchPage(e,uniqueid,text,show,bordercolor,borderradius){
  1358. let id="smallsupo_"+uniqueid;
  1359. //console.log(id);
  1360. let n=document.getElementById(id);
  1361. if(n==null){
  1362. let x=STD.createEL("span",id,"position:relative;left:0px;top:0px;padding:2px 2px 2px 2px;color:white;background-color:"+bordercolor+";");
  1363. //x.style.transform="translateXY(-96%,-96%)";
  1364. x.style.borderRadius="4px 4px 4px 4px";x.innerText=text;
  1365. e.insertBefore(x,e.firstChild);
  1366. }else{
  1367. if(show){n.style.display="block";n.innerText=text;
  1368. }else {n.style.display="none";}
  1369. }
  1370. }
  1371. static findIdInArray(text,ary){
  1372. let find=false;
  1373. if(text==null)return false;
  1374. if(text.indexOf("|")!=-1)text=text.substring(0,text.indexOf("|"));
  1375. ary.forEach((word) => {
  1376. if(word.indexOf("|")!=-1)word=word.substring(0,word.indexOf("|"));
  1377. if (text.localeCompare(word) == 0 ){find=true;}
  1378. });
  1379. return find;
  1380. }
  1381. static findChannelIdareadyhave(idtitle){
  1382. let find=false;
  1383. for(let i=0;i<tempchannelArray.length;i++){
  1384. let cid=tempchannelArray[i];
  1385. if(cid.title==idtitle){
  1386. find=true;
  1387. }
  1388. }
  1389. return find;
  1390. }
  1391. static getChannelId(idtitle){
  1392. let id=null;
  1393. for(let i=0;i<tempchannelArray.length;i++){
  1394. let cid=tempchannelArray[i];
  1395. if(cid.title==idtitle){
  1396. id=cid.id;
  1397. }
  1398. }
  1399. return id;
  1400. }
  1401. static moveChannelcontainerToUPLayer(rootn){
  1402. let dn=rootn.querySelector('div#dismissible div[class="metadata style-scope ytd-compact-video-renderer"]');
  1403. if(dn!=null){
  1404. let sn=dn.querySelector('a').querySelector('div');
  1405. if(sn!=null){
  1406. dn.appendChild(sn);
  1407. //dn.querySelector('a').querySelector('div').inner;
  1408. }
  1409. }
  1410.  
  1411. }
  1412.  
  1413. static getChannelIDformURL(rootn,link,videoid,channelcontainer,channeltitle){
  1414. fetch(link)
  1415. .then(response => response.text())
  1416. .then(data => {
  1417. let serchstartstring='<link itemprop="url" href="http://www.youtube.com/';
  1418. let startindex=data.indexOf(serchstartstring);
  1419. if(startindex<0)return;
  1420. let r=data.substring(startindex+serchstartstring.length,data.indexOf('"',startindex+serchstartstring.length));
  1421.  
  1422. if(channelcontainer==null)return;
  1423. let id=r;
  1424. //console.log(id);
  1425. let o={title:channeltitle,id:id}
  1426. tempchannelArray.push(o);
  1427. id=id+"|"+channeltitle;
  1428. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"runchannel_watch",videoid);
  1429. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"runchannel_watch"+videoid,dropdownitems_homepage,[id,videoid],STD.ABSOLUTE_RIGHT,whenPopup,null,false);
  1430. //moveChannelcontainerToUPLayer(rootn);
  1431. })
  1432. .catch(error => {
  1433. // 處理錯誤情況
  1434. console.error('Error fetching data:', error);
  1435. })
  1436. .finally(() => {
  1437. // 完成時的處理,如果需要
  1438. });
  1439. }
  1440. static drawUI(tag,cid,vid,text,e,arr){
  1441. let keeprun=true;
  1442. for(let i=0;i<arr.length;i++){
  1443. if(keeprun){
  1444. if(arr[i]==HIGHLIGHT_VIDEO&&parametersArray[HIGHLIGHT_VIDEO].filter=="true"){
  1445. if(STG.findInArray(vid,parametersArray[HIGHLIGHT_VIDEO].value,STG.COMPARE)){e.style.background=parametersSingle[HIGHLIGHT_VIDEO_BACKGROUND].value;keeprun=false;}
  1446. }else if(arr[i]==BLOCK_VIDEO&&parametersArray[BLOCK_VIDEO].filter=="true"){
  1447. if(STG.findInArray(vid,parametersArray[BLOCK_VIDEO].value,STG.COMPARE)){STD.hiddenEL(e);keeprun=false;}
  1448. }else if(arr[i]==HIGHLIGHT_VIDEO_KEYWORD&&parametersArray[HIGHLIGHT_VIDEO_KEYWORD].filter=="true"){
  1449. if(STG.findInArray(text,parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value,STG.REGX)){
  1450. let s=STG.findInArrayText(text,parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value,STG.INDEXOF);
  1451. e.style.border = parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].valuep+parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].value;
  1452. e.style.borderRadius =parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC].value+parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC].valuer;
  1453. YoutubeHandler.setHighLightTag(e,tag+vid,s,true,parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].value,e.style.borderRadius);
  1454. keeprun=true;
  1455. }
  1456. }else if(arr[i]==HIGHLIGHT_CHANNEL&&parametersArray[HIGHLIGHT_CHANNEL].filter=="true"){
  1457. if(YoutubeHandler.findIdInArray(cid,parametersArray[HIGHLIGHT_CHANNEL].value)){e.style.background=parametersSingle[HIGHLIGHT_CHANNEL_BACKGROUND].value;keeprun=false;}
  1458. }else if(arr[i]==BLOCK_CHANNEL&&parametersArray[BLOCK_CHANNEL].filter=="true"){
  1459. if(YoutubeHandler.findIdInArray(cid,parametersArray[BLOCK_CHANNEL].value)){STD.hiddenEL(e);keeprun=false;}
  1460. }else if(arr[i]==BLOCK_VIDEO_KEYWORD&&parametersArray[BLOCK_VIDEO_KEYWORD].filter=="true"){
  1461. if(STG.findInArray(text,parametersArray[BLOCK_VIDEO_KEYWORD].value,STG.INDEXOF)){STD.hiddenEL(e);keeprun=false;}
  1462. }
  1463. else if(arr[i]==HIGHLIGHT_COMMENT_USER&&parametersArray[HIGHLIGHT_COMMENT_USER].filter=="true"){
  1464. if(STG.findInArray(cid,parametersArray[HIGHLIGHT_COMMENT_USER].value,STG.COMPARE)){e.style.background=parametersSingle[HIGHLIGHT_COMMENT_USER_BACKGROUND].value;keeprun=false;}
  1465. }else if(arr[i]==BLOCK_COMMENT_USER&&parametersArray[BLOCK_COMMENT_USER].filter=="true"){
  1466. if(YoutubeHandler.findIdInArray(cid,parametersArray[BLOCK_COMMENT_USER].value)){STD.hiddenEL(e);keeprun=false;}
  1467. }else if(arr[i]==BLOCK_COMMENT_KEYWORD&&parametersArray[BLOCK_COMMENT_KEYWORD].filter=="true"){
  1468. //if(STG.findInArray(text,parametersArray[BLOCK_COMMENT_KEYWORD].value,STG.INDEXOF)){STD.hiddenEL(e);}
  1469. if(STG.findInArray(text,parametersArray[BLOCK_COMMENT_KEYWORD].value,STG.REGX)){STD.hiddenEL(e);}
  1470. }
  1471. }
  1472. }
  1473. return keeprun;
  1474. }
  1475. }
  1476. //----------------------------------------------------------------
  1477. function removeClickEvent(){
  1478. window.addEventListener('click', event => {
  1479. //console.log(event.target);
  1480. if (event.target.tagName=="H3") {
  1481. event.stopPropagation();
  1482. //event.preventDefault();
  1483. }
  1484. }, true);
  1485. }
  1486. //---------------------------------------------------------------
  1487. let CHANNELID=0,VIDEOID=1;
  1488. let dropdownitems_homepage_title=['block channel','block video','highlight channel','highlight video'];
  1489. let dropdownitems_homepage=[
  1490. {title:(attributes)=>{return dropdownitems_homepage_title[0]},
  1491. highText:(attributes)=>{return attributes[CHANNELID].split("|")[1]},
  1492. func:(attributes)=>{sp.load_parameters_fromStorage();let value=attributes[CHANNELID];if(value.indexOf("|")!=-1)value=value.substring(0,value.indexOf("|"));
  1493. parametersArray[BLOCK_CHANNEL].value=STG.addRemoveInArray(value,attributes[CHANNELID],parametersArray[BLOCK_CHANNEL].value,STG.INDEXOFREVERSE);
  1494.  
  1495. sp.save_parameters_toStorage();filter("from dropdownmenu_homepage");}},
  1496. {title:(attributes)=>{return dropdownitems_homepage_title[1]},
  1497. highText:(attributes)=>{return ''},
  1498. func:(attributes)=>{sp.load_parameters_fromStorage();parametersArray[BLOCK_VIDEO].value=STG.addRemoveInArray(attributes[VIDEOID],attributes[VIDEOID],parametersArray[BLOCK_VIDEO].value);sp.save_parameters_toStorage();filter("from dropdownmenu_homepage");}},
  1499. {title:(attributes)=>{return dropdownitems_homepage_title[2]},
  1500. highText:(attributes)=>{return ''},
  1501. func:(attributes)=>{sp.load_parameters_fromStorage();let value=attributes[CHANNELID];if(value.indexOf("|")!=-1)value=value.substring(0,value.indexOf("|"));
  1502. parametersArray[HIGHLIGHT_CHANNEL].value=STG.addRemoveInArray(value,attributes[CHANNELID],parametersArray[HIGHLIGHT_CHANNEL].value,STG.INDEXOFREVERSE);
  1503.  
  1504. sp.save_parameters_toStorage();filter("from dropdownmenu_homepage");}},
  1505. {title:(attributes)=>{return dropdownitems_homepage_title[3]},
  1506. highText:(attributes)=>{return ''},
  1507. func:(attributes)=>{sp.load_parameters_fromStorage();parametersArray[HIGHLIGHT_VIDEO].value=STG.addRemoveInArray(attributes[VIDEOID],attributes[VIDEOID],parametersArray[HIGHLIGHT_VIDEO].value);sp.save_parameters_toStorage();filter("from dropdownmenu_homepage");}}
  1508. ];
  1509. let selecttext_popupitems_homepage_title=['block','highlight'];
  1510. let selecttext_popupitems_homepage=[
  1511. {title:selecttext_popupitems_homepage_title[0]+" ",highText:(attributes)=>{''},
  1512. func:(selecttext)=>{sp.load_parameters_fromStorage();parametersArray[BLOCK_VIDEO_KEYWORD].value.push(selecttext.trim());sp.save_parameters_toStorage();filter("from selecttext_popupitems_homepage");}},
  1513. {title:selecttext_popupitems_homepage_title[1]+" ",highText:(attributes)=>{''},
  1514. func:(selecttext)=>{sp.load_parameters_fromStorage();parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value=STG.addRemoveInArray(selecttext.trim(),selecttext.trim(),parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value);sp.save_parameters_toStorage();filter("from selecttext_popupitems_homepage");}}]
  1515. function setLongTitleEvent(c){
  1516. let dh= c.style.maxHeight;
  1517. console.log(":"+dh);
  1518. c.addEventListener('mouseenter', function() {
  1519. c.style.overflow = 'visible';
  1520. c.style.maxHeight= '500px';
  1521. //console.log("mouseenter");
  1522. });
  1523. c.addEventListener('mouseleave', function() {
  1524. c.style.overflow = 'hidden';
  1525. c.style.maxHeight= dh;
  1526. //console.log("mouseleave");
  1527. });
  1528. }
  1529. function filter_homepage_newVersion(){
  1530. let videoPanels=document.querySelectorAll('ytd-rich-item-renderer[class="style-scope ytd-rich-grid-renderer"]');
  1531. for(let i=0;i<videoPanels.length;i++){
  1532. let newDayNode=YoutubeHandler.findNewDayNode(videoPanels[i]);
  1533. YoutubeHandler.elementSetToDefault(videoPanels[i],newDayNode);
  1534.  
  1535. if(videoPanels[i].querySelector('ytd-ad-slot-renderer')!=null){
  1536. STD.hiddenEL(videoPanels[i]);
  1537. }else if((""+parametersSingle[BLOCK_MEMBERSONLY].value).localeCompare("true")==0&&(videoPanels[i].querySelector('div[class*="badge-style-type-members-only"')!=null)){
  1538. STD.hiddenEL(videoPanels[i]);
  1539. }else{
  1540.  
  1541.  
  1542. let id=YoutubeHandler.find_video_channel_id_youtube_homepage(videoPanels[i]);
  1543. let text=null;
  1544. YoutubeHandler.setUnlink_HomePage(videoPanels[i]);
  1545. let videoid=STD.getDomAttribute(videoPanels[i],['div#content div#details div#meta a#video-title-link'],"href");
  1546. if(videoid!=null){
  1547. videoid=videoid.replace("/watch?v=","");
  1548. if(videoid.indexOf("&")!=-1)videoid=videoid.substring(0,videoid.indexOf("&"));
  1549. }
  1550. let channelcontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta ytd-video-meta-block div#metadata div#byline-container']);
  1551. let titlecontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta h3 yt-formatted-string#video-title']);
  1552. if(titlecontainer!=null){
  1553. text=titlecontainer.innerText;
  1554. //setLongTitleEvent(titlecontainer);
  1555. //console.log(":"+titlecontainer.style.webkitLineClamp);
  1556. }
  1557. //-------------------
  1558. let keeprun=false;
  1559. if(id!=null&&videoid!=null&&channelcontainer!=null&&titlecontainer!=null&&text!=null){
  1560. keeprun=true;
  1561. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"",videoid);
  1562. SFAC_DropDownMenu.setPopupMenu(channelcontainer,videoid,dropdownitems_homepage,[id,videoid],STD.ABSOLUTE_RIGHT,whenPopup,null,false);
  1563. let textcontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta']);
  1564. console.log("v:"+parametersSingle[NOUSELECTTEXTPOPUP].value);
  1565. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1566. SFAC_SelectTextPopup.setPopupEvent(textcontainer,null,selecttext_popupitems_homepage,"homepage",whenPopup,null);
  1567. }
  1568. //setLongTitleEvent(textcontainer);
  1569. if(newDayNode!=null&&((""+parametersSingle[HIGHTLIGHT_POSTTIME_TRUE].value).localeCompare("true")==0)){
  1570. let arr = STG.stringToRegArray(parametersSingle[HIGHTLIGHT_POSTTIME_REGX].value,",");
  1571. if(STG.findInArray(newDayNode.innerText,arr,STG.REGX)){
  1572. newDayNode.style.background=parametersSingle[HIGHTLIGHT_POSTTIME_BAKGROUND].value;
  1573. }
  1574. }
  1575. if(keeprun){YoutubeHandler.removeHighLightTag(videoPanels[i],"homehightag_");}
  1576. if(keeprun){
  1577. YoutubeHandler.drawUI("homehightag_",id,videoid,text,videoPanels[i],[HIGHLIGHT_VIDEO,BLOCK_VIDEO,HIGHLIGHT_VIDEO_KEYWORD,HIGHLIGHT_CHANNEL,BLOCK_CHANNEL,BLOCK_VIDEO_KEYWORD]);
  1578. }
  1579. }
  1580. }
  1581. }
  1582. }
  1583. function filter_homepage(){
  1584. let videoPanels=document.querySelectorAll('ytd-rich-item-renderer[class="style-scope ytd-rich-grid-row"]');
  1585. for(let i=0;i<videoPanels.length;i++){
  1586. let newDayNode=YoutubeHandler.findNewDayNode(videoPanels[i]);
  1587. YoutubeHandler.elementSetToDefault(videoPanels[i],newDayNode);
  1588. let id=YoutubeHandler.find_video_channel_id_youtube_homepage(videoPanels[i]);
  1589. let text=null;
  1590. YoutubeHandler.setUnlink_HomePage(videoPanels[i]);
  1591. let videoid=STD.getDomAttribute(videoPanels[i],['div#content div#details div#meta a#video-title-link'],"href");
  1592. if(videoid!=null){
  1593. videoid=videoid.replace("/watch?v=","");
  1594. if(videoid.indexOf("&")!=-1)videoid=videoid.substring(0,videoid.indexOf("&"));
  1595. }
  1596. let channelcontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta ytd-video-meta-block div#metadata div#byline-container']);
  1597. let titlecontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta h3 yt-formatted-string#video-title']);
  1598. if(titlecontainer!=null){text=titlecontainer.innerText;}
  1599. //-------------------
  1600. let keeprun=false;
  1601. if(id!=null&&videoid!=null&&channelcontainer!=null&&titlecontainer!=null&&text!=null){
  1602. keeprun=true;
  1603. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"",videoid);
  1604. SFAC_DropDownMenu.setPopupMenu(channelcontainer,videoid,dropdownitems_homepage,[id,videoid],STD.ABSOLUTE_RIGHT,whenPopup,null,false);
  1605. let textcontainer=STD.getDomNode(videoPanels[i],['div#content div#details div#meta']);
  1606. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1607. SFAC_SelectTextPopup.setPopupEvent(textcontainer,null,selecttext_popupitems_homepage,"homepage",whenPopup,null);
  1608. }
  1609. if(newDayNode!=null&&((""+parametersSingle[HIGHTLIGHT_POSTTIME_TRUE].value).localeCompare("true")==0)){
  1610. let arr = STG.stringToRegArray(parametersSingle[HIGHTLIGHT_POSTTIME_REGX].value,",");
  1611. if(STG.findInArray(newDayNode.innerText,arr,STG.REGX)){
  1612. newDayNode.style.background=parametersSingle[HIGHTLIGHT_POSTTIME_BAKGROUND].value;
  1613. }
  1614. }
  1615. if(keeprun){YoutubeHandler.removeHighLightTag(videoPanels[i],"homehightag_");}
  1616. if(keeprun){
  1617. YoutubeHandler.drawUI("homehightag_",id,videoid,text,videoPanels[i],[HIGHLIGHT_VIDEO,BLOCK_VIDEO,HIGHLIGHT_VIDEO_KEYWORD,HIGHLIGHT_CHANNEL,BLOCK_CHANNEL,BLOCK_VIDEO_KEYWORD]);
  1618. }
  1619. }
  1620. }
  1621. }
  1622. let rowcount=0;
  1623. function getItemRowCount(content){
  1624. if(rowcount==0)rowcount=content.parentElement.children.length;
  1625. return rowcount;
  1626. }
  1627. function filter_homepage_reorder(){
  1628. let videoPanels=document.querySelectorAll('ytd-rich-item-renderer[class="style-scope ytd-rich-grid-row"]');
  1629. if(videoPanels.length==0)return;
  1630. let content=videoPanels[0].parentElement.parentElement.parentElement;
  1631. if(content==null)return;
  1632. //let itemperrow=parseInt(videoPanels[0].getAttribute("items-per-row"));
  1633. let itemperrow=getItemRowCount(videoPanels[0]);//console.log(itemperrow);
  1634.  
  1635. let rows=content.querySelectorAll('ytd-rich-grid-row[class="style-scope ytd-rich-grid-renderer"]');
  1636. //console.log(videoPanels.length, rows.length,videoPanels.length/3);
  1637. //remove all video
  1638. for(let i=0;i<rows.length;i++){
  1639. let container=rows[i].querySelector('div[id="contents"]');
  1640. let c=container.querySelectorAll('ytd-rich-item-renderer[class="style-scope ytd-rich-grid-row"]');
  1641. // console.log(c.length);
  1642. for(let k=0;k<c.length;k++){
  1643. container.removeChild(c[k]);
  1644. }
  1645. }
  1646. //add all video
  1647. let index=0;let counter=0;
  1648. for(let i=0;i<videoPanels.length;i++){
  1649. if(index<rows.length){
  1650. let container=rows[index].querySelector('div[id="contents"]');
  1651. if(videoPanels[i].querySelector('ytd-ad-slot-renderer')!=null){
  1652. //console.log("find ad "+index+" "+i);
  1653. }else{
  1654. container.appendChild(videoPanels[i]);
  1655. if(videoPanels[i].style.display=='none'){}else{counter++;}
  1656. }
  1657. if(counter==itemperrow){index++;counter=0;}
  1658. }
  1659. }
  1660. }
  1661. //---------------------------------------------------------------
  1662. let dropdownitemscomment_watchpage_title=['block user','highlight user'];
  1663. let dropdownitemscomment_watchpage=[
  1664. {title:(attributes)=>{return dropdownitemscomment_watchpage_title[0]},
  1665. highText:(attributes)=>{return attributes[CHANNELID] },
  1666. func:(attributes)=>{sp.load_parameters_fromStorage();let value=attributes[CHANNELID];if(value.indexOf("|")!=-1)value=value.substring(0,value.indexOf("|"));
  1667. parametersArray[BLOCK_COMMENT_USER].value=STG.addRemoveInArray(value,attributes[CHANNELID],parametersArray[BLOCK_COMMENT_USER].value,STG.INDEXOFREVERSE);sp.save_parameters_toStorage();filter("from dropdownitemscomment_watchpage");}},
  1668. {title:(attributes)=>{return dropdownitemscomment_watchpage_title[1]},
  1669. highText:(attributes)=>{return ''},
  1670. func:(attributes)=>{sp.load_parameters_fromStorage();let value=attributes[CHANNELID];if(value.indexOf("|")!=-1)value=value.substring(0,value.indexOf("|"));
  1671. parametersArray[HIGHLIGHT_COMMENT_USER].value=STG.addRemoveInArray(value,attributes[CHANNELID],parametersArray[HIGHLIGHT_COMMENT_USER].value,STG.INDEXOFREVERSE);sp.save_parameters_toStorage();filter("from dropdownitemscomment_watchpage");}}
  1672. ];
  1673. let selecttext_popupitems_comment_watchpage_title=['block'];
  1674. let selecttext_popupitems_comment_watchpage=[{title:selecttext_popupitems_comment_watchpage_title[0]+" ",
  1675. func:(selecttext)=>{sp.load_parameters_fromStorage();parametersArray[BLOCK_COMMENT_KEYWORD].value.push(selecttext.trim());sp.save_parameters_toStorage();filter("from selecttext_popupitems_comment_watchpage");}}]
  1676. function filter_watchpage(){
  1677. let commentPanels=document.querySelectorAll('ytd-comment-thread-renderer[class="style-scope ytd-item-section-renderer"]');
  1678. let index=0;
  1679. for(let i=0;i<commentPanels.length;i++){
  1680. YoutubeHandler.elementSetToDefault(commentPanels[i]);
  1681. let id=YoutubeHandler.find_comment_channel_id_youtube_watchpage(commentPanels[i]);
  1682. let text=STD.getDomInnerText(commentPanels[i],['div[id="content"]','yt-attributed-string[id="content-text"]']);
  1683. let channelcontainer=STD.getDomNode(commentPanels[i],['div[id="header-author"]']);
  1684. let commentcontainer=STD.getDomNode(commentPanels[i],['div[id="content"]']);
  1685. let keeprun=false;
  1686. if(id!=null&&text!=null&&channelcontainer!=null&&commentcontainer!=null){
  1687. let cc=STD.getDomNode(commentPanels[i],['div[id="header-author"]']);
  1688. SFAC_DropDownMenu.removeUnFIndPopupMenu(cc,"comment",YoutubeHandler.cutid(id)+index);
  1689. SFAC_DropDownMenu.setPopupMenu(cc,"comment"+YoutubeHandler.cutid(id)+index,dropdownitemscomment_watchpage,[id],null,whenPopup,null,false);
  1690. //setDropdownMenuComment(cc,id,index,commentPanels[i]);
  1691. index+=1;
  1692. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1693. SFAC_SelectTextPopup.setPopupEvent(commentcontainer,null,selecttext_popupitems_comment_watchpage,"watchpage",whenPopup,null);
  1694. }
  1695. keeprun=true;
  1696. keeprun=YoutubeHandler.drawUI("",id,null,text,commentPanels[i],[HIGHLIGHT_COMMENT_USER,BLOCK_COMMENT_USER,BLOCK_COMMENT_KEYWORD]);
  1697. if(keeprun){
  1698. index=filter_comment_replay_watchpage(commentPanels[i],index,false);
  1699. }
  1700. }
  1701. }
  1702. if((""+parametersSingle[HIDE_COMMENT].value).localeCompare("true")==0){
  1703. hidden_comment_watchpage();
  1704. }else{
  1705. let hiddennode=document.getElementById("smallsupo_hiddennode");
  1706. if(hiddennode!=null)hiddennode.remove();
  1707. let comment=document.getElementById("sections");if(comment!=null)comment.style.display="block";
  1708. }
  1709. //right side video
  1710. //filter_rightside_video_watchpage();
  1711. //video self
  1712. //filter_videoself_watchpage();
  1713. }
  1714. function hidden_comment_watchpage(){
  1715. let p=document.querySelector('ytd-comments[id="comments"]');
  1716. if(p==null)return;
  1717. let hiddennode=document.getElementById("smallsupo_hiddennode");
  1718. if(hiddennode==null){
  1719. let hiddennode=STD.createEL("div","smallsupo_hiddennode",'cursor: pointer;');
  1720. let index=getCurrentLanguageIndex(language);
  1721. hiddennode.innerText=languages[index].show+"/"+languages[index].hide+" "+languages[index].comment;
  1722. p.insertBefore(hiddennode, p.children[1]);
  1723. let comment=document.getElementById("sections");comment.style.display="none";
  1724. }else{
  1725. hiddennode.onclick=(evnt)=>{
  1726. let commentnode=document.getElementById("sections");
  1727. //console.log("hi"+comment);
  1728. if(commentnode!=null){
  1729. if(commentnode.style.display=="none"){commentnode.style.display="block";}else{
  1730. commentnode.style.display="none";
  1731. }
  1732. }
  1733. };
  1734. }
  1735. }
  1736. function filter_comment_replay_watchpage(comment,index){
  1737. let replies=comment.querySelector('div[id="replies"]').querySelectorAll('ytd-comment-view-model');
  1738. //console.log(replies.length);
  1739. for(let i=0;i<replies.length;i++){
  1740. YoutubeHandler.elementSetToDefault(replies[i]);
  1741. let id=YoutubeHandler.get_channel_id_in_comment_replay_watchpage(replies[i],['div[id="header-author"]','a[id="author-text"]']);
  1742. let text=STD.getDomInnerText(replies[i],['div[id="content"]','yt-attributed-string[id="content-text"]']);
  1743. //console.log(text);
  1744. let channelcontainer=STD.getDomNode(replies[i],['div[id="header-author"]']);//,'a[id="author-text"]','yt-formatted-string']);
  1745. let commentcontainer=STD.getDomNode(replies[i],['div[id="content"]','yt-attributed-string[id="content-text"]']);
  1746. if(id!=null&&channelcontainer!=null){
  1747. //console.log(id," ",cutid(id));
  1748. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"comment",YoutubeHandler.cutid(id)+index);
  1749. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"comment"+YoutubeHandler.cutid(id)+index,dropdownitemscomment_watchpage,[id],null,whenPopup,null,false);
  1750. index+=1;
  1751. }
  1752. if(commentcontainer!=null){
  1753. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1754. SFAC_SelectTextPopup.setPopupEvent(commentcontainer,null,selecttext_popupitems_comment_watchpage,"watchpage",whenPopup,null);
  1755. }
  1756. }
  1757. let keeprun=true;
  1758. YoutubeHandler.drawUI("",id,null,text,replies[i],[HIGHLIGHT_COMMENT_USER,BLOCK_COMMENT_USER,BLOCK_COMMENT_KEYWORD]);
  1759. }
  1760. return index;
  1761. }
  1762. function filter_rightside_video_watchpage(){
  1763. //console.log("run filter_rightside_video_watchpage");
  1764. let m=document;
  1765. // let m=document.querySelector('#secondary div#items');
  1766. // if(m==null){console.log("m error");return;}
  1767. let videoP=m.querySelectorAll('ytd-compact-video-renderer');
  1768. for(let i=0;i<videoP.length;i++){
  1769. YoutubeHandler.elementSetToDefault(videoP[i]);
  1770. let tc=STD.getDomNode(videoP[i],['div[class="details style-scope ytd-compact-video-renderer"]','h3','span[id="video-title"]']);
  1771. let text=null;
  1772. let id=null;
  1773. let videoid=videoP[i].querySelector('#thumbnail').getAttribute("href");
  1774. videoid=videoid.replace("/watch?v=","");if(videoid.indexOf("&")!=-1){videoid.substring(0,videoid.indexOf("&"));}
  1775. let videourl="https://www.youtube.com/watch?v="+videoid;
  1776. let channelcontainer=videoP[i].querySelector('div#dismissible div#metadata div#byline-container');
  1777. let channeltitle=channelcontainer.querySelector('div#container yt-formatted-string').getAttribute("title");
  1778. //if(i==0){
  1779. if(YoutubeHandler.findChannelIdareadyhave(channeltitle)){
  1780. id=YoutubeHandler.getChannelId(channeltitle);
  1781. //console.log(channeltitle,"aready has",id);
  1782. id=id+"|"+channeltitle;
  1783. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"runchannel_watch",videoid);
  1784. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"runchannel_watch"+videoid,dropdownitems_homepage,[id,videoid],STD.ABSOLUTE_RIGHT,whenPopup,null,false);
  1785.  
  1786. YoutubeHandler.moveChannelcontainerToUPLayer(videoP[i]);
  1787. }else{
  1788. YoutubeHandler.getChannelIDformURL(videoid[i],videourl,videoid,channelcontainer,channeltitle);
  1789. }
  1790. //}
  1791. let keeprun=false;
  1792. if(tc!=null){
  1793. text=tc.innerText;
  1794. YoutubeHandler.setUnlinkRightSideWatchPage(videoP[i],['div[class="details style-scope ytd-compact-video-renderer"]','a']);
  1795. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1796. SFAC_SelectTextPopup.setPopupEvent(STD.getDomNode(videoP[i],['div[class="details style-scope ytd-compact-video-renderer"]'])
  1797. ,null,selecttext_popupitems_homepage,"runchannel_watch",whenPopup,null);
  1798. }
  1799. keeprun=true;
  1800. }
  1801. if(keeprun){YoutubeHandler.removeHighLightTag(videoP[i],"videohightag_");}
  1802. if(keeprun){
  1803. YoutubeHandler.drawUI("videohightag_",id,videoid,text,videoP[i],[HIGHLIGHT_VIDEO,BLOCK_VIDEO,HIGHLIGHT_VIDEO_KEYWORD,HIGHLIGHT_CHANNEL,BLOCK_CHANNEL,BLOCK_VIDEO_KEYWORD]);
  1804. }
  1805. }
  1806. }
  1807.  
  1808. function filter_videoself_watchpage(){
  1809. let r=document.querySelector('div[id="columns"]');
  1810. if (r==null)return;
  1811. let id=null;
  1812. let videoid=STD.getDomAttribute(r,['div[id="primary"]','div[id="below"]','ytd-watch-metadata'],"video-id");
  1813. let videocontainer=STD.getDomNode(r,['div[id="primary"]','div[id="below"]','ytd-watch-metadata','div[id="above-the-fold"]','div[id="title"]']);
  1814. let titlecontainer=STD.getDomNode(videocontainer,['h1']);
  1815. let channelcontainer=STD.getDomNode(r,['div[id="primary"]','div[id="below"]','div[id="above-the-fold"]','div[id="top-row"]','ytd-video-owner-renderer']);
  1816. let coveredEL=null;if(channelcontainer!=null)coveredEL=STD.getDomNode(channelcontainer,['div[id="upload-info"]']);
  1817. let text=null;
  1818. if(channelcontainer!=null&&coveredEL!=null&&videoid!=null&&channelcontainer!=null){
  1819. channelcontainer.style.background=null;
  1820. STD.setCoverEL(coveredEL,"channel",STD.UNCOVER);
  1821. STD.setCoverEL(videocontainer,"video",STD.UNCOVER);
  1822. id=YoutubeHandler.find_video_channel_id_watchpage(channelcontainer);
  1823. }
  1824. if(titlecontainer!=null){YoutubeHandler.removeHighLightTag(titlecontainer,"watchhightag_");}
  1825. let keeprun=false;
  1826. if(id!=null&&channelcontainer!=null){
  1827. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"runchannelw",id);
  1828. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"runchannelw"+id,dropdownitems_homepage,[id,videoid],null,whenPopup,null,false);
  1829. //setDropdownMenuVideoWatchPage(channelcontainer,id,"watchpage",channelcontainer);
  1830. if(videocontainer!=null){
  1831. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1832. SFAC_SelectTextPopup.setPopupEvent(videocontainer,null,selecttext_popupitems_homepage,"runchannelw",whenPopup,null);
  1833. }
  1834. //text=STD.getDomInnerText(videocontainer,['div[id="title"]','yt-formatted-string']);
  1835. text=videocontainer.innerText;
  1836. }
  1837. keeprun=true;
  1838. }
  1839.  
  1840. if(keeprun){
  1841. if(YoutubeHandler.findIdInArray(id,parametersArray[HIGHLIGHT_CHANNEL].value)&&parametersArray[HIGHLIGHT_CHANNEL].filter=="true"){
  1842. channelcontainer.style.background=parametersSingle[HIGHLIGHT_CHANNEL_BACKGROUND].value;
  1843. //keeprun=false;
  1844. }
  1845. }
  1846. if(keeprun){
  1847. if(YoutubeHandler.findIdInArray(id,parametersArray[BLOCK_CHANNEL].value)&&parametersArray[BLOCK_CHANNEL].filter=="true"){
  1848. STD.setCoverEL(coveredEL,"channel",STD.ISCOVER);
  1849. //keeprun=false;
  1850. }
  1851. }
  1852. if(keeprun){
  1853. videocontainer.style.background=null;
  1854. if(STG.findInArray(videoid,parametersArray[HIGHLIGHT_VIDEO].value,STG.INDEXOF)&&parametersArray[HIGHLIGHT_VIDEO].filter=="true"){
  1855. videocontainer.style.background=parametersSingle[HIGHLIGHT_VIDEO_BACKGROUND].value;
  1856. //keeprun=false;
  1857. }
  1858. }
  1859. if(keeprun){
  1860. if(STG.findInArray(videoid,parametersArray[BLOCK_VIDEO].value,STG.INDEXOF)&&parametersArray[BLOCK_VIDEO].filter=="true"){
  1861. STD.setCoverEL(videocontainer,"video",STD.ISCOVER);
  1862. //keeprun=false;
  1863. }
  1864. }
  1865. if(keeprun){
  1866. if(parametersArray[HIGHLIGHT_VIDEO_KEYWORD].filter=="true"){
  1867. if(STG.findInArray(text,parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value,STG.REGX)){
  1868. let s=STG.findInArrayText(text,parametersArray[HIGHLIGHT_VIDEO_KEYWORD].value,STG.INDEXOF);
  1869. //videocontainer.style.border = parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].valuep+parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].value;
  1870. videocontainer.style.borderRadius =parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC].value+parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC].valuer;
  1871. if(titlecontainer!=null){
  1872. YoutubeHandler.setHighLightTagforWatchPage(titlecontainer,"watchhightag_"+videoid,s,true,parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].value,videocontainer.style.borderRadius);
  1873. }
  1874. }
  1875. }
  1876. }
  1877. }
  1878. //---------------------------------------------------------
  1879. function filter_searchpage(){
  1880. let videoPanels=document.querySelectorAll('ytd-video-renderer');
  1881. //console.log("l:"+videoPanels.length);
  1882. for(let i=0;i<videoPanels.length;i++){
  1883. //let newDayNode=findNewDayNode(videoPanels[i]);
  1884. YoutubeHandler.elementSetToDefault(videoPanels[i],null);
  1885. let id=YoutubeHandler.find_video_channel_id_youtube_searchpage(videoPanels[i]);
  1886. let text=null;
  1887.  
  1888. YoutubeHandler.setUnlinkSearchPage(videoPanels[i]);
  1889.  
  1890. let videoid=STD.getDomAttribute(videoPanels[i],['div[id="dismissible"]','ytd-thumbnail','a'],"href");
  1891. if(videoid!=null){
  1892. videoid=videoid.replace("/watch?v=","");
  1893. if(videoid.indexOf("&")!=-1)videoid=videoid.substring(0,videoid.indexOf("&"));
  1894. //console.log(videoid);
  1895. }
  1896.  
  1897. let channelcontainer=STD.getDomNode(videoPanels[i],['div[id="channel-info"]']);
  1898. //console.log(id,videoid);)
  1899. let titlecontainer=STD.getDomNode(videoPanels[i],['div[id="dismissible"]','div[class="text-wrapper style-scope ytd-video-renderer"]','div[id="meta"]','h3']);
  1900. if(titlecontainer!=null){text=titlecontainer.innerText;}
  1901. let keeprun=false;
  1902. //console.log(""+id+","+videoid+","+channelcontainer+","+titlecontainer+","+text);
  1903. if(id!=null&&videoid!=null&&channelcontainer!=null&&titlecontainer!=null&&text!=null){
  1904. keeprun=true;
  1905. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"research",videoid);
  1906. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"research"+videoid,dropdownitems_homepage,[id,videoid],STD.ABSOLUTE_RIGHT,whenPopup,null,false);
  1907. // let textcontainer=STD.getDomNode(videoPanels[i],['div[id="content"]','div[id="details"]','div[id="meta"]']);
  1908. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1909. SFAC_SelectTextPopup.setPopupEvent(titlecontainer,null,selecttext_popupitems_homepage,"researchpage",whenPopup,null);
  1910. }
  1911. }
  1912. if(keeprun){ YoutubeHandler.removeHighLightTag(videoPanels[i],"searchhightag_");}
  1913. if(keeprun){
  1914. YoutubeHandler.drawUI("searchhightag_",id,videoid,text,videoPanels[i],[HIGHLIGHT_VIDEO,BLOCK_VIDEO,HIGHLIGHT_VIDEO_KEYWORD,HIGHLIGHT_CHANNEL,BLOCK_CHANNEL,BLOCK_VIDEO_KEYWORD]);
  1915. }
  1916. }
  1917. }
  1918. //---------------------------------------------------------
  1919. function filter_shortpageNewVersion(){
  1920. let root=document.querySelector('div#anchored-panel');
  1921. let comments=root.querySelectorAll('ytd-comment-thread-renderer');
  1922. for(let i=0;i<comments.length;i++){
  1923. let c=comments[i].querySelector('ytd-comment-view-model');
  1924. let usercontainer=STD.getDomNode(c,['#header-author']);
  1925.  
  1926. }
  1927. }
  1928. function filter_shortpage(){
  1929. let noshortad=true;
  1930. let root=document.querySelector('div[id="shorts-inner-container"]');
  1931. let comments=root.querySelectorAll('ytd-reel-video-renderer[class="reel-video-in-sequence style-scope ytd-shorts"]');
  1932. let index=0;
  1933. let currentindex=-1;
  1934. for(let i=0;i<comments.length;i++){
  1935. //YoutubeHandler.elementSetToDefault(comments[i]);
  1936. let videolink=STD.getDomAttribute(comments[i],['a[class="ytp-title-link yt-uix-sessionlink"]'],"href");
  1937. //console.log("link "+i+":"+videolink);
  1938. if(videolink!=null&&videolink.localeCompare(window.location.href)==0){
  1939. currentindex=i;
  1940. }
  1941. if(noshortad){
  1942. let ad=null;
  1943. ad=comments[i].querySelector('ytd-ad-slot-renderer');
  1944. if(ad!=null){
  1945. root.removeChild(comments[i]);
  1946. continue;
  1947. }
  1948. }
  1949.  
  1950. }
  1951. //console.log("match:"+currentindex);
  1952. // if(currentindex==-1)return;
  1953. //----
  1954. // let commentPanels=comments[currentindex].querySelectorAll('ytd-comment-thread-renderer[class="style-scope ytd-item-section-renderer"]');
  1955. // //chrome/firefoix browser paths is diffrenet
  1956. // if(commentPanels.length==0){
  1957. // root=document.querySelector('div[id="shorts-panel-container"]');
  1958. // commentPanels=root.querySelectorAll('ytd-comment-thread-renderer[class="style-scope ytd-item-section-renderer"]');
  1959. // }
  1960.  
  1961. let commentPanels=document.querySelector('div#anchored-panel').querySelectorAll('ytd-comment-thread-renderer');
  1962. //console.log(commentPanels.length);
  1963. for(let i=0;i<commentPanels.length;i++){
  1964. YoutubeHandler.elementSetToDefault(commentPanels[i]);
  1965. let usercontainer=STD.getDomNode(commentPanels[i],['#header-author']);
  1966. let userid=STD.getDomAttribute(usercontainer,['h3','a'],"href");
  1967. if(userid!=null){userid=userid.replace("/","");}
  1968. let commentcontainer=commentPanels[i].querySelector("#content");
  1969. let comment=STD.getDomInnerText(commentcontainer,["#content-text > span"]);
  1970. let keeprun=false;
  1971. //console.log(usercontainer);
  1972. //console.log(userid);
  1973. //console.log(commentcontainer);
  1974. //console.log(comment);
  1975. if(userid!=null&&comment!=null&&usercontainer!=null&&commentcontainer!=null){
  1976. SFAC_DropDownMenu.removeUnFIndPopupMenu(usercontainer,"short",YoutubeHandler.cutid(userid)+i);
  1977. SFAC_DropDownMenu.setPopupMenu(usercontainer,"short"+YoutubeHandler.cutid(userid)+i,dropdownitemscomment_watchpage,[userid],null,whenPopup,null,false);
  1978. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  1979. SFAC_SelectTextPopup.setPopupEvent(commentcontainer,null,selecttext_popupitems_comment_watchpage,"short",whenPopup,null);
  1980. }
  1981. keeprun=true;
  1982. }
  1983. if(keeprun){
  1984. keeprun=YoutubeHandler.drawUI("",userid,null,comment,commentPanels[i],[HIGHLIGHT_COMMENT_USER,BLOCK_COMMENT_USER,BLOCK_COMMENT_KEYWORD]);
  1985. }
  1986. if(keeprun){
  1987. filter_short_reply(commentPanels[i],i);
  1988. }
  1989.  
  1990. }// end for(let i=0;i<commentPanels.length;i++)
  1991.  
  1992. }//end filter_shortpage
  1993. function filter_short_reply(comment,index){
  1994. let replies=comment.querySelector('div[id="replies"]').querySelectorAll('ytd-comment-view-model');
  1995. //let replies=comment.querySelector('#anchored-panel').querySelectorAll('ytd-comment-view-model');
  1996. //chrome/firefoix browser paths is diffrenet
  1997. if(replies.length==0){
  1998.  
  1999. }
  2000. for(let i=0;i<replies.length;i++){
  2001. YoutubeHandler.elementSetToDefault(replies[i]);
  2002. let id=STD.getDomAttribute(replies[i],['div[id="header-author"]','a[id="author-text"]'],"href");
  2003. id=id+"|"+id.replace("/","");
  2004. let text=STD.getDomInnerText(replies[i],['div[id="content"]','yt-attributed-string[id="content-text"]']);
  2005. //console.log(text);
  2006. let channelcontainer=STD.getDomNode(replies[i],['div[id="header-author"]']);//,'a[id="author-text"]','yt-formatted-string']);
  2007. let commentcontainer=STD.getDomNode(replies[i],['div[id="content"]','yt-attributed-string[id="content-text"]']);
  2008. if(id!=null&&channelcontainer!=null){
  2009. //console.log(id," ",cutid(id));
  2010. SFAC_DropDownMenu.removeUnFIndPopupMenu(channelcontainer,"shortreply",YoutubeHandler.cutid(id)+index+i);
  2011. SFAC_DropDownMenu.setPopupMenu(channelcontainer,"shortreply"+YoutubeHandler.cutid(id)+index+i,dropdownitemscomment_watchpage,[id],null,whenPopup,null,false);
  2012. //setDropdownMenuComment(commentcontainer,id,index,replies[i]);
  2013. index+=1;
  2014. }
  2015. if(commentcontainer!=null){
  2016. if((""+parametersSingle[NOUSELECTTEXTPOPUP].value).localeCompare("false")==0){
  2017. SFAC_SelectTextPopup.setPopupEvent(commentcontainer,null,selecttext_popupitems_comment_watchpage,"shortreply",whenPopup,null);
  2018. }
  2019. }
  2020. let keeprun=true;
  2021. if(keeprun){
  2022. YoutubeHandler.drawUI("",id,null,text,replies[i],[HIGHLIGHT_COMMENT_USER,BLOCK_COMMENT_USER,BLOCK_COMMENT_KEYWORD]);
  2023. }
  2024. }
  2025. }//end filter_short_reply(commetPanels,index)
  2026. //------------------------------------------------------------------------------------------------------------------
  2027. let is_observer=false;let page_observer=null;
  2028.  
  2029. let isfiltering=false;
  2030. function detectYoutubeVersion(){
  2031. let newV=false;
  2032. let videoPanels=document.querySelectorAll('ytd-rich-item-renderer[class="style-scope ytd-rich-grid-row"]');
  2033. if(videoPanels.length==0)newV=true;
  2034. return newV;
  2035. }
  2036. //--------------------------------------
  2037. function waitForElementObserver(selector, functionX) {
  2038. const observer = new MutationObserver(() => {
  2039. const element = document.querySelector(selector);
  2040. if (element) {
  2041. observer.disconnect(); // 停止觀察
  2042. //console.log("hi");
  2043. functionX(element); // ✅ 把找到的 element 傳入 functionX
  2044. }
  2045. });
  2046.  
  2047. observer.observe(document.body, {
  2048. childList: true,
  2049. subtree: true,
  2050. });
  2051.  
  2052. // ✅ 若元素一開始就已存在,也直接觸發
  2053. const existing = document.querySelector(selector);
  2054. if (existing) {
  2055. observer.disconnect();
  2056. functionX(existing);
  2057. }
  2058. }
  2059. //--------------------------------------
  2060. let checkeffcient=false;
  2061. async function filter(from){
  2062. console.log("filter-run..."+from);
  2063. stop_page_observer();
  2064. stop_rightChannel_observer();
  2065. let url=window.location.href;
  2066. if(url.localeCompare("https://www.youtube.com/")==0){
  2067. //start_page_observer(document.querySelector('ytd-rich-grid-renderer'));
  2068. waitForElementObserver('ytd-rich-grid-renderer',async (dom) => {
  2069. if(checkeffcient)console.log("home");
  2070. rowcount=0;
  2071. if(detectYoutubeVersion()==true){
  2072. await delay(0);
  2073. filter_homepage_newVersion();
  2074. }else{
  2075. await delay(0);
  2076. filter_homepage();
  2077. await delay(0);
  2078. filter_homepage_reorder();
  2079. }
  2080. await delay(0);
  2081. removeClickEvent();
  2082. start_page_observer(dom);
  2083. });
  2084. }else if(/youtube.com\/watch/.test(url)){
  2085. if(checkeffcient)console.log("watch");
  2086. await delay(0);filter_watchpage();
  2087. await delay(0);filter_rightside_video_watchpage();
  2088. await delay(0);
  2089. waitForElementObserver('#above-the-fold',filter_videoself_watchpage);
  2090. waitForElementObserver('#comments',async(dom) => {start_page_observer(dom,200);});
  2091. waitForElementObserver('#secondary #secondary-inner #related #items',async (dom) => {start_rightChannel_observer(dom,500);});
  2092. }else if(/youtube.com\/results/.test(url)){
  2093. if(checkeffcient)console.log("results");
  2094. waitForElementObserver('#primary>ytd-section-list-renderer',(dom) => {
  2095. setTimeout(()=>{filter_searchpage();removeClickEvent();start_page_observer(dom)});}, 2000);
  2096. }else if(/youtube.com\/shorts/.test(url)){
  2097.  
  2098. if(checkeffcient)console.log("shorts");
  2099. waitForElementObserver('#anchored-panel',async (dom) => {await delay(0);filter_shortpage();await delay(0);start_page_observer(dom,200)});
  2100. }
  2101. isfiltering=false;
  2102. }
  2103. function delay(ms) {
  2104. return new Promise(resolve => setTimeout(resolve, ms));
  2105. }
  2106. let pre=0;let filtertimer;
  2107. function stop_page_observer(){
  2108. is_observer=false;
  2109. //if(debug)console.log("stop_page_observer");
  2110. if(page_observer!=null){page_observer.disconnect();page_observer=null;}
  2111.  
  2112. }
  2113.  
  2114.  
  2115. function debounceFilter(fn, delay) {
  2116. return function (...args) {
  2117. clearTimeout(filtertimer);
  2118. filtertimer = setTimeout(() => {
  2119. fn.apply(this, args);
  2120. }, delay);
  2121. };
  2122. }
  2123.  
  2124. const debouncedFilter = debounceFilter((from) => {
  2125. if (!isfiltering) {
  2126. isfiltering = true;
  2127. filter(from);
  2128. }
  2129. }, 500);
  2130.  
  2131. function filterDelaydeBounced(milis) {
  2132. const now = new Date();
  2133. if (now - pre > milis) {
  2134. debouncedFilter("filterDelay:" + milis / 1000);
  2135. pre = now;
  2136. }
  2137. }
  2138. function filterDelay(milis){
  2139. let now= new Date();
  2140. if(now-pre>milis){
  2141. clearTimeout(filtertimer);
  2142. filtertimer=setTimeout(()=>{
  2143. if(isfiltering!=true){isfiltering=true;filter("filterDelay:"+milis/1000);}pre=now;}, 500);
  2144. }
  2145. }
  2146. function start_page_observer(dome,delay=3000){
  2147. is_observer=true;
  2148. if(dome==null){dome=document.getElementsByTagName('body')[0];}
  2149. //if(debug)console.log("start_page_observer");
  2150. if(page_observer==null){
  2151. page_observer = new MutationObserver(mutationRecords => {filterDelay(delay);});
  2152. page_observer.observe(dome, {
  2153. attributes:false,childList: true,characterData:false,attributeOldValue:false,
  2154. subtree: true,characterDataOldValue: false});
  2155. }
  2156. }
  2157. let watchpage_rightchannel_observer=null;
  2158. function stop_rightChannel_observer(){
  2159. //console.log("stop_rightChannel_observer");
  2160. is_observer=false;
  2161. if(watchpage_rightchannel_observer!=null){watchpage_rightchannel_observer.disconnect();watchpage_rightchannel_observer=null;}
  2162. }
  2163. function start_rightChannel_observer(dome,delay=3000){
  2164. // console.log("start_rightChannel_observer");
  2165. is_observer=true;
  2166. if(dome==null){dome=document.getElementsByTagName('body')[0];}
  2167.  
  2168. if(watchpage_rightchannel_observer==null){
  2169. watchpage_rightchannel_observer = new MutationObserver(mutationRecords => {filterDelay(delay);});
  2170. watchpage_rightchannel_observer.observe(dome, {
  2171. attributes:false,childList: true,characterData:false,attributeOldValue:false,
  2172. subtree: true,characterDataOldValue: false});
  2173. }
  2174. }
  2175. //----------------------------------------------------------------
  2176. function watchUrlChange(callback) {
  2177. let lastUrl = location.href;
  2178.  
  2179. // ✅ DOM ready 後執行 callback
  2180. function waitForDOMReady(cb) {
  2181. if (document.readyState === 'complete' || document.readyState === 'interactive') {
  2182. setTimeout(cb, 50);
  2183. } else {
  2184. window.addEventListener('DOMContentLoaded', () => cb(), { once: true });
  2185. }
  2186. }
  2187.  
  2188. // ✅ 檢查網址是否改變
  2189. const onUrlChange = () => {
  2190. if (location.href !== lastUrl) {
  2191. lastUrl = location.href;
  2192. waitForDOMReady(callback);
  2193. }
  2194.  
  2195. };
  2196.  
  2197. // ✅ MutationObserver:觀察 DOM 是否有變動(例如 SPA 路由切換)
  2198. const observer = new MutationObserver(onUrlChange);
  2199. observer.observe(document, { childList: true, subtree: true });
  2200.  
  2201. // ✅ 捕捉 pushState / replaceState
  2202. ['pushState', 'replaceState'].forEach(method => {
  2203. const original = history[method];
  2204. history[method] = function () {
  2205. original.apply(this, arguments);
  2206. window.dispatchEvent(new Event('urlchange'));
  2207. };
  2208. });
  2209.  
  2210. // ✅ 監聽瀏覽器前進/後退 或 push/replace 狀況
  2211. window.addEventListener('popstate', onUrlChange);
  2212. window.addEventListener('urlchange', onUrlChange);
  2213.  
  2214. // ✅ 初始觸發一次
  2215. waitForDOMReady(callback);
  2216. }
  2217.  
  2218. function whenURLChange(){
  2219. sp.load_parameters_fromStorage();
  2220. filter("from interval");
  2221. }
  2222.  
  2223. //----------------------------------------------------------------
  2224. let currentUrl = location.href;
  2225. let page_interval=null;
  2226. function start_page_interval(milis){
  2227. //console.log("start_page_interval");
  2228. page_interval=setInterval(()=>{
  2229. if (location.href !== currentUrl) {
  2230. stop_page_interval();
  2231. setTimeout(function() {
  2232. sp.load_parameters_fromStorage();
  2233. currentUrl = location.href;
  2234. filter("from interval");
  2235. start_page_interval();
  2236. }, milis);
  2237. }
  2238. }, 3000);
  2239. }
  2240. function stop_page_interval(){
  2241. //console.log("stop_page_interval");
  2242. if(page_interval!=null){clearInterval(page_interval);}
  2243. }
  2244. //----------------------------------------------------------------
  2245. let tempchannelArray=[];let ttcasid="tempchannelArray_new_storage";
  2246. function transfertempchannelarrytostring(){
  2247. let s="";
  2248. for(let i=0;i<tempchannelArray.length-1;i++){
  2249. s+=tempchannelArray[i].title+'YYYYY'+tempchannelArray[i].id+'XXXXX';
  2250. }
  2251. if(tempchannelArray.length>0){
  2252. s+=tempchannelArray[tempchannelArray.length-1].title+'YYYYY'+tempchannelArray[tempchannelArray.length-1].id;
  2253. }
  2254. return s;
  2255. }
  2256. function save_tempchannelarray(){
  2257. let s=transfertempchannelarrytostring();
  2258. localStorage.setItem(ttcasid, JSON.stringify(tempchannelArray));
  2259. }
  2260. function load_tempchannelarray(){
  2261. const data=localStorage.getItem(ttcasid);
  2262. if(data!=null){
  2263. tempchannelArray=JSON.parse(data);
  2264. }
  2265. //console.log(tempchannelArray);
  2266. }
  2267.  
  2268. function save_tempchannelarray_old(){
  2269. let s=transfertempchannelarrytostring();
  2270. localStorage.setItem(ttcasid, s);
  2271. }
  2272. function load_tempchannelarray_old(){
  2273. let r=null;
  2274. if(!localStorage.getItem(ttcasid)){localStorage.setItem(ttcasid, "");}
  2275. let s=localStorage.getItem(ttcasid);
  2276. if(s==""){tempchannelArray.length=0;return;}
  2277. let sa=s.split("XXXXX");
  2278. tempchannelArray.length=0;
  2279. for(let i=0;i<sa.length;i++){
  2280. let temp=sa[i].split("YYYYY");
  2281. let o={title:temp[0],id:temp[1]}
  2282. tempchannelArray.push(o);
  2283. }
  2284. }
  2285. //----------------------------------------------------------------
  2286. function do_before_openSetting(){
  2287. stop_page_observer();
  2288. }
  2289. function do_after_closeSetting(){
  2290. filter("from parameter ui button closed");
  2291. }
  2292. function getCurrentLanguageIndex(language){
  2293. let index=0;
  2294. for(let i=0;i<languages.length;i++){
  2295. let l=languages[i];
  2296. if(l.language==language){
  2297. index=i;
  2298. }
  2299. }
  2300. return index;
  2301.  
  2302. }
  2303. function setLanguage(){
  2304. if(autoDectectSystemLanguage){
  2305. let systemLanguage = navigator.language;
  2306. language=systemLanguage.substring(0,2);
  2307.  
  2308. }
  2309. for(let i=0;i<languages.length;i++){
  2310. let l=languages[i];
  2311. if(l.language==language){
  2312. block=l.block;highlight=l.highlight;setting=l.setting;show=l.show;hide=l.hide;
  2313. parametersArray[BLOCK_CHANNEL].title=l.channel;
  2314. parametersArray[BLOCK_VIDEO_KEYWORD].title=l.video+" "+l.keyword;
  2315. parametersArray[BLOCK_VIDEO].title=l.video;
  2316. parametersArray[BLOCK_COMMENT_USER].title=l.comment+" "+l.user;
  2317. parametersArray[BLOCK_COMMENT_KEYWORD].title=l.comment+" "+l.keyword;
  2318. parametersArray[HIGHLIGHT_CHANNEL].title=l.channel;
  2319. parametersArray[HIGHLIGHT_VIDEO_KEYWORD].title=l.video+" "+l.keyword;
  2320. parametersArray[HIGHLIGHT_VIDEO].title=l.video;
  2321. parametersArray[HIGHLIGHT_COMMENT_USER].title=l.comment+" "+l.user;
  2322. parametersSingle[HIGHLIGHT_CHANNEL_BACKGROUND].title=l.highlight+" "+l.channel+" "+l.color;
  2323. parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_ARC].title=l.curvature;
  2324. parametersSingle[HIGHLIGHT_VIDEO_KEYWORD_BACKGROUND].title=l.color;
  2325. parametersSingle[HIGHLIGHT_VIDEO_BACKGROUND].title=l.highlight+" "+l.video+" "+l.color;
  2326. parametersSingle[HIGHLIGHT_COMMENT_USER_BACKGROUND].title=l.highlight+" "+l.comment+" "+l.user+" "+l.color;
  2327. parametersSingle[HIGHTLIGHT_POSTTIME_BAKGROUND].title=l.color;
  2328. parametersSingle[HIGHTLIGHT_POSTTIME_REGX].title=l.regex;
  2329. parametersSingle[HIGHTLIGHT_POSTTIME_TRUE].title=l.highlight+" "+l.posttime;
  2330. parametersSingle[HIDE_COMMENT].title=l.hide+" "+l.comment;
  2331. parametersSingle[DOT_COLOR].title=l.dot+" "+l.comment;
  2332. parametersSingle[BLOCK_MEMBERSONLY].title=l.block+" '"+l.membersonly+"'";
  2333. parametersSingle[NOUSELECTTEXTPOPUP].title=l.noselecttextpup;
  2334. dropdownitems_homepage_title[0]=l.block+" "+l.channel;
  2335. dropdownitems_homepage_title[1]=l.block+" "+l.video;
  2336. dropdownitems_homepage_title[2]=l.highlight+" "+l.channel;
  2337. dropdownitems_homepage_title[3]=l.highlight+" "+l.video;
  2338. selecttext_popupitems_homepage_title[0]=l.block;
  2339. selecttext_popupitems_homepage_title[1]=l.highlight;
  2340. dropdownitemscomment_watchpage_title[0]=l.block+" "+l.user;
  2341. dropdownitemscomment_watchpage_title[1]=l.highlight+" "+l.user;
  2342. selecttext_popupitems_comment_watchpage_title[0]=l.block;
  2343. selecttext_popupitems_homepage[0].title=selecttext_popupitems_homepage_title[0]+" ";
  2344. selecttext_popupitems_homepage[1].title=selecttext_popupitems_homepage_title[1]+" ";
  2345. selecttext_popupitems_comment_watchpage[0].title=selecttext_popupitems_comment_watchpage_title[0]+" ";
  2346. title_restorefile=l.restore;
  2347. title_savefile=l.backup;
  2348. needrefresh=l.needrefresh;
  2349. currentlanguageindex=i;
  2350. }
  2351. }
  2352. }
  2353. let sp;
  2354. function init(){
  2355. sp=new ParametersAgent(document.getElementsByTagName('body')[0],"Youtube-filter(channel、comment、video)");
  2356. sp.load_parameters_fromStorage();
  2357. let lines=2;sp.setPanel_Parameters(ParametersAgent.LB,do_before_openSetting,do_after_closeSetting,lines);
  2358. load_tempchannelarray();
  2359. }
  2360. //-----------------------------------------------------------------
  2361. function debounce(func, wait) {
  2362. let timeout;
  2363. return function(...args) {
  2364. clearTimeout(timeout);
  2365. timeout = setTimeout(() => func.apply(this, args), wait);
  2366. };
  2367. }
  2368. setTimeout(function() {
  2369. console.log("Youtube Filter...啟動");
  2370. setLanguage();
  2371. init();
  2372. //
  2373. watchUrlChange(whenURLChange);
  2374. //start_page_observer(document.getElementsByTagName('body')[0]);
  2375. //start_page_interval(2000);
  2376.  
  2377. document.onclick=(evnt)=>{if(currentMenu!=null){
  2378. STD.hiddenEL(currentMenu);currentMenu=null;
  2379. }};
  2380. window.addEventListener('beforeunload', function (e) { //用來避免重復爬video channel id
  2381. console.log("beforeunload");save_tempchannelarray();
  2382. });
  2383.  
  2384. window.addEventListener('resize', debounce(function() {
  2385. rowcount=0;
  2386. }));
  2387. }, 100);