Skip to content
This repository was archived by the owner on Jun 16, 2020. It is now read-only.

Commit

Permalink
Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas von Mateffy committed Sep 27, 2017
1 parent 4119722 commit b70659a
Show file tree
Hide file tree
Showing 27 changed files with 163 additions and 100 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

.DS_Store

## Build generated
build/
DerivedData/
Expand Down
9 changes: 8 additions & 1 deletion chrome-extension/src/background.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
function onClick(tab) {
chrome.tabs.sendMessage(tab.id, { type: 'get_video' }, function(response) {
// openUrl(response.url);
if (response && !response.success) {
chrome.notifications.create(null, {
type: "basic",
title: "Unable to use Picture-in-Picture",
message: "Please make sure there is an HTML5 Video on the page.",
iconUrl: "new_icon.png"
});
}
});

}
Expand Down
11 changes: 6 additions & 5 deletions chrome-extension/src/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ chrome.runtime.onMessage.addListener(async function(request, sender, sendRespons
if (request.type === 'get_video') {
const pageUrl = String(window.location);
const isYoutube = /^(https?\:\/\/)?(www\.youtube\.com|youtu\.?be)\/.+$/.test(pageUrl);

let videoData = null;
if (isYoutube) {
const videoId = getParameterByName('v');
const url = await getYoutubeVideoSource(videoId);
openUrl(url);
videoData = await getYoutubeVideoData(videoId);
} else {
const url = getDefaultUrl();
openUrl(url);
videoData = getDefaultVideoData();
}

if (videoData)
openUrl(videoData);
}
});
9 changes: 5 additions & 4 deletions chrome-extension/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["utils.js", "youtube.js", "content.js"]
"js": ["utils.js", "youtube.js", "content.js"],
"run_at": "document_end"
}],
"browser_action": {
"default_icon": "icon.png"
"default_icon": "new_icon.png"
},
"description": "__MSG_gmailcheck_description__",
"icons": {
"128": "icon.png"
"512": "new_icon.png"
},
"name": "BetterPiP",
"permissions": [
"alarms",
"tabs",
"activeTab",
"webNavigation",
"*://*.google.com/"
"notifications"
],
"version": "4.4.0",
"manifest_version": 2
Expand Down
Binary file added chrome-extension/src/new_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 17 additions & 7 deletions chrome-extension/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,31 @@ function submitRequest(buttonId) {
}
}

function openUrl(url, time){
time = time || 0
function openUrl(videoData) {
if (!videoData) return;

var d = (window.parent)?window.parent.document:window.document
var f = d.getElementById('customUrlLink')
if (f ) {f.parentNode.removeChild(f);}
var a = d.createElement('a');
a.href = 'betterpip://open?url=' + encodeURIComponent(url) //+ '&time=' + encodeURIComponent(time);
console.log(a.href);
a.href = 'betterpip://open?url=' + encodeURIComponent(videoData.url) + '&time=' + encodeURIComponent(videoData.time);
alert(a.href);
a.innerHTML = "Link"
a.setAttribute('id', 'customUrlLink');
a.setAttribute('id','customUrlLink');
a.setAttribute("style", "display:none; ");
d.body.appendChild(a);
submitRequest("customUrlLink");
}

function getDefaultUrl() {
return document.querySelector('video').src;
function getDefaultVideoData() {
const video = document.querySelector('video');
if (!video) return;

const videoSource = video.querySelector('source[type=video\\/mp4]');

video.pause();

return videoSource && videoSource.src
? { url: videoSource.src, time: video.currentTime || 0.0 }
: null;
}
19 changes: 14 additions & 5 deletions chrome-extension/src/youtube.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
async function getYoutubeVideoSource(videoId) {
// Get an mp4 stream url for a given youtube video ID.
async function getYoutubeVideoData(videoId) {
const response = await fetch(`https://www.youtube.com/get_video_info?video_id=${videoId}`);
const body = await response.text();
const videoData = decodeUrlEncodedString(body);
Expand All @@ -9,13 +10,20 @@ async function getYoutubeVideoSource(videoId) {
const videoSources = parseStreamMapUrls(videoData.url_encoded_fmt_stream_map);
const source = videoSources['hd720'] || videoSources['medium'];

if (source) {
return source.url;
}
const videoElement = document.querySelector('video');

return null;
if (videoElement)
videoElement.pause();

return {
url: source,
time: videoElement
? videoElement.currentTime
: 0.0
};
}

// Decodes a url-like encoded data string (key1=val&key2=val)
function decodeUrlEncodedString(queryString) {
const entities = queryString.split('&');
let data = {};
Expand All @@ -31,6 +39,7 @@ function decodeUrlEncodedString(queryString) {
return data;
}

// Gets mp4 videos from stream map data
function parseStreamMapUrls(streamMap) {
let urls = {};

Expand Down
44 changes: 26 additions & 18 deletions xcode/BetterPiP.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@

/* Begin PBXBuildFile section */
80F0F1F11F75805E00EC5A7A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F0F1F01F75805E00EC5A7A /* AppDelegate.swift */; };
80F0F1F31F75805E00EC5A7A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F0F1F21F75805E00EC5A7A /* ViewController.swift */; };
80F0F1F31F75805E00EC5A7A /* PiPControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F0F1F21F75805E00EC5A7A /* PiPControlViewController.swift */; };
80F0F1F51F75805E00EC5A7A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 80F0F1F41F75805E00EC5A7A /* Assets.xcassets */; };
80F0F1F81F75805E00EC5A7A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 80F0F1F61F75805E00EC5A7A /* Main.storyboard */; };
80F0F2021F75808200EC5A7A /* PIP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80F0F2001F75808200EC5A7A /* PIP.framework */; };
80F0F2051F7580E300EC5A7A /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80F0F2041F7580E300EC5A7A /* AVKit.framework */; };
80F0F2071F75811100EC5A7A /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80F0F2061F75811100EC5A7A /* AVFoundation.framework */; };
80F0F2131F75874D00EC5A7A /* LMVideoWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F0F2121F75874D00EC5A7A /* LMVideoWindowController.swift */; };
80F0F2131F75874D00EC5A7A /* PiPControlWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F0F2121F75874D00EC5A7A /* PiPControlWindowController.swift */; };
80F0F2151F758CD100EC5A7A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80F0F2141F758CD100EC5A7A /* Foundation.framework */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
80F0F1ED1F75805E00EC5A7A /* BetterPiP.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BetterPiP.app; sourceTree = BUILT_PRODUCTS_DIR; };
80F0F1F01F75805E00EC5A7A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
80F0F1F21F75805E00EC5A7A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
80F0F1F21F75805E00EC5A7A /* PiPControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPControlViewController.swift; sourceTree = "<group>"; };
80F0F1F41F75805E00EC5A7A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
80F0F1F71F75805E00EC5A7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
80F0F1F91F75805E00EC5A7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand All @@ -36,7 +36,7 @@
80F0F20F1F75831800EC5A7A /* NSObject-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject-Protocol.h"; sourceTree = "<group>"; };
80F0F2101F75832800EC5A7A /* NSEvent-PIPExtensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSEvent-PIPExtensions.h"; sourceTree = "<group>"; };
80F0F2111F75833600EC5A7A /* CDStructures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDStructures.h; sourceTree = "<group>"; };
80F0F2121F75874D00EC5A7A /* LMVideoWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LMVideoWindowController.swift; sourceTree = "<group>"; };
80F0F2121F75874D00EC5A7A /* PiPControlWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PiPControlWindowController.swift; sourceTree = "<group>"; };
80F0F2141F758CD100EC5A7A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */

Expand All @@ -55,6 +55,21 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
80B32F7A1F7C136700CEA192 /* PIP */ = {
isa = PBXGroup;
children = (
80F0F20A1F75820400EC5A7A /* BetterPiP-Bridging-Header.h */,
80F0F20B1F75829200EC5A7A /* PIPViewController.h */,
80F0F20C1F7582B500EC5A7A /* PIPViewControllerDelegate.h */,
80F0F20D1F7582EA00EC5A7A /* PIPPanel.h */,
80F0F20E1F75830A00EC5A7A /* NSViewControllerPresentationAnimator-Protocol.h */,
80F0F20F1F75831800EC5A7A /* NSObject-Protocol.h */,
80F0F2101F75832800EC5A7A /* NSEvent-PIPExtensions.h */,
80F0F2111F75833600EC5A7A /* CDStructures.h */,
);
path = PIP;
sourceTree = "<group>";
};
80F0F1E41F75805E00EC5A7A = {
isa = PBXGroup;
children = (
Expand All @@ -76,20 +91,13 @@
isa = PBXGroup;
children = (
80F0F1F01F75805E00EC5A7A /* AppDelegate.swift */,
80F0F1F21F75805E00EC5A7A /* ViewController.swift */,
80F0F2121F75874D00EC5A7A /* LMVideoWindowController.swift */,
80F0F2121F75874D00EC5A7A /* PiPControlWindowController.swift */,
80F0F1F21F75805E00EC5A7A /* PiPControlViewController.swift */,
80F0F1F41F75805E00EC5A7A /* Assets.xcassets */,
80F0F1F61F75805E00EC5A7A /* Main.storyboard */,
80F0F1F91F75805E00EC5A7A /* Info.plist */,
80F0F2001F75808200EC5A7A /* PIP.framework */,
80F0F20A1F75820400EC5A7A /* BetterPiP-Bridging-Header.h */,
80F0F20B1F75829200EC5A7A /* PIPViewController.h */,
80F0F20C1F7582B500EC5A7A /* PIPViewControllerDelegate.h */,
80F0F20D1F7582EA00EC5A7A /* PIPPanel.h */,
80F0F20E1F75830A00EC5A7A /* NSViewControllerPresentationAnimator-Protocol.h */,
80F0F20F1F75831800EC5A7A /* NSObject-Protocol.h */,
80F0F2101F75832800EC5A7A /* NSEvent-PIPExtensions.h */,
80F0F2111F75833600EC5A7A /* CDStructures.h */,
80B32F7A1F7C136700CEA192 /* PIP */,
);
path = BetterPiP;
sourceTree = "<group>";
Expand Down Expand Up @@ -176,9 +184,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
80F0F1F31F75805E00EC5A7A /* ViewController.swift in Sources */,
80F0F1F31F75805E00EC5A7A /* PiPControlViewController.swift in Sources */,
80F0F1F11F75805E00EC5A7A /* AppDelegate.swift in Sources */,
80F0F2131F75874D00EC5A7A /* LMVideoWindowController.swift in Sources */,
80F0F2131F75874D00EC5A7A /* PiPControlWindowController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -302,7 +310,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mateffy.BetterPiP;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "BetterPiP/BetterPiP-Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "BetterPiP/PIP/BetterPiP-Bridging-Header.h";
SWIFT_VERSION = 3.0;
};
name = Debug;
Expand All @@ -321,7 +329,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mateffy.BetterPiP;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "BetterPiP/BetterPiP-Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "BetterPiP/PIP/BetterPiP-Bridging-Header.h";
SWIFT_VERSION = 3.0;
};
name = Release;
Expand Down
48 changes: 31 additions & 17 deletions xcode/BetterPiP/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,44 @@ import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

var main: LMVideoWindowController!

override func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool {
return key == "videos"
}

var main: PiPControlWindowController!
let statusItem = NSStatusBar.system().statusItem(withLength:NSSquareStatusItemLength)

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application

let appleEventManager = NSAppleEventManager.shared()
appleEventManager.setEventHandler(self, andSelector: #selector(handleURL), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))

// main = NSStoryboard(name : "Main", bundle: nil).instantiateController(withIdentifier: "mainWindow") as! LMVideoWindowController
if let button = statusItem.button {
button.image = NSImage(named: NSImage.Name(string: "StatusBarButtonImage") as String)
}

let menu = NSMenu()

menu.addItem(NSMenuItem(title: "Install Chrome Extension", action: #selector(openChromeExtensionPage), keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Quit BetterPiP", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))

statusItem.menu = menu
}

func handleURL(event: NSAppleEventDescriptor, reply: NSAppleEventDescriptor) {
let window = NSStoryboard(name : "Main", bundle: nil).instantiateController(withIdentifier: "mainWindow") as! LMVideoWindowController
let window = NSStoryboard(name : "Main", bundle: nil).instantiateController(withIdentifier: "mainWindow") as! PiPControlWindowController

let url = URL(string: (event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue)!)
print("REAL URL: \(url)")

let queryUrl: String = ((url?.queryParameters?["url"]!)!).removingPercentEncoding!
print("URL: \(queryUrl)")
let startTimeString: String = (url?.queryParameters?["time"])!
var startTime: Float = 0.0;

window.showVideo(url: URL(string: queryUrl)!, seconds: 0.0)
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
if (startTimeString != "" || startTimeString != "undefined") {
startTime = Float(startTimeString)!
}

print("Received URL: \(queryUrl)")
print("Start at: \(startTime)")

window.showVideo(url: URL(string: queryUrl)!, seconds: startTime)
}

func notify(message: String) {
Expand All @@ -50,10 +58,16 @@ class AppDelegate: NSObject, NSApplicationDelegate {
notification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(notification)
}

func openChromeExtensionPage() {
if let url = URL(string: "https://www.google.com"), NSWorkspace.shared().open(url) {
print("default browser was successfully opened")
}

}
}

extension URL {

public var queryParameters: [String: String]? {
guard let components = URLComponents(url: self, resolvingAgainstBaseURL: true), let queryItems = components.queryItems else {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon.png",
"size" : "128x128",
"scale" : "1x"
},
{
Expand All @@ -42,8 +41,9 @@
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"idiom" : "mac",
"filename" : "full icon.png",
"scale" : "1x"
},
{
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
6 changes: 6 additions & 0 deletions xcode/BetterPiP/Assets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "icon.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b70659a

Please sign in to comment.