The branch, frodo has been updated
via 22f42293f107dedf45324970d61336ee6788453b (commit)
via 43738e2f9bbb8fbb3a917d318474a3012599bd57 (commit)
via f106c8095c4852c24cf1881a3a81e41d6e3a3214 (commit)
from 991559c5db9f9e13b3e43466bea6d6dca4cc506c (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=22f42293f107dedf45324970d61336ee6788453b
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=43738e2f9bbb8fbb3a917d318474a3012599bd57
commit 43738e2f9bbb8fbb3a917d318474a3012599bd57
Author: beenje <[email protected]>
Date: Wed Jan 23 22:13:51 2013 +0100
[plugin.video.khanacademy] updated to version 2.5.0
diff --git a/plugin.video.khanacademy/addon.py
b/plugin.video.khanacademy/addon.py
index 0e851e8..03ee24f 100755
--- a/plugin.video.khanacademy/addon.py
+++ b/plugin.video.khanacademy/addon.py
@@ -1,105 +1,60 @@
-#!/usr/bin/env python
-# Copyright 2011 Jonathan Beluch.
-#
-# 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 os
-import time
-try:
- import json
-except ImportError:
- import simplejson as json
-from urlparse import urljoin
-from xbmcswift import Plugin, download_page, xbmc
-from BeautifulSoup import BeautifulSoup as BS
-from resources.lib.khan import KhanData, download_playlists_json
-from resources.lib.cache import get_cached_data, put_cached_data
+'''
+ Khan Academy XBMC Addon
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ Watch videos from http://www.khanacademy.org in XBMC.
-__plugin_name__ = 'Khan Academy'
-__plugin_id__ = 'plugin.video.khanacademy'
-plugin = Plugin(__plugin_name__, __plugin_id__, __file__)
-BASE_URL = 'http://www.khanacademy.org'
+ :copyright: (c) 2013 by Jonathan Beluch
+ :license: GPLv3, see LICENSE.txt for more details.
+'''
+import xbmcswift2
+from resources.lib import khan
-# Ugly temporary hack until xbmcswift is fixed. Need to ensure the basedirs
-# for the cache already exist before we attempt to use it. Also, in pyton 2.4
-# we don't get the lovely os.makedirs :(
-def make_cache_dirs():
- '''Make plugin_id and .cache dirs for the current plugin.'''
- def make_if_not_exist(path):
- print path
- if not os.path.exists(path):
- os.mkdir(path)
- cache_root = xbmc.translatePath('special://profile/addon_data')
- make_if_not_exist(os.path.join(cache_root, __plugin_id__))
- make_if_not_exist(os.path.join(cache_root, __plugin_id__, '.cache'))
-make_cache_dirs()
-
-
-def full_url(path):
- '''Returns the full url for the given path. Uses BASE_URL.'''
- return urljoin(BASE_URL, path)
-
-
-def htmlify(url):
- '''Returns a BeautifulSoup object for a give url's response.'''
- return BS(download_page(url))
+ONE_HOUR_IN_MINUTES = 60
+YOUTUBE_URL = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s'
+plugin = xbmcswift2.Plugin()
[email protected](TTL=ONE_HOUR_IN_MINUTES)
def get_khan_data():
- '''Returns a KhanData instance containg playlist data.
-
- Behind the scenes, it checks for a local cached copy first. If the cached
- copy's lifetime has not expired it will use the local copy. Otherwise, it
- will fetch fresh data from the API and cache it locally.
+ '''A wrapper method that exists to cache the results of the remote API
+ calls.
'''
- json_fn = plugin.cache_fn('playlists.json')
- timestamp_fn = plugin.cache_fn('playlists.json.ts')
-
- _json = get_cached_data(json_fn, timestamp_fn)
- if _json is None:
- _json = download_playlists_json()
- put_cached_data(json.dumps(_json), json_fn, timestamp_fn)
+ return khan.load_topic_tree()
- return KhanData(_json)
-
-KHAN_DATA = get_khan_data()
-
-
[email protected]('/')
[email protected]('/<category>/', name='show_category')
-def main_menu(category='_root'):
- '''This view displays Categories or Playlists.
-
- This method does a lookup based on the passed category/playlist name to get
- the members. The "root" or base category is name "_root"
+def get_playable_url(video):
+ '''Returns a the direct mp4 url if present otherwise returns a URL for the
+ youtube addon.
'''
- items = [item.to_listitem(plugin)
- for item in KHAN_DATA.get_items(category)]
- return plugin.add_items(items)
+ return video['mp4_url'] or YOUTUBE_URL % video['youtube_id']
+
+
+def to_listitem(item):
+ '''Converts a khan academy dict to an xbmcswift2 item dict.'''
+ if 'mp4_url' in item.keys():
+ return {
+ 'label': item['title'],
+ 'path': get_playable_url(item),
+ 'is_playable': True,
+ 'thumbnail': item['thumbnail'],
+ 'info': {
+ 'plot': item['description'],
+ },
+ }
+ else:
+ return {
+ 'label': item['title'],
+ 'path': plugin.url_for('show_topic', topic=item['id']),
+ }
[email protected]('/play/<video_slug>/')
-def play_video(video_slug):
- '''Resolves a video page's url to a playable video url.'''
- # Videos are both in .mp4 format and youtube. For simplicity's sake just
- # use mp4 for now.
- url = 'http://www.khanacademy.org/video/%s' % video_slug
- html = htmlify(url)
- a = html.find('a', {'title': 'Download this lesson'})
- plugin.set_resolved_url(a['href'])
[email protected]('/')
[email protected]('/<topic>/', name='show_topic')
+def main_menu(topic='root'):
+ '''The one and only view which displays topics hierarchically.'''
+ return [to_listitem(item) for item in get_khan_data()[topic]]
if __name__ == '__main__':
diff --git a/plugin.video.khanacademy/addon.xml
b/plugin.video.khanacademy/addon.xml
index 30a01ff..c7f6ed8 100644
--- a/plugin.video.khanacademy/addon.xml
+++ b/plugin.video.khanacademy/addon.xml
@@ -1,18 +1,17 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.khanacademy" name="Khan Academy" version="1.4.2"
provider-name="Jonathan Beluch (jbel)">
+<addon id="plugin.video.khanacademy" name="Khan Academy"
provider-name="Jonathan Beluch (jbel)" version="2.5.0">
<requires>
- <import addon="xbmc.python" version="2.0"/>
- <import addon="script.module.beautifulsoup" version="3.0.8"/>
- <import addon="script.module.xbmcswift" version="0.2.0"/>
- <import addon="script.module.simplejson" version="2.0.10"/>
- <import addon="plugin.video.youtube" version="2.9.1"/>
+ <import addon="xbmc.python" version="2.1.0" />
+ <import addon="script.module.xbmcswift2" version="1.3.1" />
+ <import addon="script.module.requests" version="1.0.4" />
+ <import addon="plugin.video.youtube" version="4.4.1" />
</requires>
- <extension point="xbmc.python.pluginsource" library="addon.py">
+ <extension library="addon.py" point="xbmc.python.pluginsource">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
+ <language />
<platform>all</platform>
<summary>View lessons from http://www.khanacademy.org</summary>
<description>From http://www.khanacademy.org/about: "The Khan Academy is
an organization on a mission. We're a not-for-profit with the goal of changing
education for the better by providing a free world-class education to anyone
anywhere.[CR][CR]All of the site's resources are available to anyone. It
doesn't matter if you are a student, teacher, home-schooler, principal, adult
returning to the classroom after 20 years, or a friendly alien just trying to
get a leg up in earthly biology. The Khan Academy's materials and resources are
available to you completely free of charge."</description>
</extension>
-</addon>
+</addon>
\ No newline at end of file
diff --git a/plugin.video.khanacademy/changelog.txt
b/plugin.video.khanacademy/changelog.txt
index 400b802..59dc425 100644
--- a/plugin.video.khanacademy/changelog.txt
+++ b/plugin.video.khanacademy/changelog.txt
@@ -1,3 +1,8 @@
+Version 2.5.0
+* Bump major version number for Frodo.
+* Upgrade to xbmcswift2.
+* Update code to reflect remote API changes.
+
Version 1.4.2
* Update plugin to reflect Khan API changes
* Use youtube for playback when an mp4 isn't available
diff --git a/plugin.video.khanacademy/resources/lib/khan.py
b/plugin.video.khanacademy/resources/lib/khan.py
index cf70413..64dce3a 100644
--- a/plugin.video.khanacademy/resources/lib/khan.py
+++ b/plugin.video.khanacademy/resources/lib/khan.py
@@ -1,134 +1,94 @@
-try:
- import json
-except ImportError:
- import simplejson as json
-import time
-import urllib
-
-
-# Hierarchical list
-API_URL = 'http://www.khanacademy.org/api/v1/playlists/library'
-YOUTUBE_PLUGIN_PTN =
'plugin://plugin.video.youtube/?action=play_video&videoid=%s'
-
-
-def download_playlists_json():
- '''Fetches the playlist JSON from the Khan Academy API and returns the
- parsed JSON object.
+'''
+ resources.lib.khan
+ ~~~~~~~~~~~~~~~~~~~
+
+ This module interfaces with the remote Khan Academy API.
+
+ :copyright: (c) 2013 by Jonathan Beluch
+ :license: GPLv3, see LICENSE.txt for more details.
+'''
+
+import requests
+import collections
+
+
+API_URL = 'http://www.khanacademy.org/api/v1/topictree'
+
+
+def _video(item):
+ '''Returns a video dict of values parsed from the json dict.'''
+ return {
+ 'title': item['title'],
+ 'description': item['description'],
+ 'thumbnail': (item['download_urls'] or {}).get('png'),
+ 'youtube_id': item['youtube_id'],
+ 'mp4_url': (item['download_urls'] or {}).get('mp4'),
+ }
+
+
+def _topic(item):
+ '''Returns a topic dict of values parsed from the json dict.'''
+ return {
+ 'id': item['id'],
+ 'title': item['title'],
+ }
+
+
+_KINDS = {
+ 'Topic': _topic,
+ 'Video': _video,
+}
+
+
+def _flatten(item):
+ '''Returns a new dict which is a flattened version of the provided item.
+ The provided item can have an arbitrary depth, since each item can possibly
+ have a 'children' entry. Since all items have unique ids, this method
+ creates a flat dictionary, where the key is each item's unique id and the
+ value is the item's children if present.
+
+ >>> item = {
+ ... 'id': 'root',
+ ... 'children': [
+ ... {
+ ... 'id': 'Algebra',
+ ... 'children': [
+ ... { 'id': 'Lesson 1'},
+ ... { 'id': 'Lesson 2'},
+ ... ],
+ ... },
+ ... {
+ ... 'id': 'Calculus',
+ ... },
+ ... ]
+ ... }
+ >>> _flatten(item).keys()
+ ['root', 'Algebra']
'''
- conn = urllib.urlopen(API_URL)
- resp = json.load(conn)
- conn.close()
- return resp
-
-
-def _try_parse(_json, *args):
- '''Returns the parsed value or None if doesn't exist. The provided args
- correspond to dictionary keys.
-
- >>> _json = {'foo': {'bar': 'baz'}}
- >>> _try_parse(_json, 'foo', 'bar')
- baz
- >>> _try_parse(_json, 'foo', 'missingkey')
- None
+ tree = collections.defaultdict(list)
+ queue = [(child, 'root') for child in item['children']]
+ while queue:
+ item, parent_id = queue.pop(0)
+ tree[parent_id].append(item)
+ if 'children' in item.keys():
+ current_id = item['id']
+ queue.extend((child, current_id) for child in item['children'])
+ return tree
+
+
+def load_topic_tree():
+ '''The main entry point for this module. Returns a dict keyed by Topic id.
+ The value of the dict is the topic's children which are either topic dicts
+ or video dicts. To hierarchichally descend through topics, start with the
+ key 'root', and then look up each child topic's 'id' in this tree to get
+ its children.
'''
- try:
- for key in args:
- _json = _json[key]
- return _json
- except TypeError:
- return None
-
-
-class Video(object):
-
- def __init__(self, _json):
- #self.key_id = _json['key_id']
- self.title = _json['title']
- self.readable_id = _json['readable_id']
- self.youtube_url = YOUTUBE_PLUGIN_PTN % _json['youtube_id']
- self.mp4_url = _try_parse(_json, 'download_urls', 'mp4')
- self.thumbnail = _try_parse(_json, 'download_urls', 'png')
-
-
- def to_listitem(self, plugin):
- '''Returns a dict suitable for passing to xbmcswift.plugin.add_items'''
- item = {
- 'label': self.title,
- 'url': self.mp4_url or self.youtube_url,
- 'is_playable': True,
- 'is_folder': False,
- }
- if self.thumbnail:
- item['thumbnail'] = self.thumbnail
- return item
+ _json = requests.get(API_URL).json()
+ flattened = _flatten(_json)
+ tree = {}
+ for item_id, children in flattened.items():
+ tree[item_id] = [_KINDS[child['kind']](child) for child in children
+ if child['kind'] in _KINDS.keys()]
-class Playlist(object):
-
- def __init__(self, _json):
- self.title = _json['title']
- self.description = _json['description']
- self.videos = [Video(item) for item in _json['videos']]
-
- def __iter__(self):
- return iter(self.videos)
-
- def to_listitem(self, plugin):
- '''Returns a dict suitable for passing to xbmcswift.plugin.add_items'''
- return {
- 'label': self.title,
- 'url': plugin.url_for('show_category', category=self.title),
- 'info': {'plot': self.description},
- }
-
-
-class Category(object):
-
- def __init__(self, _json):
- self.name = _json['name']
-
- def to_listitem(self, plugin):
- '''Returns a dict suitable for passing to xbmcswift.plugin.add_items'''
- return {
- 'label': self.name,
- 'url': plugin.url_for('show_category', category=self.name),
- }
-
-
-class KhanData(object):
- '''This class repurposes the Khan Academy playlist JSON into more
- convenient data structures.
- '''
-
- def __init__(self, _json):
- self._items = {}
- self._parse(_json, '_root')
-
- def _is_playlist(self, item):
- return 'playlist' in item.keys()
-
- def _create_keys(self, key):
- if key not in self._items.keys():
- self._items[key] = []
-
- def _parse(self, _json, current_key):
- '''Recursive parsing function to format the _json input in a single
- dict keyable on item['name']
- '''
- self._create_keys(current_key)
-
- for item in _json:
- if self._is_playlist(item):
- playlist = Playlist(item['playlist'])
- self._items[current_key].append(playlist)
- self._items[item['name']] = playlist
- else:
- category = Category(item)
- self._items[current_key].append(category)
- self._parse(item['items'], item['name'])
-
- def get_items(self, key):
- '''For a given key, returns a list of items (Category or Playlist) or
- if the key is a playlist name, returns a Playlist object.
- '''
- return self._items[key]
+ return tree
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=f106c8095c4852c24cf1881a3a81e41d6e3a3214
commit f106c8095c4852c24cf1881a3a81e41d6e3a3214
Author: beenje <[email protected]>
Date: Wed Jan 23 22:13:49 2013 +0100
[plugin.video.ted.talks] updated to version 4.1.7
diff --git a/plugin.video.ted.talks/addon.xml b/plugin.video.ted.talks/addon.xml
index 1d81401..bdf3009 100644
--- a/plugin.video.ted.talks/addon.xml
+++ b/plugin.video.ted.talks/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.ted.talks" name="TED Talks" version="3.1.6"
provider-name="rwparris2, moreginger">
+<addon id="plugin.video.ted.talks" name="TED Talks" version="4.1.7"
provider-name="rwparris2, moreginger">
<requires>
- <import addon="xbmc.python" version="2.0"/>
+ <import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.simplejson" version="2.0.10"/>
<import addon="script.module.beautifulsoup" version="3.0.8"/>
<import addon="script.module.elementtree" version="1.2.7"/>
diff --git a/plugin.video.ted.talks/changelog.txt
b/plugin.video.ted.talks/changelog.txt
index 8e3c822..f398be7 100644
--- a/plugin.video.ted.talks/changelog.txt
+++ b/plugin.video.ted.talks/changelog.txt
@@ -1,3 +1,6 @@
+[B]Version 3.1.7[/B]
+Fix subtitles (issue#35) thanks to omega32
+
[B]Version 3.1.6[/B]
Fix getting subtitles using default xbmc language (issue#30)
diff --git a/plugin.video.ted.talks/resources/lib/model/subtitles_scraper.py
b/plugin.video.ted.talks/resources/lib/model/subtitles_scraper.py
index c2b8aa4..efee063 100644
--- a/plugin.video.ted.talks/resources/lib/model/subtitles_scraper.py
+++ b/plugin.video.ted.talks/resources/lib/model/subtitles_scraper.py
@@ -9,7 +9,7 @@ import urllib
import re
__friendly_message__ = 'Error showing subtitles'
-__talkIdKey__ = 'talkId'
+__talkIdKey__ = 'ti'
__introDurationKey__ = 'introDuration'
def format_time(time):
@@ -53,15 +53,28 @@ def get_flashvars(soup):
if not flashvar_match:
raise Exception('Could not get flashVars')
- talkId_re = re.compile('"%s":(\d+)' % (__talkIdKey__))
- introDuration_re = re.compile('"%s":(\d+)' % (__introDurationKey__))
+ talkId_re = re.compile('"?%s"?:"?(\d+)"?' % (__talkIdKey__))
flashvars = urllib.unquote(flashvar_match.group(1).encode('ascii'))
talkId_match = talkId_re.search(flashvars)
if not talkId_match:
raise Exception('Could not get talk ID')
- introDuration_match = introDuration_re.search(flashvars)
+ input_tag2 = soup.find('script', type='text/javascript',
text=re.compile('var talkDetails'))
+ if not input_tag2:
+ raise Exception('Could not find the talkDetails container')
+
+ talkDetails_re = re.compile('var talkDetails = (\{.*\})');
+ talkDetails_match = talkDetails_re.search(input_tag2.string)
+
+ if not talkDetails_match:
+ raise Exception('Could not get talkDetails')
+
+ talkDetails = urllib.unquote(talkDetails_match.group(1).encode('ascii'))
+
+ introDuration_re = re.compile('"%s":(\d+)' % (__introDurationKey__))
+ introDuration_match = introDuration_re.search(talkDetails)
+
if not introDuration_match:
raise Exception('Could not get intro duration')
diff --git
a/plugin.video.ted.talks/resources/lib/model/subtitles_scraper_test.py
b/plugin.video.ted.talks/resources/lib/model/subtitles_scraper_test.py
index 5af783c..12a7416 100644
--- a/plugin.video.ted.talks/resources/lib/model/subtitles_scraper_test.py
+++ b/plugin.video.ted.talks/resources/lib/model/subtitles_scraper_test.py
@@ -49,7 +49,7 @@ World
self.assertEquals('15', flashvars['introDuration'])
# Talk ID, need this to request subtitles.
- self.assertEquals('1253', flashvars['talkId'])
+ self.assertEquals('1253', flashvars['ti'])
expected = set(['sq', 'ar', 'hy', 'bg', 'ca', 'zh-cn', 'zh-tw', 'hr',
'cs', 'da', 'nl', 'en', 'fr', 'ka', 'de', 'el', 'he', 'hu', 'id', 'it', 'ja',
'ko', 'fa', 'mk', 'pl', 'pt', 'pt-br', 'ro', 'ru', 'sr', 'sk', 'es', 'th',
'tr', 'uk', 'vi'])
self.assertEquals(expected, set(subtitles_scraper.get_languages(soup)))
diff --git a/plugin.video.ted.talks/resources/lib/model/user.py
b/plugin.video.ted.talks/resources/lib/model/user.py
index 60a9092..07e5ead 100644
--- a/plugin.video.ted.talks/resources/lib/model/user.py
+++ b/plugin.video.ted.talks/resources/lib/model/user.py
@@ -44,9 +44,9 @@ class User:
finally:
response.close()
#set username & password in the sign in form
- form = forms[1]
- form["users[username]"] = username
- form["users[password]"] = password
- form["users[rememberme]"] = ["on"]
+ form = forms[0]
+ form["user[email]"] = username
+ form["user[password]"] = password
+ form.find_control(name="user[remember_me]", type="checkbox",
id="user_remember_me").selected = True
#click submit
return self.get_HTML(form.click())
-----------------------------------------------------------------------
Summary of changes:
plugin.video.khanacademy/addon.py | 133 +--
plugin.video.khanacademy/addon.xml | 17 +-
plugin.video.khanacademy/changelog.txt | 5 +
plugin.video.khanacademy/requirements.txt | 3 +
plugin.video.khanacademy/resources/lib/cache.py | 46 -
plugin.video.khanacademy/resources/lib/khan.py | 220 ++--
plugin.video.synopsi/LICENSE.txt | 340 +++++
plugin.video.synopsi/README.markdown | 10 +
plugin.video.synopsi/_src/TODO | 45 +
plugin.video.synopsi/_src/release-local.sh | 25 +
plugin.video.synopsi/addon.py | 291 ++++
plugin.video.synopsi/addon.xml | 30 +
plugin.video.synopsi/addonservice.py | 172 +++
plugin.video.synopsi/apiclient.py | 488 ++++++
plugin.video.synopsi/app_apiclient.py | 219 +++
plugin.video.synopsi/cache.py | 471 ++++++
plugin.video.synopsi/changelog.txt | 12 +
plugin.video.synopsi/dialog.py | 531 +++++++
plugin.video.synopsi/fanart.jpg | Bin 0 -> 75292 bytes
plugin.video.synopsi/icon.png | Bin 0 -> 11832 bytes
plugin.video.synopsi/library.py | 147 ++
plugin.video.synopsi/loggable.py | 45 +
plugin.video.synopsi/mythread.py | 19 +
.../resources/language/English/strings.xml | 26 +
.../resources/language/Slovak/strings.xml | 25 +
plugin.video.synopsi/resources/settings.xml | 45 +
.../resources/skins/Default/720p/SelectMovie.xml | 250 ++++
.../resources/skins/Default/720p/SynopsiDialog.xml | 119 ++
.../resources/skins/Default/720p/VideoInfo.xml | 409 ++++++
.../resources/skins/Default/720p/ViewsFileMode.xml | 613 ++++++++
.../skins/Default/720p/ViewsVideoLibrary.xml | 1545 ++++++++++++++++++++
.../skins/Default/720p/customLoginDialog.xml | 155 ++
.../skins/Default/720p/custom_MyVideoNav.xml | 167 +++
.../resources/skins/Default/720p/includes.xml | 3 +
.../skins/Default/media/already-watched-stack.png | Bin 0 -> 5071 bytes
.../resources/skins/Default/media/bgr.png | Bin 0 -> 3076 bytes
.../resources/skins/Default/media/button1.png | Bin 0 -> 1585 bytes
.../resources/skins/Default/media/button2.png | Bin 0 -> 1697 bytes
.../resources/skins/Default/media/debug.png | Bin 0 -> 491 bytes
.../resources/skins/Default/media/default.png | Bin 0 -> 9968 bytes
.../resources/skins/Default/media/icon.png | Bin 0 -> 70062 bytes
.../media/ondisk-AND-already-watched-stack.png | Bin 0 -> 7109 bytes
.../resources/skins/Default/media/ondisk-stack.png | Bin 0 -> 3852 bytes
.../resources/skins/Default/media/pix.png | Bin 0 -> 119 bytes
.../skins/Default/media/show_all_button.png | Bin 0 -> 4378 bytes
.../resources/skins/Default/media/videos.jpg | Bin 0 -> 260099 bytes
plugin.video.synopsi/scrobbler.py | 225 +++
plugin.video.synopsi/service.py | 92 ++
.../gui => plugin.video.synopsi/tests}/__init__.py | 0
plugin.video.synopsi/tests/apiclient.unittest.py | 340 +++++
plugin.video.synopsi/tests/cache.unittest.py | 181 +++
plugin.video.synopsi/tests/callable.py | 35 +
plugin.video.synopsi/tests/common.py | 12 +
.../tests/data}/__init__.py | 0
.../tests/data/get_all_movies.json | 729 +++++++++
.../tests/data/get_all_tvshows.json | 19 +
plugin.video.synopsi/tests/data/local_recco.py | 86 ++
plugin.video.synopsi/tests/executescript.test.py | 4 +
plugin.video.synopsi/tests/fakeenv/xbmc.py | 74 +
plugin.video.synopsi/tests/fakeenv/xbmcaddon.py | 27 +
plugin.video.synopsi/tests/fakeenv/xbmcgui.py | 25 +
.../tests/fakeenv/xbmcplugin.py | 0
plugin.video.synopsi/tests/fakeenv/xbmcvfs.py | 3 +
plugin.video.synopsi/tests/onlinecache.unittest.py | 288 ++++
plugin.video.synopsi/tests/service-test.py | 69 +
plugin.video.synopsi/tests/socketserver.py | 28 +
plugin.video.synopsi/tests/test.py | 282 ++++
plugin.video.synopsi/tests/typerror.test.py | 17 +
plugin.video.synopsi/tests/utilities.unittest.py | 49 +
plugin.video.synopsi/tests/xbmcrpc.unittest.py | 47 +
plugin.video.synopsi/top.py | 3 +
plugin.video.synopsi/utilities.py | 690 +++++++++
plugin.video.synopsi/xbmcrpc.py | 236 +++
plugin.video.ted.talks/addon.xml | 4 +-
plugin.video.ted.talks/changelog.txt | 3 +
.../resources/lib/model/subtitles_scraper.py | 21 +-
.../resources/lib/model/subtitles_scraper_test.py | 2 +-
plugin.video.ted.talks/resources/lib/model/user.py | 8 +-
78 files changed, 9940 insertions(+), 285 deletions(-)
create mode 100644 plugin.video.khanacademy/requirements.txt
delete mode 100644 plugin.video.khanacademy/resources/lib/cache.py
create mode 100644 plugin.video.synopsi/LICENSE.txt
create mode 100644 plugin.video.synopsi/README.markdown
create mode 100644 plugin.video.synopsi/_src/TODO
create mode 100755 plugin.video.synopsi/_src/release-local.sh
create mode 100644 plugin.video.synopsi/addon.py
create mode 100644 plugin.video.synopsi/addon.xml
create mode 100644 plugin.video.synopsi/addonservice.py
create mode 100644 plugin.video.synopsi/apiclient.py
create mode 100644 plugin.video.synopsi/app_apiclient.py
create mode 100644 plugin.video.synopsi/cache.py
create mode 100644 plugin.video.synopsi/changelog.txt
create mode 100644 plugin.video.synopsi/dialog.py
create mode 100644 plugin.video.synopsi/fanart.jpg
create mode 100644 plugin.video.synopsi/icon.png
create mode 100644 plugin.video.synopsi/library.py
create mode 100644 plugin.video.synopsi/loggable.py
create mode 100644 plugin.video.synopsi/mythread.py
create mode 100644 plugin.video.synopsi/resources/language/English/strings.xml
create mode 100644 plugin.video.synopsi/resources/language/Slovak/strings.xml
create mode 100644 plugin.video.synopsi/resources/settings.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/SelectMovie.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/SynopsiDialog.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/VideoInfo.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/ViewsFileMode.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/ViewsVideoLibrary.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/customLoginDialog.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/custom_MyVideoNav.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/720p/includes.xml
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/already-watched-stack.png
create mode 100644 plugin.video.synopsi/resources/skins/Default/media/bgr.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/button1.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/button2.png
create mode 100644 plugin.video.synopsi/resources/skins/Default/media/debug.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/default.png
create mode 100644 plugin.video.synopsi/resources/skins/Default/media/icon.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/ondisk-AND-already-watched-stack.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/ondisk-stack.png
create mode 100644 plugin.video.synopsi/resources/skins/Default/media/pix.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/show_all_button.png
create mode 100644
plugin.video.synopsi/resources/skins/Default/media/videos.jpg
create mode 100644 plugin.video.synopsi/scrobbler.py
create mode 100644 plugin.video.synopsi/service.py
copy {plugin.audio.qobuz/resources/lib/qobuz/gui =>
plugin.video.synopsi/tests}/__init__.py (100%)
create mode 100644 plugin.video.synopsi/tests/apiclient.unittest.py
create mode 100644 plugin.video.synopsi/tests/cache.unittest.py
create mode 100644 plugin.video.synopsi/tests/callable.py
create mode 100644 plugin.video.synopsi/tests/common.py
copy {plugin.audio.qobuz/resources/lib/qobuz/gui =>
plugin.video.synopsi/tests/data}/__init__.py (100%)
create mode 100644 plugin.video.synopsi/tests/data/get_all_movies.json
create mode 100644 plugin.video.synopsi/tests/data/get_all_tvshows.json
create mode 100644 plugin.video.synopsi/tests/data/local_recco.py
create mode 100644 plugin.video.synopsi/tests/executescript.test.py
create mode 100644 plugin.video.synopsi/tests/fakeenv/xbmc.py
create mode 100644 plugin.video.synopsi/tests/fakeenv/xbmcaddon.py
create mode 100644 plugin.video.synopsi/tests/fakeenv/xbmcgui.py
copy plugin.audio.qobuz/resources/lib/qobuz/gui/__init__.py =>
plugin.video.synopsi/tests/fakeenv/xbmcplugin.py (100%)
create mode 100644 plugin.video.synopsi/tests/fakeenv/xbmcvfs.py
create mode 100644 plugin.video.synopsi/tests/onlinecache.unittest.py
create mode 100644 plugin.video.synopsi/tests/service-test.py
create mode 100644 plugin.video.synopsi/tests/socketserver.py
create mode 100644 plugin.video.synopsi/tests/test.py
create mode 100644 plugin.video.synopsi/tests/typerror.test.py
create mode 100644 plugin.video.synopsi/tests/utilities.unittest.py
create mode 100644 plugin.video.synopsi/tests/xbmcrpc.unittest.py
create mode 100644 plugin.video.synopsi/top.py
create mode 100644 plugin.video.synopsi/utilities.py
create mode 100644 plugin.video.synopsi/xbmcrpc.py
hooks/post-receive
--
Plugins
------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. ON SALE this month only -- learn more at:
http://p.sf.net/sfu/learnnow-d2d
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons