您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Při najetí myší na odkaz na film se zobrazí náhled jeho profilu.
- // ==UserScript==
- // @name CSFD Movie Preview
- // @namespace http://csfd.cz
- // @description Při najetí myší na odkaz na film se zobrazí náhled jeho profilu.
- // @match https://www.csfd.cz/*
- // @match https://www.csfd.sk/*
- // @exclude https://www.csfd.cz/uzivatel/*/editace/
- // @exclude https://www.csfd.sk/uzivatel/*/editace/
- // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
- // @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js
- // @grant GM_registerMenuCommand
- // @grant GM.registerMenuCommand
- // @grant GM_xmlhttpRequest
- // @grant GM.xmlHttpRequest
- // @grant GM_getValue
- // @grant GM.getValue
- // @grant GM_setValue
- // @grant GM.setValue
- // @version 2.5
- // ==/UserScript==
- // CHANGES
- // -------
- // 2.5 - do náhledu vráceno hodnocení
- // 2.4 - do náhledu vrácen název filmu
- // 2.3 - opraveno načítání náhledů u epizod seriálů, úprava URL adres
- // 2.2 - úpravy kvůli novému designu webu
- // 2.1 - opraveno přepínání automatického nahrávání náhledů filmů
- // 2.0 - GM_* funkce nahrazeny novými kvůli změně API v GreaseMonkey 4.0+
- // 1.3 - upravena hlavička skriptu kvůli přechodu ČSFD na https
- // 1.2 - doplněna podpora dynamicky přidávaných odkazů
- // 1.1 - výměna jQuery.ajax(), který ve Firefoxu přestal fungovat, za GM_xmlhttpRequest()
- // 1.0 - první verze
- $ = this.jQuery = jQuery.noConflict(true);
- $('<div id="movie-preview" style="display: none; z-index: 999; width: 420px; background-color: #efefef; padding: 6px; ' +
- 'border-radius: 4px; box-shadow: 0 0 10px 4px #777777"><table border="0"><tr><td id="movie-preview-poster" width="152" ' +
- 'style="text-align: center"></td><td id="movie-preview-content" style="vertical-align: top; padding-left: 7px"></td>' +
- '</tr></table></div>').appendTo('body');
- var cacheExpires = 7; // days
- var movieBox = $('div#movie-preview');
- var movieBoxPoster = movieBox.find('#movie-preview-poster');
- var movieBoxContent = movieBox.find('#movie-preview-content');
- var movieLinkSelector = 'a[href*="/film/"], a[href*="/film.php"]';
- var thisPageMovieId = parseMovieId(window.location.href);
- var currentMovieId = null;
- var movies = [];
- var timerId = -1;
- // Greasmonkey-only section start
- if (typeof GM.registerMenuCommand == 'function' && isStorageSupported()) {
- GM.registerMenuCommand("Přepnout automatické nahrávání náhledů filmů", function() {
- GM.getValue("doPrefetch", false).then(function(doPrefetch) {
- GM.setValue("doPrefetch", !doPrefetch);
- alert("Automatické nahrávání náhledů filmů " + (doPrefetch? "vypnuto": "zapnuto") + ".\nZměna nastavení se projeví po obnovení stránky.");
- });
- });
- }
- // Greasmonkey-only section end
- function isStorageSupported() {
- return typeof(Storage) !== void(0);
- }
- function parseMovieId(movieURL) {
- var match = movieURL.match(/\/film(?:\.php\?)?(?:\/[\d]+)?.*\/([\d]+)/);
- return match && match.length >= 2? 'm' + match[1]: null;
- }
- function getDiffDays(date1, date2) {
- return Math.round(Math.abs(date1 - date2) / (1000 * 3600 * 24));
- }
- var storage = isStorageSupported()?
- { // local storage
- getStoredItem: function(movieURL) {
- return localStorage[parseMovieId(movieURL)];
- },
- setStoredItem: function(movieURL, value) {
- try {
- localStorage[parseMovieId(movieURL)] = value;
- } catch (ex) {
- // "Persistent storage maximum size reached" -> remove 10 random items
- for (var i=0; i < 10; i++) {
- var index = Math.floor(Math.random() * localStorage.length);
- var key = localStorage.key(index);
- localStorage.removeItem(key);
- }
- return this.setStoredItem(movieURL, value);
- }
- },
- cleanExpiredData: function() {
- var lastCleanup = localStorage["last-cleanup"]? Date.parse(localStorage["last-cleanup"]): new Date(0);
- // run cleanup only once per day
- if (getDiffDays(new Date(), lastCleanup) < 1) return;
- for(var key in localStorage) {
- if (key.match(/m\d+/)) {
- var cached = JSON.parse(localStorage[key]);
- if (getDiffDays(new Date(), Date.parse(cached.timestamp)) > cacheExpires) {
- localStorage.removeItem(key);
- }
- }
- }
- localStorage["last-cleanup"] = new Date();
- }
- }:
- { // dummy storage
- getStoredItem: function(movieURL) {
- return null;
- },
- setStoredItem: function(movieURL, value) {
- // noop
- },
- cleanExpiredData: function() {
- // noop
- }
- };
- function getMovieBoxPosition(event) {
- var boxWidth = movieBox.width() + 10;
- var tPosX = boxWidth - event.clientX + 30 > 0? event.pageX + 30: event.pageX - boxWidth - 30;
- var tPosY = event.pageY + event.clientY;
- if (event.clientY > 30) {
- var winHeight = $(window).height();
- var boxHeight = movieBox.height() > winHeight? winHeight - 60: movieBox.height();
- var overflowY = event.clientY + boxHeight - winHeight;
- tPosY = overflowY > 0? event.pageY - overflowY - 50: event.pageY - 30;
- }
- return { X: tPosX, Y: tPosY };
- }
- function showMovieBox(event, profile, rating) {
- var poster = profile.find(".film-posters img");
- var title = "<h1 style='font-size: 22px; padding-bottom: 12px'>" + profile.find(".film-header-name h1").text().trim() + "</h1>";
- var genre = profile.find(".genres");
- var origin = profile.find(".origin");
- var creators = profile.find(".creators");
- movieBoxPoster.html('');
- movieBoxPoster.append(poster.css('width', 140));
- movieBoxPoster.append('<h1 style="font-size: 32px; margin-top: 12px">' + rating + '</h1>');
- movieBoxContent.html('');
- movieBoxContent.append(title);
- movieBoxContent.append(genre.css('font-weight', 'bold'));
- movieBoxContent.append(origin.css('font-weight', 'bold'));
- movieBoxContent.append('<br>');
- movieBoxContent.append(creators);
- var pos = getMovieBoxPosition(event);
- movieBox.css({ 'position': 'absolute', 'top': pos.Y, 'left': pos.X }).show();
- }
- function getCachedData(movieURL) {
- var cached = storage.getStoredItem(movieURL);
- if (cached) {
- cached = JSON.parse(cached);
- if (getDiffDays(new Date(), Date.parse(cached.timestamp)) <= cacheExpires)
- return { "profile": $(cached.profile), "rating": cached.rating };
- }
- return null;
- }
- function loadMovieBox(movieURL, doneCallback, errorCallback, redirectMovieURL) {
- if (!redirectMovieURL) redirectMovieURL = movieURL;
- console.log("[CSFD Movie Preview] Loading movie page: " + redirectMovieURL);
- GM.xmlHttpRequest({
- method: "GET",
- url: redirectMovieURL,
- onload: function(response) {
- try {
- if (false /* TODO: handle redirect */) {
- loadMovieBox(movieURL, doneCallback, errorCallback, response.redirect);
- } else {
- response = $(response.responseText);
- var profile = response.find(".film-info").html().replace(/[\t\n]+/mg, ' ');
- var rating = response.find(".film-info .film-rating-average").text().trim();
- storage.setStoredItem(movieURL, JSON.stringify({ "profile": profile, "rating": rating, "timestamp": new Date() }));
- if (doneCallback) doneCallback($(profile), rating);
- }
- } catch(ex) {
- console.log("[CSFD Movie Preview] Error in AJAX handler: " + ex.message);
- if (errorCallback) errorCallback();
- }
- },
- onerror: function(response) {
- if (errorCallback) errorCallback();
- }
- });
- }
- function prefetchMovies() {
- if (!isStorageSupported()) return;
- GM.getValue("doPrefetch", false).then(function(doPrefetch) {
- var movieURL;
- if (doPrefetch && (movieURL = movies.shift())) {
- setTimeout(function() {
- if (!getCachedData(movieURL)) {
- loadMovieBox(movieURL, prefetchMovies, prefetchMovies);
- } else {
- prefetchMovies();
- }
- }, 300);
- }
- });
- }
- function addHoverHandler(element) {
- element.hover(function(event) {
- var movieURL = $(this).attr("href").trim();
- var movieId = parseMovieId(movieURL);
- // prevent previews of the movie on its page
- if (thisPageMovieId == movieId) return;
- currentMovieId = movieId;
- var cached = getCachedData(movieURL);
- if (cached) {
- showMovieBox(event, cached.profile, cached.rating);
- } else {
- clearTimeout(timerId);
- timerId = setTimeout(function() {
- loadMovieBox(movieURL, function(profile, rating) {
- if (currentMovieId == movieId) showMovieBox(event, profile, rating);
- });
- }, 30);
- }
- }, function() {
- clearTimeout(timerId);
- timerId = -1;
- currentMovieId = null;
- movieBox.hide();
- });
- }
- function setupMutationObserver() {
- var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
- var observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- for (var i=0; i < mutation.addedNodes.length; i++) {
- $(mutation.addedNodes[i]).find("a").each(function() {
- if (this.href && this.href.match(/\/film/)) {
- addHoverHandler($(this));
- var movieURL = this.href.trim();
- movies.push(movieURL);
- }
- });
- }
- });
- prefetchMovies();
- });
- observer.observe(document.querySelector("body"), {
- childList: true,
- subtree: true
- });
- }
- // program start
- storage.cleanExpiredData();
- $(movieLinkSelector).each(function() {
- addHoverHandler($(this));
- var movieURL = $(this).attr("href").trim();
- movies.push(movieURL);
- });
- setupMutationObserver();
- prefetchMovies();
- // program end