diff --git a/plugin.audio.kissfm/LICENSE.txt b/plugin.audio.kissfm/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.kissfm/addon.py b/plugin.audio.kissfm/addon.py new file mode 100644 index 0000000..cff82de --- /dev/null +++ b/plugin.audio.kissfm/addon.py @@ -0,0 +1,19 @@ +import sys +import xbmcgui +import xbmcplugin + +addon_handle = int(sys.argv[1]) + +xbmcplugin.setContent(addon_handle, 'audio') + +url = 'http://tx.whatson.com/icecast.php?i=kisstorylow.mp3' +li = xbmcgui.ListItem('Kisstory', iconImage='http://whitenoisehq.co.uk/kisstory.png', thumbnailImage='http://whitenoisehq.co.uk/kisstory.png') +li.setProperty('fanart_image', 'http://whitenoisehq.co.uk/kissbg.jpg') +xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + +url = 'http://tx.whatson.com/icecast.php?i=kissnationallow.mp3' +li = xbmcgui.ListItem('Kiss FM UK - National', iconImage='http://whitenoisehq.co.uk/kisslogo.png', thumbnailImage='http://whitenoisehq.co.uk/kisslogo.png') +li.setProperty('fanart_image', 'http://whitenoisehq.co.uk/kissbg.jpg') +xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + +xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file diff --git a/plugin.audio.kissfm/addon.xml b/plugin.audio.kissfm/addon.xml new file mode 100644 index 0000000..f68caa0 --- /dev/null +++ b/plugin.audio.kissfm/addon.xml @@ -0,0 +1,21 @@ + + + + + + + audio + + + Kiss FM UK - Live Stream + KissFMUK.com + + English + all + + + http://www.kissfmuk.com + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/plugin.audio.kissfm/changelog.txt b/plugin.audio.kissfm/changelog.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.kissfm/fanart.jpg b/plugin.audio.kissfm/fanart.jpg new file mode 100644 index 0000000..c666bc7 Binary files /dev/null and b/plugin.audio.kissfm/fanart.jpg differ diff --git a/plugin.audio.kissfm/icon.PNG b/plugin.audio.kissfm/icon.PNG new file mode 100644 index 0000000..53ba406 Binary files /dev/null and b/plugin.audio.kissfm/icon.PNG differ diff --git a/plugin.audio.kissfm/resources/icon.PNG b/plugin.audio.kissfm/resources/icon.PNG new file mode 100644 index 0000000..53ba406 Binary files /dev/null and b/plugin.audio.kissfm/resources/icon.PNG differ diff --git a/plugin.audio.kissfm/resources/lib/academicearth/__init__.py b/plugin.audio.kissfm/resources/lib/academicearth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.kissfm/resources/lib/academicearth/api.py b/plugin.audio.kissfm/resources/lib/academicearth/api.py new file mode 100644 index 0000000..dc17d6c --- /dev/null +++ b/plugin.audio.kissfm/resources/lib/academicearth/api.py @@ -0,0 +1,141 @@ +''' + + academicearth.api + ~~~~~~~~~~~~~~~~~ + + This module contains the API classes and method to parse information from + the Academic Earth website. + +''' +from scraper import (get_subjects, get_courses, get_subject_metadata, + get_course_metadata, get_lecture_metadata) + + +class AcademicEarth(object): + '''The main API object. Useful as a starting point to get available + subjects. + ''' + + def __init__(self): + pass + + def get_subjects(self): + '''Returns a list of subjects available on the website.''' + return [Subject(**info) for info in get_subjects()] + + +class Subject(object): + '''Object representing an Academic Earth subject.''' + + def __init__(self, url, name=None): + self.url = url + self._name = name + self._courses = None + self._lectures = None + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_subject_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._courses = [Course(**info) for info in resp['courses']] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._description = resp['description'] + self._loaded = True + + @property + def name(self): + '''Subject name''' + if not self._name: + self._load_metadata() + return self._name + + @property + def courses(self): + '''List of courses available for this subject''' + if not self._loaded: + self._load_metadata() + return self._courses + + @property + def lectures(self): + '''List of lectures available for this subject''' + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Course(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + self._lectures = None + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_course_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def lectures(self): + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Lecture(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_lecture_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._youtube_id = resp['youtube_id'] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def youtube_id(self): + if not self._loaded: + self._load_metadata() + return self._youtube_id diff --git a/plugin.audio.kissfm/resources/lib/academicearth/scraper.py b/plugin.audio.kissfm/resources/lib/academicearth/scraper.py new file mode 100644 index 0000000..1e14ec7 --- /dev/null +++ b/plugin.audio.kissfm/resources/lib/academicearth/scraper.py @@ -0,0 +1,151 @@ +''' + academicearth.scraper + ~~~~~~~~~~~~~~~~~~~~~ + + This module contains some functions which do the website scraping for the + API module. You shouldn't have to use this module directly. +''' +import re +from urllib2 import urlopen +from urlparse import urljoin +from BeautifulSoup import BeautifulSoup as BS + + +BASE_URL = 'http://www.academicearth.org' +def _url(path): + '''Returns a full url for the given path''' + return urljoin(BASE_URL, path) + + +def get(url): + '''Performs a GET request for the given url and returns the response''' + conn = urlopen(url) + resp = conn.read() + conn.close() + return resp + + +def _html(url): + '''Downloads the resource at the given url and parses via BeautifulSoup''' + return BS(get(url), convertEntities=BS.HTML_ENTITIES) + + +def make_showall_url(url): + '''Takes an api url and appends info to the path to force the page to + return all entries instead of paginating. + ''' + if not url.endswith('/'): + url += '/' + return url + 'page:1/show:500' + + +def get_subjects(): + '''Returns a list of subjects for the website. Each subject is a dict with + keys of 'name' and 'url'. + ''' + url = _url('subjects') + html = _html(url) + subjs = html.findAll('a', + {'href': lambda attr_value: attr_value.startswith('/subjects/') + and len(attr_value) > len('/subjects/')}) + + # subjs will contain some duplicates so we will key on url + items = [] + urls = set() + for subj in subjs: + url = _url(subj['href']) + if url not in urls: + urls.add(url) + items.append({ + 'name': subj.string, + 'url': url, + }) + + # filter out any items that didn't parse correctly + return [item for item in items if item['name'] and item['url']] + + +def get_subject_metadata(subject_url): + '''Returns metadata for a subject parsed from the given url''' + html = _html(make_showall_url(subject_url)) + name = get_subject_name(html) + courses = get_courses(html) + lectures = get_lectures(html) + desc = get_subject_description(html) + + return { + 'name': name, + 'courses': courses, + 'lectures': lectures, + 'description': desc, + } + + +def get_subject_name(html): + return html.find('article').h1.text + + +def get_course_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_lecture_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_subject_description(html): + desc_nodes = html.find('article').findAll('span') + return '\n'.join(node.text.strip() for node in desc_nodes) + + +def _get_courses_or_lectures(class_type, html): + '''class_type can be 'course' or 'lecture'.''' + nodes = html.findAll('div', {'class': class_type}) + + items = [{ + 'name': node.h3.text, + 'url': _url(node.a['href']), + 'icon': node.img['src'], + #'university': '', + #'speaker': '', + } for node in nodes] + + return items + + +def get_lectures(html): + return _get_courses_or_lectures('lecture', html) + + +def get_courses(html): + return _get_courses_or_lectures('course', html) + + +def get_course_metadata(course_url): + html = _html(make_showall_url(course_url)) + lectures = get_lectures(html) + name = get_course_name(html) + return { + 'lectures': lectures, + 'name': name, + } + + +def get_lecture_metadata(lecture_url): + html = _html(lecture_url) + name = get_lecture_name(html) + youtube_id = parse_youtube_id(html) + return { + 'name': name, + 'youtube_id': youtube_id + } + + + +def parse_youtube_id(html): + embed = html.find('embed') + yt_ptn = re.compile(r'http://www.youtube.com/v/(.+?)\?') + match = yt_ptn.search(embed['src']) + if match: + return match.group(1) + return None diff --git a/plugin.audio.kissfm/resources/settings.xml b/plugin.audio.kissfm/resources/settings.xml new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.rinsefm/LICENSE.txt b/plugin.audio.rinsefm/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.rinsefm/Thumbs.db b/plugin.audio.rinsefm/Thumbs.db new file mode 100644 index 0000000..7b4a1fe Binary files /dev/null and b/plugin.audio.rinsefm/Thumbs.db differ diff --git a/plugin.audio.rinsefm/addon.py b/plugin.audio.rinsefm/addon.py new file mode 100644 index 0000000..0525373 --- /dev/null +++ b/plugin.audio.rinsefm/addon.py @@ -0,0 +1,14 @@ +import sys +import xbmcgui +import xbmcplugin + +addon_handle = int(sys.argv[1]) + +xbmcplugin.setContent(addon_handle, 'movies') + +url = 'http://podcast.dgen.net:8000/rinseradio.m3u' +li = xbmcgui.ListItem('Rinse.FM', iconImage='http://in-reach.co.uk/wp-content/uploads/2014/02/rinse-fm-logo-620x400.png', thumbnailImage='http://in-reach.co.uk/wp-content/uploads/2014/02/rinse-fm-logo-620x400.png') +li.setProperty('fanart_image', 'http://in-reach.co.uk/wp-content/uploads/2014/02/rinse-fm-logo-620x400.png') +xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + +xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file diff --git a/plugin.audio.rinsefm/addon.xml b/plugin.audio.rinsefm/addon.xml new file mode 100644 index 0000000..fed7cfd --- /dev/null +++ b/plugin.audio.rinsefm/addon.xml @@ -0,0 +1,21 @@ + + + + + + + audio + + + Rinse.FM - Live Stream + RinseFM live from Brick Lane, London + + English + all + + + http://rinse.fm + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/plugin.audio.rinsefm/changelog.txt b/plugin.audio.rinsefm/changelog.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.rinsefm/fanart.jpg b/plugin.audio.rinsefm/fanart.jpg new file mode 100644 index 0000000..849eeee Binary files /dev/null and b/plugin.audio.rinsefm/fanart.jpg differ diff --git a/plugin.audio.rinsefm/logo.png b/plugin.audio.rinsefm/logo.png new file mode 100644 index 0000000..496e171 Binary files /dev/null and b/plugin.audio.rinsefm/logo.png differ diff --git a/plugin.audio.rinsefm/resources/icon.PNG b/plugin.audio.rinsefm/resources/icon.PNG new file mode 100644 index 0000000..5e8ad88 Binary files /dev/null and b/plugin.audio.rinsefm/resources/icon.PNG differ diff --git a/plugin.audio.rinsefm/resources/lib/academicearth/__init__.py b/plugin.audio.rinsefm/resources/lib/academicearth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugin.audio.rinsefm/resources/lib/academicearth/api.py b/plugin.audio.rinsefm/resources/lib/academicearth/api.py new file mode 100644 index 0000000..dc17d6c --- /dev/null +++ b/plugin.audio.rinsefm/resources/lib/academicearth/api.py @@ -0,0 +1,141 @@ +''' + + academicearth.api + ~~~~~~~~~~~~~~~~~ + + This module contains the API classes and method to parse information from + the Academic Earth website. + +''' +from scraper import (get_subjects, get_courses, get_subject_metadata, + get_course_metadata, get_lecture_metadata) + + +class AcademicEarth(object): + '''The main API object. Useful as a starting point to get available + subjects. + ''' + + def __init__(self): + pass + + def get_subjects(self): + '''Returns a list of subjects available on the website.''' + return [Subject(**info) for info in get_subjects()] + + +class Subject(object): + '''Object representing an Academic Earth subject.''' + + def __init__(self, url, name=None): + self.url = url + self._name = name + self._courses = None + self._lectures = None + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_subject_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._courses = [Course(**info) for info in resp['courses']] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._description = resp['description'] + self._loaded = True + + @property + def name(self): + '''Subject name''' + if not self._name: + self._load_metadata() + return self._name + + @property + def courses(self): + '''List of courses available for this subject''' + if not self._loaded: + self._load_metadata() + return self._courses + + @property + def lectures(self): + '''List of lectures available for this subject''' + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Course(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + self._lectures = None + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_course_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def lectures(self): + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Lecture(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_lecture_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._youtube_id = resp['youtube_id'] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def youtube_id(self): + if not self._loaded: + self._load_metadata() + return self._youtube_id diff --git a/plugin.audio.rinsefm/resources/lib/academicearth/scraper.py b/plugin.audio.rinsefm/resources/lib/academicearth/scraper.py new file mode 100644 index 0000000..1e14ec7 --- /dev/null +++ b/plugin.audio.rinsefm/resources/lib/academicearth/scraper.py @@ -0,0 +1,151 @@ +''' + academicearth.scraper + ~~~~~~~~~~~~~~~~~~~~~ + + This module contains some functions which do the website scraping for the + API module. You shouldn't have to use this module directly. +''' +import re +from urllib2 import urlopen +from urlparse import urljoin +from BeautifulSoup import BeautifulSoup as BS + + +BASE_URL = 'http://www.academicearth.org' +def _url(path): + '''Returns a full url for the given path''' + return urljoin(BASE_URL, path) + + +def get(url): + '''Performs a GET request for the given url and returns the response''' + conn = urlopen(url) + resp = conn.read() + conn.close() + return resp + + +def _html(url): + '''Downloads the resource at the given url and parses via BeautifulSoup''' + return BS(get(url), convertEntities=BS.HTML_ENTITIES) + + +def make_showall_url(url): + '''Takes an api url and appends info to the path to force the page to + return all entries instead of paginating. + ''' + if not url.endswith('/'): + url += '/' + return url + 'page:1/show:500' + + +def get_subjects(): + '''Returns a list of subjects for the website. Each subject is a dict with + keys of 'name' and 'url'. + ''' + url = _url('subjects') + html = _html(url) + subjs = html.findAll('a', + {'href': lambda attr_value: attr_value.startswith('/subjects/') + and len(attr_value) > len('/subjects/')}) + + # subjs will contain some duplicates so we will key on url + items = [] + urls = set() + for subj in subjs: + url = _url(subj['href']) + if url not in urls: + urls.add(url) + items.append({ + 'name': subj.string, + 'url': url, + }) + + # filter out any items that didn't parse correctly + return [item for item in items if item['name'] and item['url']] + + +def get_subject_metadata(subject_url): + '''Returns metadata for a subject parsed from the given url''' + html = _html(make_showall_url(subject_url)) + name = get_subject_name(html) + courses = get_courses(html) + lectures = get_lectures(html) + desc = get_subject_description(html) + + return { + 'name': name, + 'courses': courses, + 'lectures': lectures, + 'description': desc, + } + + +def get_subject_name(html): + return html.find('article').h1.text + + +def get_course_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_lecture_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_subject_description(html): + desc_nodes = html.find('article').findAll('span') + return '\n'.join(node.text.strip() for node in desc_nodes) + + +def _get_courses_or_lectures(class_type, html): + '''class_type can be 'course' or 'lecture'.''' + nodes = html.findAll('div', {'class': class_type}) + + items = [{ + 'name': node.h3.text, + 'url': _url(node.a['href']), + 'icon': node.img['src'], + #'university': '', + #'speaker': '', + } for node in nodes] + + return items + + +def get_lectures(html): + return _get_courses_or_lectures('lecture', html) + + +def get_courses(html): + return _get_courses_or_lectures('course', html) + + +def get_course_metadata(course_url): + html = _html(make_showall_url(course_url)) + lectures = get_lectures(html) + name = get_course_name(html) + return { + 'lectures': lectures, + 'name': name, + } + + +def get_lecture_metadata(lecture_url): + html = _html(lecture_url) + name = get_lecture_name(html) + youtube_id = parse_youtube_id(html) + return { + 'name': name, + 'youtube_id': youtube_id + } + + + +def parse_youtube_id(html): + embed = html.find('embed') + yt_ptn = re.compile(r'http://www.youtube.com/v/(.+?)\?') + match = yt_ptn.search(embed['src']) + if match: + return match.group(1) + return None diff --git a/plugin.audio.rinsefm/resources/settings.xml b/plugin.audio.rinsefm/resources/settings.xml new file mode 100644 index 0000000..e69de29 diff --git a/plugin.video.londonlive/LICENSE.txt b/plugin.video.londonlive/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.video.londonlive/addon.py b/plugin.video.londonlive/addon.py new file mode 100644 index 0000000..d141282 --- /dev/null +++ b/plugin.video.londonlive/addon.py @@ -0,0 +1,14 @@ +import sys +import xbmcgui +import xbmcplugin + +addon_handle = int(sys.argv[1]) + +xbmcplugin.setContent(addon_handle, 'movies') + +url = 'http://bcoveliveios-i.akamaihd.net/hls/live/217434/3083279840001/master.m3u8' +li = xbmcgui.ListItem('London Live', iconImage='http://whitenoisehq.co.uk/londonlivelogo.png', thumbnailImage='http://whitenoisehq.co.uk/londonlivelogo.png') +li.setProperty('fanart_image', 'fanart.jpg') +xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + +xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file diff --git a/plugin.video.londonlive/addon.xml b/plugin.video.londonlive/addon.xml new file mode 100644 index 0000000..7e26655 --- /dev/null +++ b/plugin.video.londonlive/addon.xml @@ -0,0 +1,21 @@ + + + + + + + video + + + London Live - Live Stream + LondonLive.co.uk + + English + all + + http://forum.xbmc.org/showthread.php?tid=190935 + http://www.londonlive.co.uk + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/plugin.video.londonlive/changelog.txt b/plugin.video.londonlive/changelog.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugin.video.londonlive/fanart.jpg b/plugin.video.londonlive/fanart.jpg new file mode 100644 index 0000000..849eeee Binary files /dev/null and b/plugin.video.londonlive/fanart.jpg differ diff --git a/plugin.video.londonlive/icon.PNG b/plugin.video.londonlive/icon.PNG new file mode 100644 index 0000000..8caccf5 Binary files /dev/null and b/plugin.video.londonlive/icon.PNG differ diff --git a/plugin.video.londonlive/resources/icon.PNG b/plugin.video.londonlive/resources/icon.PNG new file mode 100644 index 0000000..8caccf5 Binary files /dev/null and b/plugin.video.londonlive/resources/icon.PNG differ diff --git a/plugin.video.londonlive/resources/lib/academicearth/__init__.py b/plugin.video.londonlive/resources/lib/academicearth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugin.video.londonlive/resources/lib/academicearth/api.py b/plugin.video.londonlive/resources/lib/academicearth/api.py new file mode 100644 index 0000000..dc17d6c --- /dev/null +++ b/plugin.video.londonlive/resources/lib/academicearth/api.py @@ -0,0 +1,141 @@ +''' + + academicearth.api + ~~~~~~~~~~~~~~~~~ + + This module contains the API classes and method to parse information from + the Academic Earth website. + +''' +from scraper import (get_subjects, get_courses, get_subject_metadata, + get_course_metadata, get_lecture_metadata) + + +class AcademicEarth(object): + '''The main API object. Useful as a starting point to get available + subjects. + ''' + + def __init__(self): + pass + + def get_subjects(self): + '''Returns a list of subjects available on the website.''' + return [Subject(**info) for info in get_subjects()] + + +class Subject(object): + '''Object representing an Academic Earth subject.''' + + def __init__(self, url, name=None): + self.url = url + self._name = name + self._courses = None + self._lectures = None + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_subject_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._courses = [Course(**info) for info in resp['courses']] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._description = resp['description'] + self._loaded = True + + @property + def name(self): + '''Subject name''' + if not self._name: + self._load_metadata() + return self._name + + @property + def courses(self): + '''List of courses available for this subject''' + if not self._loaded: + self._load_metadata() + return self._courses + + @property + def lectures(self): + '''List of lectures available for this subject''' + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Course(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + self._lectures = None + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_course_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._lectures = [Lecture(**info) for info in resp['lectures']] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def lectures(self): + if not self._loaded: + self._load_metadata() + return self._lectures + + +class Lecture(object): + + def __init__(self, url, name=None, **kwargs): + self.url = url + self._name = name + self._loaded = False + + @classmethod + def from_url(cls, url): + return cls(url=url) + + def __repr__(self): + return u"" % self.name + + def _load_metadata(self): + resp = get_lecture_metadata(self.url) + if not self._name: + self._name = resp['name'] + self._youtube_id = resp['youtube_id'] + self._loaded = True + + @property + def name(self): + if not self._name: + self._load_metadata() + return self._name + + @property + def youtube_id(self): + if not self._loaded: + self._load_metadata() + return self._youtube_id diff --git a/plugin.video.londonlive/resources/lib/academicearth/scraper.py b/plugin.video.londonlive/resources/lib/academicearth/scraper.py new file mode 100644 index 0000000..1e14ec7 --- /dev/null +++ b/plugin.video.londonlive/resources/lib/academicearth/scraper.py @@ -0,0 +1,151 @@ +''' + academicearth.scraper + ~~~~~~~~~~~~~~~~~~~~~ + + This module contains some functions which do the website scraping for the + API module. You shouldn't have to use this module directly. +''' +import re +from urllib2 import urlopen +from urlparse import urljoin +from BeautifulSoup import BeautifulSoup as BS + + +BASE_URL = 'http://www.academicearth.org' +def _url(path): + '''Returns a full url for the given path''' + return urljoin(BASE_URL, path) + + +def get(url): + '''Performs a GET request for the given url and returns the response''' + conn = urlopen(url) + resp = conn.read() + conn.close() + return resp + + +def _html(url): + '''Downloads the resource at the given url and parses via BeautifulSoup''' + return BS(get(url), convertEntities=BS.HTML_ENTITIES) + + +def make_showall_url(url): + '''Takes an api url and appends info to the path to force the page to + return all entries instead of paginating. + ''' + if not url.endswith('/'): + url += '/' + return url + 'page:1/show:500' + + +def get_subjects(): + '''Returns a list of subjects for the website. Each subject is a dict with + keys of 'name' and 'url'. + ''' + url = _url('subjects') + html = _html(url) + subjs = html.findAll('a', + {'href': lambda attr_value: attr_value.startswith('/subjects/') + and len(attr_value) > len('/subjects/')}) + + # subjs will contain some duplicates so we will key on url + items = [] + urls = set() + for subj in subjs: + url = _url(subj['href']) + if url not in urls: + urls.add(url) + items.append({ + 'name': subj.string, + 'url': url, + }) + + # filter out any items that didn't parse correctly + return [item for item in items if item['name'] and item['url']] + + +def get_subject_metadata(subject_url): + '''Returns metadata for a subject parsed from the given url''' + html = _html(make_showall_url(subject_url)) + name = get_subject_name(html) + courses = get_courses(html) + lectures = get_lectures(html) + desc = get_subject_description(html) + + return { + 'name': name, + 'courses': courses, + 'lectures': lectures, + 'description': desc, + } + + +def get_subject_name(html): + return html.find('article').h1.text + + +def get_course_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_lecture_name(html): + return html.find('section', {'class': 'pagenav'}).span.text + + +def get_subject_description(html): + desc_nodes = html.find('article').findAll('span') + return '\n'.join(node.text.strip() for node in desc_nodes) + + +def _get_courses_or_lectures(class_type, html): + '''class_type can be 'course' or 'lecture'.''' + nodes = html.findAll('div', {'class': class_type}) + + items = [{ + 'name': node.h3.text, + 'url': _url(node.a['href']), + 'icon': node.img['src'], + #'university': '', + #'speaker': '', + } for node in nodes] + + return items + + +def get_lectures(html): + return _get_courses_or_lectures('lecture', html) + + +def get_courses(html): + return _get_courses_or_lectures('course', html) + + +def get_course_metadata(course_url): + html = _html(make_showall_url(course_url)) + lectures = get_lectures(html) + name = get_course_name(html) + return { + 'lectures': lectures, + 'name': name, + } + + +def get_lecture_metadata(lecture_url): + html = _html(lecture_url) + name = get_lecture_name(html) + youtube_id = parse_youtube_id(html) + return { + 'name': name, + 'youtube_id': youtube_id + } + + + +def parse_youtube_id(html): + embed = html.find('embed') + yt_ptn = re.compile(r'http://www.youtube.com/v/(.+?)\?') + match = yt_ptn.search(embed['src']) + if match: + return match.group(1) + return None diff --git a/plugin.video.londonlive/resources/settings.xml b/plugin.video.londonlive/resources/settings.xml new file mode 100644 index 0000000..e69de29 diff --git a/plugin.video.wnhq/LICENSE.txt b/plugin.video.wnhq/LICENSE.txt new file mode 100644 index 0000000..9aa03b3 --- /dev/null +++ b/plugin.video.wnhq/LICENSE.txt @@ -0,0 +1,12 @@ +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 . diff --git a/plugin.video.wnhq/README b/plugin.video.wnhq/README new file mode 100644 index 0000000..5341202 --- /dev/null +++ b/plugin.video.wnhq/README @@ -0,0 +1,2 @@ +Simply download the git, zip it as plugin.liveleak.zip and install like a normal zip. + diff --git a/plugin.video.wnhq/addon.xml b/plugin.video.wnhq/addon.xml new file mode 100644 index 0000000..3be34d8 --- /dev/null +++ b/plugin.video.wnhq/addon.xml @@ -0,0 +1,19 @@ + + + + + + + video + + + White Noise HQ live on your TV! + en + Keep up to date with the latest from everyone at White Noise HQ! + all + + diff --git a/plugin.video.wnhq/default.py b/plugin.video.wnhq/default.py new file mode 100644 index 0000000..bd15e03 --- /dev/null +++ b/plugin.video.wnhq/default.py @@ -0,0 +1,175 @@ +import sys +import urllib +import urlparse +import xbmcgui +import xbmcplugin + +base_url = sys.argv[0] +addon_handle = int(sys.argv[1]) +args = urlparse.parse_qs(sys.argv[2][1:]) + +xbmcplugin.setContent(addon_handle, 'movies') + +def build_url(query): + return base_url + '?' + urllib.urlencode(query) + +mode = args.get('mode', None) + +if mode is None: + url = build_url({'mode': 'folder', 'foldername': 'Folder One'}) + li = xbmcgui.ListItem('Live Radio (Audio)', iconImage='http://cdn.instructables.com/F21/3AKT/FX5571DH/F213AKTFX5571DH.MEDIUM.gif') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder6', 'foldername': 'Folder One'}) + li = xbmcgui.ListItem('YouTube Live Streams (Audio & Video)', iconImage='http://cdn.instructables.com/F21/3AKT/FX5571DH/F213AKTFX5571DH.MEDIUM.gif') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder1', 'foldername': 'Folder Two'}) + li = xbmcgui.ListItem('DJ Klass-A Radio Recordings', iconImage='http://static.house-mixes.com/s3/webmixes-images/accounts-410112/artwork/efa00ee9-1270-4820-92b3-0f502a85ced3.jpg/400/45/true') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder2', 'foldername': 'Folder Two'}) + li = xbmcgui.ListItem('WhiteNoiseHQ Vs Ballistic Beats', iconImage='http://www.whitenoisehq.co.uk/v3/WN&BBFront.jpg') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder3', 'foldername': 'Folder Two'}) + li = xbmcgui.ListItem('WhiteNoiseHQ - The Freeform Special', iconImage='http://farm5.static.flickr.com/4089/5040817729_d7d6efcb8e_b.jpg') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder4', 'foldername': 'Folder Two'}) + li = xbmcgui.ListItem('Lady Brock - House Series', iconImage='http://static.house-mixes.com/s3/webmixes-images/accounts-88106/artwork/73c5708c-8276-4545-afd7-b367d8bc760d.jpg/360/45/true') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + url = build_url({'mode': 'folder5', 'foldername': 'Folder Two'}) + li = xbmcgui.ListItem('White Noise HQ Recordings', iconImage='http://static.house-mixes.com/s3/webmixes-images/accounts-88106/artwork/73c5708c-8276-4545-afd7-b367d8bc760d.jpg/360/45/true') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, + listitem=li, isFolder=True) + + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder': + foldername = args['foldername'][0] + url = 'http://whitenoisehq.co.uk/v3/RevoltLive.m3u' + li = xbmcgui.ListItem('Revolt Party - Live Stream', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://whitenoisehq.co.uk/v3/RevoltBot.m3u' + li = xbmcgui.ListItem('Revolt Party - AutoDJ', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://whitenoisehq.co.uk/v3/PLUR.pls' + li = xbmcgui.ListItem('Peace Love Unity Radio', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder1': + foldername = args['foldername'][0] + url = 'http://lnd1.house-mixes.com/m/klass-a/3c081bc2-4404-45f7-8d2a-88f92441d77b.mp3' + li = xbmcgui.ListItem('DJ Klass-A - PLURadio 1st November 2014 (Hard House)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://lnd1.house-mixes.com/m/klass-a/0db80df5-8568-4e87-9d44-20d4ec6ec77b.mp3' + li = xbmcgui.ListItem('DJ Klass-A - PLURadio 25th October 2014 (UK Hardcore)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://lnd1.house-mixes.com/m/klass-a/be09b7e3-989c-4a0d-a7a8-d494096091d7.mp3' + li = xbmcgui.ListItem('DJ Klass-A with MC Tom Thumb - PLURadio 18th October 2014 (UK Hardcore)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://lnd1.house-mixes.com/m/klass-a/f892c47f-e6d9-4e5a-800e-60c88854568a.mp3' + li = xbmcgui.ListItem('DJ Klass-A - Revolt Party 19th October 2014 (UK Hardcore)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://lnd1.house-mixes.com/m/klass-a/11f7b6a5-1c3a-4904-b7ae-77a6a2d91a89.mp3' + li = xbmcgui.ListItem('DJ Klass-A - Revolt Party 12th October 2014 *(Gabba)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder2': + foldername = args['foldername'][0] + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=29' + li = xbmcgui.ListItem('Lady Brock b2b Double T @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=27' + li = xbmcgui.ListItem('Klass A b2b Program @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=28' + li = xbmcgui.ListItem('Kurt @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=24' + li = xbmcgui.ListItem('Darwin @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=26' + li = xbmcgui.ListItem('JB-C b2b Clodhopper @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=30' + li = xbmcgui.ListItem('Lil Miss Detonate b2b Bernzey @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=25' + li = xbmcgui.ListItem('Hoodzie b2b Vapour @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=32' + li = xbmcgui.ListItem('Mizel @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=31' + li = xbmcgui.ListItem('Hoodzie b2b Distortion @ White Noise HQ Vs Ballistic Beatz', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder3': + foldername = args['foldername'][0] + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=36' + li = xbmcgui.ListItem('Kevin Energy @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=39' + li = xbmcgui.ListItem('Nick235 @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=38' + li = xbmcgui.ListItem('Lady Brock @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=33' + li = xbmcgui.ListItem('Solution @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=35' + li = xbmcgui.ListItem('Greg Peaks & Pinnacle @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=37' + li = xbmcgui.ListItem('Klass-A & Program @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/?dl_id=34' + li = xbmcgui.ListItem('Double T @ White Noise HQ - The Freeform Special', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder4': + foldername = args['foldername'][0] + url = 'http://lnd1.house-mixes.com/m/lady%20brock/dab511e3-c2ae-4418-b658-cb71ec528032.mp3' + li = xbmcgui.ListItem('Lady Brock - House Series - 001 Tech & Progressive', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://lnd1.house-mixes.com/m/lady%20brock/54bac03a-a1dc-4e9f-8d37-95581a1c9792.mp3' + li = xbmcgui.ListItem('Lady Brock - House Series - 002 Electro', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder5': + foldername = args['foldername'][0] + url = 'http://www.whitenoisehq.co.uk/v3/wnhq001.m3u' + li = xbmcgui.ListItem('[WNHQ001] Lady Brock Vs Sc@r - Muppet (UK Hardcore)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/wnhq002.m3u' + li = xbmcgui.ListItem('[WNHQ002] Double T - Lil Fluffy Cloudz (Drum n Bass)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/wnhq003.m3u' + li = xbmcgui.ListItem('[WNHQ003] Force & Styles - Field Of Dreams (Firestrike Drumstep Remix) (Drumstep)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) + +elif mode[0] == 'folder6': + foldername = args['foldername'][0] + url = 'http://www.whitenoisehq.co.uk/v3/YouTube2.m3u' + li = xbmcgui.ListItem('[WNHQ Live] DJ Klass-A : Miss-Judged : Double T (UK Hardcore)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + url = 'http://www.whitenoisehq.co.uk/v3/YouTube.m3u' + li = xbmcgui.ListItem('[WNHQ Live] DJ Klass-A - Hard House Power Hour (Hard House)', iconImage='DefaultVideo.png') + xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li) + xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file diff --git a/plugin.video.wnhq/dummy.xml b/plugin.video.wnhq/dummy.xml new file mode 100644 index 0000000..de51110 --- /dev/null +++ b/plugin.video.wnhq/dummy.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + Dummyhttp://www.nada.com" dest="8"> + + + + + + + + + \ No newline at end of file diff --git a/plugin.video.wnhq/fanart.jpg b/plugin.video.wnhq/fanart.jpg new file mode 100644 index 0000000..bb56dfa Binary files /dev/null and b/plugin.video.wnhq/fanart.jpg differ diff --git a/plugin.video.wnhq/icon.png b/plugin.video.wnhq/icon.png new file mode 100644 index 0000000..ac1a48a Binary files /dev/null and b/plugin.video.wnhq/icon.png differ diff --git a/plugin.video.wnhq/resources/settings.xml b/plugin.video.wnhq/resources/settings.xml new file mode 100644 index 0000000..e747e0b --- /dev/null +++ b/plugin.video.wnhq/resources/settings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zips/addons.xml b/zips/addons.xml index 100f11f..756a7c9 100644 --- a/zips/addons.xml +++ b/zips/addons.xml @@ -1,5 +1,47 @@ + + + + + + audio + + + Kiss FM UK - Live Stream + KissFMUK.com + + English + all + + + http://www.kissfmuk.com + oli@whitenoisehq.co.uk + + + + + + + + + + audio + + + Rinse.FM - Live Stream + RinseFM live from Brick Lane, London + + English + all + + + http://rinse.fm + oli@whitenoisehq.co.uk + + + + @@ -21,6 +63,46 @@ + + + + + + video + + + London Live - Live Stream + LondonLive.co.uk + + English + all + + http://forum.xbmc.org/showthread.php?tid=190935 + http://www.londonlive.co.uk + oli@whitenoisehq.co.uk + + + + + + + + + + video + + + White Noise HQ live on your TV! + en + Keep up to date with the latest from everyone at White Noise HQ! + all + + + diff --git a/zips/addons.xml.md5 b/zips/addons.xml.md5 index 0193eea..f258e1b 100644 --- a/zips/addons.xml.md5 +++ b/zips/addons.xml.md5 @@ -1 +1 @@ -e3d70faa82043b4470f2617931f13613 \ No newline at end of file +a7bc395704ae09a3cf72205b65f2acfc \ No newline at end of file diff --git a/zips/plugin.audio.kissfm/addon.xml b/zips/plugin.audio.kissfm/addon.xml new file mode 100644 index 0000000..f68caa0 --- /dev/null +++ b/zips/plugin.audio.kissfm/addon.xml @@ -0,0 +1,21 @@ + + + + + + + audio + + + Kiss FM UK - Live Stream + KissFMUK.com + + English + all + + + http://www.kissfmuk.com + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/zips/plugin.audio.kissfm/fanart.jpg b/zips/plugin.audio.kissfm/fanart.jpg new file mode 100644 index 0000000..c666bc7 Binary files /dev/null and b/zips/plugin.audio.kissfm/fanart.jpg differ diff --git a/zips/plugin.audio.kissfm/plugin.audio.kissfm-0.2.zip b/zips/plugin.audio.kissfm/plugin.audio.kissfm-0.2.zip new file mode 100644 index 0000000..efeefbf Binary files /dev/null and b/zips/plugin.audio.kissfm/plugin.audio.kissfm-0.2.zip differ diff --git a/zips/plugin.audio.rinsefm/addon.xml b/zips/plugin.audio.rinsefm/addon.xml new file mode 100644 index 0000000..fed7cfd --- /dev/null +++ b/zips/plugin.audio.rinsefm/addon.xml @@ -0,0 +1,21 @@ + + + + + + + audio + + + Rinse.FM - Live Stream + RinseFM live from Brick Lane, London + + English + all + + + http://rinse.fm + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/zips/plugin.audio.rinsefm/fanart.jpg b/zips/plugin.audio.rinsefm/fanart.jpg new file mode 100644 index 0000000..849eeee Binary files /dev/null and b/zips/plugin.audio.rinsefm/fanart.jpg differ diff --git a/zips/plugin.audio.rinsefm/plugin.audio.rinsefm-0.2.zip b/zips/plugin.audio.rinsefm/plugin.audio.rinsefm-0.2.zip new file mode 100644 index 0000000..09c8641 Binary files /dev/null and b/zips/plugin.audio.rinsefm/plugin.audio.rinsefm-0.2.zip differ diff --git a/zips/plugin.video.londonlive/addon.xml b/zips/plugin.video.londonlive/addon.xml new file mode 100644 index 0000000..7e26655 --- /dev/null +++ b/zips/plugin.video.londonlive/addon.xml @@ -0,0 +1,21 @@ + + + + + + + video + + + London Live - Live Stream + LondonLive.co.uk + + English + all + + http://forum.xbmc.org/showthread.php?tid=190935 + http://www.londonlive.co.uk + oli@whitenoisehq.co.uk + + + \ No newline at end of file diff --git a/zips/plugin.video.londonlive/fanart.jpg b/zips/plugin.video.londonlive/fanart.jpg new file mode 100644 index 0000000..849eeee Binary files /dev/null and b/zips/plugin.video.londonlive/fanart.jpg differ diff --git a/zips/plugin.video.londonlive/plugin.video.londonlive-0.4.zip b/zips/plugin.video.londonlive/plugin.video.londonlive-0.4.zip new file mode 100644 index 0000000..a9d4077 Binary files /dev/null and b/zips/plugin.video.londonlive/plugin.video.londonlive-0.4.zip differ diff --git a/zips/plugin.video.wnhq/addon.xml b/zips/plugin.video.wnhq/addon.xml new file mode 100644 index 0000000..3be34d8 --- /dev/null +++ b/zips/plugin.video.wnhq/addon.xml @@ -0,0 +1,19 @@ + + + + + + + video + + + White Noise HQ live on your TV! + en + Keep up to date with the latest from everyone at White Noise HQ! + all + + diff --git a/zips/plugin.video.wnhq/fanart.jpg b/zips/plugin.video.wnhq/fanart.jpg new file mode 100644 index 0000000..bb56dfa Binary files /dev/null and b/zips/plugin.video.wnhq/fanart.jpg differ diff --git a/zips/plugin.video.wnhq/icon.png b/zips/plugin.video.wnhq/icon.png new file mode 100644 index 0000000..ac1a48a Binary files /dev/null and b/zips/plugin.video.wnhq/icon.png differ diff --git a/zips/plugin.video.wnhq/plugin.video.wnhq-0.3.zip b/zips/plugin.video.wnhq/plugin.video.wnhq-0.3.zip new file mode 100644 index 0000000..5c9e92a Binary files /dev/null and b/zips/plugin.video.wnhq/plugin.video.wnhq-0.3.zip differ