CSFD Movie Preview

Při najetí myší na odkaz na film se zobrazí náhled jeho profilu.

当前为 2014-08-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name CSFD Movie Preview
  3. // @namespace http://csfd.cz
  4. // @description Při najetí myší na odkaz na film se zobrazí náhled jeho profilu.
  5. // @match http://www.csfd.cz/*
  6. // @exclude http://www.csfd.cz/uzivatel/*/profile-edit/
  7. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
  8. // @grant GM_registerMenuCommand
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @version 1.0
  12. // ==/UserScript==
  13.  
  14. $ = this.jQuery = jQuery.noConflict(true);
  15.  
  16. $('<div id="movie-preview" style="display: none; z-index: 999; width: 400px; background-color: #efefef; padding: 6px; border-radius: 4px; box-shadow: 0 0 10px 4px #777777">' +
  17. '<table border="1"><tr><td id="movie-preview-poster" width="120" style="text-align: center"></td><td id="movie-preview-content" style="vertical-align: top; padding-left: 7px"></td></tr></table></div>').appendTo('body');
  18.  
  19. var cacheExpires = 7; // days
  20. var doPrefetch = false;
  21.  
  22. var movieBox = $('div#movie-preview');
  23. var movieBoxPoster = movieBox.find('#movie-preview-poster');
  24. var movieBoxContent = movieBox.find('#movie-preview-content');
  25.  
  26. var movieLinkSelector = 'a[href*="/film/"], a[href*="/film.php"]';
  27.  
  28. var thisPageMovieId = parseMovieId(window.location.href);
  29. var currentMovieId = null;
  30. var movies = [];
  31.  
  32. var timerId = -1;
  33.  
  34. // Greasmonkey-only section start
  35.  
  36. if (typeof GM_registerMenuCommand == 'function' && isStorageSupported()) {
  37. doPrefetch = GM_getValue("doPrefetch", false);
  38.  
  39. GM_registerMenuCommand("Přepnout automatické nahrávání náhledů filmů", function() {
  40. doPrefetch = !GM_getValue("doPrefetch", false);
  41.  
  42. GM_setValue("doPrefetch", doPrefetch);
  43.  
  44. alert("Automatické nahrávání náhledů filmů " + (doPrefetch? "zapnuto": "vypnuto") + ".\nZměna nastavení se projeví po obnovení stránky.");
  45. });
  46. }
  47.  
  48. // Greasmonkey-only section end
  49.  
  50. function isStorageSupported() {
  51. return typeof(Storage) !== void(0);
  52. }
  53.  
  54. function parseMovieId(movieURL) {
  55. var match = movieURL.match(/\/film(?:\.php\?|\/)([\d]+)/);
  56. return match && match.length >= 2? 'm' + match[1]: null;
  57. }
  58.  
  59. function getDiffDays(date1, date2) {
  60. return Math.round(Math.abs(date1 - date2) / (1000 * 3600 * 24));
  61. }
  62.  
  63. var storage = isStorageSupported()?
  64. { // local storage
  65. getStoredItem: function(movieURL) {
  66. return localStorage[parseMovieId(movieURL)];
  67. },
  68. setStoredItem: function(movieURL, value) {
  69. try {
  70. localStorage[parseMovieId(movieURL)] = value;
  71. } catch (ex) {
  72. // "Persistent storage maximum size reached" -> remove 10 random items
  73. for (i=0; i < 10; i++) {
  74. var index = Math.floor(Math.random() * localStorage.length);
  75. var key = localStorage.key(index);
  76.  
  77. localStorage.removeItem(key);
  78. }
  79.  
  80. return this.setStoredItem(movieURL, value);
  81. }
  82. },
  83. cleanExpiredData: function() {
  84. var lastCleanup = localStorage["last-cleanup"]? Date.parse(localStorage["last-cleanup"]): new Date(0);
  85.  
  86. // run cleanup only once per day
  87. if (getDiffDays(new Date(), lastCleanup) < 1) return;
  88.  
  89. for(var key in localStorage) {
  90. if (key.match(/m\d+/)) {
  91. var cached = JSON.parse(localStorage[key]);
  92. if (getDiffDays(new Date(), Date.parse(cached.timestamp)) > cacheExpires) {
  93. localStorage.removeItem(key);
  94. }
  95. }
  96. }
  97.  
  98. localStorage["last-cleanup"] = new Date();
  99. }
  100. }:
  101. { // dummy storage
  102. getStoredItem: function(movieURL) {
  103. return null;
  104. },
  105. setStoredItem: function(movieURL, value) {
  106. // noop
  107. },
  108. cleanExpiredData: function() {
  109. // noop
  110. }
  111. };
  112.  
  113. function getMovieBoxPosition(event) {
  114. var boxWidth = movieBox.width() + 10;
  115. var tPosX = boxWidth - event.clientX + 30 > 0? event.pageX + 30: event.pageX - boxWidth - 30;
  116. var tPosY = event.pageY + event.clientY;
  117.  
  118. if (event.clientY > 30) {
  119. var winHeight = $(window).height();
  120. var boxHeight = movieBox.height() > winHeight? winHeight - 60: movieBox.height();
  121. var overflowY = event.clientY + boxHeight - winHeight;
  122. tPosY = overflowY > 0? event.pageY - overflowY - 50: event.pageY - 30;
  123. }
  124.  
  125. return { X: tPosX, Y: tPosY };
  126. }
  127. function showMovieBox(event, profile, rating) {
  128. var poster = profile.find("#poster img");
  129. var title = "<h1 style='text-transform: none'>" + profile.find(".info h1").text().trim() + "</h1>";
  130. var genre = profile.find(".genre");
  131. var origin = profile.find(".origin");
  132. var creators = profile.find(".creators");
  133.  
  134. movieBoxPoster.html('');
  135. movieBoxPoster.append(poster.css('width', 120));
  136. movieBoxPoster.append('<br><h1 style="font-size: 32px">' + rating + '</h1>');
  137.  
  138. movieBoxContent.html('');
  139. movieBoxContent.append(title);
  140. movieBoxContent.append(genre.css('font-weight', 'bold'));
  141. movieBoxContent.append(origin.css('font-weight', 'bold'));
  142. movieBoxContent.append('<br>');
  143. movieBoxContent.append(creators);
  144.  
  145. var pos = getMovieBoxPosition(event);
  146. movieBox.css({ 'position': 'absolute', 'top': pos.Y, 'left': pos.X }).show();
  147. }
  148.  
  149. function getCachedData(movieURL) {
  150. var cached = storage.getStoredItem(movieURL);
  151.  
  152. if (cached) {
  153. cached = JSON.parse(cached);
  154.  
  155. if (getDiffDays(new Date(), Date.parse(cached.timestamp)) <= cacheExpires)
  156. return { "profile": $(cached.profile), "rating": cached.rating };
  157. }
  158.  
  159. return null;
  160. }
  161. function loadMovieBox(movieURL, doneCallback, errorCallback, redirectMovieURL) {
  162. if (!redirectMovieURL) redirectMovieURL = movieURL;
  163.  
  164. console.log("Loading movie page: " + redirectMovieURL);
  165.  
  166. $.ajax(redirectMovieURL).done(function(response) {
  167. try {
  168. if (typeof(response) === 'object') {
  169. loadMovieBox(movieURL, doneCallback, errorCallback, response.redirect);
  170. } else {
  171. response = $(response);
  172.  
  173. var profile = response.find("div#profile").html().replace(/[\t\n]+/mg, '');
  174. var rating = response.find("div#rating .average").text().trim();
  175. storage.setStoredItem(movieURL, JSON.stringify({ "profile": profile, "rating": rating, "timestamp": new Date() }));
  176. if (doneCallback) doneCallback($(profile), rating);
  177. }
  178. } catch(ex) {
  179. console.log("Error in AJAX handler: " + ex.message);
  180.  
  181. if (errorCallback) errorCallback();
  182. }
  183. }).error(function(jqXHR, textStatus, errorThrown) {
  184. if (errorCallback) errorCallback();
  185. });
  186. }
  187.  
  188. $(movieLinkSelector).hover(function(event) {
  189. var movieURL = $(this).attr("href").trim();
  190. var movieId = parseMovieId(movieURL);
  191.  
  192. // prevent previews of the movie on its page
  193. if (thisPageMovieId == movieId) return;
  194.  
  195. currentMovieId = movieId;
  196.  
  197. var cached = getCachedData(movieURL);
  198. if (cached) {
  199. showMovieBox(event, cached.profile, cached.rating);
  200. } else {
  201. clearTimeout(timerId);
  202.  
  203. timerId = setTimeout(function() {
  204. loadMovieBox(movieURL, function(profile, rating) {
  205. if (currentMovieId == movieId) showMovieBox(event, profile, rating);
  206. });
  207. }, 30);
  208. }
  209. }, function() {
  210. clearTimeout(timerId);
  211. timerId = -1;
  212. currentMovieId = null;
  213.  
  214. movieBox.hide();
  215. });
  216.  
  217. if (doPrefetch && isStorageSupported()) {
  218. var movieURL;
  219.  
  220. $(movieLinkSelector).each(function() {
  221. movieURL = $(this).attr("href").trim();
  222. movies.push(movieURL);
  223. });
  224. function prefetchMovies() {
  225. if (movieURL = movies.shift()) {
  226. setTimeout(function() {
  227. if (!getCachedData(movieURL)) {
  228. loadMovieBox(movieURL, prefetchMovies, prefetchMovies);
  229. } else {
  230. prefetchMovies();
  231. }
  232. }, 300);
  233. }
  234. }
  235. prefetchMovies();
  236. }
  237.  
  238. // clean old movies
  239. storage.cleanExpiredData();