The branch, eden has been updated
via f26ca15475b4f0784bdbbf1c5237b35273e56f9b (commit)
via c7d172532055301aa80fb43eb4ea81726a9ab37f (commit)
from 1493907613c7b46240d791b6e073cc29ddfb208e (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=f26ca15475b4f0784bdbbf1c5237b35273e56f9b
commit f26ca15475b4f0784bdbbf1c5237b35273e56f9b
Author: spiff <[email protected]>
Date: Sat Apr 28 11:19:06 2012 +0200
[plugin.video.vimeo] updated to version 2.1.0
diff --git a/plugin.video.vimeo/VimeoCore.py b/plugin.video.vimeo/VimeoCore.py
index def6281..d82a175 100755
--- a/plugin.video.vimeo/VimeoCore.py
+++ b/plugin.video.vimeo/VimeoCore.py
@@ -305,9 +305,12 @@ class VimeoCore(object):
per_page = self.common.parseDOM(value, "videos", ret="perpage")
page = self.common.parseDOM(value, "videos", ret="page")
- if int(on_this_page[0]) < int(per_page[0]):
- next = False
- elif int(on_this_page[0]) == int(per_page[0]) and int(per_page[0]) *
int(page[0]) == int(total[0]):
+ if (len(on_this_page) > 0 and len(per_page) > 0):
+ if int(on_this_page[0]) < int(per_page[0]):
+ next = False
+ elif int(on_this_page[0]) == int(per_page[0]) and int(per_page[0])
* int(page[0]) == int(total[0]):
+ next = False
+ else:
next = False
return next
diff --git a/plugin.video.vimeo/VimeoLogin.py b/plugin.video.vimeo/VimeoLogin.py
index 23ee28a..aacdb2b 100644
--- a/plugin.video.vimeo/VimeoLogin.py
+++ b/plugin.video.vimeo/VimeoLogin.py
@@ -19,8 +19,10 @@
import sys
import urllib
import re
+import cookielib
try: import simplejson as json
except ImportError: import json
+import urllib2
# ERRORCODES:
# 0 = Ignore
@@ -85,6 +87,7 @@ class VimeoLogin():
uid = urllib.unquote_plus(cookies[0])
userid = uid.split("|")[0]
+ self.common.log("Done: " + repr(userid))
return userid
def extractCrossSiteScriptingToken(self):
@@ -92,10 +95,38 @@ class VimeoLogin():
result = self.common.fetchPage({"link": "http://vimeo.com/log_in"})
xsrft = self.common.parseDOM(result["content"], "input",
- attrs={"type": "hidden", "id": "xsrft",
"name": "token"},
+ attrs={"id": "xsrft", "name": "token"},
ret="value")
+
+ if len(xsrft) == 0 and result["content"].find("xsrft:") > 0:
+ xsrft =
self.ExtractVersion6CrossSiteScriptingToken(result["content"])
+
+ if len(xsrft) == 0:
+ self.common.log("Failed to find cross site scripting token: " +
repr(result))
+ else:
+ ck = cookielib.Cookie(version=0, name='xsrft', value=xsrft[0],
port=None, port_specified=False, domain='.vimeo.com', domain_specified=True,
domain_initial_dot=True, path='/', path_specified=True, secure=False,
expires=None, discard=False, comment=None, comment_url=None, rest={},
rfc2109=False)
+ sys.modules["__main__"].cookiejar.set_cookie(ck)
+
+ self.common.log("Done: " + repr(xsrft))
return xsrft
+ def ExtractVersion6CrossSiteScriptingToken(self, html):
+ self.common.log("")
+
+ if html.find("xsrft:'") > 0:
+ xsrft = html[html.find("xsrft:'") + len("xsrft:'"):]
+ xsrft = xsrft[:xsrft.find("'")]
+ xsrft = [xsrft]
+ return xsrft
+
+ if html.find("xsrft: '") > 0:
+ xsrft = html[html.find("xsrft: '") + len("xsrft: '"):]
+ xsrft = xsrft[:xsrft.find("'")]
+ xsrft = [xsrft]
+ return xsrft
+
+ return []
+
def performHttpLogin(self, xsrft):
self.common.log("")
request = {'sign_in[email]': self.settings.getSetting("user_email"),
@@ -103,8 +134,7 @@ class VimeoLogin():
'token': xsrft}
self.common.fetchPage({"link": "http://vimeo.com/log_in", "post_data":
request,
- "refering": "http://www.vimeo.com/log_in",
- "cookie": "xsrft=" + xsrft})
+ "refering": "http://www.vimeo.com/log_in"})
self.common.log("Done")
def checkIfHttpLoginFailed(self):
@@ -125,10 +155,10 @@ class VimeoLogin():
def extractLoginTokens(self, auth_url):
self.common.log("")
result = self.common.fetchPage({"link": auth_url})
-
login_oauth_token = self.common.parseDOM(result["content"], "input",
attrs={"type": "hidden", "name": "oauth_token"} , ret="value")
- login_token = self.common.parseDOM(result["content"], "input",
attrs={"type": "hidden", "id": "xsrft", "name": "token"}, ret="value")
+ login_token = self.common.parseDOM(result["content"], "input",
attrs={"type": "hidden", "id": "token", "name": "token"}, ret="value")
+ self.common.log("Done: " + repr((login_oauth_token, login_token)))
return login_oauth_token, login_token
def authorizeAndExtractVerifier(self, login_token, login_oauth_token):
@@ -138,9 +168,7 @@ class VimeoLogin():
'permission': 'write',
'accept': 'Allow'}
- result = self.common.fetchPage({"link":
"http://vimeo.com/oauth/confirmed", "post_data": data})
-
-
+ result = self.common.fetchPage({"link":
"https://vimeo.com/oauth/confirmed", "post_data": data})
verifier = self.common.getParameters(result["new_url"])
return verifier["oauth_verifier"]
@@ -168,7 +196,6 @@ class VimeoLogin():
# part 2 request user specific authorization token
login_oauth_token, login_token = self.extractLoginTokens(auth_url)
-
if len(login_oauth_token) == 0 or len(login_token) == 0:
self.common.log("unable to find oauth tokens: login seems to have
failed")
return (self.language(30606), 303)
@@ -181,20 +208,20 @@ class VimeoLogin():
self.common.log("setting userid: " + repr(userid), 3)
self.settings.setSetting("userid", userid)
-
+
self.common.log("Login success, got verifier: " + verifier, 3)
return (verifier, 200)
def _getAuth(self):
auth = self.settings.getSetting("oauth_token")
- self.common.log("authentication token: " + repr(auth), 5)
+ self.common.log("authentication token: " + repr(auth), 1)
if (auth):
self.common.log("returning stored authentication token")
return auth
else:
-
+ self.common.log("no authentication token found, requesting new
token")
(result, status) = self._login()
if status == 200:
@@ -202,4 +229,4 @@ class VimeoLogin():
return self.settings.getSetting("oauth_token")
self.common.log("couldn't get new authentication token since login
failed")
- return False
\ No newline at end of file
+ return False
diff --git a/plugin.video.vimeo/addon.xml b/plugin.video.vimeo/addon.xml
index ac4bdbc..8fa2906 100644
--- a/plugin.video.vimeo/addon.xml
+++ b/plugin.video.vimeo/addon.xml
@@ -1,19 +1,19 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.vimeo" version="1.3.0" name="Vimeo"
provider-name="TheCollective">
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<addon id='plugin.video.vimeo' version='2.1.0' name='Vimeo'
provider-name='TheCollective'>
<requires>
- <import addon="xbmc.python" version="2.0"/>
- <import addon="script.common.plugin.cache" version="0.9.2"/>
- <import addon="script.module.parsedom" version="0.9.2"/>
- <import addon="script.module.simple.downloader" version="0.9.2"/>
+ <import addon='xbmc.python' version='2.0'/>
+ <import addon='script.common.plugin.cache' version='0.9.2'/>
+ <import addon='script.module.parsedom' version='0.9.2'/>
+ <import addon='script.module.simple.downloader' version='0.9.2'/>
</requires>
- <extension point="xbmc.python.pluginsource" library="default.py">
+ <extension point='xbmc.python.pluginsource' library='default.py'>
<provides>video</provides>
</extension>
- <extension point="xbmc.addon.metadata">
+ <extension point='xbmc.addon.metadata'>
<platform>all</platform>
- <summary lang="en">Vimeo video plugin</summary>
- <description lang="en">Plugin that allows you to browse and view videos
from everybodys favorite alternative video site!</description>
- <summary lang="bg">Ðидео добавка за Vimeo</summary>
- <description lang="bg">ÐобавкаÑа ви позволÑва да
ÑазглеждаÑе и гледаÑе видео клипове оÑ
лÑÐ±Ð¸Ð¼Ð¸Ñ Ð½Ð° вÑиÑки алÑеÑнаÑивен видео
ÑайÑ!</description>
+ <summary lang='en'>Vimeo video plugin</summary>
+ <description lang='en'>Plugin that allows you to browse and view videos
from everybodys favorite alternative video site!</description>
+ <summary lang='bg'>Ðидео добавка за Vimeo</summary>
+ <description lang='bg'>ÐобавкаÑа ви позволÑва да
ÑазглеждаÑе и гледаÑе видео клипове оÑ
лÑÐ±Ð¸Ð¼Ð¸Ñ Ð½Ð° вÑиÑки алÑеÑнаÑивен видео
ÑайÑ!</description>
</extension>
</addon>
diff --git a/plugin.video.vimeo/changelog.txt b/plugin.video.vimeo/changelog.txt
index f19cd49..9286034 100644
--- a/plugin.video.vimeo/changelog.txt
+++ b/plugin.video.vimeo/changelog.txt
@@ -3,12 +3,13 @@
- [XBMC] has Excessive Memory use after running the plugin for prolonged
periods of time
- [Vimeo] Vimeo's implementation of Oauth 1 is time sensetive, meaning that an
incorrectly set system clock will prevent the plugin from logging in
-[B]Todo 2.0.0[/B]
+[B]Todo[/B]
- Implement cache service
- scraper of vimeo's video school if possible
-- Finish refactor
-- Integration tests
-- Unit tests
+- More context menu items to take advantage of new core
+
+[B]Version 2.1.0[/B]
+- Fixed login, after vimeo site changes
[B]Version 2.0.0[/B]
- Added playlist control module to queue videos
diff --git a/plugin.video.vimeo/default.py b/plugin.video.vimeo/default.py
index 68b8678..4ac1311 100644
--- a/plugin.video.vimeo/default.py
+++ b/plugin.video.vimeo/default.py
@@ -8,7 +8,7 @@ import urllib2
import cookielib
# plugin constants
-version = "1.3.0"
+version = "2.1.0"
plugin = "Vimeo-" + version
author = "TheCollective"
url = "www.xbmc.com"
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=c7d172532055301aa80fb43eb4ea81726a9ab37f
commit c7d172532055301aa80fb43eb4ea81726a9ab37f
Author: spiff <[email protected]>
Date: Sat Apr 28 11:16:16 2012 +0200
[plugin.video.youtube] updated to version 2.9.2
diff --git a/plugin.video.youtube/YouTubeCore.py
b/plugin.video.youtube/YouTubeCore.py
index c0f1533..4a0c611 100644
--- a/plugin.video.youtube/YouTubeCore.py
+++ b/plugin.video.youtube/YouTubeCore.py
@@ -416,7 +416,7 @@ class YouTubeCore():
request.add_header('Content-Type', 'application/atom+xml')
request.add_header('Content-Length', str(len(get("request"))))
- if get("proxy") or link.find(self.settings.getSetting("proxy")) > -1:
+ if get("proxy") or (self.settings.getSetting("proxy") != "" and
link.find(self.settings.getSetting("proxy")) > -1):
proxy = self.settings.getSetting("proxy")
referer = proxy[:proxy.rfind("/")]
self.common.log("Added proxy refer: %s" % referer)
diff --git a/plugin.video.youtube/YouTubeLogin.py
b/plugin.video.youtube/YouTubeLogin.py
index ef3cc0e..3d32047 100755
--- a/plugin.video.youtube/YouTubeLogin.py
+++ b/plugin.video.youtube/YouTubeLogin.py
@@ -29,347 +29,337 @@ except ImportError: import json
class YouTubeLogin():
- APIKEY =
"AI39si6hWF7uOkKh4B9OEAX-gK337xbwR9Vax-cdeF9CF9iNAcQftT8NVhEXaORRLHAmHxj6GjM-Prw04odK4FxACFfKkiH9lg"
-
- def __init__(self):
- self.xbmc = sys.modules["__main__"].xbmc
-
- self.settings = sys.modules["__main__"].settings
- self.language = sys.modules["__main__"].language
- self.plugin = sys.modules["__main__"].plugin
- self.dbg = sys.modules["__main__"].dbg
-
- self.utils = sys.modules["__main__"].utils
- self.core = sys.modules["__main__"].core
- self.common = sys.modules["__main__"].common
-
- def login(self, params={}):
- get = params.get
- self.common.log("")
- ouname = self.settings.getSetting("username")
- opass = self.settings.getSetting("user_password")
- self.settings.openSettings()
- uname = self.settings.getSetting("username")
- self.dbg = self.settings.getSetting("debug") == "true"
- result = ""
- status = 500
-
- if uname != "":
- refreshed = False
- if get("new", "false") == "false" and
self.settings.getSetting("oauth2_refresh_token") and ouname == uname and opass
== self.settings.getSetting("user_password"):
- self.common.log("refreshing token: " +
str(refreshed))
- refreshed = self.core._oRefreshToken()
-
- if not refreshed:
- self.common.log("token not refresh, or new
uname or password")
-
-
self.settings.setSetting("oauth2_access_token", "")
-
self.settings.setSetting("oauth2_refresh_token", "")
- self.settings.setSetting("oauth2_expires_at",
"")
- self.settings.setSetting("nick", "")
- (result, status) = self._httpLogin({"new":
"true"})
-
- if status == 200:
- (result, status) = self._apiLogin()
-
- if status == 200:
-
self.utils.showErrorMessage(self.language(30031), result, 303)
- else:
-
self.utils.showErrorMessage(self.language(30609), result, status)
-
- self.xbmc.executebuiltin("Container.Refresh")
- return (result, status)
-
- def _apiLogin(self, error=0):
- self.common.log("errors: " + str(error))
+ APIKEY =
"AI39si6hWF7uOkKh4B9OEAX-gK337xbwR9Vax-cdeF9CF9iNAcQftT8NVhEXaORRLHAmHxj6GjM-Prw04odK4FxACFfKkiH9lg"
+
+ def __init__(self):
+ self.xbmc = sys.modules["__main__"].xbmc
+
+ self.settings = sys.modules["__main__"].settings
+ self.language = sys.modules["__main__"].language
+ self.plugin = sys.modules["__main__"].plugin
+ self.dbg = sys.modules["__main__"].dbg
+
+ self.utils = sys.modules["__main__"].utils
+ self.core = sys.modules["__main__"].core
+ self.common = sys.modules["__main__"].common
+
+ def login(self, params={}):
+ get = params.get
+ self.common.log("")
+ ouname = self.settings.getSetting("username")
+ opass = self.settings.getSetting("user_password")
+ self.settings.openSettings()
+ uname = self.settings.getSetting("username")
+ self.dbg = self.settings.getSetting("debug") == "true"
+ result = ""
+ status = 500
+
+ if uname != "":
+ refreshed = False
+ if get("new", "false") == "false" and
self.settings.getSetting("oauth2_refresh_token") and ouname == uname and opass
== self.settings.getSetting("user_password"):
+ self.common.log("refreshing token: " + str(refreshed))
+ refreshed = self.core._oRefreshToken()
+
+ if not refreshed:
+ self.common.log("token not refresh, or new uname or password")
- self.settings.setSetting("oauth2_expires_at", "")
self.settings.setSetting("oauth2_access_token", "")
self.settings.setSetting("oauth2_refresh_token", "")
+ self.settings.setSetting("oauth2_expires_at", "")
+ self.settings.setSetting("nick", "")
+ (result, status) = self._httpLogin({"new": "true"})
- url =
"https://accounts.google.com/o/oauth2/auth?client_id=208795275779.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=http%3A%2F%2Fgdata.youtube.com&response_type=code"
-
- logged_in = False
- fetch_options = {"link": url, "no-language-cookie": "true"}
- step = 0
- self.common.log("Part A")
- while not logged_in and fetch_options and step < 6:
- self.common.log("Step : " + str(step))
- step += 1
-
- ret = self.core._fetchPage(fetch_options)
- fetch_options = False
-
- newurl = self.common.parseDOM(ret["content"], "form",
attrs={"method": "POST"}, ret="action")
- state_wrapper = self.common.parseDOM(ret["content"],
"input", attrs={"id": "state_wrapper"}, ret="value")
-
- if len(newurl) > 0 and len(state_wrapper) > 0:
- url_data = {"state_wrapper": state_wrapper[0],
- "submit_access": "true"}
-
- fetch_options = {"link":
newurl[0].replace("&", "&"), "url_data": url_data, "no-language-cookie":
"true"}
- self.common.log("Part B")
- continue
-
- code = self.common.parseDOM(ret["content"],
"textarea", attrs={"id": "code"})
- if len(code) > 0:
- url =
"https://accounts.google.com/o/oauth2/token"
- url_data = {"client_id":
"208795275779.apps.googleusercontent.com",
- "client_secret":
"sZn1pllhAfyonULAWfoGKCfp",
- "code": code[0],
- "redirect_uri":
"urn:ietf:wg:oauth:2.0:oob",
- "grant_type":
"authorization_code"}
- fetch_options = {"link": url, "url_data":
url_data}
- self.common.log("Part C")
- continue
-
- # use token
- if ret["content"].find("access_token") > -1:
- self.common.log("Part D")
- oauth = json.loads(ret["content"])
-
- if len(oauth) > 0:
- self.common.log("Part D " +
repr(oauth["expires_in"]))
-
self.settings.setSetting("oauth2_expires_at", str(int(oauth["expires_in"]) +
time.time()))
-
self.settings.setSetting("oauth2_access_token", oauth["access_token"])
-
self.settings.setSetting("oauth2_refresh_token", oauth["refresh_token"])
-
- logged_in = True
- self.common.log("Done:" +
self.settings.getSetting("username"))
-
- if logged_in:
- return (self.language(30030), 200)
- else:
- self.common.log("Failed")
- return (self.language(30609), 303)
-
- def _httpLogin(self, params={}):
- get = params.get
- self.common.log("")
- status = 500
-
- if get("new", "false") == "true" or get("page", "false") !=
"false":
- self.settings.setSetting("login_info", "")
- self.settings.setSetting("SID", "")
- elif self.settings.getSetting("login_info") != "":
- self.common.log("returning existing login info: " +
self.settings.getSetting("login_info"))
- return (self.settings.getSetting("login_info"), 200)
-
- fetch_options = {"link": get("link",
"http://www.youtube.com/")}
-
- step = 0
- galx = ""
- ret = {}
-
- while fetch_options and step < 18: # 6 steps for 2-factor
login
- self.common.log("Step : " + str(step))
- step += 1
-
- if step == 17:
- return (self.core._findErrors(ret), 303)
-
- ret = self.core._fetchPage(fetch_options)
-
- if ret["content"].find("captcha") > -1:
- self.common.log("Captcha needs to be filled")
- break
- fetch_options = False
-
- # Check if we are logged in.
- nick = self.common.parseDOM(ret["content"], "span",
attrs={"class": "masthead-user-username"})
- if len(nick) == 0:
- nick = self.common.parseDOM(ret["content"],
"p", attrs={"id": "masthead-expanded-menu-email"})
-
- # Check if there are any errors to report
- errors = self.core._findErrors(ret, silent=True)
- if errors:
- if errors.find("The code you entered didn") ==
-1 or (errors.find("The code you entered didn") > -1 and step > 12):
- self.common.log("Returning error: " +
repr(errors))
- return (errors, 303)
-
- if len(nick) > 0:
- self.common.log("Logged in. Parsing data.")
- status = self._getLoginInfo(ret["content"])
- return(ret, status)
-
- # Click login link on youtube.com
- newurl = self.common.parseDOM(ret["content"], "a",
attrs={"class": "end"}, ret="href")
-
- if len(newurl) > 0:
- # Start login procedure
- if newurl[0] != "#":
- fetch_options = {"link":
newurl[0].replace("&", "&"), "referer": ret["location"]}
- self.common.log("Part A : " +
repr(fetch_options))
-
- # Fill out login information and send.
- newurl =
self.common.parseDOM(ret["content"].replace("\n", " "), "form", attrs={"id":
"gaia_loginform"}, ret="action")
- if len(newurl) > 0:
- (galx, url_data) =
self._fillLoginInfo(ret["content"])
- if len(galx) > 0 and len(url_data) > 0:
- fetch_options = {"link": newurl[0],
"no-language-cookie": "true", "url_data": url_data, "hidden": "true",
"referer": ret["location"]}
- self.common.log("Part B")
- self.common.log("fetch options: " +
repr(fetch_options), 10) # WARNING, SHOWS LOGIN INFO/PASSWORD
- continue
-
- newurl = self.common.parseDOM(ret["content"], "meta",
attrs={"http-equiv": "refresh"}, ret="content")
-
- if len(newurl) > 0:
- newurl = newurl[0].replace("&", "&")
- newurl = newurl[newurl.find("'") +
5:newurl.rfind("'")]
- fetch_options = {"link": newurl,
"no-language-cookie": "true", "referer": ret["location"]}
- self.common.log("Part C: " +
repr(fetch_options))
- continue
-
- ## 2-factor login start
- if ret["content"].find("smsUserPin") > -1:
- url_data = self._fillUserPin(ret["content"])
- if len(url_data) == 0:
- return (False, 500)
-
- target_url = ret["new_url"]
- if target_url.rfind("/") > 10:
- target_url =
target_url[:target_url.find("/", 10)]
- else:
- target_url += "/"
-
- new_part =
self.common.parseDOM(ret["content"], "form", attrs={"name": "verifyForm"},
ret="action")
- fetch_options = {"link": target_url +
new_part[0], "url_data": url_data, "no-language-cookie": "true", "referer":
ret["location"]}
-
- self.common.log("Part D: " +
repr(fetch_options))
- continue
-
- smsToken =
self.common.parseDOM(ret["content"].replace("\n", ""), "input", attrs={"name":
"smsToken"}, ret="value")
- cont = self.common.parseDOM(ret["content"], "input",
attrs={"name": "continue"}, ret="value")
-
- if len(cont) > 0 and len(smsToken) > 0 and galx != "":
- url_data = {"smsToken": smsToken[0],
- "continue": cont[0],
- "PersistentCookie": "yes",
- "service": "youtube",
- "GALX": galx}
-
- target_url =
self.common.parseDOM(ret["content"], "form", attrs={"name": "hiddenpost"},
ret="action")
- fetch_options = {"link": target_url[0],
"url_data": url_data, "no-language-cookie": "true", "referer": ret["location"]}
- self.common.log("Part E: " +
repr(fetch_options))
- continue
-
- ## 2-factor login finish
- if not fetch_options:
- # Check for errors.
- return (self.core._findErrors(ret), 303)
-
- return (ret, status)
-
- def _fillLoginInfo(self, content):
- rmShown = self.common.parseDOM(content, "input",
attrs={"name": "rmShown"}, ret="value")
- cont = self.common.parseDOM(content, "input", attrs={"name":
"continue"}, ret="value")
- uilel = self.common.parseDOM(content, "input", attrs={"name":
"uilel"}, ret="value")
- if len(uilel) == 0:
- uilel = self.common.parseDOM(content, "input", attrs=
{"id":"uilel"}, ret="value")
- dsh = self.common.parseDOM(content, "input", attrs={"name":
"dsh"}, ret="value")
- if len(dsh) == 0:
- dsh = self.common.parseDOM(content, "input",
attrs={"id": "dsh"}, ret="value")
-
- # Can we get this elsewhere?
- galx = self.common.parseDOM(content, "input", attrs={"name":
"GALX"}, ret="value")
- uname = self.settings.getSetting("username")
- pword = self.settings.getSetting("user_password")
-
- if pword == "":
- pword = self.common.getUserInput(self.language(30628),
hidden=True)
-
- if len(galx) == 0 or len(cont) == 0 or len(uilel) == 0 or
len(dsh) == 0 or len(rmShown) == 0 or uname == "" or pword == "":
- self.common.log("_fillLoginInfo missing values for
login form " + repr(galx) + repr(cont) + repr(uilel) + repr(dsh) +
repr(rmShown) + repr(uname) + str(len(pword)))
- return ("", {})
- else:
- galx = galx[0]
- url_data = {"pstMsg": "0",
- "ltmpl": "sso",
- "dnConn": "",
- "continue": cont[0],
- "service": "youtube",
- "uilel": uilel[0],
- "dsh": dsh[0],
- "hl": "en_US",
- "timeStmp": "",
- "secTok": "",
- "GALX": galx,
- "Email": uname,
- "Passwd": pword,
- "PersistentCookie": "yes",
- "rmShown": rmShown[0],
- "signin": "Sign in",
- "asts": ""
- }
- return (galx, url_data)
-
- def _fillUserPin(self, content):
- smsToken = self.common.parseDOM(content, "input",
attrs={"name": "smsToken"}, ret="value")
- self.smsToken = smsToken
- email = self.common.parseDOM(content, "input", attrs={"name":
"email"}, ret="value")
- userpin = self.common.getUserInputNumbers(self.language(30627))
-
- if len(userpin) > 0:
- url_data = {"smsToken": smsToken[0],
- "PersistentCookie": "yes",
- "smsUserPin": userpin,
- "smsVerifyPin": "Verify",
- "timeStmp": "",
- "secTok": "",
- "email": email[0]}
- return url_data
- else:
- self.common.log("Replace this with a message telling users
that they didn't enter a pin")
- return {}
-
- def _getCookieInfoAsHTML(self):
- cookie = repr(sys.modules["__main__"].cookiejar)
- self.common.log("Cookiejar: " + cookie)
- if cookie == '<_LWPCookieJar.LWPCookieJar[]>':
- return ""
-
- cookie = cookie.replace("<_LWPCookieJar.LWPCookieJar[", "")
- cookie = cookie.replace("), Cookie(version=0,",
"></cookie><cookie ")
- cookie = cookie.replace(")]>", "></cookie>")
- cookie = cookie.replace("Cookie(version=0,", "<cookie ")
- cookie = cookie.replace(", ", " ")
- return cookie
-
- def _getLoginInfo(self, content):
- self.common.log("")
- nick = ""
- status = 303
- nick = self.common.parseDOM(content, "span", attrs={"class":
"masthead-user-username"})
- if len(nick) == 0:
- nick = self.common.parseDOM(content, "p", attrs={"id":
"masthead-expanded-menu-email"})
-
- if len(nick) > 0:
- self.settings.setSetting("nick", nick[0])
- else:
- self.common.log("Failed to get usename from youtube")
-
- # Save cookiefile in settings
-
- login_info = ""
- SID = ""
- cookies = self._getCookieInfoAsHTML()
- login_info = self.common.parseDOM(cookies, "cookie",
attrs={"name": "LOGIN_INFO"}, ret="value")
- SID = self.common.parseDOM(cookies, "cookie", attrs={"name":
"SID", "domain": ".youtube.com"}, ret="value")
-
- if len(login_info) == 1:
- self.common.log("LOGIN_INFO: " + repr(login_info))
- self.settings.setSetting("login_info", login_info[0])
- else:
- self.common.log("Failed to get LOGIN_INFO from
youtube")
+ if status == 200:
+ (result, status) = self._apiLogin()
- if len(SID) == 1:
- self.common.log("SID: " + repr(SID))
- self.settings.setSetting("SID", SID[0])
+ if status == 200:
+ self.utils.showErrorMessage(self.language(30031), result,
303)
else:
- self.common.log("Failed to get SID from youtube")
-
- if len(SID) == 1 and len(login_info) == 1:
- status = 200
-
- self.common.log("Done")
- return status
+ self.utils.showErrorMessage(self.language(30609), result,
status)
+
+ self.xbmc.executebuiltin("Container.Refresh")
+ return (result, status)
+
+ def _apiLogin(self, error=0):
+ self.common.log("errors: " + str(error))
+
+ self.settings.setSetting("oauth2_expires_at", "")
+ self.settings.setSetting("oauth2_access_token", "")
+ self.settings.setSetting("oauth2_refresh_token", "")
+
+ url =
"https://accounts.google.com/o/oauth2/auth?client_id=208795275779.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=http%3A%2F%2Fgdata.youtube.com&response_type=code"
+
+ logged_in = False
+ fetch_options = {"link": url, "no-language-cookie": "true"}
+ step = 0
+ self.common.log("Part A")
+ while not logged_in and fetch_options and step < 6:
+ self.common.log("Step : " + str(step))
+ step += 1
+
+ ret = self.core._fetchPage(fetch_options)
+ fetch_options = False
+
+ newurl = self.common.parseDOM(ret["content"], "form",
attrs={"method": "POST"}, ret="action")
+ state_wrapper = self.common.parseDOM(ret["content"], "input",
attrs={"id": "state_wrapper"}, ret="value")
+
+ if len(newurl) > 0 and len(state_wrapper) > 0:
+ url_data = {"state_wrapper": state_wrapper[0],
+ "submit_access": "true"}
+
+ fetch_options = {"link": newurl[0].replace("&", "&"),
"url_data": url_data, "no-language-cookie": "true"}
+ self.common.log("Part B")
+ continue
+
+ code = self.common.parseDOM(ret["content"], "textarea",
attrs={"id": "code"})
+ if len(code) > 0:
+ url = "https://accounts.google.com/o/oauth2/token"
+ url_data = {"client_id":
"208795275779.apps.googleusercontent.com",
+ "client_secret": "sZn1pllhAfyonULAWfoGKCfp",
+ "code": code[0],
+ "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
+ "grant_type": "authorization_code"}
+ fetch_options = {"link": url, "url_data": url_data}
+ self.common.log("Part C")
+ continue
+
+ # use token
+ if ret["content"].find("access_token") > -1:
+ self.common.log("Part D")
+ oauth = json.loads(ret["content"])
+
+ if len(oauth) > 0:
+ self.common.log("Part D " + repr(oauth["expires_in"]))
+ self.settings.setSetting("oauth2_expires_at",
str(int(oauth["expires_in"]) + time.time()))
+ self.settings.setSetting("oauth2_access_token",
oauth["access_token"])
+ self.settings.setSetting("oauth2_refresh_token",
oauth["refresh_token"])
+
+ logged_in = True
+ self.common.log("Done:" +
self.settings.getSetting("username"))
+
+ if logged_in:
+ return (self.language(30030), 200)
+ else:
+ self.common.log("Failed")
+ return (self.language(30609), 303)
+
+ def _httpLogin(self, params={}):
+ get = params.get
+ self.common.log("")
+ status = 500
+
+ if get("new", "false") == "true" or get("page", "false") != "false":
+ self.settings.setSetting("login_info", "")
+ self.settings.setSetting("SID", "")
+ elif self.settings.getSetting("login_info") != "":
+ self.common.log("returning existing login info: " +
self.settings.getSetting("login_info"))
+ return (self.settings.getSetting("login_info"), 200)
+
+ fetch_options = {"link": get("link", "http://www.youtube.com/")}
+
+ step = 0
+ galx = ""
+ ret = {}
+
+ while fetch_options and step < 18: # 6 steps for 2-factor login
+ self.common.log("Step : " + str(step))
+ step += 1
+
+ if step == 17:
+ return (self.core._findErrors(ret), 303)
+
+ ret = self.core._fetchPage(fetch_options)
+
+ if ret["content"].find("captcha") > -1:
+ self.common.log("Captcha needs to be filled")
+ break
+ fetch_options = False
+
+ # Check if we are logged in.
+ nick = self.common.parseDOM(ret["content"], "span",
attrs={"class": "masthead-user-username"})
+ if len(nick) == 0:
+ nick = self.common.parseDOM(ret["content"], "p", attrs={"id":
"masthead-expanded-menu-email"})
+
+ # Check if there are any errors to report
+ errors = self.core._findErrors(ret, silent=True)
+ if errors:
+ if errors.find("cookie-clear-message-1") == -1 and
(errors.find("The code you entered didn") == -1 or (errors.find("The code you
entered didn") > -1 and step > 12)):
+ self.common.log("Returning error: " + repr(errors))
+ return (errors, 303)
+
+ if len(nick) > 0:
+ self.common.log("Logged in. Parsing data.")
+ status = self._getLoginInfo(ret["content"])
+ return(ret, status)
+
+ # Click login link on youtube.com
+ newurl = self.common.parseDOM(ret["content"], "a", attrs={"class":
"end"}, ret="href")
+ if len(newurl) > 0:
+ # Start login procedure
+ if newurl[0] != "#":
+ fetch_options = {"link": newurl[0].replace("&", "&"),
"referer": ret["location"]}
+ self.common.log("Part A : " + repr(fetch_options))
+
+ # Fill out login information and send.
+ newurl = self.common.parseDOM(ret["content"].replace("\n", " "),
"form", attrs={"id": "gaia_loginform"}, ret="action")
+ if len(newurl) > 0:
+ (galx, url_data) = self._fillLoginInfo(ret["content"])
+ if len(galx) > 0 and len(url_data) > 0:
+ fetch_options = {"link": newurl[0], "no-language-cookie":
"true", "url_data": url_data, "hidden": "true", "referer": ret["location"]}
+ self.common.log("Part B")
+ self.common.log("fetch options: " + repr(fetch_options),
10) # WARNING, SHOWS LOGIN INFO/PASSWORD
+ continue
+
+ newurl = self.common.parseDOM(ret["content"], "meta",
attrs={"http-equiv": "refresh"}, ret="content")
+ if len(newurl) > 0:
+ newurl = newurl[0].replace("&", "&")
+ newurl = newurl[newurl.find("'") + 5:newurl.rfind("'")]
+ fetch_options = {"link": newurl, "no-language-cookie": "true",
"referer": ret["location"]}
+ self.common.log("Part C: " + repr(fetch_options))
+ continue
+
+ ## 2-factor login start
+ if ret["content"].find("smsUserPin") > -1:
+ url_data = self._fillUserPin(ret["content"])
+ if len(url_data) == 0:
+ return (False, 500)
+
+ new_part = self.common.parseDOM(ret["content"], "form",
attrs={"name": "verifyForm"}, ret="action")
+ fetch_options = {"link": new_part[0], "url_data": url_data,
"no-language-cookie": "true", "referer": ret["location"]}
+
+ self.common.log("Part D: " + repr(fetch_options))
+ continue
+
+ smsToken = self.common.parseDOM(ret["content"].replace("\n", ""),
"input", attrs={"name": "smsToken"}, ret="value")
+
+ if len(smsToken) > 0 and galx != "":
+ url_data = {"smsToken": smsToken[0],
+ "PersistentCookie": "yes",
+ "service": "youtube",
+ "GALX": galx}
+
+ target_url = self.common.parseDOM(ret["content"], "form",
attrs={"name": "hiddenpost"}, ret="action")
+ fetch_options = {"link": target_url[0], "url_data": url_data,
"no-language-cookie": "true", "referer": ret["location"]}
+ self.common.log("Part E: " + repr(fetch_options))
+ continue
+
+ ## 2-factor login finish
+ if not fetch_options:
+ # Check for errors.
+ return (self.core._findErrors(ret), 303)
+
+ return (ret, status)
+
+ def _fillLoginInfo(self, content):
+ rmShown = self.common.parseDOM(content, "input", attrs={"name":
"rmShown"}, ret="value")
+ cont = self.common.parseDOM(content, "input", attrs={"name":
"continue"}, ret="value")
+ uilel = self.common.parseDOM(content, "input", attrs={"name":
"uilel"}, ret="value")
+ if len(uilel) == 0:
+ uilel = self.common.parseDOM(content, "input", attrs=
{"id":"uilel"}, ret="value")
+ dsh = self.common.parseDOM(content, "input", attrs={"name": "dsh"},
ret="value")
+ if len(dsh) == 0:
+ dsh = self.common.parseDOM(content, "input", attrs={"id": "dsh"},
ret="value")
+
+ # Can we get this elsewhere?
+ galx = self.common.parseDOM(content, "input", attrs={"name": "GALX"},
ret="value")
+ uname = self.settings.getSetting("username")
+ pword = self.settings.getSetting("user_password")
+
+ if pword == "":
+ pword = self.common.getUserInput(self.language(30628), hidden=True)
+
+ if len(galx) == 0 or len(cont) == 0 or len(uilel) == 0 or len(dsh) ==
0 or len(rmShown) == 0 or uname == "" or pword == "":
+ self.common.log("_fillLoginInfo missing values for login form " +
repr(galx) + repr(cont) + repr(uilel) + repr(dsh) + repr(rmShown) + repr(uname)
+ str(len(pword)))
+ return ("", {})
+ else:
+ galx = galx[0]
+ url_data = {"pstMsg": "0",
+ "ltmpl": "sso",
+ "dnConn": "",
+ "continue": cont[0],
+ "service": "youtube",
+ "uilel": uilel[0],
+ "dsh": dsh[0],
+ "hl": "en_US",
+ "timeStmp": "",
+ "secTok": "",
+ "GALX": galx,
+ "Email": uname,
+ "Passwd": pword,
+ "PersistentCookie": "yes",
+ "rmShown": rmShown[0],
+ "signin": "Sign in",
+ "asts": ""
+ }
+ return (galx, url_data)
+
+ def _fillUserPin(self, content):
+ self.common.log(repr(content), 5)
+ smsToken = self.common.parseDOM(content, "input", attrs={"name":
"smsToken"}, ret="value")
+ self.smsToken = smsToken
+ userpin = self.common.getUserInputNumbers(self.language(30627))
+
+ if len(userpin) > 0:
+ url_data = {"smsToken": smsToken[0],
+ "PersistentCookie": "yes",
+ "smsUserPin": userpin,
+ "smsVerifyPin": "Verify",
+ "timeStmp": "",
+ "secTok": ""}
+ self.common.log("Done: " + repr(url_data))
+ return url_data
+ else:
+ self.common.log("Replace this with a message telling users that
they didn't enter a pin")
+ return {}
+
+ def _getCookieInfoAsHTML(self):
+ cookie = repr(sys.modules["__main__"].cookiejar)
+ self.common.log("Cookiejar: " + cookie)
+ if cookie == '<_LWPCookieJar.LWPCookieJar[]>':
+ return ""
+
+ cookie = cookie.replace("<_LWPCookieJar.LWPCookieJar[", "")
+ cookie = cookie.replace("), Cookie(version=0,", "></cookie><cookie ")
+ cookie = cookie.replace(")]>", "></cookie>")
+ cookie = cookie.replace("Cookie(version=0,", "<cookie ")
+ cookie = cookie.replace(", ", " ")
+ return cookie
+
+ def _getLoginInfo(self, content):
+ self.common.log("")
+ nick = ""
+ status = 303
+ nick = self.common.parseDOM(content, "span", attrs={"class":
"masthead-user-username"})
+ if len(nick) == 0:
+ nick = self.common.parseDOM(content, "p", attrs={"id":
"masthead-expanded-menu-email"})
+
+ if len(nick) > 0:
+ self.settings.setSetting("nick", nick[0])
+ else:
+ self.common.log("Failed to get usename from youtube")
+
+ # Save cookiefile in settings
+
+ login_info = ""
+ SID = ""
+ cookies = self._getCookieInfoAsHTML()
+ login_info = self.common.parseDOM(cookies, "cookie", attrs={"name":
"LOGIN_INFO"}, ret="value")
+ SID = self.common.parseDOM(cookies, "cookie", attrs={"name": "SID",
"domain": ".youtube.com"}, ret="value")
+
+ if len(login_info) == 1:
+ self.common.log("LOGIN_INFO: " + repr(login_info))
+ self.settings.setSetting("login_info", login_info[0])
+ else:
+ self.common.log("Failed to get LOGIN_INFO from youtube")
+
+ if len(SID) == 1:
+ self.common.log("SID: " + repr(SID))
+ self.settings.setSetting("SID", SID[0])
+ else:
+ self.common.log("Failed to get SID from youtube")
+
+ if len(SID) == 1 and len(login_info) == 1:
+ status = 200
+
+ self.common.log("Done")
+ return status
diff --git a/plugin.video.youtube/YouTubePlayer.py
b/plugin.video.youtube/YouTubePlayer.py
index 325802a..b5b79b6 100755
--- a/plugin.video.youtube/YouTubePlayer.py
+++ b/plugin.video.youtube/YouTubePlayer.py
@@ -50,7 +50,9 @@ class YouTubePlayer():
85: "520p h264 stereo",
100: "360p vp8 webm stereo",
101: "480p vp8 webm stereo",
- 102: "720p vp8 webm stereo"
+ 102: "720p vp8 webm stereo",
+ 120: "hd720",
+ 121: "hd1080"
}
# YouTube Playback Feeds
@@ -592,9 +594,13 @@ class YouTubePlayer():
video_url = link(22)
elif (link(45)):
video_url = link(45)
+ elif link(120):
+ video_url = link(120)
if hd_quality > 2:
if (link(37)):
video_url = link(37)
+ elif link(121):
+ video_url = link(121)
if link(38) and False:
video_url = link(38)
@@ -639,11 +645,15 @@ class YouTubePlayer():
if link(37):
quality_list.append((37, "1080p"))
+ elif link(121):
+ quality_list.append((121, "1080p"))
if link(22):
quality_list.append((22, "720p"))
elif link(45):
quality_list.append((45, "720p"))
+ elif link(120):
+ quality_list.append((120, "720p"))
if link(35):
quality_list.append((35, "480p"))
diff --git a/plugin.video.youtube/YouTubeScraper.py
b/plugin.video.youtube/YouTubeScraper.py
index 997aca0..b3b786f 100644
--- a/plugin.video.youtube/YouTubeScraper.py
+++ b/plugin.video.youtube/YouTubeScraper.py
@@ -41,7 +41,7 @@ class YouTubeScraper():
urls['watched_history'] = "http://www.youtube.com/my_history"
urls['liked_videos'] = "http://www.youtube.com/my_liked_videos"
urls['music'] = "http://www.youtube.com/music"
- urls['artist'] = "http://www.youtube.com/artist?a=%s&feature=artist"
+ urls['artist'] = "http://www.youtube.com/artist?a=%s&feature=music"
urls['education'] = "http://www.youtube.com/education"
urls['education_category'] = "http://www.youtube.com/education?category=%s"
urls['playlist'] = "http://www.youtube.com/view_play_list?p=%s"
@@ -204,7 +204,7 @@ class YouTubeScraper():
item["Title"] = title
item["artist_name"] = urllib.quote_plus(title)
link = ahref[i]
- link = link[link.find("?a=") + 3:link.find("&")]
+ link = link[link.rfind("/") + 1:link.rfind("?")]
item["artist"] = link
item["icon"] = "music"
item["scraper"] = "music_artist"
@@ -230,7 +230,10 @@ class YouTubeScraper():
for artist in artists:
div = self.common.parseDOM(artist, "div", attrs={"class":
"browse-item-content"})
- ahref = self.common.parseDOM(div, "a", ret="href")[0]
+
+ id = self.common.parseDOM(div, "a", ret="href")[0]
+ id = id[id.rfind("/") + 1:id.rfind("?")]
+
atitle = self.common.parseDOM(div, "a", ret="title")[0]
athumb = self.common.parseDOM(artist, "img",
ret="data-thumb")[0]
@@ -240,9 +243,7 @@ class YouTubeScraper():
item["Title"] = title
item["scraper"] = "music_artist"
item["artist_name"] = urllib.quote_plus(title)
- link = ahref
- link = link[link.find("?a=") + 3:link.find("&")]
- item["artist"] = link
+ item["artist"] = id
item["icon"] = "music"
item["thumbnail"] = athumb
items.append(item)
diff --git a/plugin.video.youtube/addon.xml b/plugin.video.youtube/addon.xml
index 259f9e7..dc79987 100644
--- a/plugin.video.youtube/addon.xml
+++ b/plugin.video.youtube/addon.xml
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
-<addon id='plugin.video.youtube' version='2.9.1' name='YouTube'
provider-name='TheCollective'>
+<addon id='plugin.video.youtube' version='2.9.2' name='YouTube'
provider-name='TheCollective'>
<requires>
<import addon='xbmc.python' version='2.0'/>
<import addon='script.module.simplejson' version='2.0.10'/>
@@ -12,11 +12,11 @@
</extension>
<extension point='xbmc.addon.metadata'>
<platform>all</platform>
- <summary lang="en">YouTube video plugin</summary>
- <description lang="en">Plugin that let's you browse and play videos from
everybody's favorite video site!</description>
- <disclaimer lang="en">Some parts of this addon may not be legal in your
country of residence - please check with your local laws before
installing.</disclaimer>
- <summary lang="bg">Ðидео добавка за YouTube</summary>
- <description lang="bg">ÐобавкаÑа ви позволÑва да
ÑазглеждаÑе и гледаÑе видео клипове оÑ
лÑÐ±Ð¸Ð¼Ð¸Ñ Ð½Ð° на вÑиÑки видео ÑайÑ!</description>
- <disclaimer lang="bg">ÐÑкои ÑаÑÑи Ð¾Ñ Ð´Ð¾Ð±Ð°Ð²ÐºÐ°Ñа
може да Ñа незаконни в дÑÑжаваÑа, в коÑÑо Ñе
намиÑаÑе - молÑ, пÑовеÑеÑе меÑÑниÑе закони,
пÑеди да Ñ Ð¸Ð½ÑÑалиÑаÑе.</disclaimer>
+ <summary lang='en'>YouTube video plugin</summary>
+ <description lang='en'>Plugin that lets you browse and play videos from
everybody's favorite video site!</description>
+ <disclaimer lang='en'>Some parts of this addon may not be legal in your
country of residence - please check with your local laws before
installing.</disclaimer>
+ <summary lang='bg'>Ðидео добавка за YouTube</summary>
+ <description lang='bg'>ÐобавкаÑа ви позволÑва да
ÑазглеждаÑе и гледаÑе видео клипове оÑ
лÑÐ±Ð¸Ð¼Ð¸Ñ Ð½Ð° на вÑиÑки видео ÑайÑ!</description>
+ <disclaimer lang='bg'>ÐÑкои ÑаÑÑи Ð¾Ñ Ð´Ð¾Ð±Ð°Ð²ÐºÐ°Ñа
може да Ñа незаконни в дÑÑжаваÑа, в коÑÑо Ñе
намиÑаÑе - молÑ, пÑовеÑеÑе меÑÑниÑе закони,
пÑеди да Ñ Ð¸Ð½ÑÑалиÑаÑе.</disclaimer>
</extension>
</addon>
diff --git a/plugin.video.youtube/changelog.txt
b/plugin.video.youtube/changelog.txt
index 404eeca..f93968f 100644
--- a/plugin.video.youtube/changelog.txt
+++ b/plugin.video.youtube/changelog.txt
@@ -8,7 +8,7 @@
- [XBMC] Has Excessive Memory use after running the plugin for prolonged
periods of time
- [RTMPDUMP] Doesn't support handshake type 10 which is required by youtube.
-[B]TODO 2.9.2[/B]
+[B]TODO 2.9.1[/B]
- Unit test coverage of Core above 90% im looking at you "Fetch page"
- Unit test new functions in storage...
- Allow users to change sort on searches
@@ -19,6 +19,10 @@
- If not replaceable refactor show scraper at least.
- Integration tests on all user actions.
+[B]Version 2.9.2[/B]
+- Listing of folders with more than 50 items was broken
+- Listing subscriptions was broken by youtubes sudden api changes.
+
[B]Version 2.9.1[/B]
- Fixed indentation error that broke pagination of long playlists and
subscription lists, basically any folder list with more than 50 elemtents was
broken.
diff --git a/plugin.video.youtube/default.py b/plugin.video.youtube/default.py
index cf58415..ca3ae1c 100644
--- a/plugin.video.youtube/default.py
+++ b/plugin.video.youtube/default.py
@@ -29,7 +29,7 @@ except ImportError:
import xbmcvfsdummy as xbmcvfs
# plugin constants
-version = "2.9.1"
+version = "2.9.2"
plugin = "YouTube-" + version
author = "TheCollective"
url = "www.xbmc.com"
diff --git a/plugin.video.youtube/resources/language/English/strings.xml
b/plugin.video.youtube/resources/language/English/strings.xml
index 7657de6..e60b0be 100644
--- a/plugin.video.youtube/resources/language/English/strings.xml
+++ b/plugin.video.youtube/resources/language/English/strings.xml
@@ -75,6 +75,7 @@
<string id="30210">Videos per page</string>
<string id="30211">Searches to save</string>
<string id="30212">Notification length in seconds</string>
+ <string id="30213">Ask</string>
<string id="30215">SD only</string>
<string id="30216">720p</string>
<string id="30217">1080p</string>
diff --git a/plugin.video.youtube/resources/settings.xml
b/plugin.video.youtube/resources/settings.xml
index 06e931a..89279a1 100644
--- a/plugin.video.youtube/resources/settings.xml
+++ b/plugin.video.youtube/resources/settings.xml
@@ -6,7 +6,7 @@
<setting id="username" type="text" label="30200" default="" />
<setting id="user_password" type="text" option="hidden" label="30201"
enable="!eq(-1,)" default="" />
<setting type="sep" />
- <setting id="safe_search" type="enum" label="30209"
lvalues="30214|30219|30220" default="1" />
+ <setting id="safe_search" type="enum" label="30209"
lvalues="30277|30219|30220" default="1" />
<setting id="hd_videos" type="enum" label="30208"
lvalues="30213|30215|30216|30217" default="2" />
<setting type="sep" />
<setting id="download_path" type="folder" label="30207" default="" />
-----------------------------------------------------------------------
Summary of changes:
plugin.video.vimeo/CommonFunctions.py | 230 -------
plugin.video.vimeo/VimeoCore.py | 9 +-
plugin.video.vimeo/VimeoFeeds.py | 148 +++++
plugin.video.vimeo/VimeoLogin.py | 53 ++-
plugin.video.vimeo/VimeoPlayer.py | 201 ++++++
plugin.video.vimeo/VimeoPlaylistControl.py | 170 +++++
plugin.video.vimeo/VimeoScraper.py | 341 ++++++++++
.../VimeoStorage.py | 196 +-----
plugin.video.vimeo/addon.xml | 24 +-
plugin.video.vimeo/changelog.txt | 9 +-
plugin.video.vimeo/default.py | 2 +-
.../resources/language/Bulgarian/strings.xml | 127 ++++
plugin.video.vimeo/storageserverdummy.py | 30 +
plugin.video.youtube/YouTubeCore.py | 2 +-
plugin.video.youtube/YouTubeLogin.py | 666 ++++++++++----------
plugin.video.youtube/YouTubePlayer.py | 12 +-
plugin.video.youtube/YouTubeScraper.py | 13 +-
plugin.video.youtube/addon.xml | 14 +-
plugin.video.youtube/changelog.txt | 6 +-
plugin.video.youtube/default.py | 2 +-
.../resources/language/English/strings.xml | 1 +
plugin.video.youtube/resources/settings.xml | 2 +-
22 files changed, 1472 insertions(+), 786 deletions(-)
delete mode 100644 plugin.video.vimeo/CommonFunctions.py
create mode 100644 plugin.video.vimeo/VimeoFeeds.py
create mode 100644 plugin.video.vimeo/VimeoPlayer.py
create mode 100644 plugin.video.vimeo/VimeoPlaylistControl.py
create mode 100644 plugin.video.vimeo/VimeoScraper.py
copy plugin.video.youtube/YouTubeStorage.py =>
plugin.video.vimeo/VimeoStorage.py (66%)
create mode 100644 plugin.video.vimeo/resources/language/Bulgarian/strings.xml
create mode 100644 plugin.video.vimeo/storageserverdummy.py
hooks/post-receive
--
Plugins
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons