From a638cefe21f1efc6f63f57effcfc1f6a090e71a6 Mon Sep 17 00:00:00 2001 From: Maxim Stewart Date: Mon, 7 Jan 2019 01:48:10 -0600 Subject: [PATCH] Added download feature for Unix, Linux, and MacOS systems using native messaging. --- README.md | 19 ++++++++++++++----- app/web_video_dl.json | 7 +++++++ app/youtube-dl-bridge.py | 23 +++++++++++++++++++++++ src/icons/downloadVid.png | Bin 0 -> 3239 bytes src/manifest.json | 10 ++++++---- src/scripts/background.js | 7 +++++++ src/scripts/betterYoutube.js | 23 +++++++++++++++++++++++ 7 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 app/web_video_dl.json create mode 100755 app/youtube-dl-bridge.py create mode 100644 src/icons/downloadVid.png diff --git a/README.md b/README.md index fefc896..128cd11 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # Better Youtube + - Better YouTube + works to improve the YouTube experience by providing quick access to features we'd all like to have from the get-go.
* It allows quick thumbnail access of the video. @@ -8,11 +7,21 @@ Better YouTube + works to improve the YouTube experience by providing quick acce * It allows the video to be toggled to fixed or floating with drag functionality. * It allows volume control through the mouse-wheel when hovering over the player. * It allows for quick access to the YouTube video slug. + * It lets Unix, Linux, and MacOS systems the ability to download the video using native app calls. + +# Version: 1.3.6 +* Added download feature for Unix, Linux, and MacOS systems using native messaging. # Download https://addons.mozilla.org/en-US/firefox/addon/better-youtube-plus/ -# Version: 1.3.5 -* Added ranged loop feature. -* Fixed finally floating video issues. -* Removed non-working image onerror signals. +# NOTE +On *Nix systems download youtube-dl and use provided app in this repo to download videos. + +##### Mac OS/Linux Setup +To get downloading working do the following: + +1. Check that the [file permissions](https://en.wikipedia.org/wiki/File_system_permissions) for "youtube-dl-bridge.py" include the `execute` permission. +2. Edit the "path" property of "web_video_dl.json" to point to the location of "youtube-dl-bridge.py" on your computer. +3. copy "web_video_dl.json" to the correct location on your computer. See [App manifest location ](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Native_manifests#Manifest_location) to find the correct location for your OS. +4. Install the webextension and enjoy! diff --git a/app/web_video_dl.json b/app/web_video_dl.json new file mode 100644 index 0000000..2526c03 --- /dev/null +++ b/app/web_video_dl.json @@ -0,0 +1,7 @@ +{ + "name": "web_video_dl", + "description": "Video downloader using youtube-dl", + "path": "/insert/your/path/here/to/youtube-dl-bridge.py", + "type": "stdio", + "allowed_extensions": [ "webVidDownloader@1itdominator.com", "betterYoutube@itdominator.com" ] +} diff --git a/app/youtube-dl-bridge.py b/app/youtube-dl-bridge.py new file mode 100755 index 0000000..0420397 --- /dev/null +++ b/app/youtube-dl-bridge.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +import sys +import json +import struct +import subprocess + +# Python 2.x version (if sys.stdin.buffer is not defined) +# Read a message from stdin and decode it. +def getMessage(): + rawLength = sys.stdin.read(4) + if len(rawLength) == 0: + sys.exit(0) + messageLength = struct.unpack('@I', rawLength)[0] + message = sys.stdin.read(messageLength) + return json.loads(message) + +while True: + receivedMessage = getMessage() + + if receivedMessage: + command = "cd ~/Downloads && youtube-dl " + receivedMessage; + subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) diff --git a/src/icons/downloadVid.png b/src/icons/downloadVid.png new file mode 100644 index 0000000000000000000000000000000000000000..dbf54496172a175d1e1e06454462f6cdf3c91c39 GIT binary patch literal 3239 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 Iv-70?0p}(8qW}N^ literal 0 HcmV?d00001 diff --git a/src/manifest.json b/src/manifest.json index 32e5c25..2e0b308 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,18 +1,20 @@ { "manifest_version": 2, "name": "Better Youtube +", - "version": "1.3.5", + "version": "1.3.6", "description": "Enhancements for Youtube to have a better experience.", "applications": { "gecko": { - "id": "betterYoutube@itdominator.com" + "id": "betterYoutube@itdominator.com", + "strict_min_version": "50.0" } }, "permissions": [ - "*://*.youtube.com/*", - "tabs" + "nativeMessaging", + "tabs", + "*://*.youtube.com/*" ], "icons": { diff --git a/src/scripts/background.js b/src/scripts/background.js index 503bca5..fac1ab2 100644 --- a/src/scripts/background.js +++ b/src/scripts/background.js @@ -16,4 +16,11 @@ const handleUpdated = (tabId, changeInfo, tabInfo) => { } } +const notify = (data) => { + let port = browser.runtime.connectNative("web_video_dl"); + console.log("Downloding: " + data.url); + port.postMessage(data.url); +} + +browser.runtime.onMessage.addListener(notify); browser.tabs.onUpdated.addListener(handleUpdated); diff --git a/src/scripts/betterYoutube.js b/src/scripts/betterYoutube.js index 100fa96..913ce70 100644 --- a/src/scripts/betterYoutube.js +++ b/src/scripts/betterYoutube.js @@ -12,8 +12,14 @@ ytdVideoIntervalLoop; let loopingInterval = false; let count = 0; + let OSName = ""; const preSetupProc = () => { + if (navigator.appVersion.indexOf("Win")!=-1) OSName = "Windows"; + if (navigator.appVersion.indexOf("Mac")!=-1) OSName = "MacOS"; + if (navigator.appVersion.indexOf("X11")!=-1) OSName = "UNIX"; + if (navigator.appVersion.indexOf("Linux")!=-1) OSName ="Linux"; + video = document.getElementsByTagName("video")[0]; // Video Controler slugInputTag = document.createElement("INPUT"); ytRangeEnd = document.createElement("INPUT"); @@ -47,12 +53,14 @@ ytThumbImgMenu = document.createElement("DIV"); ytEnhancerMenu = document.createElement("DIV"); ytThumbnailBttn = document.createElement("IMG"); + ytDownloadBttn = document.createElement("IMG"); ytLoopBttn = document.createElement("IMG"); ytFloatBttn = document.createElement("IMG"); ytMaxDefaultImg = document.createElement("IMG"); ytHqDefaultImg = document.createElement("IMG"); ytMqDefaultImg = document.createElement("IMG"); ytSdDefaultImg = document.createElement("IMG"); + ytAMaxDefaultImg = document.createElement("A"); ytAHqDefaultImg = document.createElement("A"); ytAMedDefaultImg = document.createElement("A"); @@ -81,6 +89,14 @@ ytEnhancerMenu.appendChild(ytLoopBttn); ytEnhancerMenu.appendChild(ytRangeSection); ytEnhancerMenu.appendChild(ytFloatBttn); + + if (OSName.includes("MacOS") || OSName.includes("UNIX") || + OSName.includes("Linux")) { + console.log("System supports downloader..."); + console.log("OS is : " + OSName); + ytEnhancerMenu.appendChild(ytDownloadBttn); + } + ytRangeSection.append(ytRangeStart); ytRangeSection.append(ytRangeEnd); document.body.appendChild(poppedContainer); @@ -100,6 +116,7 @@ ytThumbnailBttn.addEventListener("click", showThumbImageVew); ytLoopBttn.addEventListener("click", setLoop); ytFloatBttn.addEventListener("click", toggleFloat); + ytDownloadBttn.addEventListener("click", downloadVideo); video.addEventListener("wheel", manageVolume); // Dragable window for floating video @@ -108,6 +125,7 @@ ytThumbnailBttn.src = browser.extension.getURL("/icons/thumbnailOff.png"); ytLoopBttn.src = browser.extension.getURL("/icons/loopFalse.png"); ytFloatBttn.src = browser.extension.getURL("/icons/floatPlayer.png"); + ytDownloadBttn.src = browser.extension.getURL("/icons/downloadVid.png"); // Set trget of Thumbnails of video ytAMaxDefaultImg.target = "_blank"; @@ -125,6 +143,7 @@ ytThumbnailBttn.className = "imageStyle"; ytLoopBttn.className = "imageStyle"; ytFloatBttn.className = "imageStyle"; + ytDownloadBttn.className = "imageStyle"; ytEnhancerMenu.id = "enhancerMenuIDRef"; poppedContainer.id = "draggable"; ytRangeStart.id = "rangeStartID"; @@ -140,6 +159,10 @@ } // Functions + const downloadVideo = () => { + browser.runtime.sendMessage( { "url": video.baseURI } ); + } + const showThumbImageVew = (e) => { videoSlug = video.baseURI.slice(32, 32+11); // Used for setting up thumbnails