├── .gitignore ├── README.md ├── data ├── icon_button.png └── modified-click.js ├── lib └── main.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.xpi -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Natively play video streams in Firefox 2 | This is firefox browser extension that gives the user the ability to play flash video streams for [multiple](http://rg3.github.io/youtube-dl/supportedsites.html) websites using [youtube-dl](http://youtube-dl.org) and a native media player of choice (which supports youtube-dl of course). The default configuration uses [mpv](http://mpv.io/) media player. 3 | 4 | ## Installing 5 | 6 | ### Build 7 | 1. Download `mozilla-youtube-dl-binding.xpi` file. 8 | 2. Open the xpi file with Firefox. 9 | 10 | ### Build it manually 11 | 1. Download the source. 12 | 2. Download de [Add-on SDK](https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/jpm#Installation). 13 | 3. Run `jpm xpi` inside the `project` directory. 14 | 4. Open the `mozilla-youtube-dl-binding@jetpack.xpi` file with Firefox. 15 | -------------------------------------------------------------------------------- /data/icon_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoniy/mpv-youtube-dl-binding/c0c4dda2ee0b3dd7f9f884557dce9eaff8ab09c6/data/icon_button.png -------------------------------------------------------------------------------- /data/modified-click.js: -------------------------------------------------------------------------------- 1 | var prefs = {}; 2 | 3 | self.port.on("prefChanged", function(name, value) { 4 | prefs[name] = value; 5 | }); 6 | 7 | window.addEventListener("click", function(event) { 8 | if (prefs.altClick && event.altKey && event.button == 0) { 9 | 10 | var link = event.target; 11 | 12 | while (link && link.localName != "a") 13 | link = link.parentNode; 14 | 15 | if (link) { 16 | self.port.emit("altClick", link.href); 17 | } 18 | } 19 | }, false); 20 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | var data = require("sdk/self").data; 2 | var tabs = require("sdk/tabs"); 3 | var simple_prefs = require("sdk/simple-prefs"); 4 | var ui = require("sdk/ui"); 5 | var { env } = require('sdk/system/environment'); 6 | const {Cc,Ci} = require("chrome"); 7 | var { Hotkey } = require("sdk/hotkeys"); 8 | var contextMenu = require("sdk/context-menu"); 9 | var querystring = require("sdk/querystring"); 10 | 11 | function play_video(url) { 12 | var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); 13 | file.initWithPath(simple_prefs.prefs.player); 14 | 15 | // create an nsIProcess 16 | var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); 17 | process.init(file); 18 | 19 | var params = simple_prefs.prefs.params; 20 | 21 | if (params) 22 | var args = params.split(" "); 23 | else 24 | var args = []; 25 | 26 | 27 | if (simple_prefs.prefs.ytStartPlAtIndex) { 28 | 29 | // Checks if running on Youtube 30 | if (url.indexOf("youtube.com") > -1) { // url is Youtube link 31 | 32 | // Parses url params to an object returning object like: 33 | // {"v":"g04s2u30NfQ","index":"3","list":"PL58H4uS5fMRzmMC_SfMelnCoHgB8COa5r"} 34 | var qs = querystring.parse(url.split("?")[1]); 35 | 36 | if (qs["list"] && qs["index"]) { // we have the playlist and the video index 37 | 38 | // args could be: ["--video-unscaled=yes","--ytdl-raw-options=format=best"] 39 | // so checking for ytdl-raw-options 40 | var ytdlRawOptionsIndex = -1; 41 | for (var i = 0; i < args.length; i++) { 42 | if (args[i].indexOf("ytdl-raw-options") > -1) { 43 | ytdlRawOptionsIndex = i; 44 | break; 45 | }; 46 | }; 47 | 48 | // Change ytdl-raw-options or add it to args if not exist 49 | if (ytdlRawOptionsIndex > -1) { 50 | args[ytdlRawOptionsIndex] += ",yes-playlist=,playlist-start=" + qs["index"]; 51 | } else { 52 | args.push("--ytdl-raw-options=yes-playlist=,playlist-start=" + qs["index"]); 53 | }; 54 | }; 55 | }; 56 | }; 57 | 58 | args.push(url); 59 | 60 | // process.run(false, args, args.length); 61 | process.runAsync(args, args.length); 62 | } 63 | 64 | var menuItem = contextMenu.Item({ 65 | label: "Watch with MPV", 66 | context: contextMenu.SelectorContext("[href]"), 67 | contentScript: 'self.on("click", function(node,data){self.postMessage(node.href);})', 68 | accessKey: "e", 69 | image: data.url("icon_button.png"), 70 | onMessage: function (url) { 71 | play_video(url); 72 | } 73 | }); 74 | 75 | var action_button = ui.ActionButton({ 76 | id: "my-button", 77 | label: "Play with MPV", 78 | icon: data.url("icon_button.png"), 79 | onClick: function(state) { 80 | play_video(tabs.activeTab.url); 81 | } 82 | }); 83 | 84 | var showHotKey = Hotkey({ 85 | combo: simple_prefs.prefs.hotkey, 86 | onPress: function() { 87 | play_video(tabs.activeTab.url); 88 | } 89 | }); 90 | 91 | tabs.on("ready", function(tab) { 92 | var worker = tab.attach({ 93 | contentScriptFile: data.url("modified-click.js") 94 | }); 95 | worker.port.on("altClick", function(url) { 96 | console.log(url); 97 | play_video(url); 98 | }); 99 | 100 | function onPrefChanged(name) { 101 | worker.port.emit("prefChanged", name, simple_prefs.prefs[name]); 102 | } 103 | 104 | var watchedPrefs = [ 105 | "altClick" 106 | ]; 107 | 108 | watchedPrefs.forEach(function(value) { 109 | simple_prefs.on(value, onPrefChanged); 110 | onPrefChanged(value); 111 | }); 112 | 113 | worker.on("detach", function() { 114 | watchedPrefs.forEach(function(value) { 115 | simple_prefs.removeListener(value, onPrefChanged); 116 | }); 117 | }); 118 | 119 | }); 120 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mpv-youtube-dl-binding", 3 | "license": "MIT", 4 | "author": "Antoniy Chonkov", 5 | "version": "0.1.0-alpha.3", 6 | "id": "jid1-6NrUw49Z9jFVxg@jetpack", 7 | "description": "Watch flash videos from various sites using native player (like mpv) and youtube-dl.", 8 | "homepage": "https://github.com/antoniy/mpv-youtube-dl-binding", 9 | "icon": "data/icon_button.png", 10 | "main": "lib/main.js", 11 | "permissions": { 12 | "private-browsing": true 13 | }, 14 | "preferences": [ 15 | { 16 | "name": "player", 17 | "title": "Native player location", 18 | "description": "Specify native player executable full path", 19 | "type": "string", 20 | "value": "/usr/bin/mpv" 21 | }, 22 | { 23 | "name": "hotkey", 24 | "title": "Hotkey", 25 | "description": "Specify hotkey binding to start the player for current page", 26 | "type": "string", 27 | "value": "accel-alt-m" 28 | }, 29 | { 30 | "name": "params", 31 | "title": "Additional player parameters", 32 | "description": "Specify additional parameters to pass the native player when started. Leave empty if none are required. Use %%url%% placeholder to be able to pass video link as a parameter (useful when using custom script to execute additional logic).", 33 | "type": "string", 34 | "value": "" 35 | }, 36 | { 37 | "name": "ytStartPlAtIndex", 38 | "title": "Start playlist playback from the selected video", 39 | "description": "While in Youtube playlist, context menu command will play the playlist starting from the selected video.", 40 | "type": "bool", 41 | "value": false 42 | }, 43 | { 44 | "name": "altClick", 45 | "title": "alt + click", 46 | "description": "Launch player for a link on 'alt + click'", 47 | "type": "bool", 48 | "value": false 49 | }, 50 | ] 51 | } 52 | --------------------------------------------------------------------------------