YouTube Perferred Settings for Private Mode

Save the setting permanently

  1. // ==UserScript==
  2. // @name YouTube Perferred Settings for Private Mode
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3
  5. // @description Save the setting permanently
  6. // @author CY Fung
  7. // @icon data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='189' height='140' viewBox='0 0 270 200' %3E%3Crect x='0' y='0' width='270' height='200'%3E%3C/rect%3E%3Cpath d='m106 190c-27.3-.6-48.3-1.5-60.6-3-7.2-.9-9.9-1.5-13.2-2.7-8.1-2.4-15-8.7-18.9-16.2-2.7-5.7-4.5-15.3-5.7-30.6-2.4-26.4-2.4-49.2 0-75.9 1.2-13.8 3-23.1 5.4-28.5 3.9-7.8 11.1-14.4 19.2-16.8 9.6-3 32.7-4.8 76.2-5.7 35.4-.6 81.3.3 105.9 2.4 20.4 1.5 27.6 3.9 34.8 11.1 7.5 7.5 9.9 15 12 37.2 1.2 12.9 1.5 22.5 1.5 39 0 25.8-1.5 46.5-4.5 59.7-1.5 6.9-4.2 12-9 16.5-7.2 7.5-14.1 9.6-34.8 11.4-24.6 1.8-71.7 3-108.3 2.1z' fill='%23018000'/%3E%3Cpath d='M110 66 178 104 110 142Z' fill='%23fff'/%3E%3C/svg%3E
  8. // @license MIT
  9. // @match https://www.youtube.com/*
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/js-cookie/3.0.1/js.cookie.min.js
  11. // @noframes
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_unregisterMenuCommand
  14. // @grant GM.setValue
  15. // @grant GM.getValue
  16. // @grant GM_addStyle
  17. // @run-at document-start
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. 'use strict';
  22.  
  23. const gmKey = 'yps-r';
  24. const cookieDomain ='youtube.com';
  25. const STORE_VERSION = 1.1;
  26. /*
  27.  
  28. this.j = g.N("ALT_PREF_COOKIE_NAME", "PREF");
  29. this.u = g.N("ALT_PREF_COOKIE_DOMAIN", "youtube.com");
  30. */
  31.  
  32. /*global Cookies*/
  33.  
  34. console.assert(typeof Cookies === "object");
  35.  
  36. const skipKeys = ['SIDCC','CONSISTENCY'];
  37.  
  38.  
  39. const isPassiveArgSupport = (typeof IntersectionObserver === 'function');
  40. // https://caniuse.com/?search=observer
  41. // https://caniuse.com/?search=addEventListener%20passive
  42.  
  43. const bubblePassive = isPassiveArgSupport ? { capture: false, passive: true } : false;
  44. const capturePassive = isPassiveArgSupport ? { capture: true, passive: true } : true;
  45.  
  46.  
  47. let registerH = 0;
  48.  
  49.  
  50.  
  51. let navigationCheckPromiseResolve = null;
  52. const navigationCheckPromise = new Promise(r=>{
  53. navigationCheckPromiseResolve=r;
  54. });
  55.  
  56. let _beginCookie = null;
  57. function regBegin(){
  58.  
  59. if(registerH>0){
  60. GM_unregisterMenuCommand(registerH);
  61. }
  62. registerH = GM_registerMenuCommand("Setting Record Begin", begin, "b");
  63. }
  64. function regEnd(){
  65.  
  66. if(registerH>0){
  67. GM_unregisterMenuCommand(registerH);
  68. }
  69. registerH = GM_registerMenuCommand("Setting Record End", end, "e");
  70. }
  71. function begin() {
  72. _beginCookie = Cookies.get();
  73. regEnd();
  74. let elm = document.querySelector('ytd-app');
  75. if(elm) elm.classList.add('yps-recording');
  76. }
  77.  
  78. function end() {
  79. regBegin();
  80. const beginCookie = _beginCookie;
  81. if (!beginCookie) return alert('Recording was not started.')
  82. _beginCookie = null;
  83.  
  84.  
  85. let elm = document.querySelector('ytd-app');
  86. if(elm) elm.classList.remove('yps-recording');
  87.  
  88. let endCookie = Cookies.get();
  89. let removed = [];
  90. let added = [];
  91. let keysBegin = Object.keys(beginCookie)
  92. let keysEnd = Object.keys(endCookie)
  93.  
  94. let changed = [];
  95. for (const key of keysBegin) {
  96.  
  97. if (keysEnd.includes(key)) {
  98. if (beginCookie[key] !== endCookie[key] && !skipKeys.includes(key)) {
  99.  
  100. changed.push({
  101. key: key,
  102. preValue: beginCookie[key],
  103. newValue: endCookie[key],
  104. changed: true
  105. })
  106. }
  107. endCookie[key] = null;
  108. continue;
  109. }
  110. removed.push({
  111. key: key,
  112. prevValue: beginCookie[key],
  113. removed: true
  114. })
  115. }
  116.  
  117. for (const key of keysEnd) {
  118.  
  119. if (endCookie[key] === null) continue;
  120. added.push({
  121. key: key,
  122. newValue: endCookie[key],
  123. added: true
  124. })
  125. }
  126.  
  127. if (removed.length > 0 || added.length > 0 || changed.length > 0) {
  128.  
  129. let ret = prompt(
  130. [
  131. `The recorded changes are as follows:`,
  132. `Removed keys: ${JSON.stringify(removed, null, 2)},`,
  133. `Added keys: ${JSON.stringify(added, null, 2)},`,
  134. `Changed keys: ${JSON.stringify(changed, null, 2)},`,
  135. `If you want to save these changes permanently, please type 'confirm'.`
  136. ].join('\n')
  137. , "confirm");
  138.  
  139.  
  140. async function goSave(req){
  141.  
  142. let gmValue = null;
  143. try{
  144. gmValue = await GM.getValue(gmKey);
  145. }catch(e){}
  146. if(!gmValue || typeof gmValue !=='string'){
  147. gmValue = '{}';
  148. }
  149. let pObj = null;
  150. try{
  151. pObj = JSON.parse(gmValue)
  152. }catch(e){
  153.  
  154. }
  155. if(!pObj || pObj.version !== STORE_VERSION){
  156. pObj = {
  157. version: STORE_VERSION,
  158. cookies:{
  159.  
  160. }
  161. };
  162. }
  163.  
  164. const cookies = pObj.cookies;
  165.  
  166. for(const {key} of req.removed){
  167.  
  168. cookies[key]={
  169. v: null
  170. }
  171. }
  172. for(const {key, newValue} of req.added){
  173.  
  174. cookies[key]={
  175. v: newValue
  176. }
  177. }
  178. for(const {key, newValue} of req.changed){
  179.  
  180. cookies[key]={
  181. v: newValue
  182. }
  183. }
  184.  
  185.  
  186. let success = true;
  187. try{
  188. let gmValue = JSON.stringify(pObj);
  189. await GM.setValue(gmKey, gmValue);
  190. }catch(e){
  191. console.warn(e);
  192. success = false;
  193. }
  194.  
  195. if(success){
  196. alert('The settings have been saved.')
  197. }
  198.  
  199.  
  200.  
  201. }
  202.  
  203.  
  204. if(ret.toLowerCase()==='confirm'){
  205. goSave({
  206. version: STORE_VERSION,
  207. removed: removed,
  208. added: added,
  209. changed: changed
  210. })
  211. }
  212. } else {
  213. alert('No changes can be recorded.')
  214. }
  215.  
  216.  
  217. }
  218.  
  219. regBegin();
  220.  
  221. async function init(){
  222. let _cookie = document.cookie||''
  223. if(_cookie.indexOf('CONSISTENCY')>=0) return;
  224. if(_cookie.indexOf('SIDCC')>=0) return;
  225.  
  226. let gmValue = null;
  227. try{
  228. gmValue = await GM.getValue(gmKey);
  229. }catch(e){}
  230. if(!gmValue) return;
  231.  
  232. let pObj = null;
  233. try{
  234. pObj = JSON.parse(gmValue)
  235. }catch(e){
  236. }
  237.  
  238. if(!pObj || pObj.version !== STORE_VERSION){
  239. pObj = {
  240. version: STORE_VERSION,
  241. cookies:{
  242. }
  243. };
  244. return;
  245. }
  246.  
  247. if(!pObj.cookies) return;
  248.  
  249. await Promise.resolve(0);
  250.  
  251. const cookies = pObj.cookies;
  252.  
  253.  
  254. for (const key in cookies) {
  255. if(cookies[key].v===null){
  256. Cookies.remove(key);
  257. }else if(typeof cookies[key].v ==='string'){
  258. Cookies.set(key, cookies[key].v, { domain: cookieDomain} )
  259. }
  260. }
  261.  
  262. if(typeof navigationCheckPromiseResolve === 'function'){
  263. navigationCheckPromiseResolve();
  264. }
  265.  
  266.  
  267. }
  268. init();
  269.  
  270.  
  271.  
  272. async function updateRecord(){
  273. return;
  274.  
  275. let gmValue = null;
  276. try{
  277. gmValue = await GM.getValue(gmKey);
  278. }catch(e){}
  279. if(!gmValue) return;
  280.  
  281. let pObj = null;
  282. try{
  283. pObj = JSON.parse(gmValue)
  284. }catch(e){
  285. }
  286.  
  287. if(!pObj || pObj.version !== STORE_VERSION){
  288. pObj = {
  289. version: STORE_VERSION,
  290. cookies:{
  291. }
  292. };
  293. return;
  294. }
  295.  
  296. if(!pObj.cookies) return;
  297.  
  298. await Promise.resolve(0);
  299.  
  300. const cookies = pObj.cookies;
  301.  
  302. let overrided = 0;
  303.  
  304. for (const key in cookies) {
  305.  
  306.  
  307. if(cookies[key].v===null){
  308. if(typeof Cookies.get(key) ==='string'){
  309. delete cookies[key];
  310. overrided++;
  311. }
  312. }else if(typeof cookies[key].v ==='string'){
  313.  
  314. if(Cookies.get(key)!==cookies[key].v){
  315. delete cookies[key];
  316. overrided++;
  317. }
  318. }
  319.  
  320. }
  321.  
  322. if(overrided>0){
  323.  
  324. let success = true;
  325. try{
  326. let gmValue = JSON.stringify(pObj);
  327. await GM.setValue(gmKey, gmValue);
  328. }catch(e){
  329. console.warn(e);
  330. success = false;
  331. }
  332.  
  333. if(success){
  334. console.log('The perferred settings have been overrided.')
  335. }
  336.  
  337.  
  338.  
  339. }
  340.  
  341.  
  342.  
  343.  
  344. }
  345.  
  346.  
  347. document.addEventListener('yt-navigate-finish', function(){
  348.  
  349. navigationCheckPromise.then(()=>{
  350. // updateRecord();
  351.  
  352. })
  353.  
  354. }, bubblePassive)
  355.  
  356.  
  357. let keyupDT = 0;
  358.  
  359. document.addEventListener('keyup', function(evt){
  360.  
  361. if(evt.shiftKey && evt.code ==='KeyR'){
  362.  
  363.  
  364. }else{
  365. if(keyupDT>0 && evt.code ==='KeyR'){
  366.  
  367. }else{
  368.  
  369. keyupDT = 0;
  370. return;
  371. }
  372. }
  373.  
  374. let t = Date.now();
  375. if(keyupDT>0){
  376. if(t - keyupDT <300){
  377. console.log('Shift-R-R')
  378.  
  379. if(!_beginCookie){
  380. begin();
  381. }else{
  382. end();
  383. }
  384. }
  385. keyupDT = 0;
  386. }
  387. keyupDT = t;
  388.  
  389.  
  390. }, bubblePassive);
  391.  
  392. GM_addStyle(
  393. `ytd-app.yps-recording{
  394. filter:brightness(0.7);
  395. }`
  396. );
  397.  
  398.  
  399. // Your code here...
  400. })();