Metacritic Improved

Save/Hide upcoming releases, various UI improvements.

  1. // ==UserScript==
  2. // @name Metacritic Improved
  3. // @namespace metacritic_improved
  4. // @description Save/Hide upcoming releases, various UI improvements.
  5. // @homepageURL https://github.com/daraeman/metacritic_improved
  6. // @author daraeman
  7. // @version 1.2
  8. // @date 2017-12-03
  9. // @include http://www.metacritic.com/browse/dvds/*
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js
  11. // ==/UserScript==
  12.  
  13. var storage_keys = {
  14. local: {
  15. ignored: "metacritic_improved_release_ignore",
  16. saved: "metacritic_improved_release_save",
  17. },
  18. };
  19.  
  20. // grab our saved data
  21.  
  22. var data = {
  23. ignored: {},
  24. saved: {},
  25. show_hidden: 0,
  26. };
  27.  
  28. function parseJson( json, assign_to, initial ) {
  29. try {
  30. var parsed = JSON.parse( json );
  31. try {
  32. if ( parsed === null )
  33. parsed = initial;
  34. data[ assign_to ] = parsed;
  35. } catch ( e ) {}
  36. } catch ( e ) {}
  37. }
  38.  
  39. parseJson( localStorage.getItem( storage_keys.local.ignored ), "ignored", {} );
  40. parseJson( localStorage.getItem( storage_keys.local.saved ), "saved", {} );
  41. parseJson( localStorage.getItem( storage_keys.local.show_hidden ), "show_hidden", 0 );
  42.  
  43. // iterate over the page
  44.  
  45. function isSaved( link ) {
  46. if ( data.saved[ link ] )
  47. return true;
  48. return false;
  49. }
  50. function isIgnored( link ) {
  51. if ( data.ignored[ link ] )
  52. return true;
  53. return false;
  54. }
  55.  
  56. function getLink( el ) {
  57. return el.find( ".title a" ).attr( "href" );
  58. }
  59.  
  60. function saveView( el ) {
  61. el.removeClass( "metacritic_improved_ignored" ).addClass( "metacritic_improved_saved" );
  62. }
  63. function ignoreView( el ) {
  64. el.removeClass( "metacritic_improved_saved" ).addClass( "metacritic_improved_ignored" );
  65. if ( ! data.show_hidden )
  66. jQuery( ".metacritic_improved_ignored" ).slideUp();
  67. }
  68. function resetView( el ) {
  69. el.removeClass( "metacritic_improved_saved" ).removeClass( "metacritic_improved_ignored" );
  70. }
  71. function stringToDate( str ) {
  72. return new Date( str );
  73. }
  74. function daysUntil( date ) {
  75. var now_millis = +new Date();
  76. var then_millis = +date;
  77. return ( ( then_millis - now_millis ) / 1000 / 60 / 60 / 24 );
  78. }
  79. function dateView( el ) {
  80. var date_el = el.find( ".date_wrapper" ).find( "span" ).first();
  81. var date_string = date_el.text();
  82. var parsed_date = stringToDate( date_string );
  83. var days_until = daysUntil( parsed_date );
  84. var rounded_date = Math.round( days_until );
  85. var words = Math.abs( rounded_date ) +" days ";
  86. words += ( days_until > 0 ) ? "" : "ago";
  87. if ( rounded_date === 0 )
  88. words = "today";
  89. else if ( rounded_date === 1 )
  90. words = "tomorrow";
  91. else if ( rounded_date === -1 )
  92. words = "yesterday";
  93. date_el.append( '<div class="metacritic_improved_date">'+ words +'</div>' );
  94. }
  95.  
  96. jQuery( ".list .summary_row" ).each(function(){
  97. var el = jQuery( this );
  98. var link = getLink( el );
  99.  
  100. dateView( el );
  101.  
  102. if ( isSaved( link ) )
  103. saveView( el );
  104. else if ( isIgnored( link ) )
  105. ignoreView( el );
  106.  
  107. el.append( '<td class="metacritic_improved_actions"><div class="metacritic_improved_save">✓</div><div class="metacritic_improved_ignore">✘</div></td>' );
  108. });
  109.  
  110. // add styles
  111.  
  112. jQuery( "head" ).append(
  113. '<style type="text/css">' +
  114. ' #metacritic_improved .metacritic_improved_actions {' +
  115. ' text-align: right;' +
  116. ' padding-left: 7px;' +
  117. ' }' +
  118. ' #metacritic_improved .metacritic_improved_save {' +
  119. ' color: rgb( 0,190,0 );' +
  120. ' cursor: pointer;' +
  121. ' }' +
  122. ' #metacritic_improved .metacritic_improved_ignore {' +
  123. ' color: rgb( 240,0,0 );' +
  124. ' cursor: pointer;' +
  125. ' margin-top: 6px;' +
  126. ' }' +
  127. ' #metacritic_improved .metacritic_improved_saved {' +
  128. ' background: rgb( 20,20,20 );' +
  129. ' color: rgb( 255,255,255 );' +
  130. ' position: relative;' +
  131. ' }' +
  132. ' #metacritic_improved .metacritic_improved_saved .score_wrapper a {' +
  133. ' position: relative;' +
  134. ' }' +
  135. ' #metacritic_improved .metacritic_improved_saved .score_wrapper a:before {' +
  136. ' content: "";' +
  137. ' position: absolute;' +
  138. ' background: rgb( 20,20,20 );' +
  139. ' width: 16px;' +
  140. ' left: -16px;' +
  141. ' height: 83px;' +
  142. ' top: -2px;' +
  143. ' }' +
  144. ' #metacritic_improved .date_wrapper .inline_see_more {' +
  145. ' bottom: 3px;' +
  146. ' }' +
  147. ' #metacritic_improved .metacritic_improved_ignored {' +
  148. ' opacity: 0.4;' +
  149. ' }' +
  150. ' #metacritic_improved .metacritic_improved_toggle_container {' +
  151. ' position: relative;' +
  152. ' }' +
  153. ' #metacritic_improved .metacritic_improved_toggle_hidden {' +
  154. ' position: absolute;' +
  155. ' top: -20px;' +
  156. ' right: 0px;' +
  157. ' line-height: 20px;' +
  158. ' padding: 0px 10px;' +
  159. ' border: 1px solid rgb( 204,204,204 );' +
  160. ' border-bottom: 0px;' +
  161. ' color: rgb( 120,120,120 );' +
  162. ' text-transform: uppercase;' +
  163. ' font-size: 12px;' +
  164. ' cursor: pointer;' +
  165. ' }' +
  166. ' #metacritic_improved .metacritic_improved_toggle_hidden[data-mi_state="on"] .off {' +
  167. ' display: none;' +
  168. ' }' +
  169. ' #metacritic_improved .metacritic_improved_toggle_hidden[data-mi_state="off"] .on {' +
  170. ' display: none;' +
  171. ' }' +
  172. ' #metacritic_improved .metacritic_improved_date {' +
  173. ' color: rgb( 130,130,130 );' +
  174. ' font-style: italic;' +
  175. ' padding-top: 5px;' +
  176. ' padding-bottom: 1px;' +
  177. ' }' +
  178. ' #metacritic_improved .browse .browse_list_wrapper.two table.list, #metacritic_improved .browse .browse_list_wrapper.three table.list {' +
  179. ' border-top: 0px;' +
  180. ' }' +
  181. '</style>'
  182. );
  183.  
  184. // hide/show actions
  185.  
  186. function save( link, el ) {
  187. if ( isIgnored( link ) )
  188. removeIgnore( link );
  189. if ( isSaved( link ) ) {
  190. removeSave( link );
  191. resetView( el );
  192. return true;
  193. }
  194. else {
  195. data.saved[ link ] = 1;
  196. saveView( el );
  197. }
  198. saveDataLocal();
  199. return true;
  200. }
  201. function ignore( link, el ) {
  202. if ( isSaved( link ) )
  203. removeSave( link );
  204. if ( isIgnored( link ) ) {
  205. removeIgnore( link );
  206. resetView( el );
  207. return true;
  208. }
  209. else {
  210. data.ignored[ link ] = 1;
  211. ignoreView( el );
  212. }
  213. saveDataLocal();
  214. return true;
  215. }
  216. function removeSave( link ) {
  217. delete data.saved[ link ];
  218. }
  219. function removeIgnore( link ) {
  220. delete data.ignored[ link ];
  221. }
  222.  
  223. function saveDataLocal() {
  224. var saved_json = JSON.stringify( data.saved );
  225. var ignored_json = JSON.stringify( data.ignored );
  226. localStorage.setItem( storage_keys.local.saved, saved_json );
  227. localStorage.setItem( storage_keys.local.ignored, ignored_json );
  228. localStorage.setItem( storage_keys.local.show_hidden, data.show_hidden );
  229. }
  230.  
  231. jQuery( ".metacritic_improved_save" ).click(function(){
  232. var el = jQuery( this );
  233. var parent = el.parent().parent();
  234. var link = getLink( parent );
  235. save( link, parent );
  236. });
  237. jQuery( ".metacritic_improved_ignore" ).click(function(){
  238. var el = jQuery( this );
  239. var parent = el.parent().parent();
  240. var link = getLink( parent );
  241. ignore( link, parent );
  242. });
  243.  
  244. jQuery( "body" ).attr( "id", "metacritic_improved" );
  245.  
  246. jQuery( ".browse_trailer_wrapper" ).parent().parent().remove();
  247.  
  248. // create the hide/show button
  249.  
  250. var initial_state_class = ( data.show_hidden ) ? "on" : "off";
  251. jQuery( ".content_after_header .inset_left2 .next_to_side_col" ).first().addClass( "metacritic_improved_toggle_container" ).append( '<div class="metacritic_improved_toggle_hidden" data-mi_state="'+ initial_state_class +'"><span class="on">hide ignored</span><span class="off">show ignored</span></div>' );
  252.  
  253. jQuery( ".metacritic_improved_toggle_hidden" ).click(function(){
  254. var el = jQuery( this );
  255. if ( el.attr( "data-mi_state" ) == "on" ) {
  256. jQuery( ".metacritic_improved_ignored" ).hide();
  257. el.attr( "data-mi_state", "off" );
  258. data.show_hidden = 0;
  259. }
  260. else {
  261. jQuery( ".metacritic_improved_ignored" ).show();
  262. el.attr( "data-mi_state", "on" );
  263. data.show_hidden = 1;
  264. }
  265. saveDataLocal();
  266. });