Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #71 - initial purchase support for linux and chrome with html 5 youtube player #73

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ nosetests.xml
.mr.developer.cfg
.project
.pydevproject

# pydev
.settings
70 changes: 70 additions & 0 deletions plugin/YouTubeBrowser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'''
YouTube plugin for XBMC
Copyright (C) 2010-2012 Tobias Ussing And Henrik Mosgaard Jensen

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''

import sys

# Some of this code has been taken from
# https://github.com/AddonScriptorDE/plugin.program.chrome.launcher
class YouTubeBrowser():
def __init__(self):
self.xbmcaddon = sys.modules["__main__"].xbmcaddon
self.common = sys.modules["__main__"].common
self.xbmc = sys.modules["__main__"].xbmc
self.os = sys.modules["__main__"].os
self.subprocess = sys.modules["__main__"].subprocess

self.osWin = self.xbmc.getCondVisibility('system.platform.windows')
self.osOsx = self.xbmc.getCondVisibility('system.platform.osx')
self.osLinux = self.xbmc.getCondVisibility('system.platform.linux')
self.addon = self.xbmcaddon.Addon()
self.addonPath = self.addon.getAddonInfo('path')

def playVideo(self, videoid):
self.xbmc.executebuiltin('LIRC.Stop')

if self.osLinux:
# the browser.sh has the specific url that is required to work with the specific linux browser
# plus whatever remote control scripting that is required.
path = self.browserPath = self.os.path.join(self.addonPath, 'browser.sh')
self.common.log("Opening %s with videoid %s" % (path, videoid));

self.subprocess.call('"'+path+'" "'+videoid+'"', shell=True)

elif self.osOsx:
# TODO - create external osx specific browser script so this stuff can all
# be customised for specific installations.
url = "https://www.youtube.com/embed/%s?autoplay=1&autohide=1" % videoid
path = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
fullUrl = self.getFullPath(path, url)
else: # self.osWin:
# TODO - create external windows specific browser.bat so this stuff can all
# be customised for specific installations.
url = "https://www.youtube.com/embed/%s?autoplay=1&autohide=1" % videoid
path = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
path64 = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
if self.os.path.exists(path):
fullUrl = self.getFullPath(path, url)
self.subprocess.Popen(fullUrl, shell=True)
elif self.os.path.exists(path64):
fullUrl = self.getFullPath(path, url)
self.subprocess.Popen(fullUrl, shell=True)

self.xbmc.executebuiltin('LIRC.Start')

def getFullPath(self, path, url):
return '"'+path+'" --start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run --kiosk "'+url+'"'
28 changes: 21 additions & 7 deletions plugin/YouTubeNavigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self):
self.storage = sys.modules["__main__"].storage
self.scraper = sys.modules["__main__"].scraper
self.subtitles = sys.modules["__main__"].subtitles

# This list contains the main menu structure the user first encounters when running the plugin
# label , path , thumbnail , login , feed / action
self.categories = (
Expand Down Expand Up @@ -76,6 +76,7 @@ def __init__(self):
{'Title':self.language(30017) ,'path':"/root/playlists" , 'thumbnail':"playlists" , 'login':"true" , 'user_feed':"playlists", 'folder':'true' },
{'Title':self.language(30003) ,'path':"/root/subscriptions" , 'thumbnail':"subscriptions" , 'login':"true" , 'user_feed':"subscriptions", 'folder':'true' },
{'Title':self.language(30004) ,'path':"/root/subscriptions/new" , 'thumbnail':"newsubscriptions" , 'login':"true" , 'user_feed':"newsubscriptions" },
{'Title':self.language(30060) ,'path':"/root/purchases" , 'thumbnail':"purchases" , 'login':"true" , 'scraper':"purchases", 'folder':'true' },
{'Title':self.language(30005) ,'path':"/root/uploads" , 'thumbnail':"uploads" , 'login':"true" , 'user_feed':"uploads" },
{'Title':self.language(30045) ,'path':"/root/downloads" , 'thumbnail':"downloads" , 'login':"false" , 'feed':"downloads" },
{'Title':self.language(30006) ,'path':"/root/search" , 'thumbnail':"search" , 'login':"false" , 'store':"searches", 'folder':'true' },
Expand Down Expand Up @@ -418,17 +419,17 @@ def addVideoListItem(self, params={}, item_params={}, listSize=0):
self.common.log("", 5)
get = params.get
item = item_params.get

icon = item("icon", "default")
if(get("scraper", "").find("music") > -1):
icon = "music"
elif(get("scraper", "").find("disco") > -1):
icon = "discoball"
elif(get("feed", "").find("live") > -1):
icon = "live"

icon = self.utils.getThumbnail(icon)

listitem = self.xbmcgui.ListItem(item("Title"), iconImage=icon, thumbnailImage=item("thumbnail"))

url = '%s?path=%s&action=play_video&videoid=%s' % (sys.argv[0], "/root/video", item("videoid"))
Expand All @@ -441,7 +442,13 @@ def addVideoListItem(self, params={}, item_params={}, listSize=0):
listitem.addContextMenuItems(cm, replaceItems=True)

listitem.setProperty("Video", "true")
listitem.setProperty("IsPlayable", "true")

# the drm param gets dropped by list play list.
if get("drm", "no") == "yes" or item("drm", "no") == "yes":
url += "&drm=yes"
else:
listitem.setProperty("IsPlayable", "true")

listitem.addStreamInfo('video', {'duration': item('Duration')})
listitem.setInfo(type='Video', infoLabels=item_params)
self.xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False, totalItems=listSize + 1)
Expand All @@ -461,8 +468,15 @@ def parseFolderList(self, params, results):

for result_params in results:
result_params["path"] = get("path")
self.addFolderListItem(params, result_params, listSize + 1)

item = result_params.get

# for purchases, we have either single videos or play lists, the only way we can tell
# is by looking for the videoid.
if len(item("videoid", "")) > 0:
self.addVideoListItem(params, result_params, 0)
else:
self.addFolderListItem(params, result_params, listSize + 1)

self.xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True, cacheToDisc=cache)
self.common.log("Done", 5)

Expand Down
9 changes: 7 additions & 2 deletions plugin/YouTubePlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class YouTubePlayer():
urls['embed_stream'] = "http://www.youtube.com/get_video_info?video_id=%s"
urls['video_info'] = "http://gdata.youtube.com/feeds/api/videos/%s"


def __init__(self):
self.xbmc = sys.modules["__main__"].xbmc
self.xbmcgui = sys.modules["__main__"].xbmcgui
self.xbmcplugin = sys.modules["__main__"].xbmcplugin

Expand All @@ -74,13 +74,18 @@ def __init__(self):
self.core = sys.modules["__main__"].core
self.login = sys.modules["__main__"].login
self.subtitles = sys.modules["__main__"].subtitles
self.browser = sys.modules["__main__"].browser

self.algoCache = {}

def playVideo(self, params={}):
self.common.log(repr(params), 3)
get = params.get


if get("drm", "no") == "yes":
self.browser.playVideo(get("videoid"))
return True

(video, status) = self.buildVideoObject(params)

if status != 200:
Expand Down
47 changes: 46 additions & 1 deletion plugin/YouTubeScraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import sys
import urllib


class YouTubeScraper():
urls = {}
urls['disco_main'] = "http://www.youtube.com/disco"
Expand All @@ -29,6 +28,7 @@ class YouTubeScraper():
urls['liked_videos'] = "http://www.youtube.com/my_liked_videos"
urls['music'] = "http://www.youtube.com/music"
urls['playlist'] = "http://www.youtube.com/view_play_list?p=%s"
urls['purchases'] = "http://www.youtube.com/purchases"

def __init__(self):
self.settings = sys.modules["__main__"].settings
Expand All @@ -44,6 +44,48 @@ def __init__(self):
self.feeds = sys.modules["__main__"].feeds
self.storage = sys.modules["__main__"].storage

#=================================== Purchases Scraper ============================================

def scrapeUserPurchases(self, params):
self.common.log("")

url = self.createUrl(params)

result = self.core._fetchPage({"link": url, "login": "true"})

contents = self.common.parseDOM(result["content"], "ul", {"class": "purchases-items-list"})
contents = self.common.parseDOM(contents, "li", {"class": "purchases-item"})

playlist_items = []
for content in contents:
item = {}
item['drm'] = 'yes'

datathumb = self.common.parseDOM(content, "img", ret="data-thumb");
if (len(datathumb) > 0):
item['thumbnail'] = datathumb[0];
else:
item['thumbnail'] = self.common.parseDOM(content, "img", ret="src")[0];

item['thumbnail'] = item['thumbnail'].replace("https://", "http://");

content = self.common.parseDOM(content, "div", {"class": "purchases-video-title"})[0]

item['Title'] = self.common.replaceHTMLCodes(self.common.parseDOM(content, "a")[0])
href = self.common.parseDOM(content, "a", ret="href")[0]

if (href.rfind("list=") > 0):
item['user_feed'] = 'playlist'
href = href[href.rfind("list=") + len("list="):]
item['playlist'] = href
elif (href.rfind("watch?v=") > 0):
href = href[href.rfind("watch?v=") + len("watch?v="):]
item['videoid'] = href;

playlist_items.append(item);

return (playlist_items, 200)

#=================================== User Scraper ============================================

def scrapeUserLikedVideos(self, params):
Expand Down Expand Up @@ -95,6 +137,9 @@ def getNewResultsFunction(self, params={}):
if (get("scraper") in ["liked_videos", "watched_history"]):
function = self.scrapeUserLikedVideos

if (get("scraper") == "purchases"):
function = self.scrapeUserPurchases

if function:
params["new_results_function"] = function

Expand Down
6 changes: 3 additions & 3 deletions plugin/addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<requires>
<import addon="xbmc.python" version="2.1.0" />
<import addon="script.module.simplejson" version="2.0.10" />
<import addon="script.common.plugin.cache.beta" version="1.5.2" />
<import addon="script.module.parsedom.beta" version="1.5.2" />
<import addon="script.module.simple.downloader.beta" version="0.9.4" />
<import addon="script.common.plugin.cache" version="2.5.2" />
<import addon="script.module.parsedom" version="2.5.2" />
<import addon="script.module.simple.downloader" version="1.9.4" />
</requires>
<extension library="default.py" point="xbmc.python.pluginsource">
<provides>video</provides>
Expand Down
50 changes: 50 additions & 0 deletions plugin/browser.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash

# Prevent loading two or more tabs due to LIRC still being enabled in XBMC / KODI
CHROME_STARTED=`ps -ef | grep google | grep chrome | grep -v "grep" | wc -l`
if [ $CHROME_STARTED -gt 0 ]; then
exit 1;
fi

# lets find out if irxevent and xdotool actually exist before we try to call them.
command -v irxevent >/dev/null 2>&1
IRXEVENT=$?
command -v xdotool >/dev/null 2>&1
XDOTOOL=$?

if [ $IRXEVENT -eq 0 ]; then
killall irxevent >/dev/null 2>&1
fi

url=$1

# notice the ampersand to send google chrome into back ground so that the script continues and we execute the xdotool below
/usr/bin/google-chrome --start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run "$url" &
CHROME_PID=$!

# http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

if [ $IRXEVENT -eq 0 ]; then
# run irxevent as a daemon so that we can call xdotool
irxevent -d $DIR/youtube.lirc &
else
echo "irxevent is not installed, can't do remote control"
fi

if [ $XDOTOOL -eq 0 ]; then
# no point sleeping if xdotool is not installed.
sleep 5
# the 800 800 is just to ensure the mouse is in middle of video but not on any controls by accident
xdotool search "Google Chrome" windowactivate --sync mousemove 800 800 click --repeat 2 1 >/dev/null 2>&1
else
echo "xdotool is not installed, can't do full screen"
fi

# wait for google-chrome to be killed before killing irxevent below. This only works if we execute irxevent as a daemon, otherwise
# the script would never finish.
wait $CHROME_PID

if [ $IRXEVENT -eq 0 ]; then
killall irxevent >/dev/null 2>&1
fi
4 changes: 4 additions & 0 deletions plugin/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import xbmcaddon
import cookielib
import xbmcplugin
import subprocess

try:
import xbmcvfs
except ImportError:
Expand Down Expand Up @@ -96,6 +98,8 @@
feeds = YouTubeFeeds.YouTubeFeeds()
import YouTubeSubtitleControl
subtitles = YouTubeSubtitleControl.YouTubeSubtitleControl()
import YouTubeBrowser
browser = YouTubeBrowser.YouTubeBrowser()
import YouTubePlayer
player = YouTubePlayer.YouTubePlayer()
import SimpleDownloader as downloader
Expand Down
4 changes: 3 additions & 1 deletion plugin/resources/language/English/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<string id="30057">YouTube Education</string>
<string id="30058">Season %s</string>
<string id="30059">My History</string>
<string id="30060">My Purchases</string>

<!-- Plugin settings strings -->
<string id="30200">Username</string>
Expand Down Expand Up @@ -152,7 +153,8 @@
<string id="30286">Show YouTube Music</string>
<string id="30287">Show YouTube Live</string>
<string id="30288">Show YouTube History</string>

<string id="30289">Show Purchases</string>

<!-- Menu strings -->
<string id="30500">Clear refinements</string>
<string id="30501">Download video</string>
Expand Down
1 change: 1 addition & 0 deletions plugin/resources/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<setting id="favorites" type="bool" label="30253" default="true" />
<setting id="playlists" type="bool" label="30254" default="true" />
<setting id="subscriptions" type="bool" label="30255" default="true" />
<setting id="purchases" type="bool" label="30289" default="true" />
<setting id="uploads" type="bool" label="30256" default="true" />
<setting id="downloads" type="bool" label="30257" default="true" />
<setting id="search" type="bool" label="30258" default="true" />
Expand Down
Binary file added plugin/thumbnails/purchases.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading