// ==UserScript==
// @name ČSFD Extended
// @name:en ČSFD Extended
// @version 2.10.0
// @description Rozšíření profilů filmů na ČSFD o funkce jako je hodnocení IMDB či odkaz na justwatch.com.
// @description:en Extension of film profiles on ČSFD with features such as IMDb ratings or a link to justwatch.com.
// @author Jakub Rychecký <jakub@rychecky.cz>
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @license WTFPL 2
// @include *csfd.cz/film/*
// @include *csfd.sk/film/*
// @namespace CSFD-E
// ==/UserScript==
/******/ (() => { // webpackBootstrap
/******/ "use strict";
var __webpack_exports__ = {};
;// CONCATENATED MODULE: ./src/classes/Csfd.js
class Csfd {
constructor(csfdPage) {
this.csfdPage = csfdPage
}
isLoggedIn() {
return this.csfdPage.find('.my-rating').length > 0;
}
getImdbCode() {
let imdbButton = this.csfdPage.find('a.button-imdb');
return imdbButton.length > 0
? imdbButton.attr('href').match(/(tt\d+)/)[0]
: null;
}
getCurrentUserRatingDate() {
let ratingDateInText = this.csfdPage.find('.current-user-rating > span').attr('title');
if (ratingDateInText === undefined) {
return null;
}
return ratingDateInText.match(/.+(\d{2}\.\d{2}\.\d{4})$/)[1];
}
isMarkedAsWantToWatch() {
let controlPanelText = this.csfdPage.find('.control-panel').text();
return controlPanelText.includes('Upravit ve Chci vidět')
|| controlPanelText.includes('Upraviť v Chcem vidieť');
}
getLinkingDataMovieTitle() {
let linkingDataJson = JSON.parse($('script[type="application/ld+json"]')[0].innerHTML);
return linkingDataJson.name + ' ' + linkingDataJson.dateCreated;
}
}
;// CONCATENATED MODULE: ./src/classes/ImdbRating.js
class ImdbRating {
constructor(
csfd,
imdbRating,
imdbVotes
) {
this.csfd = csfd;
this.initializeImdbRating(imdbRating, imdbVotes);
}
initializeImdbRating(
imdbRating,
imdbVotes
) {
if (
imdbRating === undefined
|| imdbRating === 'N/A'
|| imdbVotes === undefined
|| imdbVotes === 'N/A'
) {
return;
}
let imdbVotesSpan = $('<span>')
.css({
'display': 'block',
'font-size': '9px',
'font-weight': 'normal',
'line-height': '10px',
'padding-bottom': '8px',
})
.html('<strong>' + imdbVotes + '</strong> hlasů');
let imdbRatingBox = $('<a>')
.addClass('rating-average csfd-extended-imdb-rating')
.css({
'display': 'block',
'color': '#000000',
'cursor': 'pointer',
'line-height': '60px',
'text-align': 'center',
'font-size': '40px',
'font-weight': 'bold',
})
.attr('href', 'https://www.imdb.com/title/' + this.csfd.getImdbCode())
.html(imdbRating)
.append(imdbVotesSpan);
imdbRatingBox
.hover(
(e) => {
imdbRatingBox.css({
'background': '#F5BE18FF',
})
},
(e) => {
imdbRatingBox.css({
'background': '#F5C518',
})
},
)
.trigger('mouseleave');
imdbRatingBox.insertBefore(this.csfd.csfdPage.find('.my-rating'));
}
}
;// CONCATENATED MODULE: ./src/classes/Omdb.js
class Omdb {
constructor(
csfd,
omdbApiKey,
cache
) {
this.csfd = csfd;
this.omdbApiKey = omdbApiKey;
this.cache = cache;
this.getResponse();
}
getResponse() {
let imdbCode = this.csfd.getImdbCode();
if (imdbCode === null) {
return;
}
let cacheItem = this.cache.getItem(imdbCode);
if (cacheItem !== null && !this.cache.isItemExpired(cacheItem)) {
let responseFromCache = cacheItem.value;
new ImdbRating(
this.csfd,
responseFromCache.imdbRating,
responseFromCache.imdbVotes
);
return;
}
let request = $.ajax({
method: 'GET',
url: 'https://omdbapi.com/',
data: {
apikey: this.omdbApiKey,
i: imdbCode,
r: 'json'
},
});
request.done((response) => {
if (
response.imdbRating !== undefined
&& response.imdbRating !== 'N/A'
) {
this.cache.saveItem(imdbCode, response);
}
new ImdbRating(
this.csfd,
response.imdbRating,
response.imdbVotes
)
this.response = response;
});
}
}
;// CONCATENATED MODULE: ./src/classes/Toolbar.js
class Toolbar {
constructor(
csfd
) {
this.csfd = csfd;
this.initializeToolbar();
}
initializeToolbar() {
let boxButtons = this.csfd.csfdPage.find('.box-rating-container .box-buttons');
let imdbCode = this.csfd.getImdbCode();
let encodedLinkingDataMovieTitle = encodeURIComponent(this.csfd.getLinkingDataMovieTitle());
boxButtons.prepend(
this.createButton(
'Titulky.com',
null,
'http://www.titulky.com/?Fulltext=' + encodedLinkingDataMovieTitle
),
this.createButton(
'Trakt.TV',
null,
'https://trakt.tv/search/imdb?q=' + imdbCode
),
this.createButton(
'JustWatch',
null,
'https://www.justwatch.com/cz/vyhled%C3%A1n%C3%AD?q=' + encodedLinkingDataMovieTitle
),
this.createButton(
'Google',
null,
'https://www.google.cz/search?q=' + encodedLinkingDataMovieTitle
),
this.createButton(
'YouTube',
null,
'https://www.youtube.com/results?search_query=' + encodedLinkingDataMovieTitle
),
this.createButton(
'BoxOffice',
null,
'http://www.boxofficemojo.com/search/?q=' + encodedLinkingDataMovieTitle
),
this.createButton(
'Webshare.cz',
'pirate',
'https://webshare.cz/#/search?what=' + encodedLinkingDataMovieTitle
),
this.createButton(
'YIFY',
'pirate',
'https://www.google.cz/search?q=' + encodedLinkingDataMovieTitle + ' site:yts.mx OR site:yify-movies.net'
),
this.createButton(
'Torrent',
'pirate',
'http://www.aiosearch.com/search/4/Torrents/' + encodedLinkingDataMovieTitle
),
);
}
createButton(
name,
style,
url,
) {
let backgroundColor = '#DE5254';
let fontColor = '#FFF';
let iconClass = 'icon-globe-circle';
if (style === 'pirate') {
backgroundColor = '#A2A2A2';
iconClass = 'icon-folder';
}
let button = $('<a>')
.attr('href', url)
.addClass('button button-big')
.css({
'background-color': backgroundColor,
'color': fontColor,
'padding-left': '6px',
})
.html('<i class="icon ' + iconClass + '"></i>' + name);
button.hover(
(e) => {
$(e.target).css({
'opacity': 1.0,
});
},
(e) => {
$(e.target).css({
'opacity': 0.95,
});
},
);
button.trigger('mouseleave');
return button;
}
}
;// CONCATENATED MODULE: ./src/classes/UserRating.js
class UserRating {
constructor(
csfd
) {
this.csfd = csfd;
this.initializeUserRating();
}
initializeUserRating() {
let currentUserRatingDate = this.csfd.getCurrentUserRatingDate();
if (currentUserRatingDate === null) {
return;
}
let currentUserRatingBoxTitle = this.csfd.csfdPage.find('.my-rating h3');
if (currentUserRatingBoxTitle.length === 0) {
return;
}
currentUserRatingBoxTitle.text('Hodnoceno ' + currentUserRatingDate);
}
}
;// CONCATENATED MODULE: ./src/classes/WantToWatch.js
class WantToWatch {
constructor(
csfd
) {
this.csfd = csfd;
this.initializeWantToWatch();
}
initializeWantToWatch() {
if (!this.csfd.isMarkedAsWantToWatch()) {
return;
}
let wantToWatch = $('<a>')
.attr('href', '?name=watchlist&do=modalWindow')
.css({
'background': '#BA034F',
'border-top': '1px solid #D2D2D2',
'color': '#FFFFFF',
'display': 'block',
'opacity': 0.8,
'padding': '5px',
'text-align': 'center',
})
.html('👁️ Chci vidět');
wantToWatch.hover(
(e) => {
$(e.target).animate({
'opacity': 1.0,
});
},
(e) => {
$(e.target).animate({
'opacity': 0.8,
});
},
);
this.csfd.csfdPage.find('.tabs.tabs-rating.rating-fan-switch').prepend(wantToWatch);
}
}
;// CONCATENATED MODULE: ./src/classes/ImageFloatingPreview.js
class ImageFloatingPreview {
constructor(
csfd
) {
this.csfd = csfd;
this.initializeImageFloatingPreview();
}
initializeImageFloatingPreview() {
this.popup = $('<img>')
.css({
'box-shadow': '5px 5px 14px 8px rgba(0,0,0,0.75)',
'z-index': 999,
});
$('body').append(this.popup);
$('.creators a')
.bind('mouseenter', (e) => {
let creatorUrl = $(e.target).attr('href');
this.hoverCreatorLink(creatorUrl);
this.refreshPopupPosition(e.pageX, e.pageY);
})
.bind('mousemove', (e) => this.refreshPopupPosition(e.pageX, e.pageY))
.bind('mouseleave', () => this.abort());
}
showPopup(
imageUrl
) {
this.popup.attr('src', imageUrl);
this.popup.show();
}
hidePopup() {
this.popup.attr('src', '');
this.popup.hide();
}
refreshPopupPosition(
x,
y
) {
this.popup.css({
'position': 'absolute',
'left': x + 15,
'top': y + 15,
})
}
abort() {
this.currentRequest.abort();
this.hidePopup();
}
hoverCreatorLink(
url
) {
this.currentRequest = $.ajax({
method: 'GET',
url: url,
});
this.currentRequest.done((response) => {
if (
typeof response === 'object'
&& 'redirect' in response
) {
this.hoverCreatorLink(response.redirect);
return;
}
let creatorImageUrl = $(response).find('.creator-profile-content>figure img').attr('src');
if (creatorImageUrl !== undefined) {
this.showPopup(creatorImageUrl);
}
});
}
}
;// CONCATENATED MODULE: ./src/classes/CacheItem.js
class CacheItem {
constructor(
name,
value,
expireAt
) {
this.name = name;
this.expireAt = expireAt;
this.value = value;
}
}
;// CONCATENATED MODULE: ./src/classes/Cache.js
class Cache {
constructor(
expirationInSeconds
) {
this.expirationInSeconds = 600;
this.namespace = 'csfd-extended';
}
saveItem(
key,
value
) {
let cacheItem = new CacheItem(
this.addNamespaceToName(key),
value,
Math.floor(Date.now() / 1000) + this.expirationInSeconds
)
localStorage.setItem(
this.addNamespaceToName(key),
JSON.stringify(cacheItem)
)
}
getItem(
key
) {
let cacheItem = localStorage.getItem(
this.addNamespaceToName(key)
);
return cacheItem !== null
? JSON.parse(cacheItem)
: null;
}
isItemExpired(
caheItem
) {
return caheItem.expireAt < Math.floor(Date.now() / 1000);
}
addNamespaceToName(name) {
return this.namespace + '.' + name;
}
}
;// CONCATENATED MODULE: ./src/index.js
let cache = new Cache(7 * 24 * 3600);
let csfd = new Csfd($('div.page-content'));
let omdb = new Omdb(csfd, 'ee2fe641', cache);
let userRating = new UserRating(csfd);
let wantToWatch = new WantToWatch(csfd);
let toolbar = new Toolbar(csfd);
let imageFloatingPreview = new ImageFloatingPreview(csfd);
/******/ })()
;