Changeset View
Changeset View
Standalone View
Standalone View
extension/content-script.js
Show First 20 Lines • Show All 775 Lines • ▼ Show 20 Line(s) | 637 | if (document.documentElement.tagName.toLowerCase() === "html") { | |||
---|---|---|---|---|---|
776 | 776 | | |||
777 | // here we replace the document.createElement function with our own so we can detect | 777 | // here we replace the document.createElement function with our own so we can detect | ||
778 | // when an <audio> tag is created that is not added to the DOM which most pages do | 778 | // when an <audio> tag is created that is not added to the DOM which most pages do | ||
779 | // while a <video> tag typically ends up being displayed to the user, audio is not. | 779 | // while a <video> tag typically ends up being displayed to the user, audio is not. | ||
780 | // HACK We cannot really pass variables from the page's scope to our content-script's scope | 780 | // HACK We cannot really pass variables from the page's scope to our content-script's scope | ||
781 | // so we just blatantly insert the <audio> tag in the DOM and pick it up through our regular | 781 | // so we just blatantly insert the <audio> tag in the DOM and pick it up through our regular | ||
782 | // mechanism. Let's see how this goes :D | 782 | // mechanism. Let's see how this goes :D | ||
783 | 783 | | |||
784 | // HACK When removing a media object from DOM it is paused, so what we do here is once the | ||||
785 | // player loaded some data we add it (doesn't work earlier since it cannot pause when | ||||
786 | // there's nothing loaded to pause) to the DOM and before we remove it, we note down that | ||||
787 | // we will now get a paused event because of that. When we get it, we just play() the player | ||||
788 | // so it continues playing :-) | ||||
789 | const addPlayerToDomEvadingAutoPlayBlocking = ` | ||||
790 | player.registerInDom = () => { | ||||
791 | player.pausedBecauseOfDomRemoval = true; | ||||
792 | player.removeEventListener("play", player.registerInDom); | ||||
793 | | ||||
794 | (document.head || document.documentElement).appendChild(player); | ||||
795 | player.parentNode.removeChild(player); | ||||
796 | }; | ||||
797 | | ||||
798 | player.replayAfterRemoval = () => { | ||||
799 | if (player.pausedBecauseOfDomRemoval === true) { | ||||
800 | delete player.pausedBecauseOfDomRemoval; | ||||
801 | player.removeEventListener("pause", player.replyAfterRemoval); | ||||
802 | | ||||
803 | player.play(); | ||||
804 | } | ||||
805 | }; | ||||
806 | | ||||
807 | player.addEventListener("play", player.registerInDom); | ||||
808 | player.addEventListener("pause", player.replayAfterRemoval); | ||||
809 | `; | ||||
810 | | ||||
784 | executeScript(`function() { | 811 | executeScript(`function() { | ||
785 | var oldCreateElement = Document.prototype.createElement; | 812 | var oldCreateElement = Document.prototype.createElement; | ||
786 | Document.prototype.createElement = function() { | 813 | Document.prototype.createElement = function() { | ||
787 | var createdTag = oldCreateElement.apply(this, arguments); | 814 | var createdTag = oldCreateElement.apply(this, arguments); | ||
788 | 815 | | |||
789 | var tagName = arguments[0]; | 816 | var tagName = arguments[0]; | ||
790 | 817 | | |||
791 | if (typeof tagName === "string") { | 818 | if (typeof tagName === "string") { | ||
792 | if (tagName.toLowerCase() === "audio" || tagName.toLowerCase() === "video") { | 819 | if (tagName.toLowerCase() === "audio") { | ||
820 | const player = createdTag; | ||||
821 | ${addPlayerToDomEvadingAutoPlayBlocking} | ||||
822 | } else if (tagName.toLowerCase() === "video") { | ||||
793 | (document.head || document.documentElement).appendChild(createdTag); | 823 | (document.head || document.documentElement).appendChild(createdTag); | ||
794 | createdTag.parentNode.removeChild(createdTag); | 824 | createdTag.parentNode.removeChild(createdTag); | ||
795 | } | 825 | } | ||
796 | } | 826 | } | ||
797 | 827 | | |||
798 | return createdTag; | 828 | return createdTag; | ||
799 | }; | 829 | }; | ||
800 | } | 830 | } | ||
801 | `); | 831 | `); | ||
802 | 832 | | |||
803 | // We also briefly add items created as new Audio() to the DOM so we can control it | 833 | // We also briefly add items created as new Audio() to the DOM so we can control it | ||
804 | // similar to the document.createElement hack above since we cannot share variables | 834 | // similar to the document.createElement hack above since we cannot share variables | ||
805 | // between the actual website and the background script despite them sharing the same DOM | 835 | // between the actual website and the background script despite them sharing the same DOM | ||
806 | // HACK When removing a media object from DOM it is paused, so what we do here is once the | 836 | | ||
807 | // player loaded some data we add it (doesn't work earlier since it cannot pause when | | |||
808 | // there's nothing loaded to pause) to the DOM and before we remove it, we note down that | | |||
809 | // we will now get a paused event because of that. When we get it, we just play() the player | | |||
810 | // so it continues playing :-) | | |||
811 | if (IS_FIREFOX) { | 837 | if (IS_FIREFOX) { | ||
812 | // Firefox enforces Content-Security-Policy also for scripts injected by the content-script | 838 | // Firefox enforces Content-Security-Policy also for scripts injected by the content-script | ||
813 | // This causes our executeScript calls to fail for pages like Nextcloud | 839 | // This causes our executeScript calls to fail for pages like Nextcloud | ||
814 | // It also doesn't seem to have the aggressive autoplay prevention Chrome has, | 840 | // It also doesn't seem to have the aggressive autoplay prevention Chrome has, | ||
815 | // so the horrible replyAfterRemoval hack from above isn't copied into this | 841 | // so the horrible replyAfterRemoval hack from above isn't copied into this | ||
816 | // See Bug 411148: Music playing from the ownCloud Music app does not show up | 842 | // See Bug 411148: Music playing from the ownCloud Music app does not show up | ||
817 | var oldAudio = window.Audio; | 843 | var oldAudio = window.Audio; | ||
818 | exportFunction(function() { | 844 | exportFunction(function(...args) { | ||
819 | var createdAudio = new (Function.prototype.bind.apply(oldAudio, arguments)); | 845 | const player = new oldAudio(...args); | ||
820 | 846 | eval(addPlayerToDomEvadingAutoPlayBlocking); | |||
821 | (document.head || document.documentElement).appendChild(createdAudio); | 847 | return player; | ||
822 | createdAudio.parentNode.removeChild(createdAudio); | | |||
823 | | ||||
824 | return createdAudio; | | |||
825 | }, window, {defineAs: "Audio"}); | 848 | }, window, {defineAs: "Audio"}); | ||
826 | } else { | 849 | } else { | ||
827 | executeScript(`function() { | 850 | executeScript(`function() { | ||
828 | var oldAudio = window.Audio; | 851 | var oldAudio = window.Audio; | ||
829 | window.Audio = function () { | 852 | window.Audio = function (...args) { | ||
830 | var createdAudio = new (Function.prototype.bind.apply(oldAudio, arguments)); | 853 | const player = new oldAudio(...args); | ||
831 | 854 | ${addPlayerToDomEvadingAutoPlayBlocking} | |||
832 | createdAudio.registerInDom = function() { | 855 | return player; | ||
833 | (document.head || document.documentElement).appendChild(createdAudio); | | |||
834 | createdAudio.pausedBecauseOfDomRemoval = true; | | |||
835 | createdAudio.parentNode.removeChild(createdAudio); | | |||
836 | | ||||
837 | createdAudio.removeEventListener("loadeddata", createdAudio.registerInDom); | | |||
838 | }; | | |||
839 | | ||||
840 | createdAudio.replayAfterRemoval = function() { | | |||
841 | if (createdAudio.pausedBecauseOfDomRemoval) { | | |||
842 | if (createdAudio.paused) { | | |||
843 | createdAudio.play(); | | |||
844 | } | | |||
845 | delete createdAudio.pausedBecauseOfDomRemoval; | | |||
846 | | ||||
847 | createdAudio.removeEventListener("pause", createdAudio.replayAfterRemoval); | | |||
848 | } | | |||
849 | }; | | |||
850 | | ||||
851 | createdAudio.addEventListener("loadeddata", createdAudio.registerInDom); | | |||
852 | createdAudio.addEventListener("pause", createdAudio.replayAfterRemoval); | | |||
853 | | ||||
854 | return createdAudio; | | |||
855 | }; | 856 | }; | ||
856 | }`); | 857 | }`); | ||
857 | } | 858 | } | ||
858 | } | 859 | } | ||
859 | } | 860 | } | ||
860 | 861 | | |||
861 | // PURPOSE / WEB SHARE API | 862 | // PURPOSE / WEB SHARE API | ||
862 | // ------------------------------------------------------------------------ | 863 | // ------------------------------------------------------------------------ | ||
▲ Show 20 Lines • Show All 117 Lines • Show Last 20 Lines |