decembre

GM - YouTube Grid & Preview Player v.1.2.2 (last Version)

Dec 24th, 2019
491
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         YouTube Grid & Preview Player
  3. // @namespace    YouTubeGridView
  4. // @version      1.2.2
  5. // @description  YouTube grid view layout and preview player. Video ratings and definition info on thumbs. Auto load page content and search results.
  6. // @author       Costas
  7. // @match        http://www.youtube.com/*
  8. // @match        https://www.youtube.com/*
  9. // @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAeUlEQVR42u2UwQ2AMAwDk52YCWaCmdgp7QshKP6QKn7Yv0pudEqcuBXLBXB/7GaBzFv3Z3k+AdYY/z3cr+IZHgywPCZzxrv4T48AyAFAeKaH0ICmr2GFuDpAkQGOLRBAOQAIjw5Rtrg6QJEBji0QQDkACI8OUbYE0ADbonowcNn6sgAAAABJRU5ErkJggg==
  10. // @grant        GM_setValue
  11. // @grant        GM_getValue
  12. // @grant        GM_xmlhttpRequest
  13. // @noframes
  14. // ==/UserScript==
  15.  
  16. //==================================================================
  17. //Rating thresholds
  18.  
  19. var red_threshold = 50;
  20. var orange_threshold = 70;
  21.  
  22. //==================================================================
  23. //Userscript specific functions
  24.  
  25. var doc = document;
  26. var win = window;
  27.  
  28. if (win.frameElement) throw new Error("Stopped JavaScript.");
  29.  
  30. function set_pref(preference, new_value) {
  31.     GM_setValue(preference, new_value);
  32. }
  33.  
  34. function get_pref(preference) {
  35.     return GM_getValue(preference);
  36. }
  37.  
  38. function init_pref(preference, new_value) {
  39.     var value = get_pref(preference);
  40.     if (value == null) {
  41.         set_pref(preference, new_value);
  42.         value = new_value;
  43.     }
  44.     return value;
  45. }
  46.  
  47. function httpReq(url, callback, param1, param2, param3, param4) {
  48.     //message(url);
  49.  
  50.     GM_xmlhttpRequest({
  51.         method: "GET",
  52.         url: url,
  53.         onload: function (response) {
  54.             //message(response.responseText);
  55.             callback(response.responseText, param1, param2, param3, param4);
  56.         }
  57.     });
  58. }
  59.  
  60. var myparser = new DOMParser();
  61.  
  62. //==================================================================
  63. //==================================================================
  64.  
  65.  
  66. //==================================================================
  67. // Styles
  68.  
  69. var style_ads_other = "\
  70. /* remove ads */\
  71. #content[gridtube_grid='search'] #google_flash_inline_div,\
  72. #content[gridtube_auto_load_search] #google_flash_inline_div,\
  73. #content[gridtube_grid='search'] .branded-page-v2-secondary-col,\
  74. #content[gridtube_auto_load_search] .branded-page-v2-secondary-col,\
  75. #content[gridtube_grid='search'] .pyv-afc-ads-container,\
  76. #content[gridtube_auto_load_search] .pyv-afc-ads-container {display:none !important;}\
  77. #content[gridtube_grid='related'] #watch7-sidebar-ads {display:none !important;}\
  78. /* hide pager */\
  79. #content[gridtube_auto_load_search] .search-pager {display:none !important;}\
  80. /* user links */\
  81. a[gridtube_meta_user_mark2] {display:inline !important; text-decoration:none !important; padding:0px !important;}\
  82. a[gridtube_meta_user_mark2]:hover {text-decoration:underline !important;}\
  83. li.video-list-item.related-list-item:hover a[gridtube_meta_user_mark2] {color:#167ac6 !important;}\
  84. /* watched videos */\
  85. .watched .video-thumb {opacity:1 !important;}\
  86. ";
  87.  
  88. var style_grid_basic = "\
  89. /*Grid for search results*/\
  90. #content[gridtube_grid='search'] {width: 96% !important;}\
  91. #content[gridtube_grid='search'] .item-section {margin-left:5px !important;}\
  92. #content[gridtube_grid='search'] ol.item-section > li {width: 246px !important; height: 226px !important; float: left !important; margin:5px 10px !important; overflow:hidden !important;}\
  93. #content[gridtube_grid='search'] ol.item-section > li:hover {overflow:visible !important;}\
  94. #content[gridtube_grid='search'] ol.item-section > li:hover > div {z-index:1 !important; background-color:white !important;}\
  95. #content[gridtube_grid='search'] ol.item-section > li > div {padding:0px 0px 3px 0px !important;}\
  96. #content[gridtube_grid='search']:not([gridtube_auto_load_search]) .search-pager {display:inline-block !important; width:100% !important; margin-top:50px !important;}\
  97. /*Grid for history or recommended*/\
  98. #content[gridtube_grid='history'] {width: 96% !important;}\
  99. #content[gridtube_grid='history'] #browse-items-primary {margin-left:10px !important;}\
  100. #content[gridtube_grid='history'] .item-section-header {margin-left:-5px !important;}\
  101. #content[gridtube_grid='history'] ol.item-section > li:not(.item-section-header) {width: 196px !important; height: 196px !important; float: left !important; margin:5px 10px !important; overflow:hidden !important;}\
  102. #content[gridtube_grid='history'] ol.item-section > li:not(.item-section-header):hover {overflow:visible !important;}\
  103. #content[gridtube_grid='history'] ol.item-section > li:not(.item-section-header):hover > div {z-index:1 !important; background-color:white !important;}\
  104. #content[gridtube_grid='history'] ol.item-section > li:not(.item-section-header) > div {padding:0px 0px 3px 0px !important; border-bottom:0px !important;}\
  105. #content[gridtube_grid='history'] .yt-uix-menu-top-level-button-container {margin-right:-4px !important;}\
  106. #content[gridtube_grid='history'] .shelf-title-table {display:none !important;}\
  107. /*Grid for trending*/\
  108. #content[gridtube_grid='trending'] {width: 96% !important;}\
  109. #content[gridtube_grid='trending'] .expanded-shelf-content-item-wrapper {width: 196px !important; height: 196px !important; float: left !important; margin:5px 10px !important; overflow:hidden !important; padding:0px !important;}\
  110. #content[gridtube_grid='trending'] .expanded-shelf-content-item-wrapper:hover {overflow:visible !important;}\
  111. #content[gridtube_grid='trending'] .expanded-shelf-content-item-wrapper:hover .yt-lockup-video {z-index:1 !important; background-color:white !important;}\
  112. #content[gridtube_grid='trending'] .expanded-shelf-content-item-wrapper .yt-lockup-video {padding:0px 0px 3px 0px !important;}\
  113. /*Grid for userquery search*/\
  114. #content[gridtube_grid='userquery'] #browse-items-primary {margin-top:10px !important;}\
  115. #content[gridtube_grid='userquery'] .feed-item-container {width: 196px !important; height: 196px !important; float: left !important; margin:5px 10px !important; overflow:hidden !important; border-bottom:0px !important; padding-bottom:0px !important; padding-top:0px !important;}\
  116. #content[gridtube_grid='userquery'] .feed-item-container:hover {overflow:visible !important;}\
  117. #content[gridtube_grid='userquery'] .feed-item-container:hover .yt-lockup-video {z-index:1 !important; background-color:white !important;}\
  118. #content[gridtube_grid='userquery'] .feed-item-container .yt-lockup-video {padding:0px 0px 3px 0px !important;}\
  119. /*common lockup*/\
  120. #content[gridtube_grid] .yt-lockup-channel .video-thumb {float:left !important;}\
  121. #content[gridtube_grid] .yt-lockup-content {float:left !important; width:100% !important;}\
  122. #content[gridtube_grid] .yt-lockup-title {font-size:13px !important; line-height:1.2em !important; max-height:2.4em !important; margin-bottom:1px !important;}\
  123. #content[gridtube_grid='search'] .yt-lockup-title {margin-top:1px !important; margin-right:5px !important;}\
  124. #content[gridtube_grid='history'] .yt-lockup-title {margin-right:15px !important;}\
  125. #content[gridtube_grid] .yt-lockup-title .yt-uix-tile-link {line-height:1.2em !important; margin-right:0px !important;}\
  126. #content[gridtube_grid] .yt-lockup-byline {font-size:11px !important; line-height:13px !important;}\
  127. #content[gridtube_grid] .yt-lockup-meta {font-size:11px !important; line-height:13px !important;}\
  128. #content[gridtube_grid] .yt-lockup-description {font-size: 10px !important; line-height:12px !important;}\
  129. #content[gridtube_grid] .yt-lockup-badges {margin:0px !important;}\
  130. #content[gridtube_grid] .yt-lockup-playlist-items {margin:0px !important;}\
  131. #content[gridtube_grid='userquery'] .yt-lockup-playlist-item-title {font-size:11px !important; line-height:13px !important;}\
  132. #content[gridtube_grid='userquery'] .yt-lockup-playlist-item-length {font-size:11px !important; line-height:13px !important;}\
  133. #content[gridtube_grid='search'] .yt-lockup-action-menu {margin-right:-8px !important;}\
  134. "
  135.  
  136. var style_grid_related = "\
  137. /*Grid for related*/\
  138. /*#watch7-sidebar-contents {min-height:1770px !important;}*/\
  139. #watch-related {position:absolute !important;}\
  140. #watch-related > li:not(.related-list-item) {display:none !important;} /*ads*/\
  141. #watch-related li {width: 195px !important; height:160px !important; margin-bottom:0px !important; float: left !important; overflow:hidden !important;}\
  142. #watch-related .content-wrapper {width:168px !important; margin-left:5px !important; margin-top:94px !important;}\
  143. #watch-related .yt-pl-thumb-link .title {width:168px !important; margin-top:95px !important;}\
  144. #watch-related .title {font-size:12px !important; line-height:1.2em !important; max-height:2.4em !important; margin:1px 4px 1px 0px !important;}\
  145. #watch-related .yt-uix-menu-container.related-item-action-menu {right:21px !important; top:100px !important;}\
  146. #watch-related .view-count .yt-badge-list {vertical-align:top !important;}\
  147. ";
  148.  
  149. var style_grid_plist = "\
  150. /*Grid for playlists*/\
  151. .pl-video {position:relative !important; width:250px !important; height:200px !important; margin-top:5px !important; margin-bottom:5px !important; border-bottom:0px !important; float: left !important; overflow:hidden !important;}\
  152. .pl-video .pl-video-thumbnail {width: 196px !important; padding-bottom:2px !important; /*padding-left:2px !important;*/}\
  153. .pl-video .pl-video-thumb {width: 196px !important;}\
  154. .pl-video .yt-thumb {width: 196px !important;}\
  155. .pl-video .yt-thumb-clip > img {width:196px !important; height:auto !important;}\
  156. .pl-video .pl-video-title  {display:block !important; min-width:0px !important; width:196px !important; padding:0px 0px 0px 35px !important;}\
  157. .pl-video .pl-video-title-link {width:100% !important; max-height:3.9em !important; overflow:hidden !important; text-overflow: ellipsis !important;}\
  158. .pl-video .pl-video-owner {margin-top: 0px !important;}\
  159. .pl-video .pl-video-badges {padding:5px 0px 0px 35px !important;}\
  160. .pl-video .pl-video-added-by {display:none !important;}\
  161. .pl-video .pl-video-time {position:absolute !important; top:-22px !important; left:20px !important; text-align:left !important; color:gray !important;}\
  162. .pl-video-index::before {/*font-size:12px !important;*/ font-weight:bold !important;}\
  163. .pl-video-edit-options {position:absolute !important; top:36px !important; right:-126px !important;}\
  164. ";
  165.  
  166. var style_basic = "\
  167. /* messages */\
  168. .gridtube_message {font:12px/15px arial,sans-serif; text-align:left; white-space:pre; float:left; clear:both; color:black; background:beige; margin:10px 0px 0px 300px; z-index:2147483647;}\
  169. /* selection icons */\
  170. #gridtube_icon_area {position:relative; height:23px; width:58px; float:right !important; clear:none;}\
  171. .gridtube_icon_area_search, .gridtube_icon_area_hist {margin:0px 0px -7px 10px;}\
  172. .gridtube_icon_area_plist {margin:-26px 100px 0px 0px; border:1px dotted lightgray; padding:5px;}\
  173. #gridtube_icon_area img {cursor:pointer; height:16px; width:16px; padding:4px 3px 3px 4px; margin:0px 3px; border-radius:2px; position:relative; overflow:visible; opacity:0.8;}\
  174. #gridtube_icon_area img:hover {opacity:1;}\
  175. #gridtube_icon_area img[selected] {box-shadow:0px 0px 0px 1px gray;}\
  176. /* bottom bar */\
  177. #gridtube_bottom_area {position:relative; clear:both; width:100%; padding-bottom:20px;}\
  178. .gridtube_result_bar {position:relative; width:50%; height:84px; clear:both; margin:auto;}\
  179. .gridtube_result_bar_inner {font:bold 18px/34px arial,sans-serif; width:100%; height:34px; position:absolute; top:40px; color:steelblue; cursor:pointer; border-radius:5px; text-align:center; background:linear-gradient(white,lightgray); opacity:0.8; overflow:hidden;}\
  180. .gridtube_result_bar_inner:hover {opacity:1;}\
  181. .gridtube_result_bar img {height:26px; width:26px; margin-right:7px; vertical-align:middle;}\
  182. /* prefs */\
  183. #gridtube_pref_popup {font:11px/11px arial,sans-serif; color:white; background:linear-gradient(#788898,#687888); padding:5px; border-radius:5px; box-shadow:0px 0px 5px 5px slategray; /*z-index:2147483647;*/ z-index:2147483646;}\
  184. #gridtube_pref_popup[top] {position:fixed; right:0px; top:0px;}\
  185. #gridtube_pref_popup[bottom] {position:fixed; right:0px; bottom:0px;}\
  186. .gridtube_pref_group {margin-left:15px; color:yellow;}\
  187. #gridtube_pref_close {font:14px/14px arial,sans-serif; color:black; position:absolute; top:3px; right:5px; cursor:pointer;}\
  188. #gridtube_pref_close:hover {color:lightgray;}\
  189. #gridtube_pref_title {font:bold 13px/13px arial,sans-serif; padding:5px !important; color:lightyellow;}\
  190. #gridtube_pref_button {cursor:pointer; width:20px; height:20px; background-size:contain; background-repeat:no-repeat; opacity:0.7;}\
  191. #gridtube_pref_button[top] {position:absolute; right:0px; top:0px; visibility:hidden; z-index:10;}\
  192. #gridtube_pref_button[bottom] {position:fixed; right:0px; bottom:0px; visibility:visible;}\
  193. #gridtube_pref_button:hover {opacity:0.9;}\
  194. #gridtube_pref_button {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAeUlEQVR42u2UwQ2AMAwDk52YCWaCmdgp7QshKP6QKn7Yv0pudEqcuBXLBXB/7GaBzFv3Z3k+AdYY/z3cr+IZHgywPCZzxrv4T48AyAFAeKaH0ICmr2GFuDpAkQGOLRBAOQAIjw5Rtrg6QJEBji0QQDkACI8OUbYE0ADbonowcNn6sgAAAABJRU5ErkJggg==');}\
  195. #yt-masthead-container:hover  #gridtube_pref_button {visibility:visible !important;}\
  196. /* meta data */\
  197. .gridtube_meta_def_container {font:bold 10px/13px arial,sans-serif; position:absolute; left:0px; background:#F0F0F0; padding:0px 3px; border-radius:2px; opacity:0.9; display:none; cursor:default;}\
  198. .gridtube_meta_def_container.top {top:0px;}\
  199. .gridtube_meta_def_container.bottom {bottom:0px;}\
  200. *[gridtube_progress_bar] .gridtube_meta_def_container.bottom, .contains-percent-duration-watched .gridtube_meta_def_container.bottom {bottom:4px !important;}\
  201. .gridtube_meta_def_container[reveal] {display:block;}\
  202. .gridtube_meta_def_container[space] .gridtube_meta_def_hd {margin-right:3px;}\
  203. .gridtube_meta_def_format {position:relative; color:black;}\
  204. .gridtube_meta_def_hd {position:relative;}\
  205. .gridtube_meta_def_hd.HD {color:magenta;}\
  206. .gridtube_meta_def_hd.UHD {color:red;}\
  207. .gridtube_meta_rate {font:bold 10px/13px arial,sans-serif; position:absolute; top:0px; right:0px; background:green; color:white; opacity:0.9; padding:0px 3px; border-radius:2px; cursor:default;}\
  208. .gridtube_meta_rate[bad] {background:red !important;}\
  209. .gridtube_meta_rate[med] {background:darkorange !important;}\
  210. #gridtube_meta_box {position:relative; float:left; height:13px; margin-top:3px;}\
  211. #gridtube_meta_box .gridtube_meta_def_container {font:bold 11px/13px arial,sans-serif; opacity:1; position:relative; clear:none; float:left; background:white;}\
  212. #gridtube_meta_box .gridtube_meta_rate {opacity:1; position:relative; clear:none; float:right; margin-left:5px;}\
  213. #gridtube_title_container {position:absolute; top:5px; right:5px;}\
  214. /* play button*/\
  215. #gridtube_meta_playing {font:bold 12px/12px arial,sans-serif; position:absolute; top:0px; left:0px; background:red; color:white; opacity:0.9; padding:3px 5px; border-radius:2px; cursor:default; z-index:1;}\
  216. *[gridtube_meta_thumb_mark]:hover .gridtube_meta_play {visibility:visible !important;}\
  217. .gridtube_meta_play_container {position:absolute; bottom:0px; left:0px; width:100%; visibility:hidden;}\
  218. .gridtube_meta_play {visibility:hidden !important; display:block !important; position:relative !important; padding-bottom:1px !important; margin:0px auto !important; width:25px !important; height:25px !important; opacity:0.75 !important; cursor:pointer !important; background-size: 25px !important; background-repeat:no-repeat !important; text-decoration:none !important;}\
  219. .gridtube_meta_play:hover {opacity:1 !important;}\
  220. .gridtube_meta_play {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAG7AAABuwBHnU4NQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAOqSURBVFiF5ZdPSBxnGMZ/M98s1V1nV01A17VZUwMRqsGY9FyQlBJQ2gYPIbaB0nMgwYZWeumxIQhlT7aQW0Mhl54CvQQiISQhkixN\
  221. bWKXaNSaYuzu6v4Z98+38/WgY9Vu9l835NAHvsvM983zvs/7vPPOaEopXif018oOGAAfjY4GgEvAu0DnK+b8A5gCvvjp6tVl7cMzZ94EwkArgM/n42BXF7peX3Fs22b+2TPW19edSzGg3wAmgFbTNPlybIyDBw7UlXgv5hcX+WZigmQy2QpMiJ6+vhDQ9Pn587wVDGLb9itdXtOku7ubW7dvA+wzgHa3201XMEg2nyebzyOlpN69oQGG\
  222. YfCGy0VXMIjb7cayrHYDoDMQIJPLkUynKdh2nal3Q+g6psdDZyDA75HIZhcoIJFKIQuFkofz2SxCCHTDqDkA27ZJpFLbCusAuVyOvJQopUquWDzO5OQkfy4vl91bauWlJJfL/ROAlLJiEy0sLfFtKMTP16+TsayazSilBLZeRI405aBsm8JWmW7cvMn0gweMnDrFocOHay7JpgeUqiiAQqGwHQBALB7n+ytXONLXx/DQEKbPVzGxM4Oq\
  223. U0CpXQE4eBgOMzMzwwfDwwwcO1aVSatSwN5Rgr1TVErJj9eucefuXUZGRmjz+8smAzumYUXmKRSQUiKl3C7H3vV0fp5Lly9za2oKrcRzdylQLKOiCkDREuzFe4ODfDo6yloqxUo0WnJvzSUohg6/n/GxMXp6eogsLJDd6vViqM2ELwlACMHHp0/z2dmzLK2s8MvsbNlnOai6DZ0XiIMjvb18PT6Ox+vl4ZMnFZXI4dwOAKpvwyaPhwvn\
  224. zjF08iSzc3Msrq5WRLwX28OoGg+8f+IEX128SMKyuBcO1zS6nTObClRYAndjI9+FQvT29vJbJMJGNlsDtRPBjhLouo6tFFqZM/v278dsamL60aPaidnM3vnmNIQQaEKwYVk0NDSUPJhMp0mm0/+JHCCTyaALgcswMLymqWwptfVEgkwmg9vtRgiBppXTozo4BrYsi2wuh7JtvF6vMjra21+sRqNtqVSKtKYRi8frSvyyYDSgw+9/YRw/\
  225. evTpnfv329aiUQyXC+qceRF2lG3T0tzM8f7+OW3m8eP++NrajXvT061SSqRSZb8Ny6FoCpqGEIIGw8DlcvHOwEC82ecb1JRS/BWLvZ1MJn/I5/N+lGpUOwxQSo+SPtm6968dmrbhEuK51zQ/aWlp+VX73/8d/w3y7NP9Di2fPgAAAABJRU5ErkJggg==') !important;}\
  226. /* preview player */\
  227. #gridtube_player_area {position:fixed; width:100%; height:100%; top:0px; left:0px; background:rgba(0,0,0,0.5); overflow:hidden !important; z-index:2147483646 !important; }\
  228. #gridtube_player_area2 {position:relative; width:100%; height:100%; visibility:hidden;}\
  229. #gridtube_player_box {position:absolute; background:#606060; box-shadow:0px 0px 20px 5px #606060; border-radius:10px; max-width:100%; max-height:100%;}\
  230. #gridtube_player_box[player_pos='00']:not([player_size='fit']) {top:0px; left:0px;}\
  231. #gridtube_player_box[player_pos='01']:not([player_size='fit']) {top:0px; left:0px; right:0px; margin:auto;}\
  232. #gridtube_player_box[player_pos='02']:not([player_size='fit']) {top:0px; right:0px;}\
  233. #gridtube_player_box[player_pos='10']:not([player_size='fit']) {top:0px; bottom:0px; left:0px; margin:auto;}\
  234. #gridtube_player_box[player_pos='11']:not([player_size='fit']) {top:0px; bottom:0px; left:0px; right:0px; margin:auto;}\
  235. #gridtube_player_box[player_pos='12']:not([player_size='fit']) {top:0px; bottom:0px; right:0px; margin:auto;}\
  236. #gridtube_player_box[player_pos='20']:not([player_size='fit']) {bottom:0px; left:0px;}\
  237. #gridtube_player_box[player_pos='21']:not([player_size='fit']) {bottom:0px; left:0px; right:0px; margin:auto;}\
  238. #gridtube_player_box[player_pos='22']:not([player_size='fit']) {bottom:0px; right:0px;}\
  239. #gridtube_player_box[player_pos='right']:not([player_size='fit']) {float:right;}\
  240. #gridtube_player_box[player_size='tiny'] {/*320x180*/ width:340px; height:220px;}\
  241. #gridtube_player_box[player_size='small'] {/*512x288*/ width:532px; height:328px;}\
  242. #gridtube_player_box[player_size='medium'] {/*768x432*/  width:788px; height:472px;}\
  243. #gridtube_player_box[player_size='large'] {/*1024x576*/ width:1044px; height:616px;}\
  244. #gridtube_player_box[player_size='huge'] {/*1280x720*/ width:1300px; height:760px;}\
  245. #gridtube_player_box[player_size='fit'] {width:100%; height:100%; border-radius:0px !important;}\
  246. #gridtube_player_holder {position:relative; width:100%; height:100%;}\
  247. #gridtube_player_holder2 {position:absolute; top:20px; left:10px; right:10px; bottom:20px; margin:auto;}\
  248. #gridtube_player_box[player_size='fit'] #gridtube_player_holder2 {left:0px !important; right:0px !important;}\
  249. #gridtube_player_frame {position:relative; width:100%; height:100%; display:block; border:0px;}\
  250. #gridtube_player_button_area_top {font:bold 12px/20px arial,sans-serif; color:#101010; position:absolute; top:0px; left:10px;}\
  251. #gridtube_player_button_area_bottom {font:bold 18px/20px arial,sans-serif; color:#101010; position:absolute; bottom:0px; left:10px;}\
  252. .gridtube_player_button {position:relative; cursor:pointer; padding:0px 5px;}\
  253. .gridtube_player_button[button_kind='plus'], .gridtube_player_button[button_kind='minus'] {font:bold 18px/20px arial,sans-serif !important; top:2px;}\
  254. .gridtube_player_button[button_kind='left'] {padding:0px 2px 0px 5px;}\
  255. .gridtube_player_button[button_kind='right'] {padding:0px 2px;}\
  256. .gridtube_player_button[button_kind='up'] {padding:0px 2px;}\
  257. .gridtube_player_button[button_kind='down'] {padding:0px 5px 0px 2px;}\
  258. .gridtube_player_button:hover {color:#E0E0E0;}\
  259. #gridtube_player_close_mark {font:14px/20px arial,sans-serif; color:#B0B0B0; position:absolute; top:0px; right:5px; cursor:pointer; visibility:hidden;}\
  260. #gridtube_player_close_mark:hover {color:#E0E0E0;}\
  261. #gridtube_player_box:hover #gridtube_player_close_mark {visibility:inherit;}\
  262. /* player options */\
  263. #gridtube_player_options_popup {position:absolute; left:0px; top:0px; font:11px/11px arial,sans-serif; color:white; background:linear-gradient(#888888,#787878); padding:5px; border-radius:5px; /*z-index:2147483647;*/ z-index:2147483646;}\
  264. .gridtube_player_options_text {font-weight:bold; margin-left:5px; margin-top:7px; color:lemonchiffon;}\
  265. .gridtube_player_options_close {font:14px/14px arial,sans-serif; color:black; position:absolute; top:3px; right:5px; cursor:pointer;}\
  266. .gridtube_player_options_close:hover {color:lightgray;}\
  267. .gridtube_player_options_title {font:bold 13px/13px arial,sans-serif; padding:5px !important; color:lemonchiffon;}\
  268. ";
  269.  
  270. //more icons
  271. var icon_grid = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKElEQVR42mNkYGD4z4AAjKTyYQJk0yTbiM0FFAGquGA0DEbDYBiEAQDsrkARdSFMWAAAAABJRU5ErkJggg==";
  272. var icon_list = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAM0lEQVR42mNkYGD4z4AAjA0NDch8vAColpERagAyTRKAaUTmk2wARQDDBaNhMBoGIzQMAMm+IBGUaVrGAAAAAElFTkSuQmCC";
  273.  
  274.  
  275. //==============================================================
  276. //basic
  277.  
  278. function newNode(kind, id, classname, refnode, position) {
  279.  
  280.     var node = doc.createElement(kind);
  281.  
  282.     if (node == null) return null;
  283.  
  284.     if (id != null) node.id = id;
  285.  
  286.     if (classname != null) node.className = classname;
  287.  
  288.     if (refnode != null) {
  289.         switch (position) {
  290.             //insert after refnode
  291.             case 'after':
  292.                 if (refnode.nextSibling != null)
  293.                     refnode.parentNode.insertBefore(node, refnode.nextSibling);
  294.                 else
  295.                     refnode.parentNode.appendChild(node);
  296.                 break;
  297.  
  298.                 //insert before refnode
  299.             case 'before':
  300.                 refnode.parentNode.insertBefore(node, refnode);
  301.                 break;
  302.  
  303.                 //insert as first child of refnode                  
  304.             case 'first':
  305.                 var child = refnode.childNodes[0];
  306.                 if (child != null)
  307.                     refnode.insertBefore(node, child);
  308.                 else
  309.                     refnode.appendChild(node);
  310.                 break;
  311.  
  312.                 //insert as last child of refnode
  313.             case 'last':
  314.             default:
  315.                 refnode.appendChild(node);
  316.                 break;
  317.         }
  318.     }
  319.  
  320.     return node;
  321. }
  322.  
  323.  
  324. function message(str) {
  325.     var node = newNode("div", null, "gridtube_message", doc.body);
  326.     node.textContent = str + "\n";
  327. }
  328.  
  329.  
  330. function insertStyle(str, id) {
  331.     var styleNode = null;
  332.  
  333.     if (id != null) {
  334.         styleNode = doc.getElementById(id);
  335.     }
  336.  
  337.     if (styleNode == null) {
  338.         styleNode = newNode("style", id, null, doc.head);
  339.         styleNode.setAttribute("type", "text/css");
  340.     }
  341.  
  342.     if (styleNode.textContent != str)
  343.         styleNode.textContent = str;
  344. }
  345.  
  346.  
  347. function injectScript(str, src) {
  348.     var script = doc.createElement("script");
  349.     if (str) script.textContent = str;
  350.     if (src) script.src = src;
  351.     doc.body.appendChild(script);
  352.     if (!src) doc.body.removeChild(script);
  353. }
  354.  
  355.  
  356. function xpath(outer_dom, inner_dom, query) {
  357.     //XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7
  358.     return outer_dom.evaluate(query, inner_dom, null, 7, null);
  359. }
  360.  
  361.  
  362. function docsearch(query) {
  363.     return xpath(doc, doc, query);
  364. }
  365.  
  366.  
  367. function innersearch(inner, query) {
  368.     return xpath(doc, inner, query);
  369. }
  370.  
  371.  
  372. function simulClick(el) {
  373.     var clickEvent = doc.createEvent('MouseEvents');
  374.     clickEvent.initEvent('click', true, true);
  375.     el.dispatchEvent(clickEvent);
  376. }
  377.  
  378.  
  379. function jmessage(json) {
  380.     message(JSON.stringify(json, null, '                  '));
  381. }
  382.  
  383. function disable_ajax(e) {
  384.     e.stopPropagation();
  385. }
  386.  
  387. function filter(str, w, delim) {
  388.     if (str == null) return null;
  389.  
  390.     var r = null;
  391.     var m = str.match(RegExp("[" + delim + "]" + w + "[^" + delim + "]*"));
  392.     if (m != null) {
  393.         r = m[0];
  394.         r = r.replace(RegExp("[" + delim + "]" + w), "");
  395.     }
  396.     return r;
  397. }
  398.  
  399.  
  400. function number_comma(str) {
  401.     if (str == null) return null;
  402.  
  403.     return str.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
  404. }
  405.  
  406.  
  407. //returns object with fields: size, format, HD, UHD
  408. function extract_resolution(txt) {
  409.     if (txt == null) return null;
  410.  
  411.     //message(txt);
  412.  
  413.     var str = filter("%" + txt, "26size%3D", "%");
  414.     if (str == null || str == "") {
  415.         str = filter("&" + txt, "fmt_list=", "&?");
  416.     }
  417.  
  418.     if (str == null) return null;
  419.  
  420.     //message(str);
  421.  
  422.     var m = str.match(/([0-9])+x([0-9])+/);
  423.  
  424.     if (m == null) return null;
  425.  
  426.     if (m.length == 0) return null;
  427.  
  428.     var pos_max = -1;
  429.     var format_max = "";
  430.     var int0_max = -1;
  431.     var int1_max = -1;
  432.  
  433.     for (var i = 0; i < m.length; i++) {
  434.         var size = m[i];
  435.         var nums = size.split("x");
  436.         var int1 = parseInt(nums[1]);
  437.  
  438.         if (int1 > int1_max) {
  439.             pos_max = i;
  440.             format_max = nums[1];
  441.             int0_max = parseInt(nums[0]);
  442.             int1_max = int1;
  443.         }
  444.     }
  445.  
  446.     var ret = new Object();
  447.     ret.size = m[pos_max];
  448.     ret.format = format_max;
  449.     ret.HD = ((int0_max >= 1280) || (int1_max >= 720));
  450.     ret.UHD = (int0_max >= 7680) ? '8K' : (int0_max >= 5120) ? '5K' : (int0_max >= 3840) ? '4K' : null;
  451.     //jmessage(ret);
  452.  
  453.     return ret;
  454. }
  455.  
  456.  
  457. //==============================================================
  458. //preferences
  459.  
  460. var pref_playerEnable = init_pref("playerEnable", true);
  461. var pref_gridEnable = init_pref("gridEnable", true);
  462. var pref_gridSearch = init_pref("gridSearch", true);
  463. var pref_gridTrend = init_pref("gridTrend", true);
  464. var pref_gridHist = init_pref("gridHist", true);
  465. var pref_gridRecom = init_pref("gridRecom", true);
  466. var pref_gridPlist = init_pref("gridPlist", true);
  467. var pref_gridRel = init_pref("gridRel", true);
  468. var pref_autoLoadSearch = init_pref("autoLoadSearch", true);
  469. var pref_autoLoadOther = init_pref("autoLoadOther", true);
  470. var pref_rateEnable = init_pref("rateEnable", true);
  471. var pref_defEnable = init_pref("defEnable", true);
  472. var pref_defTop = init_pref("defTop", false);
  473. var pref_hideRecom = init_pref("hideRecom", false);
  474. var pref_userLink = init_pref("userLink", false);
  475. var pref_newTab = init_pref("newTab", false);
  476. var pref_ytFocus = init_pref("ytFocus", false);
  477.  
  478.  
  479. if (!pref_gridEnable) {
  480.     pref_gridSearch = false;
  481.     pref_gridTrend = false;
  482.     pref_gridHist = false;
  483.     pref_gridRecom = false;
  484.     pref_gridPlist = false;
  485.     pref_gridRel = false;
  486. }
  487.  
  488.  
  489. function new_checkbox(prefname, str, node_kind, parent, value, func) {
  490.     var div = newNode(node_kind, null, "gridtube_generic", parent);
  491.     var input = newNode("input", null, "gridtube_generic", div);
  492.     input.type = "checkbox";
  493.     if (!value) {
  494.         input.checked = get_pref(prefname);
  495.         input.onclick = function (e) {
  496.             var val = get_pref(prefname);
  497.             set_pref(prefname, !val);
  498.             e.target.checked = !val;
  499.             if (func) func();
  500.         };
  501.     }
  502.     else {
  503.         input.value = value;
  504.         input.checked = (get_pref(prefname) == input.value);
  505.         input.onclick = function (e) {
  506.             var val = get_pref(prefname);
  507.             set_pref(prefname, e.target.value);
  508.             e.target.checked = true;
  509.             var other = innersearch(parent.parentNode, ".//input[@value='" + val + "']").snapshotItem(0);
  510.             if (other) other.checked = false;
  511.             if (func) func();
  512.         };
  513.     }
  514.     var span = newNode("span", null, "gridtube_generic", div);
  515.     span.textContent = str;
  516. }
  517.  
  518.  
  519. function pref_popup(pos) {
  520.     var popup = doc.getElementById("gridtube_pref_popup");
  521.     if (popup) return;
  522.  
  523.     popup = newNode("span", "gridtube_pref_popup", null, doc.body);
  524.     if (pos) popup.setAttribute(pos, "true");
  525.  
  526.     var title_node = newNode("div", "gridtube_pref_title", null, popup);
  527.     title_node.textContent = "Grid & Player Options";
  528.  
  529.     var changed = false;
  530.     function mark() {
  531.         changed = true;
  532.     }
  533.  
  534.     var closemark = newNode("span", "gridtube_pref_close", null, popup);
  535.     closemark.textContent = "\u2716";
  536.     closemark.title = "close options";
  537.     closemark.onclick = function () {
  538.         popup.parentNode.removeChild(popup);
  539.         if (changed) win.location.reload();
  540.     };
  541.  
  542.     new_checkbox("playerEnable", "Preview Player", "div", popup, null, mark);
  543.     new_checkbox("gridEnable", "Grid View", "div", popup, null, mark);
  544.     if (pref_gridEnable) {
  545.         var group1 = newNode("div", null, "gridtube_pref_group", popup);
  546.         var group2 = newNode("div", null, "gridtube_pref_group", popup);
  547.         new_checkbox("gridSearch", "Search", "span", group1, null, mark);
  548.         new_checkbox("gridHist", "History", "span", group1, null, mark);
  549.         new_checkbox("gridPlist", "Playlists", "span", group1, null, mark);
  550.         new_checkbox("gridTrend", "Trending", "span", group2, null, mark);
  551.         new_checkbox("gridRel", "Related", "span", group2, null, mark);
  552.         new_checkbox("gridRecom", "Recomm.", "span", group2, null, mark);
  553.     }
  554.     new_checkbox("autoLoadSearch", "Auto Load for Search Results", "div", popup, null, mark);
  555.     new_checkbox("autoLoadOther", "Auto Load for Other Pages", "div", popup, null, mark);
  556.     new_checkbox("rateEnable", "Show Video Rating", "div", popup, null, mark);
  557.     new_checkbox("defEnable", "Show Video Definition", "div", popup, null, mark);
  558.     if (pref_defEnable) {
  559.         var group3 = newNode("div", null, "gridtube_pref_group", popup);
  560.         new_checkbox("defTop", "Top of Thumb", "span", group3, null, mark);
  561.     }
  562.     new_checkbox("hideRecom", "Hide Recommended from Related", "div", popup, null, mark);
  563.     new_checkbox("userLink", "Open User Links in User Videos", "div", popup, null, mark);
  564.     new_checkbox("newTab", "Open Links in New Tab", "div", popup, null, mark);
  565.     new_checkbox("ytFocus", "Pause at out of Focus Tab", "div", popup, null, mark);
  566. }
  567.  
  568.  
  569. function pref_button() {
  570.     var node = doc.getElementById("gridtube_pref_button");
  571.     var pos = null;
  572.     if (!node) {
  573.         var par = doc.getElementById("yt-masthead-container");
  574.         if (par) {
  575.             node = newNode("span", "gridtube_pref_button", null, par);
  576.             node.setAttribute("top", "true");
  577.             pos = "top";
  578.         }
  579.         else {
  580.             node = newNode("span", "gridtube_pref_button", null, doc.body);
  581.             node.setAttribute("bottom", "true");
  582.             pos = "bottom";
  583.         }
  584.     }
  585.     node.title = "Grid & Player Options";
  586.     node.onclick = function () {
  587.         pref_popup(pos);
  588.     };
  589. }
  590.  
  591. pref_button();
  592.  
  593. var pref_button_timeout = null;
  594.  
  595. function pref_button_show() {
  596.     var node = doc.getElementById("gridtube_pref_button");
  597.     if (!node) return;
  598.  
  599.     var pos = node.getAttribute("top");
  600.     if (!(pos == "true")) return;
  601.  
  602.     node.style.visibility = "visible";
  603.     if (pref_button_timeout)
  604.         win.clearTimeout(pref_button_timeout);
  605. }
  606.  
  607. function pref_button_hide() {
  608.     var node = doc.getElementById("gridtube_pref_button");
  609.     if (!node) return;
  610.  
  611.     var pos = node.getAttribute("top");
  612.     if (!(pos == "true")) return;
  613.  
  614.     //node.style.visibility = "hidden";
  615.     pref_button_timeout = win.setTimeout(function () { node.style.visibility = "hidden"; }, 2000);
  616. }
  617.  
  618.  
  619. //==================================================================
  620. // Choice Icons
  621.  
  622. function choice_icons(page_kind) {
  623.  
  624.     if (doc.getElementById("gridtube_icon_area") != null) return;
  625.  
  626.     function setfunc(prefvalue, prefname, islist) {
  627.         if (islist ? prefvalue : !prefvalue) {
  628.             set_pref(prefname, !prefvalue);
  629.             win.location.reload();
  630.         }
  631.     }
  632.  
  633.     function build_icons(pref_grid_value, pref_grid_name, refnode, position) {
  634.         var icon_box = newNode("span", "gridtube_icon_area", "gridtube_icon_area_" + page_kind, refnode, position);
  635.         if (!icon_box) return;
  636.  
  637.         icon_box.onmouseover = pref_button_show;
  638.         icon_box.onmouseout = pref_button_hide;
  639.  
  640.         //list icon
  641.         var img_list = newNode("img", null, null, icon_box);
  642.         if (!pref_grid_value)
  643.             img_list.setAttribute("selected", "true");
  644.  
  645.         img_list.src = icon_list;
  646.         img_list.title = "list view";
  647.         img_list.addEventListener('click', function () { setfunc(pref_grid_value, pref_grid_name, true); });
  648.  
  649.         //grid icon
  650.         var img_grid = newNode("img", null, null, icon_box);
  651.         if (pref_grid_value)
  652.             img_grid.setAttribute("selected", "true");
  653.  
  654.         img_grid.src = icon_grid;
  655.         img_grid.title = "grid view";
  656.         img_grid.addEventListener('click', function () { setfunc(pref_grid_value, pref_grid_name, false); });
  657.     }
  658.  
  659.  
  660.     // initialization
  661.     var refnode = null;
  662.  
  663.     switch (page_kind) {
  664.         case "search":
  665.             refnode = docsearch("//*[contains(@class,'num-results')]").snapshotItem(0);
  666.             if (refnode)
  667.                 build_icons(pref_gridSearch, "gridSearch", refnode, 'after');
  668.             break;
  669.  
  670.         case "plist":
  671.             refnode = docsearch("//*[contains(@class,'playlist-actions')]").snapshotItem(0);
  672.             if (refnode)
  673.                 build_icons(pref_gridPlist, "gridPlist", refnode, 'after');
  674.             break;
  675.  
  676.         case "hist":
  677.             refnode = docsearch("//*[@id='channel-navigation-menu']").snapshotItem(0);
  678.             if (refnode)
  679.                 build_icons(pref_gridHist, "gridHist", refnode, 'after');
  680.             break;
  681.  
  682.         case "recom":
  683.             refnode = docsearch("//*[contains(@class,'feed-header') and contains(@class, 'clearfix')]").snapshotItem(0);
  684.             if (refnode)
  685.                 build_icons(pref_gridRecom, "gridRecom", refnode, 'first');
  686.             break;
  687.     }
  688. }
  689.  
  690.  
  691. //==================================================================
  692. // Player
  693.  
  694. var basic_str = "(contains(@class,'video-thumb') or contains(@class,'thumb-wrap'))\
  695.                 and (not(descendant::*[contains(@class,'video-thumb') or contains(@class,'thumb-wrap')]))\
  696.                 and (not(ancestor::*[(@gridtube_ads_mark) or (@gridtube_hide_recomm) or (@gridtube_marked_deleted) or (@ytpc_disable_autoplay)\
  697.                                      or (@id='player-playlist')\
  698.                                      or (@id='pl-suggestions')"
  699.                                       + (!pref_gridRel ? "" : " or (@id='pyv-watch-related-dest-url')")
  700.                                       + (pref_gridPlist ? "" : " or (@id='pl-video-list')") + "\
  701.                                      ]))";
  702.  
  703. function player_script() {
  704.     injectScript("\
  705.                       if (YT) {\
  706.                            var player = new YT.Player('gridtube_player_frame');\
  707.                            var errort = null;\
  708.                            function error_reset() { if (errort) window.clearTimeout(errort); }\
  709.                            function check_error(t,fid) {\
  710.                               errort = window.setTimeout(\
  711.                                    function (fid) {\
  712.                                       var f = document.getElementById('gridtube_player_frame');\
  713.                                       if (!f) return;\
  714.                                       if (f.getAttribute('fid') != fid) return;\
  715.                                       var s = player.getPlayerState();\
  716.                                       var a = player.getPlaylist();\
  717.                                       var i = player.getPlaylistIndex();\
  718.                                       if (a != null ? a.length == 0 : false)\
  719.                                           f.dispatchEvent(new Event('playend'));\
  720.                                       else\
  721.                                           if (s == -1 || s == 5)\
  722.                                              if ((a != null && i != null) ? i < a.length - 1 : false)\
  723.                                                 player.nextVideo();\
  724.                                              else\
  725.                                                 f.dispatchEvent(new Event('playend'));\
  726.                                    }, t, fid);\
  727.                            }\
  728.                            player.addEventListener('onReady',\
  729.                                   function () {\
  730.                                        var f = document.getElementById('gridtube_player_frame');\
  731.                                        if (f) {\
  732.                                             var q = f.getAttribute('quality');\
  733.                                             if (q != 'default' && q != null) player.setPlaybackQuality(q);\
  734.                                         }\
  735.                                   });\
  736.                            player.addEventListener('onStateChange',\
  737.                                 function () {\
  738.                                    var f = document.getElementById('gridtube_player_frame');\
  739.                                    if (!f) return;\
  740.                                    var s = player.getPlayerState();\
  741.                                    var a = player.getPlaylist();\
  742.                                    var i = player.getPlaylistIndex();\
  743.                                    var cond = ((a != null && i != null) ? i == a.length - 1 : true);\
  744.                                    var q = f.getAttribute('quality');\
  745.                                    if (s == -1 && q != 'default' && q != null) player.setPlaybackQuality(q);\
  746.                                    else if (s == 0 && cond) {\
  747.                                        error_reset();\
  748.                                        f.dispatchEvent(new Event('playend'));\
  749.                                    }\
  750.                                 });\
  751.                            var frame = document.getElementById('gridtube_player_frame');\
  752.                            if (frame) {\
  753.                                  check_error(10000,frame.getAttribute('fid'));\
  754.                                  frame.addEventListener('loadnewvideo',\
  755.                                                          function (x) {\
  756.                                                             var fid = x.target.getAttribute('fid');\
  757.                                                             var url = x.target.getAttribute('newvidurl');\
  758.                                                             var plist = x.target.getAttribute('plist');\
  759.                                                             error_reset();\
  760.                                                             player.pauseVideo();\
  761.                                                             if (plist) {\
  762.                                                                player.loadPlaylist({'list':plist});\
  763.                                                                check_error(10000,fid);\
  764.                                                             }\
  765.                                                             else if (url) {\
  766.                                                                player.loadVideoByUrl(url);\
  767.                                                                check_error(10000,fid);\
  768.                                                             }\
  769.                                                          });\
  770.                                  frame.addEventListener('pausevideo',\
  771.                                                          function (x) {\
  772.                                                             player.pauseVideo();\
  773.                                                          });\
  774.                                  }\
  775.                      }");
  776. }
  777.  
  778. var choices_def = ['default', 'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'highres'];
  779. var choices_size = ['tiny', 'small', 'medium', 'large', 'huge'];
  780. var choices_pos = ['00', '01', '02', '10', '11', '12', '20', '21', '22'];
  781.  
  782. //player preferences
  783. if (pref_playerEnable) {
  784.     init_pref("playerFit", false);
  785.     init_pref("playerDef", "default");
  786.     init_pref("playerSize", "medium");
  787.     init_pref("playerPos", "11");
  788.     init_pref("playerNext", true);
  789.     init_pref("playerClose", true);
  790.     init_pref("playerPause", true);
  791.     init_pref("playerFocus", false);
  792.     init_pref("playerDim", true);
  793.  
  794.     //fix char preferences
  795.     if (choices_def.indexOf(get_pref("playerDef")) < 0) set_pref("playerDef", 'default');
  796.     if (choices_size.indexOf(get_pref("playerSize")) < 0) set_pref("playerSize", 'medium');
  797.     if (choices_pos.indexOf(get_pref("playerPos")) < 0) set_pref("playerPos", '11');
  798. }
  799.  
  800.  
  801. function player_options(parent) {
  802.     var popup = doc.getElementById("gridtube_player_options_popup");
  803.     if (popup) return;
  804.  
  805.     popup = newNode("span", "gridtube_player_options_popup", null, parent);
  806.  
  807.     var title_node = newNode("div", null, "gridtube_player_options_title", popup);
  808.     title_node.textContent = "Preview Player Options";
  809.  
  810.     var closemark = newNode("span", null, "gridtube_player_options_close", popup);
  811.     closemark.textContent = "\u2716";
  812.     closemark.title = "close options";
  813.     closemark.onclick = close_player_options;
  814.  
  815.  
  816.     new_checkbox("playerNext", "Auto Play Next", "div", popup);
  817.     new_checkbox("playerDim", "Dim Background", "div", popup, null, function () {
  818.         doc.getElementById("gridtube_player_area").style.visibility = (get_pref("playerDim") ? "visible" : "hidden");
  819.     });
  820.     new_checkbox("playerClose", "Close on Clicking Outside Player", "div", popup);
  821.     new_checkbox("playerPause", "Pause YouTube Player at Launch", "div", popup);
  822.     new_checkbox("playerFocus", "Pause at out of Focus Tab", "div", popup);
  823.  
  824.     var div = newNode("div", null, "gridtube_player_options_text", popup);
  825.     //default, small, medium, large, hd720, hd1080, hd1440, highres;
  826.     div.textContent = "Definition";
  827.     var group1 = newNode("div", null, "gridtube_player_options_group", popup);
  828.     var group2 = newNode("div", null, "gridtube_player_options_group", popup);
  829.     new_checkbox("playerDef", "Default", "span", group1, "default");
  830.     new_checkbox("playerDef", "LQ 240", "span", group1, "small");
  831.     new_checkbox("playerDef", "MQ 360", "span", group1, "medium");
  832.     new_checkbox("playerDef", "HQ 480", "span", group1, "large");
  833.     new_checkbox("playerDef", "HD 720", "span", group2, "hd720");
  834.     new_checkbox("playerDef", "HD 1080", "span", group2, "hd1080");
  835.     new_checkbox("playerDef", "HD 1440", "span", group2, "hd1440");
  836.     new_checkbox("playerDef", "MAX", "span", group2, "highres");
  837. }
  838.  
  839.  
  840. function close_player_options() {
  841.     var popup = doc.getElementById("gridtube_player_options_popup");
  842.     if (popup) popup.parentNode.removeChild(popup);
  843. }
  844.  
  845.  
  846. function build_player() {
  847.     //constants
  848.     var next_choice = new Object();
  849.     next_choice['plus'] = new Object();
  850.     next_choice['minus'] = new Object();
  851.     next_choice['left'] = new Object();
  852.     next_choice['right'] = new Object();
  853.     next_choice['up'] = new Object();
  854.     next_choice['down'] = new Object();
  855.  
  856.     next_choice['plus']['tiny'] = 'small';
  857.     next_choice['plus']['small'] = 'medium';
  858.     next_choice['plus']['medium'] = 'large';
  859.     next_choice['plus']['large'] = 'huge';
  860.     next_choice['plus']['huge'] = 'huge';
  861.  
  862.     next_choice['minus']['tiny'] = 'tiny';
  863.     next_choice['minus']['small'] = 'tiny';
  864.     next_choice['minus']['medium'] = 'small';
  865.     next_choice['minus']['large'] = 'medium';
  866.     next_choice['minus']['huge'] = 'large';
  867.  
  868.     {
  869.         for (var i = 0; i < 3; i++)
  870.             for (var j = 0; j < 3; j++) {
  871.                 next_choice['left'][i.toString() + j.toString()] = i.toString() + (j - 1 >= 0 ? j - 1 : 0).toString();
  872.                 next_choice['right'][i.toString() + j.toString()] = i.toString() + (j + 1 <= 2 ? j + 1 : 2).toString();
  873.                 next_choice['up'][i.toString() + j.toString()] = (i - 1 >= 0 ? i - 1 : 0).toString() + j.toString();
  874.                 next_choice['down'][i.toString() + j.toString()] = (i + 1 <= 2 ? i + 1 : 2).toString() + j.toString();
  875.             }
  876.     }
  877.  
  878.     var area = null;
  879.     var area2 = null;
  880.     var box = null;
  881.     var holder = null;
  882.     var holder2 = null;
  883.  
  884.     var new_size = get_pref("playerSize");
  885.     var new_pos = get_pref("playerPos");
  886.     var new_fit = get_pref("playerFit");
  887.  
  888.     var that = this;
  889.     var frame_count = 0;
  890.  
  891.     //public
  892.     this.playerShow = function (vid, pid, node) {
  893.         var vis = box.style.visibility;
  894.         if (vis == "hidden") {
  895.             new_size = get_pref("playerSize");
  896.             new_pos = get_pref("playerPos");
  897.             new_fit = get_pref("playerFit");
  898.         }
  899.         playerAdjust((new_fit ? 'fit' : new_size), new_pos, "visible", vid, pid);
  900.         adjust_playing(node);
  901.     }
  902.  
  903.     this.playerClose = function () {
  904.         playerAdjust(null, null, "hidden", null, null);
  905.         close_player_options();
  906.         adjust_playing();
  907.         move_enable = false;
  908.     }
  909.  
  910.     this.playerPause = function () {
  911.         var frame = doc.getElementById("gridtube_player_frame");
  912.         if (frame != null) {
  913.             var event = doc.createEvent('Event');
  914.             event.initEvent('pausevideo', true, true);
  915.             frame.dispatchEvent(event);
  916.         }
  917.     }
  918.  
  919.     //private
  920.     function playerUrl(vid, pid) {
  921.  
  922.         var url = win.location.protocol + "//www.youtube.com/";
  923.  
  924.         if (vid) url += "embed/" + vid + "?" + (pid ? "&list=" + pid : "");
  925.         else if (pid) url += "embed?listType=playlist&list=" + pid;
  926.  
  927.         url += "&autoplay=1&fs=1&iv_load_policy=3&rel=1&version=3&enablejsapi=1";
  928.  
  929.         return (url);
  930.     }
  931.  
  932.  
  933.     function adjust_playing(node) {
  934.         var playing = doc.getElementById("gridtube_meta_playing");
  935.         if (playing)
  936.             playing.parentNode.removeChild(playing);
  937.  
  938.         if (node) {
  939.             playing = newNode("span", "gridtube_meta_playing", null, node);
  940.             playing.textContent = "now playing";
  941.         }
  942.     }
  943.  
  944.  
  945.     function play_next(findprevious) {
  946.  
  947.         var playing = doc.getElementById("gridtube_meta_playing");
  948.         if (!playing) return;
  949.  
  950.         var pos = -2;
  951.         var l = null;
  952.  
  953.         var myimg = innersearch(playing.parentNode, ".//img[@src or @data-thumb]").snapshotItem(0);
  954.         if (myimg) {
  955.             //l = docsearch("//*[(" + basic_str + ") and (not(ancestor::*[contains(@class,'vve-check')]))]//img[contains(@src,'vi/') or contains(@src,'vi_webp/')]");
  956.             l = docsearch("//*[(" + basic_str + ")]//img[contains(@src,'vi/') or contains(@src,'vi_webp/') or contains(@src,'/p/') or contains(@src,'/s_p/')]");
  957.  
  958.             myimg.setAttribute("matchfind", "true");
  959.  
  960.             for (var i = 0; i < l.snapshotLength; i++) {
  961.                 if (l.snapshotItem(i).getAttribute("matchfind")) {
  962.                     pos = i;
  963.                     break;
  964.                 }
  965.             }
  966.  
  967.             myimg.removeAttribute("matchfind");
  968.         }
  969.  
  970.         pos = (findprevious ? pos - 1 : pos + 1);
  971.  
  972.         if (pos >= 0) {
  973.             var img = l.snapshotItem(pos);
  974.             if (img) {
  975.                 var str1 = img.getAttribute("src");
  976.                 var vid = filter(str1, "vi/", "/&?#");
  977.                 if (!vid) vid = filter(str1, "vi_webp/", "/&?#");
  978.  
  979.                 var pid = find_plist(img);
  980.                 img.setAttribute("matchfindimg", true);
  981.                 var target = docsearch("//*[" + basic_str + " and (.//img[@matchfindimg])]").snapshotItem(0);
  982.                 if (target) {
  983.                     that.playerShow(vid, pid, target);
  984.                 }
  985.                 img.removeAttribute("matchfindimg");
  986.             }
  987.         }
  988.     }
  989.  
  990.  
  991.     function playerAdjust(size, pos, vis, vid, pid) {
  992.  
  993.         if (vis != null) {
  994.             box.style.visibility = vis;
  995.             area.style.visibility = (get_pref("playerDim") ? vis : "hidden");
  996.  
  997.             var frame = doc.getElementById("gridtube_player_frame");
  998.             if (frame != null && (vis == 'hidden')) {
  999.                 frame.parentNode.removeChild(frame);
  1000.                 frame = null;
  1001.             }
  1002.  
  1003.             if (vis == "visible") {
  1004.                 var vidurl = playerUrl(vid, pid);
  1005.                 var def = get_pref("playerDef");
  1006.                 frame_count++;
  1007.  
  1008.                 if (frame) {
  1009.                     frame.setAttribute("newvidurl", vidurl);
  1010.                     if (pid) frame.setAttribute("plist", pid);
  1011.                     else frame.removeAttribute("plist");
  1012.                     frame.setAttribute("quality", def);
  1013.                     frame.setAttribute("fid", frame_count.toString());
  1014.  
  1015.                     var event = doc.createEvent('Event');
  1016.                     event.initEvent('loadnewvideo', true, true);
  1017.                     frame.dispatchEvent(event);
  1018.                 }
  1019.                 else {
  1020.                     frame = newNode("iframe", "gridtube_player_frame", null, holder2);
  1021.                     frame.setAttribute("type", "text/html");
  1022.                     frame.setAttribute("frameborder", "0");
  1023.                     frame.setAttribute("allowfullscreen", "true");
  1024.                     frame.setAttribute("quality", def);
  1025.                     frame.setAttribute("fid", frame_count.toString());
  1026.                     frame.src = vidurl;
  1027.                     frame.addEventListener('playend', function f() { if (get_pref("playerNext")) play_next(); });
  1028.  
  1029.                     player_script();
  1030.                 }
  1031.             }
  1032.         }
  1033.  
  1034.         if (size != null) {
  1035.             box.setAttribute("player_size", size);
  1036.             holder.setAttribute("player_size", size);
  1037.         }
  1038.  
  1039.         if (pos != null)
  1040.             box.setAttribute("player_pos", pos);
  1041.     }
  1042.  
  1043.  
  1044.     function click_pos_size(e) {
  1045.         var kind = e.target.getAttribute("button_kind");
  1046.  
  1047.         if (new_fit && !(kind == 'options' || kind == 'prev' || kind == 'next')) {
  1048.             set_pref("playerFit", false);
  1049.             new_fit = false;
  1050.             playerAdjust(new_size, new_pos);
  1051.             return;
  1052.         }
  1053.  
  1054.         switch (kind) {
  1055.             case 'plus':
  1056.             case 'minus':
  1057.                 new_size = next_choice[kind][new_size];
  1058.                 set_pref("playerSize", new_size);
  1059.                 playerAdjust(new_size, new_pos);
  1060.                 break;
  1061.  
  1062.             case 'fit':
  1063.                 set_pref("playerFit", true);
  1064.                 new_fit = true;
  1065.                 playerAdjust('fit');
  1066.                 break;
  1067.  
  1068.             case 'left':
  1069.             case 'right':
  1070.             case 'up':
  1071.             case 'down':
  1072.                 new_pos = next_choice[kind][new_pos];
  1073.                 set_pref("playerPos", new_pos);
  1074.                 playerAdjust(new_size, new_pos);
  1075.                 break;
  1076.  
  1077.             case 'options':
  1078.                 player_options(box);
  1079.                 break;
  1080.  
  1081.             case 'prev':
  1082.                 play_next(true);
  1083.                 break;
  1084.  
  1085.             case 'next':
  1086.                 play_next();
  1087.                 break;
  1088.         }
  1089.     }
  1090.  
  1091.  
  1092.     function new_button(kind, str, str_popup, parent) {
  1093.         var node = newNode("span", null, "gridtube_player_button", parent);
  1094.         node.textContent = str;
  1095.         node.title = str_popup;
  1096.         node.setAttribute("button_kind", kind);
  1097.         node.onclick = click_pos_size;
  1098.     }
  1099.  
  1100.     //initialization;
  1101.     if (doc.getElementById("gridtube_player_area")) return;
  1102.  
  1103.     area = newNode("div", "gridtube_player_area", null, doc.body);
  1104.     area2 = newNode("div", "gridtube_player_area2", null, area);
  1105.     box = newNode("div", "gridtube_player_box", null, area2);
  1106.     holder = newNode("div", "gridtube_player_holder", null, box);
  1107.     holder2 = newNode("div", "gridtube_player_holder2", null, holder);
  1108.     box.style.visibility = "hidden";
  1109.     area.style.visibility = "hidden";
  1110.     holder.title = "close player";
  1111.  
  1112.     holder.onclick = function (e) {
  1113.         if (e.target.id == "gridtube_player_holder") that.playerClose();
  1114.     };
  1115.  
  1116.     area.onclick = function (e) {
  1117.         if (e.target.id == "gridtube_player_area")
  1118.             if (get_pref("playerClose")) that.playerClose();
  1119.     };
  1120.  
  1121.     var buttonArea = newNode("span", "gridtube_player_button_area_top", null, box);
  1122.     new_button("plus", "\u002B", "increase player size", buttonArea);
  1123.     new_button("minus", "\u2212", "decrease player size", buttonArea);
  1124.     new_button("fit", "\u2610", "fit player to window", buttonArea);
  1125.     new_button('left', '\u25C4', 'move player left', buttonArea);
  1126.     new_button('right', '\u25BA', 'move player right', buttonArea);
  1127.     new_button('up', '\u25B2', 'move player up', buttonArea);
  1128.     new_button('down', '\u25BC', 'move player down', buttonArea);
  1129.     new_button("options", "Options", "player options", buttonArea);
  1130.  
  1131.     var bottomArea = newNode("span", "gridtube_player_button_area_bottom", null, box);
  1132.     new_button("prev", "\u140A\u140A", "play previous in page", bottomArea);
  1133.     new_button("next", "\u1405\u1405", "play next in page", bottomArea);
  1134.     //new_button("loop", "\u21BB", "repeat video", bottomArea);
  1135.  
  1136.     var mark = newNode("span", "gridtube_player_close_mark", null, box);
  1137.     mark.textContent = "\u2716";
  1138.     mark.title = "close player";
  1139.     mark.onclick = this.playerClose;
  1140. }
  1141.  
  1142.  
  1143. var player = null;
  1144. if (pref_playerEnable) {
  1145.     player = new build_player();
  1146.     injectScript(null, 'https://www.youtube.com/iframe_api');
  1147. }
  1148.  
  1149.  
  1150. function player_close(e) {
  1151.     if (!player) return;
  1152.  
  1153.     if (e) {
  1154.         if (!get_pref("playerClose")) return;
  1155.  
  1156.         var pattern = /gridtube|ytpc|button|subscribe/;
  1157.  
  1158.         if (e.target.id)
  1159.             if (e.target.id.match(pattern))
  1160.                 return;
  1161.  
  1162.         if (e.target.className)
  1163.             if (e.target.className.match(pattern))
  1164.                 return;
  1165.  
  1166.         if (e.target.nodeName == "BUTTON" || e.target.nodeName == "INPUT")
  1167.             return;
  1168.     }
  1169.  
  1170.     player.playerClose();
  1171. }
  1172.  
  1173.  
  1174. function ytpause() {
  1175.     injectScript("var a = document.getElementById('c4-player') || document.getElementById('movie_player');\
  1176.                   if (a != null)\
  1177.                      if (a.pauseVideo != null){\
  1178.                          a.pauseVideo();\
  1179.                      }\
  1180.                  ");
  1181. }
  1182.  
  1183.  
  1184. //==================================================================
  1185. //meta data
  1186.  
  1187. var api_key = "AIzaSyAxn6m4k-YdsYhrwUZ2Mxf_Lh5jC-lWeyA";
  1188.  
  1189. function data_entry_v3(entry) {
  1190.  
  1191.     var ret = new Object();
  1192.  
  1193.     ret.feedKind = null;
  1194.     ret.feedId = null;
  1195.  
  1196.     ret.title = null;
  1197.     ret.descr = null;
  1198.     ret.length = null;
  1199.  
  1200.     ret.views = null;
  1201.     ret.length = null;
  1202.     ret.likes = null;
  1203.     ret.dislikes = null;
  1204.     ret.HD = null;
  1205.  
  1206.     ret.user = new Object();
  1207.     ret.user.id = null;
  1208.     ret.user.name = null;
  1209.     ret.user.channelId = null;
  1210.  
  1211.     if (entry.kind)
  1212.         if (entry.kind == "youtube#video")
  1213.             ret.feedKind = "video";
  1214.  
  1215.     if (entry.id)
  1216.         ret.feedId = entry.id;
  1217.  
  1218.     //message("feedKind=" + ret.feedKind);
  1219.     //message("feedId=" + ret.feedId);
  1220.  
  1221.     if (entry.snippet) {
  1222.         if (entry.snippet.title)
  1223.             ret.title = entry.snippet.title;
  1224.         if (entry.snippet.description)
  1225.             ret.descr = entry.snippet.description;
  1226.         if (entry.snippet.channelId)
  1227.             ret.user.channelId = entry.snippet.channelId;
  1228.         if (entry.snippet.channelTitle)
  1229.             ret.user.name = entry.snippet.channelTitle;
  1230.  
  1231.         //message("title=" + ret.title);
  1232.         //message("description=" + ret.descr);
  1233.         //message("channelId=" + ret.user.channelId);
  1234.     }
  1235.  
  1236.  
  1237.     if (entry.contentDetails) {
  1238.         if (entry.contentDetails.definition)
  1239.             if (entry.contentDetails.definition == "hd")
  1240.                 ret.HD = true;
  1241.  
  1242.         if (entry.contentDetails.duration)
  1243.             ret.length = entry.contentDetails.duration;
  1244.  
  1245.         //message("HD=" + ret.HD);
  1246.         //message("length=" + ret.length + "  converted:" + time_column(ret.length));
  1247.     }
  1248.  
  1249.     if (entry.statistics) {
  1250.         if (entry.statistics.viewCount)
  1251.             ret.views = entry.statistics.viewCount;
  1252.         if (entry.statistics.likeCount)
  1253.             ret.likes = entry.statistics.likeCount;
  1254.         if (entry.statistics.dislikeCount)
  1255.             ret.dislikes = entry.statistics.dislikeCount;
  1256.  
  1257.         //message("views=" + ret.views + "     likes=" + ret.likes + "       dislikes=" + ret.dislikes);
  1258.     }
  1259.  
  1260.     return ret;
  1261. }
  1262.  
  1263.  
  1264. function data_feed_v3(json_txt) {
  1265.  
  1266.     //object to be returned
  1267.     var ret = new Object();
  1268.     ret.totalResults = 0;
  1269.     ret.entry = new Array();
  1270.  
  1271.     //main code
  1272.     var job = null; //json object
  1273.     if (json_txt != null)
  1274.         job = JSON.parse(json_txt);
  1275.  
  1276.     if (job == null) return ret;
  1277.  
  1278.     //jmessage(job);
  1279.  
  1280.     if (job.pageInfo != null)
  1281.         if (job.pageInfo.totalResults != null) {
  1282.             ret.totalResults = job.pageInfo.totalResults;
  1283.             //message("totalResults=" + ret.totalResults);
  1284.         }
  1285.  
  1286.     if (job.items != null)
  1287.         if (job.items.length != 0)
  1288.             for (var i = 0; i < job.items.length; i++) {
  1289.                 var data = data_entry_v3(job.items[i]);
  1290.                 if (data.feedKind != null) {
  1291.                     ret.entry.push(data);
  1292.                 }
  1293.             }
  1294.  
  1295.     return ret;
  1296. }
  1297.  
  1298.  
  1299. function callback2(json_txt, def_node, buildHD, buildRate, parent) {
  1300.     //message(json_txt);
  1301.  
  1302.     var feed = data_feed_v3(json_txt);
  1303.  
  1304.     if (feed.entry.length != 1) return;
  1305.     var entry = feed.entry[0];
  1306.  
  1307.     //message("here");
  1308.  
  1309.     if (buildHD) {
  1310.         if (entry.HD != null) {
  1311.             def_node.setAttribute("reveal", "true");
  1312.             def_node.title = "high definition";
  1313.             var node_hd = newNode("span", null, "gridtube_meta_def_hd HD", def_node);
  1314.             node_hd.textContent = "HD";
  1315.         }
  1316.     }
  1317.  
  1318.     //message("there");
  1319.  
  1320.     if (buildRate) {
  1321.         var num_likes = (entry.likes != null ? parseInt(entry.likes) : 0);
  1322.         var num_dislikes = (entry.dislikes != null ? parseInt(entry.dislikes) : 0);
  1323.  
  1324.         if ((num_likes != 0) || (num_dislikes != 0)) {
  1325.             var perc = 100 - Math.round(num_dislikes * 100.0 / (num_likes + num_dislikes));
  1326.  
  1327.             var rateBrief = newNode("div", null, "gridtube_meta_rate", parent);
  1328.             rateBrief.title = perc + "% likes: +" + number_comma(num_likes.toString()) + "  -" + number_comma(num_dislikes.toString());
  1329.             rateBrief.onmouseover = pref_button_show;
  1330.             rateBrief.onmouseout = pref_button_hide;
  1331.  
  1332.             if (entry.views != null) {
  1333.                 var view_num = number_comma(entry.views);
  1334.                 rateBrief.title += "\n" + view_num + " views";
  1335.             }
  1336.  
  1337.             if (perc >= red_threshold) {
  1338.                 rateBrief.textContent = "\uD83D\uDC4D " + perc;
  1339.                 if (perc < orange_threshold) {
  1340.                     rateBrief.setAttribute("med", "true");
  1341.                 }
  1342.             }
  1343.             else {
  1344.                 rateBrief.textContent = "\uD83D\uDC4E " + perc;
  1345.                 rateBrief.setAttribute("bad", "true");
  1346.             }
  1347.         }
  1348.     }
  1349. }
  1350.  
  1351.  
  1352. function callback1(txt, def_node, url2, parent) {
  1353.     //message(txt);
  1354.     var res = extract_resolution(txt);
  1355.  
  1356.     if (res) {
  1357.         def_node.setAttribute("reveal", "true");
  1358.         def_node.title = res.size + " definition";
  1359.         if (res.HD) {
  1360.             var node_hd = newNode("span", null, "gridtube_meta_def_hd" + (res.UHD ? " UHD" : " HD"), def_node);
  1361.             node_hd.textContent = res.UHD ? res.UHD : "HD";
  1362.             def_node.setAttribute("space", "true");
  1363.         }
  1364.         var node_attr = newNode("span", null, "gridtube_meta_def_format", def_node);
  1365.         node_attr.textContent = res.format;
  1366.  
  1367.         if (pref_rateEnable) {
  1368.             //message("callback");
  1369.             httpReq(url2, callback2, null, false, true, parent);
  1370.         }
  1371.     }
  1372.     else {
  1373.         //message("callback");
  1374.         httpReq(url2, callback2, def_node, true, pref_rateEnable, parent);
  1375.     }
  1376. }
  1377.  
  1378.  
  1379. function def_rate(v_id, parent) {
  1380.     var url1 = "https://www.youtube.com/get_video_info?video_id=" + v_id;
  1381.     var url2 = "https://www.googleapis.com/youtube/v3/videos?id=" + v_id + "&key=" + api_key + "&part=contentDetails,statistics";
  1382.  
  1383.     //httpreq
  1384.     if (pref_defEnable) {
  1385.         var def_node = newNode("span", null, "gridtube_meta_def_container" + (pref_defTop ? " top" : " bottom"), parent);
  1386.         httpReq(url1, callback1, def_node, url2, parent);
  1387.         def_node.onmouseover = pref_button_show;
  1388.         def_node.onmouseout = pref_button_hide;
  1389.     }
  1390.     else
  1391.         if (pref_rateEnable)
  1392.             httpReq(url2, callback2, null, false, true, parent);
  1393. }
  1394.  
  1395.  
  1396. function play(vid, pid, parent) {
  1397.     var playArea = newNode("div", null, "gridtube_meta_play_container", parent);
  1398.     var playNode = newNode("a", null, "gridtube_meta_play", playArea);
  1399.     playNode.href = "javascript:;";
  1400.     playNode.target = "_self";
  1401.     playNode.setAttribute('gridtube_meta_link_mark', 'true');
  1402.     playNode.title = "click to play";
  1403.  
  1404.     function play_handle(e) {
  1405.         disable_ajax(e);
  1406.  
  1407.         var parpar = e.target.parentNode.parentNode;
  1408.  
  1409.         if (innersearch(parpar, ".//*[@id='gridtube_meta_playing']").snapshotLength > 0)
  1410.             player_close();
  1411.         else {
  1412.             player.playerShow(vid, pid, parpar);
  1413.             if (get_pref("playerPause")) ytpause();
  1414.         }
  1415.     }
  1416.  
  1417.     playNode.onclick = play_handle;
  1418.     playNode.onmouseover = pref_button_show;
  1419.     playNode.onmouseout = pref_button_hide;
  1420. }
  1421.  
  1422.  
  1423. function find_plist(img) {
  1424.     var anc = innersearch(img, ".//ancestor::*[contains(@href,'&list=') and contains(@class,'yt-pl-thumb')]").snapshotItem(0);
  1425.     var plist = null;
  1426.     if (anc)
  1427.         plist = filter(anc.href, "list=", "/&?#");
  1428.     //message(plist);
  1429.     return plist;
  1430. }
  1431.  
  1432. function meta_data() {
  1433.  
  1434.     var vid_str = "//*[" + basic_str + " and (not(.//img[@data-thumb])) and (not(@gridtube_meta_thumb_mark))]";
  1435.  
  1436.     var link_str = "//div[(@id='content') or (contains(@class,'playlist-info'))]\
  1437.                        //a[(not(@gridtube_meta_link_mark))\
  1438.                            and (not(contains(@href,'javascript')))\
  1439.                            and (not(ancestor::*[contains(@class,'branded-page-v2-top-row')\
  1440.                                                    or contains(@class, 'tabs-area')\
  1441.                                                    or contains(@class, 'search-header')\
  1442.                                                    or contains(@class, 'search-pager')\
  1443.                                                    or contains(@class, 'spell-correction')\
  1444.                                                    or contains(@class, 'menu-container')\
  1445.                                                    or contains(@id, 'creator-page-sidebar')\
  1446.                                                    or contains(@id, 'channel-navigation-menu')\
  1447.                                                    or contains(@id, 'watch-discussion')\
  1448.                                                ]))\
  1449.                            ]";
  1450.  
  1451.     var user_str = "//*[contains(@class,'yt-lockup-byline')\
  1452.                        or contains(@class, 'pl-video-owner')\
  1453.                        or contains(@class,'pl-header-details')\
  1454.                        or contains(@class, 'yt-user-info')\
  1455.                        or contains(@class, 'author-attribution')\
  1456.                        or contains(@class, 'content-uploader')]\
  1457.                             //a[(contains(@href,'/user/') or contains(@href,'/channel/')) and (not(@gridtube_meta_user_mark))]";
  1458.  
  1459.     var user_str2 = "//li[contains(@class,'related-list-item')]\
  1460.                     //span[contains(@class,'g-hovercard') and (@data-ytid) and (not(@gridtube_meta_user_mark2))]";
  1461.  
  1462.  
  1463.     function check_def_rate_play() {
  1464.         if (pref_defEnable || pref_rateEnable || pref_playerEnable) {
  1465.  
  1466.             if ((pref_defEnable || pref_rateEnable) && in_video_page()) {
  1467.                 var wvid = filter(win.location.href, "v=", "?&#");
  1468.                 if (wvid) {
  1469.                     var par = doc.getElementById("gridtube_meta_box");
  1470.                     if (!par) {
  1471.                         var target = doc.getElementById("gridtube_title_container");
  1472.                         if (!target) {
  1473.                             //var pp = doc.getElementById("watch7-user-header");
  1474.                             var pp = doc.getElementById("watch-header");
  1475.                             if (pp) target = newNode("span", "gridtube_title_container", null, pp);
  1476.                         }
  1477.                         if (target) {
  1478.                             par = newNode("span", 'gridtube_meta_box', null, target);
  1479.                             def_rate(wvid, par);
  1480.                         }
  1481.                     }
  1482.                 }
  1483.             }
  1484.  
  1485.             //check everything else
  1486.             var p = docsearch(vid_str);
  1487.             //message(p.snapshotLength);
  1488.             for (var i = 0; i < p.snapshotLength; i++) {
  1489.                 var parent = p.snapshotItem(i);
  1490.                 parent.setAttribute('gridtube_meta_thumb_mark', 'true');
  1491.                 var img = innersearch(parent, ".//img[contains(@src,'vi/') or contains(@src,'vi_webp/') or contains(@src,'/p/') or contains(@src,'/s_p/')]").snapshotItem(0);
  1492.                 if (!img) continue;
  1493.  
  1494.                 var vid = filter(img.src, "vi/", "/&?#");
  1495.                 if (!vid) vid = filter(img.src, "vi_webp/", "/&?#");
  1496.  
  1497.                 //detect progress bar
  1498.                 if ((pref_defEnable && !pref_defTop) && (in_plist_page() || in_user_page())) {
  1499.                     if (innersearch(parent.parentNode.parentNode, ".//*[contains(@class,'resume-playback-progress-bar')]").snapshotLength > 0) {
  1500.                         parent.parentNode.parentNode.setAttribute("gridtube_progress_bar", "true");
  1501.                     }
  1502.                 }
  1503.  
  1504.                 if (vid) {//video or playlist
  1505.                     if (pref_defEnable || pref_rateEnable)
  1506.                         def_rate(vid, parent);
  1507.                 }
  1508.  
  1509.                 if (pref_playerEnable) {
  1510.                     //check for playlist
  1511.                     var plist = find_plist(img);
  1512.                     //message(plist);
  1513.                     play(vid, plist, parent);
  1514.                 }
  1515.             }
  1516.         }
  1517.     }
  1518.  
  1519.  
  1520.     function check_tab() {
  1521.         //new tab for links
  1522.         if (pref_newTab) {
  1523.             var anodes = docsearch(link_str);
  1524.             //message(anodes.snapshotLength);
  1525.             for (var j = 0; j < anodes.snapshotLength; j++) {
  1526.                 var a = anodes.snapshotItem(j);
  1527.                 a.target = "_blank";
  1528.                 a.setAttribute('gridtube_meta_link_mark', 'true');
  1529.                 a.onclick = disable_ajax;
  1530.                 //message(a.href);
  1531.             }
  1532.         }
  1533.     }
  1534.  
  1535.  
  1536.     function check_user() {
  1537.         //open user links in video section
  1538.         if (pref_userLink) {
  1539.             var anodes = docsearch(user_str);
  1540.             //message(anodes.snapshotLength);
  1541.             for (var j = 0; j < anodes.snapshotLength; j++) {
  1542.                 var a = anodes.snapshotItem(j);
  1543.                 a.setAttribute('gridtube_meta_user_mark', 'true');
  1544.                 //message(a.href);
  1545.  
  1546.                 var arr = a.href.split(/user[/]|channel[/]/);
  1547.                 //message(arr);
  1548.                 if (arr.length != 2) continue;
  1549.                 if (arr[1].indexOf('/') != -1) continue;
  1550.                 a.href += "/videos";
  1551.             }
  1552.         }
  1553.  
  1554.  
  1555.         //related user links
  1556.         var unodes = docsearch(user_str2);
  1557.         for (var j = 0; j < unodes.snapshotLength; j++) {
  1558.             var node = unodes.snapshotItem(j);
  1559.             node.setAttribute('gridtube_meta_user_mark2', 'true');
  1560.             //message(a.href);
  1561.  
  1562.             var a = doc.createElement("a");
  1563.             var attr = node.attributes;
  1564.             for (var i = 0; i < attr.length; i++) {
  1565.                 a.setAttribute(attr[i].nodeName, attr[i].nodeValue);
  1566.             }
  1567.             a.setAttribute("gridtube_meta_user_mark2", "true");
  1568.             a.href = win.location.protocol + "//www.youtube.com/channel/" + node.getAttribute("data-ytid") + (pref_userLink ? "/videos" : "");
  1569.             a.textContent = node.textContent;
  1570.             node.parentNode.replaceChild(a, node);
  1571.         }
  1572.     }
  1573.  
  1574.     check_def_rate_play();
  1575.     check_tab();
  1576.     check_user();
  1577. }
  1578.  
  1579.  
  1580. //==================================================================
  1581. // Search pages
  1582.  
  1583. var aux = new Object();
  1584.  
  1585. function bottom_bar(kind) {
  1586.     var irend = doc.getElementById("gridtube_result_end");
  1587.     var txt_node = null;
  1588.     var img_node = null;
  1589.     if (irend == null) {
  1590.         var results_end_bar = doc.getElementById("gridtube_results_end_bar");
  1591.         irend = newNode("div", "gridtube_result_end", "gridtube_result_bar_inner", results_end_bar);
  1592.         img_node = newNode("img", "gridtube_result_end_img", null, irend);
  1593.         img_node.style.visibility = "hidden";
  1594.         img_node.src = "https://www.google.com/images/nycli1.gif";
  1595.         txt_node = newNode("span", "gridtube_result_end_text", null, irend);
  1596.     }
  1597.     else {
  1598.         txt_node = doc.getElementById("gridtube_result_end_text");
  1599.         img_node = doc.getElementById("gridtube_result_end_img");
  1600.     }
  1601.  
  1602.     switch (kind) {
  1603.         case "loading":
  1604.             irend.onclick = function (e) { };
  1605.             txt_node.textContent = "Loading Page " + aux.next_button.textContent;
  1606.             img_node.style.visibility = "visible";
  1607.             img_node.style.width = "auto";
  1608.             break;
  1609.  
  1610.         case "end":
  1611.             irend.onclick = function (e) { win.scroll(0, 0); };
  1612.             irend.setAttribute("title", "go to top of page");
  1613.             txt_node.textContent = "End of Results" + (aux.last_page ? " - Page " + aux.last_page : "");
  1614.             img_node.style.visibility = "hidden";
  1615.             img_node.style.width = "0px";
  1616.             break;
  1617.     }
  1618. }
  1619.  
  1620.  
  1621. function search_pages(cond) {
  1622.     //message(cond);
  1623.  
  1624.     var next_str = "//*[contains(@class,'search-pager')]/a[contains(@class,'yt-uix-button') and (@href) and (preceding-sibling::button)]";
  1625.  
  1626.     var parent = docsearch("//*[@id='results']/ol/li/ol").snapshotItem(0);
  1627.     if (!parent) return;
  1628.  
  1629.     function find_next_search() {
  1630.         if (aux.next_button) {
  1631.             aux.next_href = aux.next_button.getAttribute("href");
  1632.             if (aux.next_href.indexOf(win.location.origin) != 0) {
  1633.                 aux.next_href = win.location.origin + aux.next_href;
  1634.                 //message("fixed url");
  1635.             }
  1636.             //message(aux.next_href);
  1637.             //message(aux.next_button.textContent);
  1638.             aux.last_page = aux.next_button.textContent;
  1639.             bottom_bar("loading");
  1640.         }
  1641.         else
  1642.             bottom_bar("end");
  1643.     }
  1644.  
  1645.     //Initialize
  1646.     if (!parent.getAttribute("gridtube_auto_page_started")) {
  1647.  
  1648.         parent.setAttribute("gridtube_auto_page_started", "true");
  1649.  
  1650.         //disable ajax from results
  1651.         //var liitems = docsearch("//*[@id='results']/ol/li/ol/li");
  1652.         //for (var i = 0; i < liitems.snapshotLength; i++) {
  1653.         //    liitems.snapshotItem(i).onclick = disable_ajax;
  1654.         //}
  1655.  
  1656.         aux.bottom_area = newNode("div", "gridtube_bottom_area", null, parent);
  1657.         newNode("div", "gridtube_results_end_bar", "gridtube_result_bar", aux.bottom_area);
  1658.  
  1659.         aux.last_page = null;
  1660.         aux.next_button = docsearch(next_str).snapshotItem(0);
  1661.         find_next_search();
  1662.         aux.fetch_pending = false;
  1663.     }
  1664.  
  1665.  
  1666.     function exec_page(htm) {
  1667.         //message(htm);
  1668.         var newdoc = myparser.parseFromString(htm, "text/html");
  1669.  
  1670.         var li = xpath(newdoc, newdoc, "//*[@id='results']/ol/li/ol/li[not(.//*[contains(@class,'spell-correction') or contains(@class,'display-message')])]");
  1671.  
  1672.         //message(li.snapshotLength);
  1673.  
  1674.         for (var i = 0; i < li.snapshotLength; i++) {
  1675.             var clone = li.snapshotItem(i).cloneNode(true);
  1676.             clone.setAttribute("gridtube_clone_node", "true");
  1677.             var newnode = parent.insertBefore(clone, aux.bottom_area);
  1678.             //firefox 50 wierdness
  1679.             parent.replaceChild(newnode, newnode);
  1680.             //disable ajax
  1681.             //clone.onclick = disable_ajax;
  1682.         }
  1683.  
  1684.         remove_more_ads();
  1685.         aux.next_button = xpath(newdoc, newdoc, next_str).snapshotItem(0);
  1686.         find_next_search();
  1687.         aux.fetch_pending = false;
  1688.         //message("done");
  1689.     }
  1690.  
  1691.  
  1692.     function fetch() {
  1693.         if (aux.fetch_pending) return;
  1694.  
  1695.         if (aux.next_button) {
  1696.             httpReq(aux.next_href, exec_page);
  1697.             aux.fetch_pending = true;
  1698.         }
  1699.     }
  1700.  
  1701.     if (cond) fetch();
  1702. }
  1703.  
  1704.  
  1705. //==================================================================
  1706. // Plist
  1707.  
  1708. function plist_adjust() {
  1709.     if (!pref_gridPlist) return;
  1710.  
  1711.     //adjust thumb quality
  1712.     var aitems = docsearch("//*[contains(@class,'pl-video')]//img[contains(@src,'hqdefault.jpg?custom') or contains(@data-thumb, 'hqdefault.jpg?custom')]");
  1713.  
  1714.     for (var i = 0; i < aitems.snapshotLength; i++) {
  1715.         var item = aitems.snapshotItem(i);
  1716.         var src = item.getAttribute("src");
  1717.         var data = item.getAttribute("data-thumb");
  1718.  
  1719.         if (src) {
  1720.             var new_src = src.replace(/hqdefault.jpg[?]custom(.*)/, 'mqdefault.jpg');
  1721.             if (src != new_src)
  1722.                 item.setAttribute("src", new_src);
  1723.         }
  1724.  
  1725.         if (data) {
  1726.             var new_data = data.replace(/hqdefault.jpg[?]custom(.*)/, 'mqdefault.jpg');
  1727.             if (data != new_data)
  1728.                 item.setAttribute("data-thumb", new_data);
  1729.         }
  1730.     }
  1731.  
  1732.     //remove deleted vids
  1733.     var ditems = docsearch("//*[(@id='pl-video-list') and (not(contains(@class,'pl-video-list-editable')))]\
  1734.                            //tr[contains(@class,'pl-video') and (not(@gridtube_marked_deleted))\
  1735.                            and ((@data-title='[Deleted video]') or (@data-title='[Private video]'))]");
  1736.  
  1737.     for (var i = 0; i < ditems.snapshotLength; i++) {
  1738.         var item = ditems.snapshotItem(i);
  1739.         item.style.display = "none";
  1740.         item.setAttribute("gridtube_marked_deleted", true);
  1741.     }
  1742. }
  1743.  
  1744. //==================================================================
  1745. // Related
  1746.  
  1747. function hide_recommended() {
  1748.     if (!pref_hideRecom || !in_video_page()) return;
  1749.  
  1750.     var items = docsearch("//ul[@id='watch-related']//li[not(@gridtube_hide_recomm) and contains(@class,'related-list-item')\
  1751.                                                         and (.//*[contains(@class,'stat') and contains(@class,'view-count')\
  1752.                                                                   and contains(text(),'Recommended')])]");
  1753.     for (var i = 0; i < items.snapshotLength; i++) {
  1754.         items.snapshotItem(i).style.display = "none";
  1755.         items.snapshotItem(i).setAttribute("gridtube_hide_recomm", "true");
  1756.     }
  1757. }
  1758.  
  1759.  
  1760. function related_adjust(win_resized) {
  1761.     if (!pref_gridRel || !in_video_page()) return;
  1762.  
  1763.     var node = doc.getElementById("watch7-sidebar-contents");
  1764.     if (!node) return;
  1765.  
  1766.     if (node.offsetWidth < 416)
  1767.         insertStyle("", "gridtube_style_grid_related");
  1768.     else
  1769.         insertStyle(style_grid_related, "gridtube_style_grid_related");
  1770.  
  1771.  
  1772.     var strnum = node.getAttribute("gridtube_stored_num");
  1773.     var stored_num = strnum ? parseInt(strnum) : 0;
  1774.  
  1775.     var litems = docsearch("//ul[@id='watch-related']//li[contains(@class,'related-list-item')]");
  1776.  
  1777.     var num = litems.snapshotLength;
  1778.  
  1779.     //message(num);
  1780.     if (num == 0) return;
  1781.  
  1782.     if (num == stored_num && !win_resized) return;
  1783.  
  1784.     node.setAttribute("gridtube_stored_num", num.toString());
  1785.  
  1786.     //var first = litems.snapshotItem(0);
  1787.     var last = litems.snapshotItem(num - 1);
  1788.  
  1789.     var y1 = node.getBoundingClientRect().top;
  1790.     var y2 = last.getBoundingClientRect().bottom;
  1791.  
  1792.     var d = Math.round(Math.abs(y1 - y2));
  1793.     //message("diff=" + d);
  1794.     var res = d + 30;
  1795.     var str = res.toString() + "px";
  1796.  
  1797.     if (node.style.height != str)
  1798.         node.style.height = str;
  1799. }
  1800.  
  1801.  
  1802. //==================================================================
  1803. // Main
  1804.  
  1805. function in_search_page() {
  1806.     return (win.location.pathname.indexOf("/results") == 0);
  1807. }
  1808.  
  1809. function in_plist_page() {
  1810.     return (win.location.pathname.indexOf("/playlist") == 0);
  1811. }
  1812.  
  1813. function in_trend_page() {
  1814.     return (win.location.pathname == "/feed/trending");
  1815. }
  1816.  
  1817. function in_hist_page() {
  1818.     return (win.location.pathname == "/feed/history");
  1819. }
  1820.  
  1821. function in_recom_page() {
  1822.     return (win.location.pathname == "/feed/recommended");
  1823. }
  1824.  
  1825. function in_video_page() {
  1826.     return (win.location.href.indexOf("watch?") >= 0);
  1827. }
  1828.  
  1829. function in_userq_page() {
  1830.     return (((win.location.pathname.indexOf("/user") == 0) || (win.location.pathname.indexOf("/channel") == 0))
  1831.             && (win.location.href.indexOf("search?query=") >= 0));
  1832. }
  1833.  
  1834. //not for grid use
  1835. function in_user_page() {
  1836.     return ((win.location.pathname.indexOf("/user") == 0) || (win.location.pathname.indexOf("/channel") == 0));
  1837. }
  1838.  
  1839. //insert styles
  1840. insertStyle(style_basic, "gridtube_style_basic");
  1841. insertStyle(style_ads_other, "gridtube_style_ads_other");
  1842.  
  1843. if (pref_playerEnable) //hide overlay of playlist
  1844.     insertStyle(".yt-pl-thumb-overlay {display:none !important;}", "gridtube_style_list_overlay");
  1845.  
  1846. if (pref_gridEnable) {
  1847.     if (pref_gridSearch || pref_gridTrend || pref_gridHist || pref_gridRecom)
  1848.         insertStyle(style_grid_basic, "gridtube_style_grid_basic");
  1849.  
  1850.     if (pref_gridPlist)
  1851.         insertStyle(style_grid_plist, "gridtube_style_grid_plist");
  1852.  
  1853.     if (pref_gridRel)
  1854.         insertStyle(style_grid_related, "gridtube_style_grid_related");
  1855. }
  1856.  
  1857. //mark content if in search mode to apply correct style
  1858. function mark_content() {
  1859.     var content = doc.getElementById("content");
  1860.     if (!content) return;
  1861.  
  1862.     var insearch = in_search_page();
  1863.  
  1864.     if (insearch && pref_gridSearch && !(content.getAttribute("gridtube_grid") == "search"))
  1865.         content.setAttribute("gridtube_grid", "search");
  1866.     else
  1867.         if (!insearch && (content.getAttribute("gridtube_grid") == "search"))
  1868.             content.removeAttribute("gridtube_grid");
  1869.  
  1870.     if (insearch && pref_autoLoadSearch && !content.getAttribute("gridtube_auto_load_search"))
  1871.         content.setAttribute("gridtube_auto_load_search", "true");
  1872.     else
  1873.         if (!insearch && content.getAttribute("gridtube_auto_load_search"))
  1874.             content.removeAttribute("gridtube_auto_load_search");
  1875.  
  1876.     var intrend = in_trend_page();
  1877.  
  1878.     if (intrend && pref_gridTrend && !(content.getAttribute("gridtube_grid") == "trending"))
  1879.         content.setAttribute("gridtube_grid", "trending");
  1880.     else
  1881.         if (!intrend && (content.getAttribute("gridtube_grid") == "trending"))
  1882.             content.removeAttribute("gridtube_grid");
  1883.  
  1884.     var inhist = in_hist_page();
  1885.     var inrecom = in_recom_page();
  1886.  
  1887.     if (((inhist && pref_gridHist) || (inrecom && pref_gridRecom)) && !(content.getAttribute("gridtube_grid") == "history"))
  1888.         content.setAttribute("gridtube_grid", "history");
  1889.     else
  1890.         if (!inhist && !inrecom && (content.getAttribute("gridtube_grid") == "history"))
  1891.             content.removeAttribute("gridtube_grid");
  1892.  
  1893.     var inuserq = in_userq_page();
  1894.  
  1895.     if (inuserq && pref_gridSearch && !(content.getAttribute("gridtube_grid") == "userquery"))
  1896.         content.setAttribute("gridtube_grid", "userquery");
  1897.     else
  1898.         if (!inuserq && (content.getAttribute("gridtube_grid") == "userquery"))
  1899.             content.removeAttribute("gridtube_grid");
  1900.  
  1901.     var invid = in_video_page();
  1902.  
  1903.     if (invid && pref_gridRel && !(content.getAttribute("gridtube_grid") == "related"))
  1904.         content.setAttribute("gridtube_grid", "related");
  1905.     else
  1906.         if (!invid && (content.getAttribute("gridtube_grid") == "related"))
  1907.             content.removeAttribute("gridtube_grid");
  1908.  
  1909.     var inplist = in_plist_page();
  1910.  
  1911.     if (inplist && pref_gridPlist && !(content.getAttribute("gridtube_grid") == "playlist"))
  1912.         content.setAttribute("gridtube_grid", "playlist");
  1913.     else
  1914.         if (!inplist && (content.getAttribute("gridtube_grid") == "playlist"))
  1915.             content.removeAttribute("gridtube_grid");
  1916. }
  1917.  
  1918.  
  1919. //remove more_ads in grid search mode or auto load
  1920. function remove_more_ads() {
  1921.     if (in_search_page() && (pref_gridSearch || pref_autoLoadSearch)) {
  1922.         var nodes = docsearch("//li/*[(contains(@class,'pyv-afc-ads-container')\
  1923.                                or contains(@class,'search-refinements')\
  1924.                                or contains(@class,'exploratory-section')\
  1925.                                or contains(@class,'feed-item-container'))\
  1926.                                and (not(@gridtube_ads_mark))]");
  1927.  
  1928.         for (var i = 0; i < nodes.snapshotLength; i++) {
  1929.             var node = nodes.snapshotItem(i);
  1930.             node.setAttribute("gridtube_ads_mark", "true");
  1931.             node.parentNode.style.display = "none";
  1932.         }
  1933.     }
  1934. }
  1935.  
  1936.  
  1937. //auto load
  1938. function auto_page_load(win_resize_scroll) {
  1939.     if (!pref_autoLoadSearch && !pref_autoLoadOther) return;
  1940.  
  1941.     var scrollMaxY = (win.scrollMaxY | (doc.documentElement.scrollHeight - doc.documentElement.clientHeight));
  1942.  
  1943.     //search pages
  1944.     if (in_search_page() && pref_autoLoadSearch) {
  1945.         //message(win.pageYOffset + "    " + win.scrollMaxY + "    " + win.innerHeight);
  1946.         search_pages(win.pageYOffset >= scrollMaxY - win.innerHeight);
  1947.         //search_pages(true);
  1948.     }
  1949.  
  1950.     //other pages
  1951.     if (pref_autoLoadOther) {
  1952.         var button_list = docsearch("//button[((@id='watch-more-related-button')\
  1953.                                or (contains(@class,'load-more-button')))\
  1954.                                and (not(contains(@class, 'error') or contains(@class, 'loading') or contains(@class, 'comment')))]");
  1955.  
  1956.         for (var i = 0; i < button_list.snapshotLength; i++) {
  1957.             var button = button_list.snapshotItem(i);
  1958.  
  1959.             if (win_resize_scroll) button.setAttribute("gridtubeclick", "0");
  1960.             var count = 0;
  1961.             var countstr = button.getAttribute("gridtubeclick");
  1962.             if (countstr) count = parseInt(countstr);
  1963.  
  1964.             if ((button.style.display != 'none') && (count < 10)) {
  1965.                 //alert(cond + "  " + count);
  1966.                 var rect = button.getBoundingClientRect();
  1967.                 //message(rect.top + "  " +   win.pageYOffset);
  1968.                 if (2 * win.innerHeight >= rect.top)
  1969.                     simulClick(button);
  1970.                 button.setAttribute("gridtubeclick", (count + 1).toString());
  1971.             }
  1972.         }
  1973.     }
  1974. }
  1975.  
  1976.  
  1977. //close player at out of focus page (except last)
  1978. function get_storage_count() {
  1979.     var value = -1;
  1980.     var tabstr = win.localStorage.getItem("gridtube_tab_count");
  1981.     if (tabstr) value = parseInt(tabstr);
  1982.     return value;
  1983. }
  1984.  
  1985. function set_storage_count() {
  1986.     var value = get_storage_count();
  1987.     value++;
  1988.     if (value > 1000000) value = 0;
  1989.     win.localStorage.setItem("gridtube_tab_count", value.toString());
  1990.     return value;
  1991. }
  1992.  
  1993. var tab_count = -2;
  1994. var set_storage_executed = false;
  1995.  
  1996. function check_focus() {
  1997.  
  1998.     if (!doc.hasFocus()) {
  1999.         //message("out of focus: " + tab_count);
  2000.         //check if last focused tab
  2001.         if (get_storage_count() != tab_count) {
  2002.             if (pref_ytFocus) ytpause();
  2003.             if (pref_playerEnable)
  2004.                 if (get_pref("playerFocus"))
  2005.                     player.playerPause();
  2006.         }
  2007.         set_storage_executed = false;
  2008.     }
  2009.     else {
  2010.         //message("in focus: " + tab_count);
  2011.         if (!set_storage_executed) {
  2012.             tab_count = set_storage_count();
  2013.             set_storage_executed = true;
  2014.         }
  2015.     }
  2016. }
  2017.  
  2018. var old_addr = win.location.href;
  2019. var nochanges_count = -1;
  2020. var start_count = -1; //not used now
  2021.  
  2022. win.addEventListener("focus", function () { nochanges_count = -1; check_focus(); }, false);
  2023. win.addEventListener("blur", function () { nochanges_count = -1; check_focus(); }, false);
  2024. win.addEventListener("resize", function () { nochanges_count = -1; related_adjust(true); auto_page_load(true); }, false);
  2025. win.addEventListener("scroll", function () { nochanges_count = -1; auto_page_load(true); }, false);
  2026. win.addEventListener("click", function (e) { nochanges_count = -1; player_close(e); }, false);
  2027.  
  2028. //main routine
  2029. function check_changes() {
  2030.     if (old_addr == win.location.href) {
  2031.         if (nochanges_count < 20) nochanges_count++;
  2032.         if (start_count < 20) start_count++;
  2033.     }
  2034.     else {
  2035.         nochanges_count = 0;
  2036.         start_count = 0;
  2037.         old_addr = win.location.href;
  2038.         player_close();
  2039.         //message("new addr");
  2040.     }
  2041.  
  2042.     if (nochanges_count >= 20) return;
  2043.  
  2044.     check_focus();
  2045.  
  2046.     if (pref_gridEnable) {
  2047.         mark_content();
  2048.         if (in_search_page()) choice_icons("search");
  2049.         if (in_hist_page()) choice_icons("hist");
  2050.         if (in_recom_page()) choice_icons("recom");
  2051.         if (in_plist_page()) { choice_icons("plist"); plist_adjust(); }
  2052.         related_adjust(false);
  2053.     }
  2054.  
  2055.     hide_recommended();
  2056.     remove_more_ads();
  2057.     meta_data();
  2058.     auto_page_load(false);
  2059. }
  2060.  
  2061. win.setInterval(check_changes, 1000);
  2062. check_changes();
Add Comment
Please, Sign In to add comment