· 6 years ago · Feb 19, 2020, 11:14 PM
1// ==UserScript==
2// @name Skrypt umożliwiający pobieranie materiałów ze znanych serwisów VOD.
3// @version 6.9.3
4// @description Skrypt służący do pobierania materiałów ze znanych serwisów VOD.
5// Działa poprawnie tylko z rozszerzeniem Tampermonkey.
6// Cześć kodu pochodzi z:
7// miniskrypt.blogspot.com,
8// miniskrypt.hubaiitv.pl
9// @author Przmus, zacny
10// @namespace http://www.ipla.tv/
11// @source https://github.com/zacny/voddownloader
12// @include https://vod.tvp.pl/video/*
13// @include /^https?://.*\.tvp.pl/sess/TVPlayer2/embed.*$/
14// @include https://cyfrowa.tvp.pl/video/*
15// @include https://www.ipla.tv/*
16// @include https://player.pl/*
17// @include https://*.cda.pl/*
18// @include https://vod.pl/*
19// @include https://redir.atmcdn.pl/*
20// @include https://*.redcdn.pl/file/o2/redefine/partner/*
21// @include https://partner.ipla.tv/embed/*
22// @include https://wideo.wp.pl/*
23// @include https://ninateka.pl/*
24// @include https://www.arte.tv/*/videos/*
25// @include https://pulsembed.eu/*
26// @exclude http://www.tvp.pl/sess/*
27// @exclude https://www.cda.pl/iframe/*
28// @grant GM_getResourceText
29// @grant GM_xmlhttpRequest
30// @grant GM_download
31// @grant GM_setClipboard
32// @grant GM_info
33// @connect tvp.pl
34// @connect getmedia.redefine.pl
35// @connect distro.redefine.pl
36// @connect player-api.dreamlab.pl
37// @connect api.arte.tv
38// @connect b2c.redefine.pl
39// @connect player.pl
40// @run-at document-end
41// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js
42// @require https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js
43// @require https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.min.js
44// @require https://gitcdn.xyz/cdn/zacny/voddownloader/4b17a120f521eaddf476d6e8fe3be152d506f244/lib/js/mdb-with-waves-patch.js
45// @resource buttons_css https://raw.githubusercontent.com/zacny/voddownloader/master/lib/css/voddownloader-buttons.css
46// @resource content_css https://raw.githubusercontent.com/zacny/voddownloader/master/lib/css/voddownloader-content.css
47// ==/UserScript==
48
49(function vodDownloader($, platform, Waves) {
50 'use strict';
51
52 var Exception = (function(error, templateParams) {
53 this.error = error;
54 this.templateParams = Array.isArray(templateParams) ? templateParams : [templateParams];
55 });
56
57 var Tool = (function(Tool) {
58 Tool.deleteParametersFromUrl = function(url){
59 return decodeURIComponent(url.replace(/\?.*/,''));
60 };
61
62 Tool.getUrlParameter = function(paramName, url){
63 var results = new RegExp('[\?&]' + paramName + '=([^&#]*)').exec(url);
64 if (results==null) {
65 return null;
66 }
67 return decodeURIComponent(results[1]) || 0;
68 };
69
70 Tool.formatConsoleMessage = function(message, params){
71 console.log.apply(this, $.merge([message], params));
72 };
73
74 Tool.downloadFile = function(fileUrl, title){
75 var extension = Tool.deleteParametersFromUrl(fileUrl.split('.').pop());
76 var movieTitle = (title !== undefined && title !== '' ) ? title : 'nieznany';
77 movieTitle = movieTitle.replace(new RegExp(config.windowsNotAllowedFileNameCharsMask), '');
78 var name = movieTitle + '.' + extension;
79 GM_download(fileUrl, name);
80 };
81
82 Tool.template = function(templates, ...keys){
83 return (function(...values) {
84 var dict = values[values.length - 1] || {};
85 var result = [templates[0]];
86 keys.forEach(function(key, i) {
87 var value = Number.isInteger(key) ? values[key] : dict[key];
88 result.push(value, templates[i + 1]);
89 });
90 return result.join('');
91 });
92 };
93
94 Tool.getRealUrl = function(){
95 var topUrl = window.sessionStorage.getItem(config.storage.topWindowLocation);
96 return topUrl !== null ? topUrl : window.location.href;
97 };
98
99 Tool.isTopWindow = function(){
100 return window.top === window.self;
101 };
102
103 Tool.pad = function(number, characters){
104 return(1e15+number+"").slice(-characters)
105 };
106
107 Tool.mapDescription = function(data){
108 var defaults = config.description.defaults;
109 var sourceDescriptions = config.description.sources[data.source] || {};
110 var descriptionVariant = sourceDescriptions[data.key] || {};
111 var output = {
112 video: descriptionVariant.video ? descriptionVariant.video : data.video,
113 index: descriptionVariant.index ? descriptionVariant.index : 99,
114 audio: data.audio ? data.audio : defaults.audio,
115 language: data.language ? data.language: defaults.language,
116 url: data.url
117 };
118 return $.extend(true, data, output);
119 };
120
121 return Tool;
122 }(Tool || {}));
123
124 const config = {
125 attempts: 10,
126 attemptTimeout: 1500,
127 storage: {
128 doNotWarn: 'voddownloader.doNotwarnIfIncorrectPluginSettingsDetected',
129 topWindowLocation: 'voddownloader.topWindowLocation'
130 },
131 urlParamPattern: '#',
132 urlParamDefaultKey: 'videoId',
133 urlPartPattern: '~',
134 windowsNotAllowedFileNameCharsMask: '[\\/:\*\?"<>|]+',
135 include: {
136 fontawesome: {
137 id: 'fontawesome',
138 css: 'https://use.fontawesome.com/releases/v5.8.2/css/all.css'
139 },
140 bootstrap: {
141 id: 'bootstrap',
142 css: 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css'
143 },
144 mdb: {
145 id: 'mdb',
146 css: 'https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.8.2/css/mdb.min.css',
147 }
148 },
149 error: {
150 id: {
151 caption: 'Nie udało się odnaleźć idetyfikatora.',
152 template: Tool.template`Algorytm rozpoznawania identyfikatora wideo na stronie: ${0} \
153 zakończył się niepowodzeniem. Może to oznaczać błąd skryptu.`,
154 },
155 tvnId: {
156 caption: 'Nie udało się odnaleźć idetyfikatora.',
157 template: Tool.template`Algorytm rozpoznawania identyfikatora wideo na stronie: ${0} \
158 zakończył się niepowodzeniem.\nJeżeli jest to główna strona programu oznacza to, \
159 że nie udało się odnaleźć identyfikatora ostatniego odcinka. Wejdź na stronę odcinka \
160 i spróbuj ponownie.\nMoże to również oznaczać błąd skryptu.`,
161 },
162 call: {
163 caption: 'Błąd pobierania informacji o materiale.',
164 template: Tool.template`Wystąpił błąd w wykonaniu skryptu w kroku: ${0} na stronie: ${1} \
165 Zgłoś problem autorom skryptu.`,
166 },
167 noSource: {
168 caption: 'Nie udało się odnaleźć źródeł do materiału.',
169 template: Tool.template`Materiał ze strony ${0} nie posiada zdefiniowanych źródeł, które mogłyby zostać \
170 wyświetlone. \nMoże to oznaczać, że nie jest on publicznie dostępny, dostępne źródła nie mogą zostać \
171 wyświetlone w przeglądarce bez dodatkowego oprogramowania lub jest umieszczony w płatnej strefie.`,
172 type: 'info'
173 },
174 timeout: {
175 caption: 'Zbyt długi czas odpowiedzi.',
176 template: Tool.template`Dla kroku: ${0} na stronie "${1}" nie dotarły \
177 informacje zwrotne.\nPrzypuszczalnie jest to problem sieciowy. Spróbuj ponownie za jakiś czas.`
178 },
179 noParent: {
180 caption: 'Brak zakładki ze stroną główną.',
181 template: Tool.template`Została zamknięta zakładka ze stroną na której został uruchomiony skrypt. \
182 Ta zakładka nie może przez to działać poprawnie. Otwórz ponownie stronę główną: \n ${0} \n
183 by przywrócić prawidłowe funkcjonowanie skryptu.`
184 }
185 },
186 description: {
187 defaults: {
188 language: 'polski',
189 audio: 'MPEG ACC'
190 },
191 sources: {
192 IPLA: {
193 '1080p': {video: 'H264 MPEG-4 AVC, 4011 kb/s, 1920x1080, 25fps, 16:9', index: 1},
194 '720p': {video: 'H264 MPEG-4 AVC, 1672 kb/s, 1280x720, 25fps, 16:9', index: 2},
195 '576p': {video: 'H264 MPEG-4 AVC, 1175 kb/s, 1024x576, 25fps, 16:9', index: 3},
196 '384p': {video: 'H264 MPEG-4 AVC, 256 kb/s, 484x272, 25fps, 16:9', index: 4}
197 },
198 WP: {
199 HQ: {video: 'H264 MPEG-4 AVC, 1804 kb/s, 1280x720, 24fps, 16:9', index: 1},
200 LQ: {video: 'H264 MPEG-4 AVC, 616 kb/s, 640x360, 24fps, 16:9', index: 2}
201 },
202 TVN: {
203 'HD': {video: 'H264 MPEG-4 AVC, 2776 kb/s, 1280x720, 25fps, 16:9', index: 1},
204 'Bardzo wysoka': {video: 'H264 MPEG-4 AVC, 1786 kb/s, 1280x720, 25fps, 16:9', index: 2},
205 'Wysoka': {video: 'H264 MPEG-4 AVC, 1191 kb/s, 720x576, 25fps, 5:4', index: 3},
206 'Standard': {video: 'H264 MPEG-4 AVC, 794 kb/s, 720x576, 25fps, 5:4', index: 4},
207 'Średnia': {video: 'H264 MPEG-4 AVC, 596 kb/s, 640x480, 25fps, 4:3', index: 5},
208 'Niska': {video: 'H264 MPEG-4 AVC, 417 kb/s, 512x384, 25fps, 4:3', index: 6},
209 'Bardzo niska': {video: 'H264 MPEG-4 AVC, 238 kb/s, 320x240, 25fps, 4:3', index: 7}
210 },
211 VOD: {
212 '720': {video: 'H264 MPEG-4 AVC, 2467 kb/s, 1280x720, 25fps, 16:9', index: 1},
213 '576': {video: 'H264 MPEG-4 AVC,1810 kb/s, 1024x576, 25fps, 16:9', index: 2},
214 '480': {video: 'H264 MPEG-4 AVC, 911 kb/s, 854x480, 25fps, 16:9', index: 3},
215 '360': {video: 'H264 MPEG-4 AVC, 450 kb/s, 640x360, 25fps, 16:9', index: 4},
216 '240': {video: 'H264 MPEG-4 AVC, 200 kb/s, 426x240, 25fps, 16:9', index: 5}
217 },
218 TVP: {
219 '9100000': {video: 'H264 MPEG-4 AVC, 21030 kb/s, 1920x1080, 25fps, 16:9', index: 1},
220 '5420000': {video: 'H264 MPEG-4 AVC, 9875 kb/s, 1280x720, 25fps, 16:9', index: 2},
221 '2850000': {video: 'H264 MPEG-4 AVC, 4661 kb/s, 960x540, 25fps, 16:9', index: 3},
222 '1750000': {video: 'H264 MPEG-4 AVC, 1782 kb/s, 800x450, 25fps, 16:9', index: 4},
223 '1250000': {video: 'H264 MPEG-4 AVC, 1255 kb/s, 640x360, 25fps, 16:9', index: 5},
224 '820000': {video: 'H264 MPEG-4 AVC, 809 kb/s, 480x270, 25fps, 16:9', index: 6},
225 '590000': {video: 'H264 MPEG-4 AVC, 581 kb/s, 398x224, 25fps, 199:112', index: 7}
226 },
227 ARTE: {
228 '2200': {video: 'H264 MPEG-4 AVC, 2438 kb/s, 1280x720, 25fps, 16:9', index: 1},
229 '1500': {video: 'H264 MPEG-4 AVC, 1619 kb/s, 720x406, 25fps, 360:203', index: 2},
230 '800': {video: 'H264 MPEG-4 AVC, 805 kb/s, 640x360, 25fps, 16:9', index: 3},
231 '300': {video: 'H264 MPEG-4 AVC, 357 kb/s, 384x216, 25fps, 16:9', index: 4}
232 },
233 NINATEKA: {
234 def: {video: 'H264 MPEG-4 AVC, 900 kb/s, 640x360, 25fps, 16:9', index: 1}
235 },
236 CDA: {
237 '1080p': {video: 'H264 MPEG-4 AVC, 1920x1080, 16:9', index: 1},
238 '720p': {video: 'H264 MPEG-4 AVC, 1280x720, 16:9', index: 2},
239 '480p': {video: 'H264 MPEG-4 AVC, 854x480, 427:240', index: 3},
240 '360p': {video: 'H264 MPEG-4 AVC, 640x360, 16:9', index: 4},
241 }
242 }
243 }
244 };
245
246
247 var Step = (function(properties){
248 var step = {
249 urlTemplateParts: [],
250 urlTemplate: '',
251 beforeStep: function(input){return input},
252 afterStep: function (output) {return output},
253 resultUrlParams: function (input, template) {
254 var urlParams = {};
255 $.each(input, function (key, value) {
256 template = template.replace(new RegExp(config.urlParamPattern + key,'g'), value);
257 urlParams[key] = value;
258 });
259
260 return {
261 url: template,
262 urlParams: urlParams
263 };
264 },
265 resolveUrl: function (input, partIndex) {
266 return this.resultUrlParams(input, this.resolveUrlParts(partIndex));
267 },
268 isRemote: function(){
269 return this.urlTemplate.length > 0;
270 },
271 method: 'GET',
272 responseType: 'json',
273 retryErrorCodes: [],
274 methodParam: function(){return {}},
275 resolveUrlParts: function(partIndex){
276 if(this.urlTemplateParts.length){
277 return this.urlTemplate.replace(config.urlPartPattern, this.urlTemplateParts[partIndex]);
278 }
279
280 return this.urlTemplate;
281 }
282 };
283
284 return $.extend(true, step, properties);
285 });
286
287 var Notification = (function(Notification) {
288 var create = function(title, bodyContent, special) {
289 var specialContentClasses = special ? ' special-color white-text' : '';
290 var content = $('<div>').addClass('toast notification' + specialContentClasses).attr('role', 'alert')
291 .attr('aria-live', 'assertive').attr('aria-atomic', 'true')
292 .attr('name', special ? 'special' : 'normal').attr('data-delay', '5000');
293 var header = $('<div>').addClass('toast-header special-color-dark white-text');
294 var warnIcon = $('<i>').addClass('fas fa-exclamation-triangle pr-2');
295 var notificationTitle = $('<strong>').addClass('mr-auto').text(title);
296 var time = $('<small>').text(new Date().toLocaleTimeString());
297 var close = $('<button>').attr('type', 'button').addClass('ml-2 mb-1 close white-text')
298 .attr('data-dismiss', 'toast').attr('aria-label', 'Close')
299 .append($('<span>').attr('aria-hidden', 'true').text('\u00D7'));
300
301 if(special){
302 header.append(warnIcon);
303 content.attr('data-autohide', 'false');
304 }
305 header.append(notificationTitle).append(time).append(close);
306 var body = $('<div>').addClass('toast-body notification-body').append(bodyContent);
307
308 content.append(header).append(body);
309 return content;
310 };
311
312 Notification.show = function(options, w){
313 options = options || {};
314 var special = false;
315 if (options.hasOwnProperty('special')) {
316 special = options.special;
317 }
318 if(!options.hasOwnProperty('title') || !options.hasOwnProperty('content')){
319 return;
320 }
321
322 var rootElement = $(w.document.body);
323 var notification = create(options.title, options.content, special);
324 $('#notification-container', rootElement).append(notification);
325 $('.toast', rootElement).toast('show');
326 $('.toast', rootElement).on('hidden.bs.toast', function (){
327 $.each($(this), function(index, value) {
328 var element = $(value);
329 element.remove();
330 });
331 })
332 };
333
334 return Notification;
335 }(Notification || {}));
336
337 var PluginSettingsDetector = (function(PluginSettingsDetector){
338 var prepareWarningNotification = function(w) {
339 var bodyContent = $('<div>')
340 .append('Twój dodatek ma nieprawidłowe ustawienia, przez co nie możesz korzystać z opcji ')
341 .append('bezpośredniego pobierania plików. Możesz skorygować je w następujący sposób:');
342 var list = $('<ol>').addClass('m-0')
343 .append($('<li>').text('Otwórz Panel sterowania Tampermonkey i kliknij ustawienia.'))
344 .append($('<li>').text('Ogólne > Tryb konfiguracji > Expert'))
345 .append($('<li>').text('Pobieranie BETA > Tryb pobierania > API przeglądarki'))
346 .append($('<li>').text('Zapisz ustawienia, a jeżeli przeglądarka zapyta o możliwość zarządzania' +
347 ' pobieranymi plikami, należy się zgodzić'));
348 bodyContent.append(list).append(createButton(w));
349 var options = {title: 'Wykryto problem', content: bodyContent, special: true};
350 Notification.show(options, w);
351 };
352
353 var createButton = function(w){
354 return $('<button>').attr('type', 'button').addClass('btn btn-dark btn-sm m-1 pl-3 pr-3')
355 .append($('<i>').addClass('fas pr-1 fa-window-close')).append('Nie pokazuj więcej').click(function(){
356 var rootElement = $(w.document.body);
357 w.localStorage.setItem(config.storage.doNotWarn, true);
358 $('.toast.special-color', rootElement).toast('hide');
359 setTimeout(function(){
360 $('.toast.special-color', rootElement).remove();
361 }, 1000);
362 });
363 };
364
365 var disableDownload = function(w){
366 var rootElement = $(w.document.body);
367 $('.fa-save', rootElement).closest('button').attr('disabled', true);
368 };
369
370 PluginSettingsDetector.detect = function(w){
371 var downloadMode = GM_info.downloadMode;
372 if(downloadMode !== 'browser'){
373 disableDownload(w);
374 var value = w.localStorage.getItem(config.storage.doNotWarn);
375 if(value !== 'true'){
376 prepareWarningNotification(w);
377 }
378 }
379 };
380 return PluginSettingsDetector;
381 }(PluginSettingsDetector || {}));
382
383 var DomTamper = (function(DomTamper){
384
385 DomTamper.injectStyle = function(w, name){
386 var head = $(w.document.head);
387 if(!head.find('style[name="' + name + '"]').length){
388 var styleElement = $('<style>').attr('type', 'text/css')
389 .attr('name', name).text((GM_getResourceText(name)));
390 head.append(styleElement);
391 }
392 };
393
394 var injectStylesheet = function (w, setting) {
395 var head = $(w.document.head);
396 if(!head.find('link[name="' + setting.id + '"]').length){
397 var stylesheet = $('<link>').attr('name', setting.id).attr('type', 'text/css').attr('rel', 'stylesheet')
398 .attr('href', setting.css);
399 head.append(stylesheet);
400 }
401 };
402
403 var prepareHead = function(w){
404 injectStylesheet(w, config.include.fontawesome);
405 injectStylesheet(w, config.include.bootstrap);
406 injectStylesheet(w, config.include.mdb);
407 DomTamper.injectStyle(w, 'content_css');
408 };
409
410 var createLinks = function(w, additionalClass){
411 var links = [
412 {
413 url: 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RWX4EUR77CMKU',
414 icon: 'fa-hand-holding-usd',
415 tooltip: 'dotacje'
416 },
417 {
418 url: 'https://greasyfork.org/pl/scripts/6049-skrypt-umo%C5%BCliwiaj%C4%85cy-pobieranie-' +
419 'materia%C5%82%C3%B3w-ze-znanych-serwis%C3%B3w-vod/feedback',
420 icon: 'fa-comments',
421 tooltip: 'problemy, komentarze'
422 },
423 {
424 url: 'https://github.com/zacny/voddownloader/issues',
425 icon: 'fa-bug',
426 tooltip: 'zgłoś błąd'
427 }
428 ];
429 var container = $('<div>').addClass('links-position');
430 links.forEach(function(link){
431 var button = $('<button>').attr('type', 'button').attr('title', link.tooltip)
432 .addClass('btn btn-sm m-1 p-2').addClass(additionalClass)
433 .append($('<i>').addClass('fas').addClass(link.icon).addClass('fa-2x'));
434 button.click(function(){
435 w.open(link.url);
436 });
437 container.append(button);
438 });
439 return container;
440 };
441
442 var prepareBody = function(w, pageContent, detection) {
443 appendOrReplace(w, pageContent);
444 attachWaveEffect(w, pageContent);
445 if(detection) {
446 PluginSettingsDetector.detect(w);
447 }
448 };
449
450 var appendOrReplace = function (w, pageContent) {
451 var body = $(w.document.body);
452 if(body.children().length > 0){
453 body.children(":first").replaceWith(pageContent);
454 }
455 else {
456 body.append(pageContent);
457 }
458 };
459
460 var attachWaveEffect = function(w, pageContent){
461 var buttons = pageContent.find('.btn:not(.btn-flat), .btn-floating');
462 Waves.attach(buttons, ['waves-light']);
463 Waves.init({}, w);
464 };
465
466 DomTamper.handleError = function(exception, w){
467 if(w === undefined){
468 w = window.open();
469 }
470
471 prepareHead(w);
472 var errorData = getErrorData(exception);
473 var pageContent = $('<div>').addClass('page-content');
474 pageContent.append(createErrorContent(errorData));
475 pageContent.append(createLinks(w, errorData.type === 'error' ?
476 'btn-danger' : 'special-color white-text'));
477 prepareBody(w, pageContent);
478 };
479
480 var getErrorData = function(exception){
481 var type = 'error';
482 var caption = 'Niespodziewany błąd';
483 var message = 'Natrafiono na niespodziewany błąd: ' + exception;
484 if(exception.error){
485 message = exception.error.template.apply(this, exception.templateParams).replace(/\n/g, '<br/>');
486 caption = exception.error.caption;
487 type = exception.error.type !== undefined ? exception.error.type : 'error';
488 }
489
490 return {
491 message: linkify(message),
492 caption: caption,
493 type: type
494 }
495 };
496
497 var linkify = function(text) {
498 var linkDetectionRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
499 return text.replace(linkDetectionRegex, function(url) {
500 return '<u><a class="text-white" href="' + url + '">' + url + '</a></u>';
501 });
502 };
503
504 var createErrorContent = function(errorData){
505 var typeClass = errorData.type === 'error' ? 'bg-danger' : 'bg-dark';
506 var card = $('<div>').addClass('card text-white mb-3').addClass(typeClass);
507 var cardHeader = $('<div>').addClass('card-header')
508 .text('Niestety natrafiono na problem, który uniemożliwił dalsze działanie');
509 var cardBody = $('<div>').addClass('card-body')
510 .append($('<h5>').addClass('card-title').text(errorData.caption))
511 .append($('<div>').addClass('card-text text-white mb-3').append(errorData.message))
512 .append($('<div>').addClass('card-text text-white')
513 .append('Informacje o systemie: ').append(platform.description))
514 .append($('<div>').addClass('card-text text-white')
515 .append('Wersja pluginu: ').append(GM_info.version))
516 .append($('<div>').addClass('card-text text-white')
517 .append('Wersja skryptu: ').append(GM_info.script.version));
518 card.append(cardHeader).append(cardBody);
519 return card;
520 };
521
522 DomTamper.createButton = function(properties){
523 properties.wrapper.get().find('#'+properties.button.id).remove();
524 var button = $('<input>').attr('id', properties.button.id).attr('type', 'button')
525 .attr('style', properties.button.style).attr('value', 'Pobierz video').addClass(properties.button.class);
526 button.bind('click', properties.button.click);
527 properties.wrapper.get().append(button);
528 };
529
530 DomTamper.createLoader = function(w){
531 prepareHead(w);
532 var pageContent = $('<div>').addClass('page-content');
533 pageContent.append(createLoaderContent());
534 pageContent.append(createLinks(w, 'special-color white-text'));
535 prepareBody(w, pageContent);
536 Unloader.init(w);
537 };
538
539 var createLoaderContent = function(){
540 var card = $('<div>').addClass('card text-white bg-dark');
541 var cardHeader = $('<div>').addClass('card-header').text('Poczekaj trwa wczytywanie danych...');
542 var cardBody = $('<div>').addClass('card-body');
543 var bodyContainer = $('<div>').addClass('d-flex justify-content-center m-3');
544 var spinner = $('<div>').addClass('spinner-border spinner-size').attr('role', 'status')
545 .append($('<span>').addClass('sr-only').text('Loading...'));
546 cardBody.append(bodyContainer.append(spinner));
547 card.append(cardHeader).append(cardBody);
548
549 return card;
550 };
551
552 var setWindowTitle = function(data, w){
553 var head = $(w.document.head);
554 var title = head.find('title');
555 if(title.length) {
556 title.text(data.title);
557 }
558 else {
559 head.append($('<title>').text(data.title));
560 }
561 };
562
563 DomTamper.createDocument = function(data, w){
564 prepareHead(w);
565 setWindowTitle(data, w);
566 var pageContent = $('<div>').addClass('page-content');
567 pageContent.append(Accordion.create(w, data));
568 pageContent.append(createLinks(w, 'special-color white-text'));
569 pageContent.append(createNotificationContainer());
570 prepareBody(w, pageContent, true);
571 Unloader.init(w);
572 Accordion.bindActions(w, data);
573 };
574
575 var createNotificationContainer = function(){
576 return $('<div>').attr('id', 'notification-container')
577 .attr('aria-live', 'polite').attr('aria-atomic', 'true').addClass('notification-container');
578 };
579
580 return DomTamper;
581 }(DomTamper || {}));
582
583 var Accordion = (function(Accordion) {
584 Accordion.create = function(w, data){
585 var mainCardTitle = $('<div>').addClass('card-header').text(data.title);
586
587 var accordion = $('<div>').addClass('accordion md-accordion').attr('id', 'accordion')
588 .attr('role', 'tablist').attr('aria-multiselectable', 'true');
589
590 createCards(accordion, data);
591
592 var mainCardBody = $('<div>').addClass('card-body p-0').append(accordion);
593 return $('<div>').addClass('card').append(mainCardTitle).append(mainCardBody);
594 };
595
596 var createCards = function(accordion, data) {
597 for(var key in data.cards) {
598 var card = createCard({
599 card: data.cards[key],
600 key: key,
601 title: data.title
602 });
603 accordion.append(card);
604 }
605 };
606
607 var createCard = function(data){
608 var accordionCard = $('<div>').addClass('border border-top-0');
609 var content = $('<div>').addClass('card-body pt-0');
610
611 var badgeClass = 'badge-light';
612 var textMuted = 'text-muted';
613 if(data.card.items.length > 0){
614 badgeClass = 'badge-danger';
615 textMuted = 'text-dark';
616 content.append(createCardContent(data));
617 }
618
619 var icon = $('<i>').addClass('fas').addClass(data.card.icon).addClass('pr-2');
620 var badge = $('<span>').addClass('badge mr-3 float-right').addClass(badgeClass)
621 .text(data.card.items.length);
622 var cardTitle = $('<h6>').addClass('mb-0').addClass(textMuted).append(icon).append(badge)
623 .append($('<span>').text(data.card.label));
624 var link = $('<a>').append(cardTitle);
625 var cardHeader = $('<div>').addClass('ml-3 p-2').attr('role', 'tab').attr('id', data.key).append(link);
626
627 var cardBody = $('<div>').addClass('collapse').attr('role', 'tabpanel')
628 .attr('aria-labelledby', data.key).append(content);
629 if(data.card.collapse){
630 cardBody.addClass('show');
631 }
632
633 accordionCard.append(cardHeader);
634 accordionCard.append(cardBody);
635 return accordionCard;
636 };
637
638 var createCardContent = function(data){
639 var table = $('<table>').addClass('table table-bordered table-striped btn-table');
640 var tbody = $('<tbody>');
641 table.append(tbody);
642 createRows(tbody, data);
643
644 return table;
645 };
646
647 var createRows = function(tableBody, data){
648 data.card.items.forEach(function(item) {
649 tableBody.append(createRow({
650 item: item,
651 info: data.card.info,
652 title: data.title,
653 actions: data.card.actions
654 }));
655 });
656 };
657
658 var createRow = function(data){
659 var actions = $('<td>').attr('scope', 'row').addClass('action-row-' + data.actions.length);
660 data.actions.forEach(function(action){
661 actions.append(createButton(action, data));
662 });
663
664 var description = $('<td>').html(createDescriptionHtml(data));
665 return $('<tr>').append(actions).append(description);
666 };
667
668 var createDescriptionHtml = function(data){
669 var descriptionHtml = $('<div>');
670
671 createDescription(data).forEach(function(item, idx, array){
672 descriptionHtml.append($('<b>').text(item.desc + ': '))
673 .append($('<span>').text(item.value));
674 if(idx !== array.length - 1) {//not last
675 descriptionHtml.append($('<span>').text(', '));
676 }
677 });
678 return descriptionHtml;
679 };
680
681 var itemExist = function(data, info){
682 return data.item.hasOwnProperty(info.name) && data.item[info.name] != null
683 };
684
685 var createDescription = function(data){
686 var description = [];
687 data.info.forEach(function(info){
688 if (itemExist(data, info)) {
689 description.push({
690 desc: info.desc,
691 value: data.item[info.name]
692 });
693 }
694 });
695 return description;
696 };
697
698 var createButton = function(action, data){
699 return $('<button>').attr('type', 'button').attr('data-url', data.item.url).attr('data-title', data.title)
700 .addClass('btn btn-dark btn-sm m-1 pl-3 pr-3')
701 .append($('<i>').addClass('fas pr-1').addClass(action.icon)).append(action.label);
702 };
703
704 Accordion.bindActions = function(w, data){
705 cardActions(w, data);
706 buttonActions(w);
707 };
708
709 var cardActions = function(w, data){
710 for(var key in data.cards) {
711 var cardHeader = $(w.document.body).find('#' + key);
712 var disabled = cardHeader.find('h6.text-muted');
713 if(disabled.length){
714 disabled.addClass('cursor-normal');
715 return;
716 }
717
718 $(w.document.body).find('#' + key).click(function() {
719 var id = $(this).attr('id');
720 $(w.document.body).find('div[aria-labelledby="' + id + '"]').toggle();
721 });
722 }
723 };
724
725 var buttonActions = function(w){
726 getButton(w, '.fa-clone').click(function(){ copyActionClick($(this), w) });
727 getButton(w, '.fa-film').click(function(){ openActionClick($(this), w) });
728 getButton(w, '.fa-download').click(function(){ downloadActionClick($(this), w) });
729 };
730
731 var getButton = function(w, iconClass){
732 return $(w.document.body).find(iconClass).parent();
733 };
734
735 var downloadActionClick = function (element, w) {
736 var options = {title: 'Rozpoczęto pobieranie pliku', content: element.attr('data-title')};
737 Tool.downloadFile(element.attr('data-url'), element.attr('data-title'));
738 Notification.show(options, w);
739 };
740
741 var copyActionClick = function (element, w) {
742 GM_setClipboard(element.attr('data-url'));
743 var options = {title: 'Kopiowanie', content: 'Skopiowano do schowka'};
744 Notification.show(options, w);
745 };
746
747 var openActionClick = function (element, w) {
748 w.open(element.attr('data-url'));
749 };
750
751 return Accordion;
752 }(Accordion || {}));
753
754 var Executor = (function(Executor){
755 var execute = function(service, options, w){
756 var setup = setupStep(service, options);
757 logStepInfo(options, setup);
758 if(setup.isRemote()){
759 executeAsync(service, setup, options, w);
760 }
761 else {
762 options.temporaryData = {};
763 callback(service, options, w);
764 }
765 };
766
767 var executeAsync = function(service, setup, options, w){
768 var chain = options.chainNames[options.chainIndex];
769 var chainStep = chain + '[' + options.stepIndex + ']';
770 var exceptionParams = [chainStep, Tool.getRealUrl()];
771 var requestParams = {
772 method: setup.method,
773 url: setup.resolveUrl.url,
774 data: JSON.stringify(setup.methodParam()),
775 responseType: setup.responseType,
776 onload: function(data) {
777 var currentStep = getCurrentStep(service, options);
778 if(retryPossible(currentStep, options, data.status)){
779 execute(service, options, w);
780 }
781 else {
782 if(setup.responseType === 'jsonp'){
783 var match = data.responseText.match(/callback\(([\s\S]*?)\);/);
784 if(match && match[1] && !match[1].startsWith('null')){
785 options.temporaryData = JSON.parse(match[1]);
786 }
787 }
788 else {
789 options.temporaryData = data.response || {};
790 }
791 callback(service, options, w);
792 }
793 },
794 onerror: function(data){
795 DomTamper.handleError(new Exception(config.error.call, exceptionParams), w);
796 },
797 ontimeout: function(){
798 DomTamper.handleError(new Exception(config.error.timeout, exceptionParams), w);
799 }
800 };
801 GM_xmlhttpRequest(requestParams);
802 };
803
804 var retryPossible = function(step, options, status){
805 return step.retryErrorCodes.indexOf(status) >= 0 && step.urlTemplateParts[options.retries++];
806 };
807
808 var logStepInfo = function(options, setup){
809 var chain = options.chainNames[options.chainIndex];
810 var step = chain + '[' + options.stepIndex + ']';
811 var stepParams = $.isEmptyObject(setup.methodParam()) ? '' : JSON.stringify(setup.methodParam());
812 var params = [
813 'color:green', options.retries+1, 'color:black', ':',
814 'color:blue', step, 'color:red', setup.isRemote ? setup.method : '---',
815 'color:black;font-weight: bold', setup.resolveUrl.url, 'color:magenta', stepParams
816 ];
817 Tool.formatConsoleMessage('%c%s%c%s%c%s%c %s %c %s %c%s', params);
818 };
819
820 var setupStep = function(service, options){
821 var currentStep = getCurrentStep(service, options);
822 prepareStepOutput(currentStep, options);
823 var setup = $.extend(true, {}, currentStep);
824 setup.resolveUrl = currentStep.resolveUrl(options.urlParams, options.retries);
825 return setup;
826 };
827
828 var getCurrentStep = function(service, options){
829 var chain = options.chainNames[options.chainIndex];
830 var steps = service.asyncChains[chain];
831 return steps[options.stepIndex];
832 };
833
834 var prepareStepOutput = function(currentStep, options){
835 var stepOutput = {};
836 var result = currentStep.beforeStep(options.temporaryData);
837 if(typeof result === 'string' || typeof result == 'number'){
838 stepOutput[config.urlParamDefaultKey] = result;
839 }
840 else if(typeof result === 'object'){
841 stepOutput = result;
842 }
843
844 if(options.urlParams){
845 $.extend(true, options.urlParams, stepOutput);
846 }
847 else {
848 options.urlParams = stepOutput;
849 }
850 };
851
852 var hasNextStep = function(service, options){
853 var chain = options.chainNames[options.chainIndex];
854 var steps = service.asyncChains[chain];
855 return steps.length - 1 > options.stepIndex;
856 };
857
858 var hasNextChain = function(service, options){
859 return options.chainNames.length - 1 > options.chainIndex;
860 };
861
862 var setChainResult = function(options){
863 var chain = options.chainNames[options.chainIndex];
864 if(!options.hasOwnProperty('results')){
865 options.results = {};
866 }
867 var chainResult = options.results;
868 chainResult[chain] = options.temporaryData;
869 options.temporaryData = {};
870 };
871
872 var pushChain = function(service, options){
873 setChainResult(options);
874 if(hasNextChain(service, options)){
875 options.chainIndex += 1;
876 options.stepIndex = 0;
877 return true;
878 }
879 return false;
880 };
881
882 var pushStep = function(service, options) {
883 if(hasNextStep(service, options)){
884 options.stepIndex += 1;
885 return true;
886 }
887 return false;
888 };
889
890 var afterStep = function(service, options) {
891 var currentStep = getCurrentStep(service, options);
892 var output = currentStep.afterStep(options.temporaryData);
893 options.retries = 0;
894 options.temporaryData = output;
895 };
896
897 var callback = function(service, options, w){
898 try {
899 afterStep(service, options);
900 if(pushStep(service, options) || pushChain(service, options)) {
901 return Promise.resolve().then(
902 Executor.chain(service, options, w)
903 );
904 }
905 else {
906 return Promise.resolve().then(
907 service.onDone(options.results, w)
908 );
909 }
910 }
911 catch(e){
912 DomTamper.handleError(e, w);
913 }
914 };
915
916 Executor.chain = function(service, options, w){
917 try {
918 if(w === undefined){
919 w = window.open();
920 DomTamper.createLoader(w);
921 }
922
923 execute(service, options, w);
924 }
925 catch(e){
926 DomTamper.handleError(e, w);
927 }
928 };
929
930 return Executor;
931 }(Executor || {}));
932
933 function Configurator(properties){
934 var service = {
935 wrapper: {
936 selector: '',
937 get: function(){
938 return $(service.wrapper.selector);
939 },
940 exist: function(){
941 return $(service.wrapper.selector).length > 0;
942 }
943 },
944 button: {
945 id: 'direct-download',
946 style: '',
947 class: '',
948 click: function(){
949 var chainNames = service.chainSelector();
950 Executor.chain(service, {
951 stepIndex: 0,
952 chainIndex: 0,
953 retries: 0,
954 chainNames: chainNames
955 });
956 }
957 },
958 cardsData: {
959 title: '',
960 cards: {
961 videos: {
962 icon: 'fa-video', label: 'Video', collapse: true, items: [],
963 info: [
964 {name: 'video', desc: 'video'},
965 {name: 'audio', desc: 'audio'},
966 {name: 'language', desc: 'wersja językowa'}
967 ],
968 actions: [
969 {label: 'Pobierz', icon: 'fa-download'},
970 {label: 'Kopiuj', icon: 'fa-clone'},
971 {label: 'Otwórz', icon: 'fa-film'}
972 ]
973 },
974 subtitles: {
975 icon: 'fa-file-alt', label: 'Napisy', collapse: false, items: [],
976 info: [
977 {name: 'description', desc: 'opis'},
978 {name: 'format', desc: 'format'},
979 ],
980 actions: [
981 {label: 'Pobierz', icon: 'fa-download'}
982 ]
983 }
984 }
985 },
986 asyncChains: {
987 videos: []
988 },
989 chainSelector: function(){
990 return ['videos'];
991 },
992 formatter: function(data){
993 data.cards['videos'].items.sort(function (a, b) {
994 return a.index - b.index;
995 });
996 data.cards['subtitles'].items.sort(function (a, b) {
997 return ('' + a.format).localeCompare(b.format);
998 });
999 },
1000 aggregate: function(data){
1001 var aggregatedData = {};
1002 $.extend(true, aggregatedData, service.cardsData);
1003 var chains = service.chainSelector();
1004 chains.forEach(function(chain){
1005 $.extend(true, aggregatedData, data[chain]);
1006 });
1007 return aggregatedData;
1008 },
1009 onDone: function(data, w) {
1010 var aggregatedData = service.aggregate(data);
1011 service.formatter(aggregatedData);
1012 DomTamper.createDocument(aggregatedData, w);
1013 }
1014 };
1015
1016 return $.extend(true, service, properties);
1017 }
1018
1019 var Detector = (function(conf) {
1020 var configuration = conf;
1021
1022 var logMessage = function(attempt){
1023 var color = configuration.logStyle || 'color:black;font-weight:bold';
1024 var existColor = configuration.success() ? 'color:green' : 'color:red';
1025 if(configuration.unlimited){
1026 var params = [
1027 existColor, configuration.target, 'color:black'
1028 ];
1029 Tool.formatConsoleMessage('[%c%s%c]', params);
1030 }
1031 else {
1032 var params = [
1033 'color:black', color, configuration.target, 'color:black',
1034 existColor + ';font-weight:bold', attempt, 'color:black'
1035 ];
1036 Tool.formatConsoleMessage('%c[%c%s%c] [%c%s%c]', params);
1037 }
1038 };
1039
1040 var check = function(attempt){
1041 logMessage(attempt);
1042 if (configuration.success()) {
1043 return Promise.resolve().then(
1044 configuration.successCallback()
1045 );
1046 } else if(configuration.unlimited || attempt > 0){
1047 attempt = attempt-1;
1048 return Promise.resolve().then(
1049 setTimeout(check, config.attemptTimeout, attempt)
1050 );
1051 }
1052 };
1053
1054 this.detect = function() {
1055 check(config.attempts);
1056 };
1057 });
1058
1059 var ChangeVideoDetector = (function(ChangeVideoDetector){
1060 ChangeVideoDetector.run = function(videoChangeCallback) {
1061 var detector = new Detector({
1062 unlimited: true,
1063 previousLocation: window.location.href,
1064 target: 'video-change',
1065 success: function(){
1066 return this.previousLocation !== window.location.href
1067 },
1068 successCallback: videoChangeCallback
1069 });
1070 detector.detect();
1071 };
1072 return ChangeVideoDetector;
1073 }(ChangeVideoDetector || {}));
1074
1075 var WrapperDetector = (function(WrapperDetector){
1076 WrapperDetector.run = function(properties, videoChangeCallback) {
1077 var detector = new Detector({
1078 logStyle: 'color:orange',
1079 target: properties.wrapper.selector,
1080 success: properties.wrapper.exist,
1081 successCallback: function(){
1082 DomTamper.createButton(properties);
1083 }
1084 });
1085 detector.detect();
1086
1087 if(typeof videoChangeCallback === "function"){
1088 ChangeVideoDetector.run(videoChangeCallback);
1089 }
1090 };
1091 return WrapperDetector;
1092 }(WrapperDetector || {}));
1093
1094 var ElementDetector = (function(ElementDetector){
1095 ElementDetector.detect = function(selector, callback){
1096 var detector = new Detector({
1097 logStyle: 'color:dodgerblue',
1098 target: selector,
1099 success: function(){
1100 return $(this.target).length > 0;
1101 },
1102 successCallback: callback
1103 });
1104 detector.detect();
1105 };
1106
1107 return ElementDetector;
1108 }(ElementDetector || {}));
1109
1110 var Unloader = (function(Unloader) {
1111 var win;
1112 var url;
1113
1114 Unloader.init = function(w){
1115 win = w;
1116 url = Tool.getRealUrl();
1117 $(window).bind('beforeunload', function(){
1118 if(!win.closed) {
1119 DomTamper.handleError(new Exception(config.error.noParent, url), win);
1120 }
1121 });
1122 };
1123
1124 return Unloader;
1125 }(Unloader || {}));
1126
1127 var MessageReceiver = (function(MessageReceiver) {
1128 var win;
1129 var origin;
1130 var callbackFunction;
1131 var alreadyConfirmed = false;
1132 var alreadyPosted = false;
1133
1134 var receiveMessage = function(event, callback){
1135 if (event.origin !== origin) {
1136 return;
1137 }
1138
1139 var data = JSON.parse(event.data);
1140 if(data.confirmation){
1141 alreadyConfirmed = true;
1142 }
1143 else {
1144 data.confirmation = true;
1145 if(!alreadyPosted) {
1146 window.removeEventListener('message', callbackFunction);
1147 alreadyPosted = true;
1148 postMessage(data);
1149 callback(data);
1150 }
1151 }
1152 };
1153
1154 var postMessage = function(data){
1155 data = JSON.stringify(data);
1156 win.postMessage(data, '*');
1157 };
1158
1159 MessageReceiver.awaitMessage = function(object, callback){
1160 initCommunication(object, callback);
1161 };
1162
1163 var initCommunication = function(object, callback){
1164 callbackFunction = function(e){
1165 receiveMessage(e, callback);
1166 };
1167 window.addEventListener('message', callbackFunction);
1168 win = getProperty(object, 'windowReference');
1169 origin = getProperty(object, 'origin');
1170 };
1171
1172 var getProperty = function(object, prop){
1173 if(object.hasOwnProperty(prop)){
1174 return object[prop];
1175 }
1176 };
1177
1178 MessageReceiver.postUntilConfirmed = function(object){
1179 initCommunication(object);
1180 isMessageConfirmed(config.attempts, getProperty(object, 'message'))
1181 };
1182
1183 var isMessageConfirmed = function(attempt, message){
1184 if (alreadyConfirmed || attempt <= 0) {
1185 return Promise.resolve().then(function(){
1186 window.removeEventListener('message', callbackFunction);
1187 if(attempt <= 0){
1188 console.warn("Nie udało się przekazać adresu z okna głównego.");
1189 }
1190 });
1191 } else if(attempt > 0){
1192 attempt = attempt-1;
1193 postMessage(message);
1194 return Promise.resolve().then(
1195 setTimeout(isMessageConfirmed, config.attemptTimeout, attempt, message)
1196 );
1197 }
1198 };
1199
1200 return MessageReceiver;
1201 }(MessageReceiver || {}));
1202
1203 var COMMON_SOURCE = (function(COMMON_SOURCE) {
1204 COMMON_SOURCE.grabIplaSubtitlesData = function(data){
1205 var items = [];
1206 var subtitles = (((data.result || {}).mediaItem || {}).displayInfo || {}).subtitles || [];
1207 subtitles.forEach(function(subtitle) {
1208 items.push({
1209 url: subtitle.src,
1210 description: subtitle.name,
1211 format: subtitle.format
1212 })
1213 });
1214 return {
1215 cards: {subtitles: {items: items}}
1216 };
1217 };
1218
1219 var removeUnsupportedVideoFormats = function(files){
1220 var result = [];
1221 files.forEach(function (file) {
1222 if (file['type'] === 'any_native') {
1223 result.push(file);
1224 }
1225 });
1226 return result;
1227 };
1228
1229 COMMON_SOURCE.grapTvpVideoData = function(data){
1230 var items = [];
1231 var subtitlesItems = [];
1232 var info = ((data || {}).content || {}).info || {};
1233 var files = ((data || {}).content || {}).files || [];
1234 var subtitles = ((data || {}).content || {}).subtitles || [];
1235 var files = removeUnsupportedVideoFormats(files);
1236 if(files.length) {
1237 files.forEach(function (file) {
1238 var videoDesc = file.quality.bitrate;
1239 items.push(Tool.mapDescription({
1240 source: 'TVP',
1241 key: videoDesc,
1242 video: videoDesc,
1243 url: file.url
1244 }));
1245 });
1246 subtitles.forEach(function(subtitle) {
1247 var extension = subtitle.type;
1248 subtitlesItems.push({
1249 url: 'https:' + subtitle.url,
1250 format: extension,
1251 description: subtitle.lang
1252 })
1253 });
1254
1255 return {
1256 title: (info.title != null ? info.title : '') + (info.subtitle != null ? ' ' + info.subtitle : ''),
1257 cards: {
1258 videos: {items: items},
1259 subtitles: {items: subtitlesItems}
1260 }
1261 }
1262 }
1263 throw new Exception(config.error.noSource, window.location.href);
1264 };
1265
1266 return COMMON_SOURCE;
1267 }(COMMON_SOURCE || {}));
1268 var VOD_TVP = (function() {
1269 var properties = new Configurator({
1270 wrapper: {
1271 selector: '#JS-TVPlayer2-Wrapper, #player2'
1272 },
1273 button: {
1274 class: 'tvp_vod_downlaod_button',
1275 },
1276 asyncChains: {
1277 videos: [
1278 new Step({
1279 urlTemplate: 'https://tvp.pl/pub/stat/videofileinfo?video_id=#videoId',
1280 beforeStep: function (input) {
1281 return idParser();
1282 }
1283 }),
1284 new Step({
1285 urlTemplate: 'https://vod.tvp.pl/sess/TVPlayer2/api.php?id=#videoId&@method=getTvpConfig' +
1286 '&@callback=callback',
1287 responseType: 'jsonp',
1288 beforeStep: function (json) {
1289 return getRealVideoId(json);
1290 },
1291 afterStep: COMMON_SOURCE.grapTvpVideoData
1292 })
1293 ]
1294 }
1295 });
1296
1297 var idParser = function() {
1298 var src = $(properties.wrapper.selector).attr('data-video-id');
1299 if(src !== undefined){
1300 return {
1301 videoId: src.split("/").pop()
1302 };
1303 }
1304
1305 throw new Exception(config.error.id, window.location.href);
1306 };
1307
1308 var getRealVideoId = function(json){
1309 var videoId = json.copy_of_object_id !== undefined ?
1310 json.copy_of_object_id : json.video_id;
1311 return {
1312 videoId: videoId
1313 };
1314 };
1315
1316 this.setup = function(){
1317 WrapperDetector.run(properties);
1318 };
1319 });
1320
1321 var CYF_TVP = (function() {
1322 var properties = new Configurator({
1323 wrapper: {
1324 selector: 'div.playerContainerWrapper'
1325 },
1326 button: {
1327 class: 'tvp_cyf_downlaod_button'
1328 },
1329 asyncChains: {
1330 videos: [
1331 new Step({
1332 urlTemplate: 'https://vod.tvp.pl/sess/TVPlayer2/api.php?id=#videoId&@method=getTvpConfig' +
1333 '&@callback=callback',
1334 responseType: 'jsonp',
1335 beforeStep: function (input) {
1336 return idParser();
1337 },
1338 afterStep: COMMON_SOURCE.grapTvpVideoData
1339 })
1340 ]
1341 }
1342 });
1343
1344 var idParser = function(){
1345 var src = $('iframe#JS-TVPlayer').attr('src');
1346 if(src !== undefined) {
1347 return src.split("/").pop();
1348 }
1349 else {
1350 var div = $('div.playerWidget');
1351 if(div !== undefined){
1352 return div.attr('data-video-id');
1353 }
1354 }
1355
1356 throw new Exception(config.error.id, window.location.href);
1357 };
1358
1359 this.setup = function(){
1360 WrapperDetector.run(properties);
1361 };
1362 });
1363
1364 var TVN = (function() {
1365 var properties = new Configurator({
1366 wrapper: {
1367 selector: '#player-container, div.custom-alert-inner-wrapper'
1368 },
1369 button: {
1370 class: 'btn btn-primary tvn_download_button'
1371 },
1372 asyncChains: {
1373 videos: [
1374 new Step({
1375 urlTemplate: 'http://player.pl/api/?platform=ConnectedTV&terminal=Panasonic&format=json' +
1376 '&authKey=064fda5ab26dc1dd936f5c6e84b7d3c2&v=3.1&m=getItem&id=#videoId',
1377 beforeStep: function(input){
1378 return idParser();
1379 },
1380 afterStep: function(output) {
1381 return grabVideoData(output);
1382 }
1383 })
1384 ]
1385 },
1386 });
1387
1388 var idParser = function(){
1389 var watchingNow = $('.watching-now').closest('.embed-responsive').find('.embed-responsive-item');
1390 if(watchingNow.length > 0){
1391 return watchingNow.attr('href').split(',').pop();
1392 }
1393
1394 return episodeIdParser();
1395 };
1396
1397 var episodeIdParser = function () {
1398 var match = window.location.href.match(/odcinki,(\d+)\/.*,(\d+)/);
1399 if(match && match[2]){
1400 return match[2];
1401 }
1402
1403 return serialIdParser();
1404 };
1405
1406 var serialIdParser = function () {
1407 var match = window.location.href.match(/odcinki,(\d+)/);
1408 if(match && match[1]){
1409 throw new Exception(config.error.tvnId, Tool.getRealUrl());
1410 }
1411
1412 return vodIdParser();
1413 };
1414
1415 var vodIdParser = function(){
1416 var match = window.location.href.match(/,(\d+)/);
1417 if(match && match[1]){
1418 return match[1];
1419 }
1420
1421 throw new Exception(config.error.tvnId, Tool.getRealUrl());
1422 };
1423
1424 var grabVideoData = function(data){
1425 var items = [];
1426 var main = ((data.item || {}).videos || {}).main || {};
1427 var video_content = main.video_content || {};
1428 if(main.video_content_license_type !== 'WIDEVINE' && video_content && video_content.length > 0){
1429 $.each(video_content, function( index, value ) {
1430 items.push(Tool.mapDescription({
1431 source: 'TVN',
1432 key: value.profile_name,
1433 video: value.profile_name,
1434 url: value.url
1435 }));
1436 });
1437
1438 return {
1439 title: getTitle(data),
1440 cards: {videos: {items: items}}
1441 }
1442 }
1443 throw new Exception(config.error.noSource, Tool.getRealUrl());
1444 };
1445
1446 var getTitle = function(data){
1447 var episode = data.item.episode ? 'E'+Tool.pad(data.item.episode, 2) : '';
1448 var season = data.item.season != null ? 'S'+Tool.pad(data.item.season, 2) : '';
1449 var serie_title = data.item.serie_title != null ? data.item.serie_title : '';
1450 var episodeTitle = data.item.title ? ' ' + data.item.title : '';
1451 var seasonAndEpisode = season + episode;
1452
1453 return serie_title + (seasonAndEpisode !== '' ? ' - ' + seasonAndEpisode : '') +
1454 (episodeTitle !== '' ? ' - ' + episodeTitle : '');
1455 };
1456
1457 var inVodFrame = function(){
1458 var regexp = new RegExp('https:\/\/player\.pl(.*)');
1459 var match = regexp.exec(window.location.href);
1460 if(match[1]) {
1461 window.sessionStorage.setItem(config.storage.topWindowLocation, 'https://vod.pl' + match[1]);
1462 }
1463 };
1464
1465 this.setup = function(){
1466 if(!Tool.isTopWindow()) {
1467 inVodFrame();
1468 }
1469
1470 WrapperDetector.run(properties, this.setup);
1471 };
1472 });
1473
1474 var IPLA = (function() {
1475 var properties = new Configurator({
1476 wrapper: {
1477 selector: 'div.player-wrapper:visible:first-child, div.promo-box:visible:first-child,' +
1478 ' div.player-error-presentation:visible:first-child'
1479 },
1480 button: {
1481 class: 'ipla_download_button'
1482 },
1483 chainSelector: function(){
1484 return ['videos', 'subtitles'];
1485 },
1486 asyncChains: {
1487 videos: [
1488 new Step({
1489 urlTemplateParts: [
1490 'ua=www_iplatv_html5/12345',
1491 'ua=mipla_ios/122'
1492 ],
1493 urlTemplate: 'https://getmedia.redefine.pl/vods/get_vod/?cpid=1&~&media_id=#videoId',
1494 retryErrorCodes: [404],
1495 beforeStep: function (input) {
1496 return grabVideoIdFromUrl();
1497 },
1498 afterStep: function(data){
1499 return grabVideoData(data);
1500 }
1501 })
1502 ],
1503 subtitles: [
1504 new Step({
1505 urlTemplate: 'https://b2c.redefine.pl/rpc/navigation/',
1506 method: 'POST',
1507 methodParam: function(){
1508 return getParamsForSubtitles();
1509 },
1510 afterStep: COMMON_SOURCE.grabIplaSubtitlesData
1511 })
1512 ]
1513 }
1514 });
1515
1516 var grabVideoData = function(data){
1517 var items = [];
1518 var vod = data.vod || {};
1519 if(vod.copies && vod.copies.length > 0 && !vod.drm){
1520 $.each(vod.copies, function( index, value ) {
1521 var videoDesc = value.quality_p + ', ' + value.bitrate;
1522 items.push(Tool.mapDescription({
1523 source: 'IPLA',
1524 key: value.quality_p,
1525 video: videoDesc,
1526 url: value.url
1527 }));
1528 });
1529 return {
1530 title: vod.title,
1531 cards: {videos: {items: items}}
1532 }
1533 }
1534 throw new Exception(config.error.noSource, Tool.getRealUrl());
1535 };
1536
1537 var getParamsForSubtitles = function(){
1538 var mediaId = grabVideoIdFromUrl();
1539 return {
1540 jsonrpc: "2.0",
1541 id: 1,
1542 method: "prePlayData",
1543 params: {
1544 userAgentData: {
1545 application: "firefox",
1546 portal: "ipla"
1547 },
1548 cpid: 1,
1549 mediaId: mediaId
1550 }
1551 }
1552 };
1553
1554 this.setup = function(){
1555 WrapperDetector.run(properties, this.setup);
1556 };
1557
1558 var matchingId = function(input, failureAction){
1559 input = input ? input : '';
1560 var match = matchingHexId(input);
1561 if(!match){
1562 match = matchingDecId(input);
1563 }
1564 return match ? match : failureAction();
1565 };
1566
1567 var matchingHexId = function(input){
1568 var match = input.match(/[0-9a-f]{32}/);
1569 if(match && match[0]) {
1570 return match[0];
1571 }
1572
1573 return null;
1574 };
1575
1576 var matchingDecId = function(input) {
1577 var match = input.match(/([\d]+)?(\?.*)$/);
1578 if(match && match[1]) {
1579 return match[1];
1580 }
1581
1582 return null;
1583 };
1584
1585 var grabVideoIdFromUrl = function(){
1586 return matchingId(location.href, grabVideoIdFromWatchingNowElement);
1587 };
1588
1589 var grabVideoIdFromWatchingNowElement = function(){
1590 return matchingId($('div.vod-image-wrapper__overlay').closest('a').attr('href'), grabVideoIdFromHtmlElement);
1591 };
1592
1593 var grabVideoIdFromHtmlElement = function(){
1594 var frameSrc = $('app-commercial-wallpaper iframe:first-child').attr('src');
1595 if(frameSrc !== undefined) {
1596 return Tool.getUrlParameter('vid', frameSrc);
1597 }
1598 throw new Exception(config.error.id, Tool.getRealUrl());
1599 };
1600 });
1601
1602 var VOD = (function() {
1603 var properties = new Configurator({
1604 wrapper: {
1605 selector: '#v_videoPlayer'
1606 },
1607 button: {
1608 class: 'vod_download_button'
1609 },
1610 asyncChains: {
1611 videos: [
1612 new Step({
1613 urlTemplate: 'https://player-api.dreamlab.pl/?body[id]=#videoId&body[jsonrpc]=2.0' +
1614 '&body[method]=get_asset_detail&body[params][ID_Publikacji]=#videoId' +
1615 '&body[params][Service]=vod.onet.pl&content-type=application/jsonp' +
1616 '&x-onet-app=player.front.onetapi.pl&callback=',
1617 beforeStep: function (input) {
1618 return idParser();
1619 },
1620 afterStep: function (output) {
1621 return grabVideoData(output);
1622 }
1623 })
1624 ]
1625 }
1626 });
1627
1628 var idParser = function () {
1629 var id = $(".mvp").attr('id');
1630 if(id !== undefined){
1631 return id.match(/mvp:(.+)/)[1];
1632 }
1633
1634 return parseFromJS();
1635 };
1636
1637 var parseFromJS = function(){
1638 var scripts = $('script[type="text/javascript"]').filter(':not([src])');
1639 for (var i = 0; i < scripts.length; i++) {
1640 var match = $(scripts[i]).text().match(/\"mvpId\"\s*:\s*\"(\d+\.\d+)\"/);
1641 if(match && match[1]){
1642 return match[1];
1643 }
1644 }
1645
1646 throw new Exception(config.error.id, Tool.getRealUrl());
1647 };
1648
1649 var grabVideoData = function (data) {
1650 var items = [];
1651 var subtitlesItems = [];
1652 var video = (((data.result || new Array())[0] || {}).formats || {}).wideo || {};
1653 var meta = ((data.result || new Array())[0] || {}).meta || {};
1654 var subtitles = meta.subtitles || [];
1655 var videoData = video['mp4-uhd'] && video['mp4-uhd'].length > 0 ? video['mp4-uhd'] : video['mp4'];
1656 if(videoData && videoData.length > 0){
1657 videoData.forEach(function(value) {
1658 var videoDesc = value.vertical_resolution + ', ' + value.video_bitrate;
1659 items.push(Tool.mapDescription({
1660 source: 'VOD',
1661 key: value.vertical_resolution,
1662 video: videoDesc,
1663 url: value.url
1664 }));
1665 });
1666
1667 subtitles.forEach(function(subtitle) {
1668 var extension = subtitle.name.split('.').pop();
1669 subtitlesItems.push({
1670 url: subtitle.url,
1671 format: extension,
1672 description: subtitle.name
1673 })
1674 });
1675
1676 return {
1677 title: meta.title,
1678 cards: {
1679 videos: {items: items},
1680 subtitles: {items: subtitlesItems}
1681 }
1682 }
1683 }
1684 throw new Exception(config.error.noSource, Tool.getRealUrl());
1685 };
1686
1687 var iplaDetected = function(){
1688 return $('#v_videoPlayer div.pulsembed_embed').length > 0;
1689 };
1690
1691 var workWithSubService = function(){
1692 var src = 'https://pulsembed.eu';
1693 var frameSelector = 'iframe[src^="' + src + '"]';
1694
1695 ElementDetector.detect(frameSelector, function () {
1696 MessageReceiver.postUntilConfirmed({
1697 windowReference: $(frameSelector).get(0).contentWindow,
1698 origin: src,
1699 message: {
1700 location: window.location.href
1701 }
1702 });
1703 });
1704 };
1705
1706 this.setup = function(){
1707 if(iplaDetected()) {
1708 workWithSubService();
1709 }
1710 else if(Tool.isTopWindow()){
1711 WrapperDetector.run(properties);
1712 }
1713 };
1714 });
1715
1716 var VOD_IPLA = (function() {
1717 var properties = new Configurator({
1718 wrapper: {
1719 selector: '#player-wrapper, #playerContainer'
1720 },
1721 button: {
1722 class: 'vod_ipla_downlaod_button'
1723 },
1724 chainSelector: function(){
1725 return ['videos', 'subtitles'];
1726 },
1727 asyncChains: {
1728 videos: [
1729 new Step({
1730 urlTemplate: 'https://distro.redefine.pl/partner_api/v1/2yRS5K/media/#media_id/vod/player_data?' +
1731 'dev=pc&os=linux&player=html&app=firefox&build=12345',
1732 beforeStep: function (input) {
1733 return {media_id: idParser()};
1734 },
1735 afterStep: function(data){
1736 return grabVideoData(data);
1737 }
1738 })
1739 ],
1740 subtitles: [
1741 new Step({
1742 afterStep: function (output) {
1743 return parseSubtitleData();
1744 }
1745 })
1746 ]
1747 }
1748 });
1749
1750 var grabVideoData = function(data){
1751 var items = [];
1752 var displayInfo = (data.mediaItem || {}).displayInfo || {};
1753 var mediaSources = ((data.mediaItem || {}).playback || {}).mediaSources || {};
1754 var videos = $.grep(mediaSources, function(source) {
1755 return source.accessMethod === 'direct';
1756 });
1757 if(videos && videos.length > 0){
1758 $.each(videos, function( index, value ) {
1759 items.push(Tool.mapDescription({
1760 source: 'IPLA',
1761 key: value.quality,
1762 video: value.quality,
1763 url: value.url
1764 }));
1765 });
1766 return {
1767 title: displayInfo.title,
1768 cards: {videos: {items: items}}
1769 }
1770 }
1771 throw new Exception(config.error.noSource, Tool.getRealUrl());
1772 };
1773
1774 var getJson = function(){
1775 var match = $('script:not(:empty)').text().match(/(window\.CP\.embedSetup\()(.*)\);/);
1776 if(match) {
1777 var jsonObject = JSON.parse(match[2]);
1778 return JSON.parse(jsonObject[0].media);
1779 }
1780
1781 return {};
1782 };
1783
1784 var idParser = function(){
1785 try {
1786 if($('#player-wrapper').length > 0) {
1787 return (((getJson() || {}).result || {}).mediaItem || {}).id;
1788 }
1789 else if($('#playerContainer').length > 0){
1790 return getMediaId();
1791 }
1792 }
1793 catch(e){
1794 throw new Exception(config.error.id, Tool.getRealUrl());
1795 }
1796 };
1797
1798 var getMediaId = function(){
1799 var match = $('script:not(:empty)').text().match(/mediaId: "(\w+)",/);
1800 return match[1];
1801 };
1802
1803 var parseSubtitleData = function(){
1804 return COMMON_SOURCE.grabIplaSubtitlesData(getJson());
1805 };
1806
1807 this.setup = function(){
1808 var callback = function(data) {
1809 window.sessionStorage.setItem(config.storage.topWindowLocation, data.location);
1810 WrapperDetector.run(properties);
1811 };
1812 MessageReceiver.awaitMessage({
1813 origin: 'https://pulsembed.eu',
1814 windowReference: window.parent
1815 }, callback);
1816 };
1817 });
1818
1819 var WP = (function() {
1820 var properties = new Configurator({
1821 wrapper: {
1822 selector: '#Player0 > div'
1823 },
1824 button: {
1825 class: 'wp_download_button material__category'
1826 },
1827 asyncChains: {
1828 videos: [
1829 new Step({
1830 urlTemplate: 'https://wideo.wp.pl/player/mid,#videoId,embed.json',
1831 beforeStep: function (input) {
1832 return idParser();
1833 },
1834 afterStep: function (output) {
1835 return grabVideoData(output);
1836 }
1837 })
1838 ]
1839 }
1840 });
1841
1842 var idParser = function () {
1843 try {
1844 var id = window.location.href.match(/^(.*)-(\d+)v$/)[2];
1845 //__NEXT_DATA__ is a variable on page
1846 return __NEXT_DATA__.props.initialPWPState.material[id].mid;
1847 }
1848 catch(e){
1849 throw new Exception(config.error.id, window.location.href);
1850 }
1851 };
1852
1853 var grabVideoData = function(data){
1854 var items = [];
1855 var urls = (data.clip || {}).url || {};
1856 if(urls && urls.length > 0){
1857 $.each(urls, function( index, value ) {
1858 if(value.type === 'mp4@avc'){
1859 var videoDesc = value.quality + ', ' + value.resolution;
1860 items.push(Tool.mapDescription({
1861 source: 'WP',
1862 key: value.quality,
1863 video: videoDesc,
1864 url: value.url
1865 }));
1866 }
1867 });
1868 return {
1869 title: data.clip.title,
1870 cards: {videos: {items: items}}
1871 }
1872 }
1873 throw new Exception(config.error.noSource, window.location.href);
1874 };
1875
1876 this.setup = function(){
1877 WrapperDetector.run(properties, this.setup);
1878 };
1879 });
1880
1881 var CDA = (function() {
1882 var properties = new Configurator({
1883 wrapper: {
1884 selector: '.pb-video-player-wrap'
1885 },
1886 button: {
1887 class: 'cda_download_button',
1888 click: function(){
1889 clickButton();
1890 }
1891 }
1892 });
1893
1894 var clickButton = function(){
1895 var w = window.open();
1896 try {
1897 var url = $("video.pb-video-player").attr('src');
1898 if(url !== undefined){
1899 if(!url.match(/blank\.mp4/)){
1900 prepareResult(url, w);
1901 }
1902 else if(l !== undefined){
1903 prepareResult(l, w);
1904 }
1905 else {
1906 throw new Exception(config.error.id, window.location.href);
1907 }
1908 }
1909 }catch(e){
1910 DomTamper.handleError(e, w);
1911 }
1912 };
1913
1914 var prepareResult = function(url, w) {
1915 var cardsData = properties.cardsData;
1916 var title = $('meta[property="og:title"]');
1917 var quality = $('.quality-btn-active');
1918 cardsData.title = title.length > 0 ? title.attr('content').trim() : 'brak danych';
1919 var videoDesc = quality.length > 0 ? quality.text() : '-';
1920 cardsData.cards['videos'].items = [
1921 Tool.mapDescription({
1922 source: 'CDA',
1923 key: videoDesc,
1924 video: videoDesc,
1925 audio: '-',
1926 url: url
1927 })
1928 ];
1929
1930 DomTamper.createDocument(cardsData, w);
1931 };
1932
1933 this.setup = function(){
1934 WrapperDetector.run(properties);
1935 };
1936 });
1937
1938 var NINATEKA = (function() {
1939 var properties = new Configurator({
1940 wrapper: {
1941 selector: '#videoPlayer, #player'
1942 },
1943 button: {
1944 class: 'ninateka_download_button',
1945 click: function(){
1946 clickButton();
1947 }
1948 }
1949 });
1950
1951 var prepareResult = function(url, w) {
1952 var title = $('meta[name="title"]');
1953 var cardsData = properties.cardsData;
1954 cardsData.title = title.length > 0 ? title.attr('content').trim() : 'brak danych';
1955 cardsData.cards['videos'].items = [
1956 Tool.mapDescription({
1957 source: 'NINATEKA',
1958 key: 'def',
1959 url: url
1960 })
1961 ];
1962 DomTamper.createDocument(cardsData, w);
1963 };
1964
1965 var getMp4Source = function(w, sources){
1966 for(var i = 0; i < sources.length; i++){
1967 if(sources[i].type && sources[i].type.match(/mp4/g)){
1968 prepareResult(sources[i].src, w);
1969 return;
1970 }
1971 }
1972
1973 throw new Exception(config.error.id, window.location.href);
1974 };
1975
1976 var clickButton = function(){
1977 var w = window.open();
1978 try {
1979 var videoPlayer = $('#videoPlayer').data('player-setup');
1980 var sources = (videoPlayer || {}).sources || {};
1981 if(sources.length > 0){
1982 getMp4Source(w, sources);
1983 }
1984 else {
1985 var scripts = $('script[type="text/javascript"]').filter(':not([src])');
1986 for (var i = 0; i < scripts.length; i++) {
1987 var match = $(scripts[i]).text().match(/fn_\S+\(playerOptionsWithMainSource,\s*\d+\)\.sources/g);
1988 if(match && match[0]){
1989 sources = eval(match[0]);
1990 getMp4Source(w, sources);
1991 break;
1992 }
1993 }
1994 }
1995 }catch(e){
1996 DomTamper.handleError(e, w);
1997 }
1998 };
1999
2000 this.setup = function(){
2001 WrapperDetector.run(properties);
2002 };
2003 });
2004
2005 var ARTE = (function() {
2006 var properties = new Configurator({
2007 wrapper: {
2008 selector: 'div.avp-player'
2009 },
2010 button: {
2011 class: 'arte_download_button',
2012 },
2013 asyncChains: {
2014 videos: [
2015 new Step({
2016 urlTemplate: 'https://api.arte.tv/api/player/v1/config/#langCode/#videoId',
2017 beforeStep: function (input) {
2018 return idParser();
2019 },
2020 afterStep: function (output) {
2021 return grabVideoData(output);
2022 }
2023 })
2024 ]
2025 },
2026 formatter: function(data) {
2027 data.cards['videos'].items.sort(function (a, b) {
2028 return a.index - b.index;
2029 });
2030
2031 var sortingOrder = {'POL': 1};
2032 data.cards['videos'].items.sort(function (a, b) {
2033 var aLangOrder = sortingOrder[a.langCode] ? sortingOrder[a.langCode] : -1,
2034 bLangOrder = sortingOrder[b.langCode] ? sortingOrder[b.langCode] : -1;
2035 return bLangOrder - aLangOrder;
2036
2037 });
2038 }
2039 });
2040
2041 var detectLanguage = function() {
2042 var regexp = new RegExp('https:\/\/www.arte\.tv\/(\\w{2})\/');
2043 var match = regexp.exec(window.location.href);
2044 return match[1];
2045 };
2046
2047 var detectVideoId = function(){
2048 var regexp = new RegExp('https:\/\/www.arte\.tv\/\\w{2}\/videos\/([\\w-]+)\/');
2049 var match = regexp.exec(window.location.href);
2050 return match[1];
2051 };
2052
2053 var idParser = function() {
2054 try {
2055 return {
2056 videoId: detectVideoId(),
2057 langCode: detectLanguage()
2058 };
2059 }
2060 catch(e){
2061 throw new Exception(config.error.id, window.location.href);
2062 }
2063 };
2064
2065 var grabVideoData = function(data){
2066 var items = [];
2067 var title = (((data || {}).videoJsonPlayer || {}).eStat || {}).streamName || '';
2068 var streams = ((data || {}).videoJsonPlayer || {}).VSR || {};
2069 if(streams){
2070 Object.keys(streams).filter(function(k, i) {
2071 return k.startsWith("HTTPS");
2072 }).forEach(function(k) {
2073 var stream = streams[k];
2074 var videoDesc = stream.width + 'x' + stream.height + ', ' + stream.bitrate;
2075 items.push(Tool.mapDescription({
2076 source: 'ARTE',
2077 key: stream.bitrate,
2078 video: videoDesc,
2079 langCode: stream.versionShortLibelle,
2080 language: stream.versionLibelle,
2081 url: stream.url
2082 }));
2083 });
2084 return {
2085 title: title,
2086 cards: {videos: {items: items}}
2087 }
2088 }
2089 throw new Exception(config.error.noSource, window.location.href);
2090 };
2091
2092 this.setup = function(){
2093 WrapperDetector.run(properties);
2094 };
2095
2096 });
2097
2098 var VOD_FRAME = (function() {
2099 this.setup = function(){
2100 var callback = function(data) {
2101 var srcArray = ['https://redir.atmcdn.pl', 'https://partner.ipla.tv'];
2102 setupDetector(srcArray, data);
2103 };
2104 MessageReceiver.awaitMessage({
2105 origin: 'https://vod.pl',
2106 windowReference: window.parent
2107 }, callback);
2108 };
2109
2110 var setupDetector = function(srcArray, data){
2111 var selectors = createArrySelectors(srcArray);
2112 var multiSelector = createMultiSelector(selectors);
2113
2114 ElementDetector.detect(multiSelector, function() {
2115 selectors.forEach(function(element){
2116 if($(element.frameSelector).length > 0){
2117 MessageReceiver.postUntilConfirmed({
2118 windowReference: $(element.frameSelector).get(0).contentWindow,
2119 origin: element.src,
2120 message: {
2121 location: data.location
2122 }
2123 });
2124 }
2125 });
2126 });
2127 };
2128
2129 var createArrySelectors = function(srcArray){
2130 return jQuery.map(srcArray, function(src) {
2131 return {
2132 src: src,
2133 frameSelector: 'iframe[src^="' + src + '"]'
2134 }
2135 });
2136 };
2137
2138 var createMultiSelector = function(selectors){
2139 return $.map(selectors, function(src){
2140 return src.frameSelector
2141 }).join(', ');
2142 }
2143 });
2144
2145 var Starter = (function(Starter) {
2146 var sources = [
2147 {objectName: 'VOD_TVP', urlPattern: /^https:\/\/vod\.tvp\.pl\/video\/|^https?:\/\/.*\.tvp.pl\/sess\/TVPlayer2\/embed.*$/},
2148 {objectName: 'CYF_TVP', urlPattern: /^https:\/\/cyfrowa\.tvp\.pl\/video\//},
2149 {objectName: 'TVN', urlPattern: /^https:\/\/(?:w{3}\.)?(?:tvn)?player\.pl\//},
2150 {objectName: 'CDA', urlPattern: /^https:\/\/.*\.cda\.pl\//},
2151 {objectName: 'VOD', urlPattern: /^https:\/\/vod.pl\//},
2152 {objectName: 'VOD_IPLA', urlPattern: /^https:\/\/partner\.ipla\.tv\/embed\/|^https:\/\/.*\.redcdn.pl\/file\/o2\/redefine\/partner\//},
2153 {objectName: 'IPLA', urlPattern: /^https:\/\/www\.ipla\.tv\//},
2154 {objectName: 'WP', urlPattern: /^https:\/\/wideo\.wp\.pl\//},
2155 {objectName: 'NINATEKA', urlPattern: /^https:\/\/ninateka.pl\//},
2156 {objectName: 'ARTE', urlPattern: /^https:\/\/www.arte.tv\/.*\/videos\//},
2157 {objectName: 'VOD_FRAME', urlPattern: /^https:\/\/pulsembed\.eu\//}
2158 ];
2159
2160 Starter.start = function() {
2161 sources.some(function(source){
2162 if(location.href.match(source.urlPattern)){
2163 var object = eval('new ' + source.objectName + '()');
2164 console.info('voddownloader: jQuery v' + $().jquery + ', context: ' + source.objectName);
2165 object.setup();
2166 return true;
2167 }
2168 });
2169 };
2170
2171 return Starter;
2172 }(Starter || {}));
2173
2174 $(document).ready(function(){
2175 DomTamper.injectStyle(window, 'buttons_css');
2176 Starter.start();
2177 });
2178
2179}).bind(this)(jQuery, platform, Waves);