From 03fc44afa3471bcc8a22217a36b1b6be39f34056 Mon Sep 17 00:00:00 2001 From: Corbin Davenport Date: Sat, 18 Jan 2020 17:03:31 -0500 Subject: [PATCH 01/10] Bump version to 6.2, add support for Flash Player variables --- js/noplugin.js | 18 +++++++++++++++++- manifest.json | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/js/noplugin.js b/js/noplugin.js index 051559e..5ebea33 100644 --- a/js/noplugin.js +++ b/js/noplugin.js @@ -633,7 +633,13 @@ function replaceEmbed(object) { } else { var name = '' } - injectPlayer(object, id, url, width, height, cssclass, cssstyles) + // Add Flash variables to end of URL if they exist + if (object.hasAttribute('FlashVars')) { + var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) + flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters + url = url + '?' + flashVars + } + injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) injectHelp() } @@ -702,6 +708,16 @@ function replaceObject(object) { } else { var name = '' } + // Add Flash variables to end of URL if they exist + if (object.hasAttribute('FlashVars')) { + var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) + flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters + url = url + '?' + flashVars + } else if (object.querySelector('param[name="FLASHVARS" i]')) { + var flashVars = DOMPurify.sanitize(object.querySelector('param[name="FLASHVARS" i]').getAttribute('value'), { ALLOW_UNKNOWN_PROTOCOLS: true }) + flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters + url = url + '?' + flashVars + } injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) injectHelp() } diff --git a/manifest.json b/manifest.json index 72980d8..0bcb769 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "NoPlugin", - "version": "6.1", + "version": "6.2", "author": "Corbin Davenport", "description": "Play legacy media in modern browsers without plugins.", "homepage_url": "https://github.com/corbindavenport/noplugin", From 930b9625a2ffcef5fb9c4d4045bffffcd0614503 Mon Sep 17 00:00:00 2001 From: Corbin Davenport Date: Sat, 18 Jan 2020 18:06:29 -0500 Subject: [PATCH 02/10] Pass attributes to injectPlayer as JSON --- js/noplugin.js | 146 +++++++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 64 deletions(-) diff --git a/js/noplugin.js b/js/noplugin.js index 5ebea33..39d0ef7 100644 --- a/js/noplugin.js +++ b/js/noplugin.js @@ -344,14 +344,15 @@ function playbackError(mediaPlayer, id, url, width, height, cssclass, cssstyles) } // Replace plugin embeds with native players -function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { - if (url == null) { +function injectPlayer(object, media, mediaUrl) { + console.log(mediaUrl) + if ((mediaUrl === '') || (mediaUrl === null)) { // There is a URL error var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' @@ -360,42 +361,42 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { container.appendChild(content) object.parentNode.replaceChild(container, object) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) - } else if (url.includes('youtube.com/v/')) { + console.log('[NoPlugin] Replaced plugin embed but could not detect URL:', media) + } else if (mediaUrl.includes('youtube.com/v/')) { // Old Flash-based YouTube embed var frame = document.createElement('iframe') - frame.setAttribute('class', cssclass) - frame.id = id - frame.setAttribute('style', 'border: 0; width:' + width + 'px; height:' + height + 'px;') + frame.setAttribute('class', media.cssClass) + frame.id = media.id + frame.setAttribute('style', 'style', media.cssStyles + ' border: 0; width:' + media.width + 'px; height:' + media.height + 'px;') // Parse video ID and replace object - var youtubeID = url.match(youtubeRegex)[1] + var youtubeID = mediaUrl.match(youtubeRegex)[1] frame.setAttribute('src', 'https://www.youtube.com/embed/' + youtubeID) object.parentNode.replaceChild(frame, object) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) - } else if (url.includes('vimeo.com/moogaloop.swf')) { + console.log('[NoPlugin] Replaced YouTube embed:', media) + } else if (mediaUrl.includes('vimeo.com/moogaloop.swf')) { // Old Flash-based Vimeo embed var frame = document.createElement('iframe') - frame.setAttribute('class', cssclass) - frame.id = id - frame.setAttribute('style', 'border: 0; width:' + width + 'px; height:' + height + 'px;') + frame.setAttribute('class', media.cssClass) + frame.id = media.id + frame.setAttribute('style', 'style', media.cssStyles + ' border: 0; width:' + media.width + 'px; height:' + media.height + 'px;') // Parse video ID and replace object - var vimeoID = url.split('clip_id=').pop().split('&')[0]; + var vimeoID = mediaUrl.split('clip_id=').pop().split('&')[0] frame.setAttribute('src', 'https://player.vimeo.com/video/' + vimeoID) object.parentNode.replaceChild(frame, object) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) - } else if (url.includes('mms://') || url.includes('rtsp://') || url.endsWith('.ram') || streamDetectRegex.test(url)) { + console.log('[NoPlugin] Replaced Vimeo embed:', media) + } else if (mediaUrl.includes('mms://') || mediaUrl.includes('rtsp://') || mediaUrl.endsWith('.ram') || streamDetectRegex.test(mediaUrl)) { // This is a media stream var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' - if (url.endsWith('.ram')) { + if (mediaUrl.endsWith('.ram')) { content.innerHTML = 'This page is trying to load a RealPlayer stream here. You will need RealPlayer to open this file.' } else { content.textContent = 'This page is trying to load a video/audio stream here. You might be able to play this with a media player.' @@ -404,7 +405,7 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { // Create play button var playStreamButton = document.createElement('button') playStreamButton.type = 'button' - playStreamButton.setAttribute('data-url', url) + playStreamButton.setAttribute('data-url', mediaUrl) playStreamButton.textContent = 'Open stream' content.appendChild(playStreamButton) // Write container to page @@ -412,17 +413,17 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { object.parentNode.replaceChild(container, object) // Create eventListener for button playStreamButton.addEventListener('click', function () { - openInPlayer(url) + openInPlayer(mediaUrl) }) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) - } else if (url.includes('.swf')) { + console.log('[NoPlugin] Replaced playlist embed:', media) + } else if (mediaUrl.includes('.swf')) { // This is a Flash Player file var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' @@ -431,7 +432,7 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { // Create play button var playStreamButton = document.createElement('button') playStreamButton.type = 'button' - playStreamButton.setAttribute('data-url', url) + playStreamButton.setAttribute('data-url', mediaUrl) playStreamButton.textContent = 'Open media' content.appendChild(playStreamButton) // Write container to page @@ -439,21 +440,21 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { object.parentNode.replaceChild(container, object) // Create eventListener for button playStreamButton.addEventListener('click', function () { - openInFlash(url) + openInFlash(mediaUrl) }) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) - } else if (url.endsWith('.asx') || url.endsWith('.wpl') || url.endsWith('.qtl') || url.endsWith('.m3u')) { + console.log('[NoPlugin] Replaced Flash embed:', media) + } else if (mediaUrl.endsWith('.asx') || mediaUrl.endsWith('.wpl') || mediaUrl.endsWith('.qtl') || mediaUrl.endsWith('.m3u')) { // This is a playlist file try { - var mediaArray = parsePlaylist(url) + var mediaArray = parsePlaylist(mediaUrl) } catch (error) { // If the file is invalid/couldn't be reached, display an error var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' @@ -462,17 +463,17 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { container.appendChild(content) object.parentNode.replaceChild(container, object) // Add message to console - console.error('[NoPlugin] Error replacing plugin embed for ' + url + ':', error) + console.error('[NoPlugin] Error replacing playlist embed for ' + mediaUrl + ':', error) } if (mediaArray.length === 1) { // If there is only one item in the playlist, run the injectPlayer() function again with it as the new URL - injectPlayer(object, id, mediaArray[0], width, height, cssclass, cssstyles) + injectPlayer(object, media, mediaArray[0]) } else { var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' @@ -481,10 +482,10 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { // Create play button var playPlaylistButton = document.createElement('button') playPlaylistButton.type = 'button' - playPlaylistButton.setAttribute('data-url', url) + playPlaylistButton.setAttribute('data-url', mediaUrl) playPlaylistButton.textContent = 'Open playlist' playPlaylistButton.addEventListener('click', function () { - openInPlayer(url) + openInPlayer(mediaUrl) }) content.appendChild(playPlaylistButton) content.appendChild(document.createElement('br')) @@ -508,31 +509,31 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { container.appendChild(content) object.parentNode.replaceChild(container, object) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) + console.log('[NoPlugin] Replaced plugin embed:', media) } - } else if ((url.endsWith('.mp3')) || (url.endsWith('.m4a')) || (url.endsWith('.wav'))) { + } else if ((mediaUrl.endsWith('.mp3')) || (mediaUrl.endsWith('.m4a')) || (mediaUrl.endsWith('.wav'))) { // This is an audio file var mediaPlayer = document.createElement('audio') mediaPlayer.setAttribute('controlsList', 'nofullscreen nodownload') - mediaPlayer.id = id + mediaPlayer.id = media.id mediaPlayer.controls = true mediaPlayer.name = name - mediaPlayer.setAttribute('style', cssstyles + ' width:' + width + 'px !important; height:' + height + 'px !important;') + mediaPlayer.setAttribute('style', media.cssStyles + ' width:' + media.width + 'px !important; height:' + media.height + 'px !important;') // Add source to audio player var source = document.createElement('source') - source.src = url + source.src = mediaUrl mediaPlayer.appendChild(source) // Write container to page object.parentNode.replaceChild(mediaPlayer, object) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) + console.log('[NoPlugin] Replaced audio embed:', media) } else { // Attempt to play other formats (MP4, FLV, QuickTime, etc.) in the browser var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + cssclass) - container.id = id + container.setAttribute('class', 'noplugin ' + media.cssClass) + container.id = media.id container.align = 'center' - container.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') + container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Create text content var content = document.createElement('div') content.className = 'noplugin-content' @@ -541,22 +542,21 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { // Create play button var playMediaButton = document.createElement('button') playMediaButton.type = 'button' - playMediaButton.setAttribute('data-url', url) + playMediaButton.setAttribute('data-url', mediaUrl) playMediaButton.textContent = 'Play media file' content.appendChild(playMediaButton) // Create video player var mediaPlayer = document.createElement('video') mediaPlayer.controls = true - mediaPlayer.setAttribute('class', 'noplugin ' + cssclass) - mediaPlayer.id = id - mediaPlayer.setAttribute('style', cssstyles + ' width:' + (width - 10) + 'px !important; height:' + (height - 10) + 'px !important;') - mediaPlayer.setAttribute('autopictureinpicture', 'true') + mediaPlayer.setAttribute('class', 'noplugin ' + media.cssClass) + mediaPlayer.id = media.id + mediaPlayer.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') // Add source to video player var source = document.createElement('source') - source.src = url + source.src = mediaUrl source.addEventListener('error', function (event) { if (event.type === 'error') { - playbackError(mediaPlayer, id, url, width, height, cssclass, cssstyles) + playbackError(mediaPlayer, media.id, mediaUrl, media.width, media.height, media.cssClass, media.cssStyles) } }) // Write container to page @@ -571,7 +571,7 @@ function injectPlayer(object, id, url, width, height, cssclass, cssstyles) { mediaPlayer.play() }) // Add message to console - console.log('[NoPlugin] Replaced plugin embed for ' + url) + console.log('[NoPlugin] Replaced plugin embed:', media) } } @@ -639,7 +639,16 @@ function replaceEmbed(object) { flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters url = url + '?' + flashVars } - injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + //injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + injectPlayer(object, { + id: id, + links: [url], + width: width, + height: height, + cssClass: cssclass, + cssStyles: cssstyles, + name: name + }, url) injectHelp() } @@ -718,7 +727,16 @@ function replaceObject(object) { flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters url = url + '?' + flashVars } - injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + //injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + injectPlayer(object, { + id: id, + links: [url], + width: width, + height: height, + cssClass: cssclass, + cssStyles: cssstyles, + name: name + }, url) injectHelp() } From 43e0614702e319a398a824665697dd6796a892de Mon Sep 17 00:00:00 2001 From: Corbin Davenport Date: Sat, 18 Jan 2020 19:03:24 -0500 Subject: [PATCH 03/10] Pass all possible media links to injectPlayer() --- js/noplugin.js | 92 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/js/noplugin.js b/js/noplugin.js index 39d0ef7..e9e9d3a 100644 --- a/js/noplugin.js +++ b/js/noplugin.js @@ -345,7 +345,6 @@ function playbackError(mediaPlayer, id, url, width, height, cssclass, cssstyles) // Replace plugin embeds with native players function injectPlayer(object, media, mediaUrl) { - console.log(mediaUrl) if ((mediaUrl === '') || (mediaUrl === null)) { // There is a URL error var container = document.createElement('div') @@ -577,26 +576,25 @@ function injectPlayer(object, media, mediaUrl) { // Parse tag attributes and pass data to injectPlayer() function replaceEmbed(object) { - // Create ID for player - var id = String(Math.floor((Math.random() * 1000000) + 1)) - // Find video source of object + // Find video sources + var links = [] if (object.hasAttribute('qtsrc')) { // var url = DOMPurify.sanitize(object.getAttribute('qtsrc'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.hasAttribute('href')) { + url = getFullURL(url) + links.push(url) + } + if (object.hasAttribute('href')) { // var url = DOMPurify.sanitize(object.getAttribute('href'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.hasAttribute('src')) { + url = getFullURL(url) + links.push(url) + } + if (object.hasAttribute('src')) { // var url = DOMPurify.sanitize(object.getAttribute('src'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else { - var url = null - } - if ((url != null) && (url != undefined)) { - // Sanitize URL - url = DOMPurify.sanitize(url, { ALLOW_UNKNOWN_PROTOCOLS: true }) - // Get exact URL url = getFullURL(url) + links.push(url) } // Find attributes of object if (object.hasAttribute('width')) { @@ -633,54 +631,68 @@ function replaceEmbed(object) { } else { var name = '' } - // Add Flash variables to end of URL if they exist + // Add Flash variables to end of URLs if (object.hasAttribute('FlashVars')) { var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters - url = url + '?' + flashVars + links.forEach(function (link) { + link = link + '?' + flashVars + }) } - //injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + // Remove duplicate URLs + links = [...new Set(links)] + // Inject the player injectPlayer(object, { id: id, - links: [url], + links: links, width: width, height: height, cssClass: cssclass, cssStyles: cssstyles, name: name - }, url) + }, links[0]) injectHelp() } // Parse tag attributes and pass data to injectPlayer() function replaceObject(object) { - // Find video source of object + // Find video sources + var links = [] if (object.hasAttribute('data')) { // var url = DOMPurify.sanitize(object.getAttribute('data'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.querySelector('param[name="MOVIE" i]')) { + url = getFullURL(url) + links.push(url) + } + if (object.querySelector('param[name="MOVIE" i]')) { // var url = DOMPurify.sanitize(object.querySelector('param[name="MOVIE" i]').getAttribute('value'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.querySelector('param[name="HREF" i]')) { + url = getFullURL(url) + links.push(url) + } + if (object.querySelector('param[name="HREF" i]')) { // var url = DOMPurify.sanitize(object.querySelector('param[name="HREF" i]').getAttribute('value'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.querySelector('param[name="SRC" i]')) { + url = getFullURL(url) + links.push(url) + } + if (object.querySelector('param[name="SRC" i]')) { // var url = DOMPurify.sanitize(object.querySelector('param[name="SRC" i]').getAttribute('value'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.querySelector('embed').getAttribute('src')) { + url = getFullURL(url) + links.push(url) + } + if (object.querySelector('embed') && object.querySelector('embed').getAttribute('src')) { // var url = DOMPurify.sanitize(object.querySelector('embed').getAttribute('src'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else if (object.querySelector('embed').getAttribute('target')) { + url = getFullURL(url) + links.push(url) + } + if (object.querySelector('embed') && object.querySelector('embed').getAttribute('target')) { // var url = DOMPurify.sanitize(object.querySelector('embed').getAttribute('target'), { ALLOW_UNKNOWN_PROTOCOLS: true }) - } else { - var url = null - } - if ((url != null) && (url != undefined)) { - // Sanitize URL - url = DOMPurify.sanitize(url, { ALLOW_UNKNOWN_PROTOCOLS: true }) - // Get exact URL url = getFullURL(url) + links.push(url) } // Find attributes of object if (object.hasAttribute('width')) { @@ -717,26 +729,32 @@ function replaceObject(object) { } else { var name = '' } - // Add Flash variables to end of URL if they exist + // Add Flash variables to end of URLs if (object.hasAttribute('FlashVars')) { var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters - url = url + '?' + flashVars + links.forEach(function (link) { + link = link + '?' + flashVars + }) } else if (object.querySelector('param[name="FLASHVARS" i]')) { var flashVars = DOMPurify.sanitize(object.querySelector('param[name="FLASHVARS" i]').getAttribute('value'), { ALLOW_UNKNOWN_PROTOCOLS: true }) flashVars = flashVars.replace(/&/g, '&') // Fix DOMPurify breaking & characters - url = url + '?' + flashVars + links.forEach(function (link) { + link = link + '?' + flashVars + }) } - //injectPlayer(object, id, url, width, height, cssclass, cssstyles, name) + // Remove duplicate URLs + links = [...new Set(links)] + // Inject the player injectPlayer(object, { id: id, - links: [url], + links: links, width: width, height: height, cssClass: cssclass, cssStyles: cssstyles, name: name - }, url) + }, links[0]) injectHelp() } From fd53cde5ad168479479f4cff3d27ef6cba9f7819 Mon Sep 17 00:00:00 2001 From: Corbin Davenport Date: Sat, 18 Jan 2020 21:45:05 -0500 Subject: [PATCH 04/10] Bumped version to 7.0, add blacklists for embeds and sites --- js/blocklist.js | 18 +++++++++++++++++ js/noplugin.js | 53 ++++++++++++++++++++++++++----------------------- manifest.json | 3 ++- 3 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 js/blocklist.js diff --git a/js/blocklist.js b/js/blocklist.js new file mode 100644 index 0000000..0ff064f --- /dev/null +++ b/js/blocklist.js @@ -0,0 +1,18 @@ +// This is where NoPlugin stores its blacklists. + +// URL patterns of sites that NoPlugin shouldn't run on +// Examples: Sites that heavily rely on Flash, sites that host tracking scripts +var siteBlocks = [ + //'^https:\/\/corbin.io', (for testing) + '^https:\/\/www\.xfinity\.com\/stream', // Xfinity Stream (#70) +] + +// URL patterns of files NoPlugin shouldn't load +// Examples: Tracking scripts, fallbacks for HTML5 players, etc. +var embedBlocks = [ + 'fp.swf', // Tracking (#66) +] + +// Generate regexes +const globalSiteBlockList = new RegExp(siteBlocks.join('|'), 'i') +const globalEmbedBlockList = new RegExp(embedBlocks.join('|'), 'i') \ No newline at end of file diff --git a/js/noplugin.js b/js/noplugin.js index e9e9d3a..436f610 100644 --- a/js/noplugin.js +++ b/js/noplugin.js @@ -346,21 +346,8 @@ function playbackError(mediaPlayer, id, url, width, height, cssclass, cssstyles) // Replace plugin embeds with native players function injectPlayer(object, media, mediaUrl) { if ((mediaUrl === '') || (mediaUrl === null)) { - // There is a URL error - var container = document.createElement('div') - container.setAttribute('class', 'noplugin ' + media.cssClass) - container.id = media.id - container.align = 'center' - container.setAttribute('style', media.cssStyles + ' width:' + (media.width - 10) + 'px !important; height:' + (media.height - 10) + 'px !important;') - // Create text content - var content = document.createElement('div') - content.className = 'noplugin-content' - content.textContent = 'This page is trying to load plugin content here, but NoPlugin could not detect the media address.' - // Write container to page - container.appendChild(content) - object.parentNode.replaceChild(container, object) - // Add message to console - console.log('[NoPlugin] Replaced plugin embed but could not detect URL:', media) + // Silently fail + return } else if (mediaUrl.includes('youtube.com/v/')) { // Old Flash-based YouTube embed var frame = document.createElement('iframe') @@ -631,6 +618,10 @@ function replaceEmbed(object) { } else { var name = '' } + // Remove duplicate URLs + links = [...new Set(links)] + // Remove blacklisted URLs + links = links.filter(link => !globalEmbedBlockList.test(link)) // Add Flash variables to end of URLs if (object.hasAttribute('FlashVars')) { var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) @@ -639,9 +630,12 @@ function replaceEmbed(object) { link = link + '?' + flashVars }) } - // Remove duplicate URLs - links = [...new Set(links)] + // Inject help if there are any valid links + if (links < 0) { + injectHelp() + } // Inject the player + var mainLink = links[0] || null injectPlayer(object, { id: id, links: links, @@ -650,8 +644,7 @@ function replaceEmbed(object) { cssClass: cssclass, cssStyles: cssstyles, name: name - }, links[0]) - injectHelp() + }, mainLink) } // Parse tag attributes and pass data to injectPlayer() @@ -729,6 +722,10 @@ function replaceObject(object) { } else { var name = '' } + // Remove duplicate URLs + links = [...new Set(links)] + // Remove blacklisted URLs + links = links.filter(link => !globalEmbedBlockList.test(link)) // Add Flash variables to end of URLs if (object.hasAttribute('FlashVars')) { var flashVars = DOMPurify.sanitize(object.getAttribute('FlashVars'), { ALLOW_UNKNOWN_PROTOCOLS: true }) @@ -743,9 +740,12 @@ function replaceObject(object) { link = link + '?' + flashVars }) } - // Remove duplicate URLs - links = [...new Set(links)] + // Inject help if there are any valid links + if (links < 0) { + injectHelp() + } // Inject the player + var mainLink = links[0] || null injectPlayer(object, { id: id, links: links, @@ -754,8 +754,7 @@ function replaceObject(object) { cssClass: cssclass, cssStyles: cssstyles, name: name - }, links[0]) - injectHelp() + }, mainLink) } // Replace URLs for specific and