How to use Flowplayer functions in a content script?
Asked Answered
R

1

8

I am trying to write a Firefox add-on for personal use and to learn a bit more about both JavaScript and the Firefox Add-on SDK. The add-on should open a vivo.sx URL and then automatically start the player, but I have 2 issues. I hope you guys can help me.

The relevant add-on-code:

function vivoplay()
{
    pageMod.PageMod({
        include: "https://vivo.sx/*",
        contentScriptFile: "./vivoplay.js",
        onAttach: play
    });

    function play(worker)                       //Fires 2 Times
    {
        console.log("Timeout");
        tmr.setTimeout(sendplay, 14000);
        function sendplay() 
        {
            var a = 0;
            worker.port.emit("start", a);
        }
    }
}

content-script

self.port.on("start", function(a) {
    console.log("Load");
    flowplayer().load();         //ReferenceError: flowplayer is not defined
    console.log("Loaded");
});

The first problem is that the function play fires 2 times, but should only run once. It's probably the onAttach that does not work correctly. What do you think about that?

The more important problem is the ReferenceError. I have a Greasemonkey script where I use the function flowplayer().load();. I thought the content script is running like a Greasemonkey script. So, I should be able to use this function. Is that correct? How can I fix this?

my greasemonkey script

// ==UserScript==
// @name        3. Vivo
// @namespace   Autoplay
// @include     https://vivo.sx/* 
// @version     1
// @grant       none
// ==/UserScript==

window.setTimeout(Play, 2000);
function Play()
{
  flowplayer().load(); 
  console.log("Loaded");
  flowplayer().fullscreen();
  console.log("Fullscreen started");
}

I am quite new to this so please be patience with me :)

If you need more information, please leave a comment.

Rectangle answered 21/10, 2016 at 3:9 Comment(6)
Where do you define flowplayer()?Threescore
nowhere cause I don't know to define itRectangle
Then how does it get included into the environment which you are using in Greasemonkey? Is it included as part of the page you are attempting to interact with?Threescore
I didn't include it in my Greasemonkey script iam simply use the functions. I added my Greasemonkey script above, maybe I understood something wrong. The player is part of the page.Rectangle
My guess is that flowplayer() already exists in the page in which you are wanting your content script loaded and you are wanting to call the method flowplayer().load() which exists in the page script for the web page you are viewing. Is that accurate?Threescore
Exactly that is what iam trying to doRectangle
T
1

The problem you are experiencing is that you are not taking into account that your content script is executing in a different context than the scripts in the webpage (page scripts). Keeping content scripts separate from page scripts is a normal architecture for browser extensions which is done for security reasons. Your content script has higher privileges than are granted to page scripts. While you technically could execute a function provided by the page from within your content script context, for security reasons, you should never do so. If you do choose to do so, your extension will not pass review by Mozilla for being listed on AMO.

While you can expose functions which exist in your content script to page scripts, and create objects in the page script scope, the way to actually execute code from within the page script context is to add a <script> element to the document containing the code you desire to execute.

For the code in your question, this could be implemented as:

self.port.on("start", function(a) {
    let newScript = document.createElement('script');
    //The calls to console.log don't need to be in the page script.
    //  However, the code in the newScript is executed asynchronously. Thus, if the
    //  console.log("Loaded"); 
    //  is in the content script it will be executed prior to flowplayer().load() actually
    //  being called.
    newScript.innerHTML = 'console.log("Load");'
                        + 'flowplayer().load();'
                        + 'console.log("Loaded");' ;
    document.head.appendChild(newScript);
});

onAttach/play running more than once:
Without your full code and a screenshot of what the browser looked like it is impossible to be certain why this would occur.

The most likely reason is that you had more than one tab open to an address that matched "https://vivo.sx/*". Your onAttach code will be called each time the content script is attached to a page. It will be attached once for each tab which is open to a matching URL. If you had two tabs open to matching URLs when the add-on was loaded, then the onAttach code will be executed twice.

Another possibility is that you have executed vivoplay more than once resulting in setting up multiple PageMods each of which would attach a separate copy of your content script to each tab. Given the name you used for this function, vivoplay, you may be treating it as a play function which you are executing more than once. With how you have things organized within that function, you should not do so.

Overly complex for what is shown:
Your code is overly complex for what is shown. You are using the onAttach event to sent start to the content script. The content script is only loaded/executed when it is attached. Thus, informing the content script that it is attached by sending start is redundant. This might be reasonable if you are intending to modify the code to only send start in response to some other event (e.g. the user clicking a button). However, if it is your intent to always auto-start the Flowplayer, then there is no need to send a start message to the content script. The content script can have the setTimeout and just go ahead and execute that code when it is run.

Threescore answered 23/10, 2016 at 22:42 Comment(8)
Thank you for your replies. I finally got my add-on to work. But I had a few questions about your solution. when will the script element I add executed? And can you give me a tip how I can undo my attached content scripts so the brower works normally after my add-on done his work?Rectangle
The <script> which I show being added will execute (almost) immediately after the script which added it completes execution (i.e. is no longer doing anything). I'm not sure I understood your second question correctly. Are you asking about what to do when your add-on is disabled/uninstalled? Your content scripts should (to a reasonable extent) track changes they make to pages. They should use self.port.on("detach",.. and clean up when they receive that event. (continued)Threescore
(continued) How exactly you do that depends on what your content script does. Most important is they stop doing anything. One of the more important things is that you should be sure to remove any event listeners you have added to the page, and stop any timers. Doing that will often be sufficient to prevent any additional changes to each page. What is intended is a good user experience. The thing to keep in mind is that you are getting that event because the user no longer wants your add-on. You should, as much as possible, make it as if your add-on was never installed/enabled.Threescore
An alternate interpretation of your question is that you are concerned that something is not going to be working while your add-on is enabled. If that is the case, you are going to need to expand on what you concern is in order for me to address it.Threescore
My add-on is opening and closing tabs while a for-loop is running. After the for-loop is done all opened tabs are closed and if I go now manually to a url like "https://vivo.sx/*" my content script for this url will execute again. But this is not my intention I would like to go manually to this url without executing the script again.Rectangle
How best to implement that will depend on your add-on (i.e. need more detail). However, a first look at it would suggest setting up the page-mod prior to opening and closing the tabs, then using the destroy() method to destroy the page-mod when you are done with it. It may be more appropriate to use attach() instead of a page-mod.Threescore
Thx again destroy() works ok only on the last url the script gets still attached, but its ok for now, maybe I will rework my add-on to use attach(). Can you answer me one last question, is it possible to change Firefox config with an add-on? I need to change the full-screen-api.allow-trusted-requests-only dom.allow_scripts_to_close_windows values and back to normal after my script ended. For full functionality.Rectangle
Yes, an Add-on SDK extension can change those. They are called preferences. You will want to look into the preferences/service API.Threescore

© 2022 - 2024 — McMap. All rights reserved.