diff --git a/addons.xml b/addons.xml index 45c66df..c860357 100644 --- a/addons.xml +++ b/addons.xml @@ -25,10 +25,10 @@ - + @@ -526,7 +526,7 @@ diff --git a/addons.xml.md5 b/addons.xml.md5 index cebc05b..d22e202 100644 --- a/addons.xml.md5 +++ b/addons.xml.md5 @@ -1 +1 @@ -5bb1b3da70a69cd175cb83de1dafde41 addons.xml +66eb21924d62f198cf8e0aceceedb88c addons.xml diff --git a/plugin.audio.qingting/plugin.audio.qingting-1.0.1.zip b/plugin.audio.qingting/plugin.audio.qingting-1.0.1.zip index bfd7225..6ff7830 100644 Binary files a/plugin.audio.qingting/plugin.audio.qingting-1.0.1.zip and b/plugin.audio.qingting/plugin.audio.qingting-1.0.1.zip differ diff --git a/plugin.video.rrsp/addon.xml b/plugin.video.rrsp/addon.xml index d75f980..ad07253 100644 --- a/plugin.video.rrsp/addon.xml +++ b/plugin.video.rrsp/addon.xml @@ -1,7 +1,7 @@ diff --git a/plugin.video.rrsp/changelog.txt b/plugin.video.rrsp/changelog.txt index 9b902f5..0312b95 100644 --- a/plugin.video.rrsp/changelog.txt +++ b/plugin.video.rrsp/changelog.txt @@ -1,3 +1,7 @@ +v1.0.4 (2017.12.16) +- sort episodes +- add acfun.py. some videos come from ACFUN + v1.0.3 (2017.12.4) - add local search, search videos diff --git a/plugin.video.rrsp/dbase.py b/plugin.video.rrsp/dbase.py new file mode 100644 index 0000000..a4e1880 --- /dev/null +++ b/plugin.video.rrsp/dbase.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sqlite3 +import json +import urllib +conn = sqlite3.connect('test.db') + +c = conn.cursor() +c.execute('''CREATE TABLE MJINDEX + (ID INT PRIMARY KEY NOT NULL, + NAME TEXT NOT NULL);''') + +f = open('jss', 'r') +x = f.read() + +js = json.loads(x) +for x in js: + name = x.encode('utf-8') + cmd = "INSERT INTO MJINDEX (ID, NAME) VALUES ({0}, \"{1}\")".format(js[x], name) + print cmd + c.execute(cmd) + +conn.commit() +conn.close() diff --git a/plugin.video.rrsp/default.py b/plugin.video.rrsp/default.py index fbfa53c..958ee45 100644 --- a/plugin.video.rrsp/default.py +++ b/plugin.video.rrsp/default.py @@ -10,7 +10,10 @@ sys.path.append(os.path.join(ADDON_PATH, 'resources', 'lib')) from xbmcswift2 import Plugin, ListItem, xbmc, xbmcgui + from rrmj import RenRenMeiJu +from acfun import video_from_url + from urlparse import parse_qsl from urllib import urlencode from json import loads, dumps @@ -180,12 +183,8 @@ def movieCatList(catid): moviecat = Meiju.movie_catname()['data']['categoryList'] dialog = xbmcgui.Dialog() catlist = [x['name'] for x in moviecat] - cat_id = [x['id'] for x in moviecat] sel = dialog.select('分类(可能不全)', ['全部'] + catlist) - if sel == 0: - catid = '0' - elif sel > 0: - catid = cat_id[sel-1] + catid = moviecat[sel-1]['id'] if sel > 0 else '0' return movies(1, catid) @@ -232,16 +231,20 @@ def videodetail(videoId, title): video = Meiju.video_detail(videoId) play_url = video['data']['playLink'] if play_url: - stackurl = play_url.split('|') - play_url = 'stack://' + ' , '.join(stackurl) - li = ListItem(title, path=play_url) - li.set_info('video', {'title': title}) - plugin.set_resolved_url(li) + play_url = play_url.split('|') else: video = Meiju.video_detail2(videoId) url = video['data']['videoDetailView']['playLink'] - xbmcgui.Dialog().ok('视频地址' + url.encode('utf-8'), - '请使用其他插件搜索播放') + if 'acfun' in url: + play_url = video_from_url(url) + else: + xbmcgui.Dialog().ok('视频地址' + url.encode('utf-8'), + '请使用其他插件搜索播放') + return + + stackurl = 'stack://' + ' , '.join(play_url) + plugin.set_resolved_url(stackurl) + @plugin.route('/leafCategory//') @@ -364,7 +367,7 @@ def search(title, page): items = [] if searchlist: items.append({ - 'label': colorize(u'剧集', 'yellow'), + 'label': colorize(u'剧集搜索-'+ title.decode('utf-8'), 'yellow'), 'path': url_for('stay') }) for item in searchlist: @@ -409,6 +412,7 @@ def search(title, page): items += previous_page('search', page, total_page, title=title) for x in searchlist['results']: t = x.get('videoDuration', 0) + if int(t) < 0: t = 0 items.append({ 'label': x['title'], 'path': url_for('videodetail', @@ -477,8 +481,10 @@ def detail(seasonId): 'season': 0}, }) - plugin.finish(items, sort_methods=['episode']) - return items + unsorted = [(dict_['info']['episode'], dict_) for dict_ in items] + unsorted.sort() + sorted = [dict_ for (key, dict_) in unsorted] + return sorted @plugin.route('/play///', name='play_season') @@ -488,11 +494,11 @@ def play(seasonId='', index='', Esid=''): episode_sid = Esid play_url, _ = Meiju.get_by_sid(episode_sid, plugin.get_setting('quality')) if play_url is not None: - stackurl = play_url.split('|') - play_url = 'stack://' + ' , '.join(stackurl) + play_url = play_url.split('|') + stackurl = 'stack://' + ' , '.join(play_url) add_history(seasonId, index, Esid, title) li = ListItem(title+index, - path=play_url, + path=stackurl, thumbnail=season_data.get('cover')) li.set_info('video', {'title': title+index, 'plot': season_data.get('brief','')}) @@ -556,7 +562,7 @@ def update(page): # main entrance @plugin.route('/') def index(): - set_auto_play() + #set_auto_play() yield { 'label': u'分类', 'path': url_for('category'), diff --git a/plugin.video.rrsp/local.db b/plugin.video.rrsp/local.db new file mode 100644 index 0000000..1b37b9a Binary files /dev/null and b/plugin.video.rrsp/local.db differ diff --git a/plugin.video.rrsp/plugin.video.rrsp-1.0.3.zip b/plugin.video.rrsp/plugin.video.rrsp-1.0.4.zip similarity index 93% rename from plugin.video.rrsp/plugin.video.rrsp-1.0.3.zip rename to plugin.video.rrsp/plugin.video.rrsp-1.0.4.zip index 542a807..ced6e23 100644 Binary files a/plugin.video.rrsp/plugin.video.rrsp-1.0.3.zip and b/plugin.video.rrsp/plugin.video.rrsp-1.0.4.zip differ diff --git a/plugin.video.rrsp/resources/lib/acfun.py b/plugin.video.rrsp/resources/lib/acfun.py new file mode 100644 index 0000000..cd18db2 --- /dev/null +++ b/plugin.video.rrsp/resources/lib/acfun.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python + +from common import get_html, r1, match1 +from json import loads +import re +import base64 +import time + +def rc4(key, data): + c = list(range(256)) + g = 0 + for j in range(256): + g = (g + c[j] + ord(key[j % len(key)])) & 0xff + c[j], c[g] = c[g], c[j] + + g = j = 0 + f = '' + for m in range(len(data)): + j = (j + 1) & 0xff + g = (g + c[j]) & 0xff + c[j], c[g] = c[g], c[j] + + t = data[m] if isinstance(data[m], int) else ord(data[m]) + f += chr(t ^ c[(c[j] + c[g]) & 0xff]) + return f + + +class ACfun(): + def get_srt_json(self, id): + url = 'http://danmu.aixifan.com/V2/%s' % id + return get_html(url) + + def youku_acfun_proxy(self, vid, sign, ref): + endpoint = 'http://player.acfun.cn/flash_data?vid={}&ct=85&ev=3&sign={}&time={}' + url = endpoint.format(vid, sign, str(int(time.time() * 1000))) + json_data = loads(get_html(url, headers=dict(referer=ref)))['data'] + enc_text = base64.b64decode(json_data) + dec_text = rc4(b'8bdc7e1a', enc_text).decode('utf8') + youku_json = loads(dec_text) + + yk_streams = {} + for stream in youku_json['stream']: + tp = stream['stream_type'] + yk_streams[tp] = [], stream['total_size'] + if stream.get('segs'): + for seg in stream['segs']: + yk_streams[tp][0].append(seg['url']) + else: + yk_streams[tp] = stream['m3u8'], stream['total_size'] + + return yk_streams + + def video_from_vid(self, vid, **kwargs): + """str, str, str, bool, bool ->None + + Download Acfun video by vid. + + Call Acfun API, decide which site to use, and pass the job to its + extractor. + """ + + #first call the main parasing API + info = loads(get_html('http://www.acfun.tv/video/getVideo.aspx?id=' + vid)) + + sourceType = info['sourceType'] + + #decide sourceId to know which extractor to use + sourceId = info.get('sourceId', '') + # danmakuId = info['danmakuId'] + + #call extractor decided by sourceId + if sourceType == 'sina': + sina_download_by_vid(sourceId) + elif sourceType == 'youku': + youku_download_by_vid(sourceId, **kwargs) + elif sourceType == 'tudou': + tudou_download_by_iid(sourceId) + elif sourceType == 'qq': + qq_download_by_vid(sourceId) + elif sourceType == 'letv': + letvcloud_download_by_vu(sourceId, '2d8c027396') + elif sourceType == 'zhuzhan': + #As in Jul.28.2016, Acfun is using embsig to anti hotlink so we need to pass this + #In Mar. 2017 there is a dedicated ``acfun_proxy'' in youku cloud player + #old code removed + url = 'http://www.acfun.cn/v/ac' + vid + yk_streams = self.youku_acfun_proxy(info['sourceId'], info['encode'], url) + seq = ['mp4hd3', 'mp4hd2', 'mp4hd', 'flvhd', 'm3u8_flv'] + for t in seq: + if yk_streams.get(t): + preferred = yk_streams[t] + break + + return preferred[0] + else: + raise NotImplementedError(sourceType) + + + def video_from_url(self, url, **kwargs): + assert re.match(r'http://[^\.]*\.*acfun\.[^\.]+/\D/\D\D(\d+)', url) + html = get_html(url) + + title = r1(r'data-title="([^"]+)"', html) + assert title + if match1(url, r'_(\d+)$'): # current P + title = title + " " + r1(r'active">([^<]*)', html) + + vid = r1('data-vid="(\d+)"', html) + up = r1('data-name="([^"]+)"', html) + p_title = r1('active">([^<]+)', html) + title = '%s (%s)' % (title, up) + if p_title: + title = '%s - %s' % (title, p_title) + return self.video_from_vid(vid, **kwargs) + +site = ACfun() +video_from_url = site.video_from_url diff --git a/plugin.video.rrsp/resources/lib/rrmj.py b/plugin.video.rrsp/resources/lib/rrmj.py index dd07341..b2f977a 100644 --- a/plugin.video.rrsp/resources/lib/rrmj.py +++ b/plugin.video.rrsp/resources/lib/rrmj.py @@ -152,7 +152,6 @@ def get_token(self): def get_by_sid(self, episodeSid, quality='super'): API = '/video/findM3u8ByEpisodeSid' API = '/video/findM3u8ByEpisodeSidAuth' - url = SERVER + API headers = self.header body = { 'episodeSid': episodeSid, @@ -160,8 +159,7 @@ def get_by_sid(self, episodeSid, quality='super'): 'seasonId': 0, 'token': headers['token'] } - ppp = get_html(url, data=urlencode(body), headers=headers) - data = loads(ppp) + data = self.get_json(API, data=urlencode(body)) if data['code'] != '0000': return None, None else: diff --git a/plugin.video.rrsp/scratch.py b/plugin.video.rrsp/scratch.py new file mode 100644 index 0000000..9ad3a65 --- /dev/null +++ b/plugin.video.rrsp/scratch.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import urllib2 +from urllib import urlencode +import json +import gzip +import StringIO +import re + +SERVER = "https://api.rr.tv" +TOKEN = '0cd2626c822d49d5a27c4424a299dbaa' +TOKEN = 'a65cb45354614c23bf3e30ca12e043d3' +TOKEN = '8e575ee9b50643368d1c0792eb1a3f22' +#TOKEN = '1d71c7d377bc4b81b0c607b622b84b4b' +#TOKEN = "79e7dc7de5814908bc11e62972b6b819" +TOKEN = '6b6cfdd3e90843c0a0914425638db7ef' +FAKE_HEADERS = { + "clientType": "android_RRMJ", + "clientVersion": "3.6.2", + "token": TOKEN, + 'deviceId': '861134030056126', + 'signature': '643c184f77372e364550e77adc0360cd', + "Authentication": "RRTV 470164b995ea4aa5a53f9e5cbceded472:IxIYBj:LPWfRb:I9gvePR5R2N8muXD7NWPCj" +}; + + +UserAgent = 'PUClient/3.5.5 (iPhone; iOS 10.0.1; Scale/2.00)' +UserAgent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0' + +def GetHttpData(url, data=None, cookie=None, headers=None): +# print 'url: %s, data: %s, headers: %s' % (url, data, headers) + req = urllib2.Request(url, data) + req.add_header('User-Agent', UserAgent) + req.add_header('Accept-encoding', 'gzip') + if cookie is not None: + req.add_header('Cookie', cookie) + if headers is not None: + for header in headers: + req.add_header(header, headers[header]) + + response = urllib2.urlopen(req, timeout=3) + httpdata = response.read() + if response.headers.get('content-encoding', None) == 'gzip': + httpdata = gzip.GzipFile(fileobj=StringIO.StringIO(httpdata)).read() + response.close() + match = re.compile('encoding=(.+?)"').findall(httpdata) + if not match: + match = re.compile('meta charset="(.+?)"').findall(httpdata) + if match: + charset = match[0].lower() + if (charset != 'utf-8') and (charset != 'utf8'): + httpdata = unicode(httpdata, charset).encode('utf8') +# print httpdata + return httpdata + + +class RenRenMeiJu(): + """docstring for RenRenMeiJu""" + + def __init__(self): + self.header = FAKE_HEADERS + + def get_json(self, api, data=None, pretty=False): + headers = self.header + html = GetHttpData(SERVER+api, data=data, headers=FAKE_HEADERS) + s = json.loads(html) + if pretty: + print headers + print json.dumps(s, sort_keys=True, + indent=4, separators=(',', ': ')) + return html + + def func(self, API='/v3plus', **kwargs): + return self.get_json(API, data=urlencode(kwargs)) + +#x = GetTokenX() +meiju=RenRenMeiJu() +API='/v3plus/season/detail' + +for x in range(13000,14000): + html = meiju.func(API=API,seasonId=x) + js = json.loads(html) + if js['code'] != '0000': + print js['msg'] + continue + print js['data']['season']['title'], js['data']['season']['id'] + diff --git a/plugin.video.youku2/addon.xml b/plugin.video.youku2/addon.xml index 8720dc7..4072d2d 100644 --- a/plugin.video.youku2/addon.xml +++ b/plugin.video.youku2/addon.xml @@ -1,8 +1,9 @@ + diff --git a/plugin.video.youku2/default.py b/plugin.video.youku2/default.py index 8aa5485..93da37b 100644 --- a/plugin.video.youku2/default.py +++ b/plugin.video.youku2/default.py @@ -1,17 +1,13 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -import xbmc -from xbmcgui import Dialog, ListItem -import xbmcplugin +from xbmcswift2 import Plugin, xbmcgui, xbmc import xbmcaddon -from urlparse import parse_qsl from urllib import quote_plus -import sys from json import loads from bs4 import BeautifulSoup from common import get_html, match1 -from youku import video_from_url as video_from_url +from youku import video_from_url, video_from_vid ######################################################################## # 优酷 www.youku.com @@ -19,70 +15,16 @@ # Plugin constants __addon__ = xbmcaddon.Addon() -__addonid__ = __addon__.getAddonInfo('id') __addonname__ = __addon__.getAddonInfo('name') -__profile__ = xbmc.translatePath(__addon__.getAddonInfo('profile')) - -UserAgent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)' -UserAgent = 'Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5' -#UserAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3' -UserAgent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0' LIST_URL = 'http://list.youku.com' BANNER_FMT = '[COLOR FFDEB887][%s][/COLOR]' -TIMER_FMT = '[COLOR FF8040C0](%s)[/COLOR]' -INDENT_FMT0 = '[COLOR FFDEB887] %s[/COLOR]' -INDENT_FMT1 = '[COLOR FFDEB8FF] %s[/COLOR]' +plugin = Plugin() +url_for = plugin.url_for ############################################################################ -def PlayVideo(params): - url = params['url'] - title = params['title'] - thumb = params.get('thumb') - level = int(__addon__.getSetting('resolution')) - playmode = __addon__.getSetting('video_vplaycont') - - if level == 4: - dialog = Dialog() - level = dialog.select('清晰度选择', ['流畅', '高清', '超清', '1080P']) - level = max(0, level) - - playlistA = xbmc.PlayList(1) - playlist = xbmc.PlayList(0) - playlist.clear() - - title = title.split('.') - v_pos = int(title[0]) - title = '.'.join(title[1:]) - psize = playlistA.size() - - for x in range(v_pos, psize): - p_item = playlistA.__getitem__(x) - p_url = p_item.getfilename(x) - p_list = p_item.getdescription(x) - li = p_item # pass all li items including the embedded thumb image - - urls = video_from_url(url, level=level) - - ulen = len(urls) - if ulen < 1: - Dialog().ok(__addonname__, '未匹配到VID') - return - - for i in range(ulen): - name = title + '(%d/%d)' % (i + 1, ulen) - li = ListItem(name, thumbnailImage=thumb) - li.setInfo(type='Video', infoLabels={'Title': name}) - playlist.add(urls[i], li) - - if x == v_pos: - xbmc.Player(0).play(playlist) - xbmc.sleep(1500) - if playmode == 'false': - break - def httphead(url): if len(url) < 2: @@ -95,93 +37,34 @@ def httphead(url): return url -def mainMenu(): - li = ListItem('[COLOR FF00FF00] 【优酷视频 - 搜索】[/COLOR]') - u = sys.argv[0] + '?mode=search' - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) +@plugin.route('/stay') +def stay(): + pass - html = get_html(LIST_URL) - tree = BeautifulSoup(html, 'html.parser') - soup = tree.find_all('div', {'class': 'yk-filter'}) - grp = soup[0].find_all('li') - for prog in grp[1:]: - try: - href = prog.a['href'] - except: - break - name = prog.text - href = httphead(href) +@plugin.route('/playvideo/') +def playvideo(url): + level = int(__addon__.getSetting('resolution')) - li = ListItem(name) - u = sys.argv[0] + '?url=' + href - u += '&mode=videolist&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) + urls = video_from_url(url, level=level) - xbmcplugin.endOfDirectory(int(sys.argv[1])) + stackurl = 'stack://' + ' , '.join(urls) + plugin.set_resolved_url(stackurl) -def listSubMenu(params): - name = params['name'] - url = params['url'] - filter = params.get('filter', '') - sort = params.get('sort', '') +@plugin.route('/playvid/') +def playvid(vid): + level = int(__addon__.getSetting('resolution')) - li = ListItem(BANNER_FMT % (name+'(分类过滤 %s)' % filter.encode('utf-8'))) - u = sys.argv[0] + '?url=' + url - u += '&mode=select&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) + urls = video_from_vid(vid, level=level) - html = get_html(url) - tree = BeautifulSoup(html, 'html.parser') - # 分页 - soup = tree.find_all('ul', {'class': 'yk-pages'}) - pages = soup[0].find_all('li') - for page in pages: - try: - href = page.a['href'] - except: - continue - title = page.text - href = httphead(href) - li = ListItem(BANNER_FMT % title) - u = sys.argv[0] + '?url=' + href - u += '&mode=videolist&name=' + quote_plus(name) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) + stackurl = 'stack://' + ' , '.join(urls) + plugin.set_resolved_url(stackurl) - # 剧目清单 - #items = soup[0].find_all('div', {'class': 'p-thumb'}) - items = tree.find_all('div', {'class': 'yk-pack'}) - for item in items: - title = item.a['title'] - href = httphead(item.a['href']) - img = httphead(item.img['src']) - pay = item.find('span', {'class': 'vip-free'}) - if pay: - pay = '([COLOR FFFF00FF]%s' + pay.text + '[/COLOR])' - else: - pay = '%s' - pt = item.find('span', {'class': 'p-time'}) - try: - ptime = pt.text + ' ' - except: - ptime = '' - li = ListItem(title + pay % (ptime), - iconImage=img, thumbnailImage=img) - u = sys.argv[0] + '?url=' + href - u += '&name=' + quote_plus(name) - u += '&mode=episodelist&title=' + title - u += '&thumb=' + img - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'movies') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def normalSelect(params): - url = params.get('url') - name = params.get('name') - filter = params.get('filter', '') + +@plugin.route('/select/') +def select(url): + filter = '' surl = url.split('/') purl = surl[-1][:-5].split('_') keystate = {'a': 0, # 地区 @@ -202,9 +85,9 @@ def normalSelect(params): html = get_html(url) tree = BeautifulSoup(html, 'html.parser') - color = '[COLOR FF00FF00]%s[/COLOR]' + color = '[COLOR purple]%s[/COLOR]' - list = [] + lists = [] soup = tree.find_all('div', {'class': 'item'}) for iclass in soup[1:]: x = [] @@ -219,7 +102,7 @@ def normalSelect(params): href = subitem.a['href'].encode('utf-8') x.append(dict({title: href})) - list.append(dict({label: x})) + lists.append(dict({label: x})) sort = tree.find_all('div', {'class': 'yk-sort-item'}) for iclass in sort: @@ -231,11 +114,11 @@ def normalSelect(params): href = subitem.a['href'].encode('utf-8') x.append(dict({title: href})) - list.append(dict({label: x})) + lists.append(dict({label: x})) - dialog = Dialog() + dialog = xbmcgui.Dialog() - for item in list: + for item in lists: title = item.keys()[0] y = item[title] l = [x.keys()[0] for x in y] @@ -268,7 +151,6 @@ def normalSelect(params): if purl[index+1] not in keyword: oldv = purl.pop(index+1) purl.insert(index+1, v) - except: purl += [k, v] @@ -277,86 +159,69 @@ def normalSelect(params): surl[-1] = '_'.join(purl) + '.html' url = '/'.join(surl) - params['url'] = url - params['filter'] = filter - listSubMenu(params) + return videolist(url=url, filter=filter.encode('utf-8')) -def episodesList(params): - url = params['url'] - thumb = params['thumb'] +@plugin.route('/episodelist/') +def episodelist(url): + plugin.set_content('video') html = get_html(url) tree = BeautifulSoup(html, 'html.parser') - - playlist = xbmc.PlayList(1) - playlist.clear() - j = 0 + items = [] # 主题视频 #soup = tree.find_all('div', {'class': 'lists'}) - items = tree.find_all('div', {'class': 'program'}) - if len(items) < 1: - desc = tree.find_all('meta', {'name': 'description'}) - info = desc[0]['content'] - title = params['title'] - p_thumb = params['thumb'] - u = sys.argv[0] + '?url=' + url - u += '&mode=playvideo' - u += '&title=%d.%s' % (j, title) - u += '&thumb=' + p_thumb - li = ListItem(title, - iconImage=p_thumb, thumbnailImage=p_thumb) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - playlist.add(url, li) - j += 1 + programs = tree.find_all('div', {'class': 'program'}) + if len(programs) < 1: + info = tree.find('meta', {'name': 'description'})['content'] + title = tree.find('meta', {'name': 'title'})['content'] + items.append({ + 'label': title, + 'path': url_for('playvideo', url=url), + 'is_playable': True, + 'info': {'title': title, 'plot': info} + }) else: - for item in items: - title = item['title'] - href = httphead(item.a['href']) - img = item.img['src'] - t = item.find('span', {'class': 'c-time'}) - time = t.text - u = sys.argv[0] + '?url=' + href + '&mode=playvideo' - u += '&title=%d.%s' % (j, title) + '&thumb=' + img - li = ListItem(title + '(' + time + ')', - iconImage=img, thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title}) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - playlist.add(href, li) - j += 1 - - items = tree.find_all('div', {'class': 'item '}) - - for item in items: - title = item['title'] - href = httphead(item.a['href']) - u = sys.argv[0] + '?url=' + href + '&mode=playvideo' - u += '&title=%d.%s' % (j, title) + '&thumb=' + thumb - li = ListItem(title, iconImage=thumb, thumbnailImage=thumb) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - playlist.add(href, li) - j += 1 - - li = ListItem(BANNER_FMT % '相关视频') - u = sys.argv[0] - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) + for item in programs: + dr = item.find('span', {'class': 'c-time'}).text + duration = 0 + for t in dr.split(':'): + duration = duration * 60 + int(t) + items.append({ + 'label': item['title'], + 'path': url_for('playvideo', url=httphead(item.a['href'])), + 'thumbnail': item.img['src'], + 'is_playable': True, + 'info': {'title': item['title'], 'duration': duration} + }) + + programs = tree.find_all('div', {'class': 'item '}) + + for item in programs: + intro = item.find('div', {'class': 'show_aspect'}) + items.append({ + 'label': item['title'], + 'path': url_for('playvideo', url=httphead(item.a['href'])), + 'is_playable': True, + 'info': {'title': item['title'], 'plot': intro.text} + }) # 相关视频 + items.append({ + 'label': BANNER_FMT % '相关视频', + 'path': url_for('stay') + }) soup = tree.find_all('div', {'class': 'textlists'}) try: - items = soup[0].find_all('li') - for item in items: - title = item['title'] - href = httphead(item.a['href']) - u = sys.argv[0] + '?url=' + href - u += '&mode=playvideo&title=%d.%s' % (j, title) - li = ListItem(title) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - playlist.add(href, li) - j += 1 - + lists = soup[0].find_all('li') + for item in lists: + items.append({ + 'label': item['title'], + 'path': url_for('playvideo', url=httphead(item.a['href'])), + 'is_playable': True, + 'info': {'title': item['title']} + }) except: pass @@ -373,21 +238,18 @@ def episodesList(params): jsdata = loads(html.encode('utf-8')) jsdata = jsdata['data'] for item in jsdata: - title = item['title'] - href = httphead(item['playLink']) - img = item['picUrl'] - u = sys.argv[0] + '?url=' + href - u += '&mode=playvideo&title=%d.%s' % (j, title) + '&thumb=' + img - li = ListItem(title, iconImage=img, thumbnailImage=img) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - playlist.add(href, li) - j += 1 - - xbmcplugin.setContent(int(sys.argv[1]), 'episodes') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def searchInYouku(params): + items.append({ + 'label': item['title'], + 'path': url_for('playvideo', url=httphead(item['playLink'])), + 'thumbnail': item['picUrl'], + 'is_playable': True, + 'info': {'title': item['title']} + }) + return items + + +@plugin.route('/search/') +def search(): keyboard = xbmc.Keyboard('', '请输入搜索内容') xbmc.sleep(1500) keyboard.doModal() @@ -395,52 +257,110 @@ def searchInYouku(params): return keyword = keyboard.getText() key = quote_plus(keyword) - p_url = 'http://www.soku.com/search_video/q_' + searchapi = 'http://tv.api.3g.youku.com/openapi-wireless/videos/search/{}?pid=0ce22bfd5ef5d2c5&pz=500' - link = get_html(p_url + key) + link = get_html(searchapi.format(key)) if link is None: - li = ListItem(' 抱歉,没有找到[COLOR FFFF0000] ' + keyword + ' [/COL OR]的相关视频') - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - xbmcplugin.endOfDirectory(int(sys.argv[1])) - return + xbmcgui.Dialog().ok(__addonname__, + ' 抱歉,没有找到[COLOR FFFF0000] ' + keyword + + ' [/COLOR]的相关视频') + return [] # fetch and build the video series episode list - content = BeautifulSoup(link, 'html.parser') - soup1 = content.find_all('div', {'class': 's_movie clearfix'}) - soup2 = content.find_all('div', {'class': 's_tv clearfix'}) - - for item in soup1 + soup2: - img = item.img['src'] - detail = item.find('div', {'class': 's_detail'}) - href = detail.a['href'] - title = detail.a.text - info = item.find('div', {'class': 'info_cont'}) - info = info.span.text - - li = ListItem(title, iconImage='', thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - u = sys.argv[0] + '?url=' + href + '&mode=episodelist' - u += '&thumb=' + img + '&title=' + title - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'episodes') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -# main programs goes here ######################################### -params = sys.argv[2][1:] -params = dict(parse_qsl(params)) - -mode = params.get('mode') - -runlist = { - None: 'mainMenu()', - 'videolist': 'listSubMenu(params)', - 'episodelist': 'episodesList(params)', - 'playvideo': 'PlayVideo(params)', - 'search': 'searchInYouku(params)', - 'select': 'normalSelect(params)' -} - -exec(runlist[mode]) + finds = loads(link) + items = [] + for item in finds['results']: + img = item['img'] + videoid = item['videoid'] + title = item['title'] + info = item['desc'] + duration = 0 + for t in item['duration'].split(':'): + duration = duration*60 + int(t) + + items.append({ + 'label': item['title'], + 'path': url_for('playvid', vid=videoid), + 'thumbnail': item['img'], + 'is_playable': True, + 'info': {'title': item['title'], 'plot': item['desc'], + 'duration': duration} + }) + return items + + +@plugin.route('/videolist//') +def videolist(url, filter): + filter1 = '' if filter == '0' else filter + items = [{ + 'label': BANNER_FMT % ('分类过滤: ' + filter1), + 'path': url_for('select', url=url) + }] + + html = get_html(url) + tree = BeautifulSoup(html, 'html.parser') + # 分页 + soup = tree.find_all('ul', {'class': 'yk-pages'}) + try: + pages = soup[0].find_all('li') + for page in pages: + try: + href = page.a['href'] + except: + continue + items.append({ + 'label': BANNER_FMT % page.text, + 'path': url_for('videolist', url=httphead(href), filter=filter) + }) + except: + pass + + # 剧目清单 + #items = soup[0].find_all('div', {'class': 'p-thumb'}) + lists = tree.find_all('div', {'class': 'yk-pack'}) + for item in lists: + pay = item.find('span', {'class': 'vip-free'}) + if pay: + pay = '([COLOR pink]%s' + pay.text + '[/COLOR])' + else: + pay = '%s' + pt = item.find('span', {'class': 'p-time'}) + try: + ptime = pt.text + ' ' + except: + ptime = '' + + items.append({ + 'label': item.a['title'] + pay % (ptime), + 'path': url_for('episodelist', url=httphead(item.a['href'])), + 'thumbnail': httphead(item.img['src']), + }) + return items + + +@plugin.route('/') +def index(): + yield { + 'label': '[COLOR green] 【优酷视频 - 搜索】[/COLOR]', + 'path': url_for('search') + } + + html = get_html(LIST_URL) + tree = BeautifulSoup(html, 'html.parser') + soup = tree.find_all('div', {'class': 'yk-filter'}) + + grp = soup[0].find_all('li') + for prog in grp[1:]: + try: + href = prog.a['href'] + except: + continue + yield { + 'label': prog.text, + 'path': url_for('videolist', url=httphead(href), filter='0') + } + + +if __name__ == '__main__': + plugin.run() diff --git a/plugin.video.youku2/plugin.video.youku2-1.0.1.zip b/plugin.video.youku2/plugin.video.youku2-1.0.2.zip similarity index 92% rename from plugin.video.youku2/plugin.video.youku2-1.0.1.zip rename to plugin.video.youku2/plugin.video.youku2-1.0.2.zip index a9b8069..61b1b93 100644 Binary files a/plugin.video.youku2/plugin.video.youku2-1.0.1.zip and b/plugin.video.youku2/plugin.video.youku2-1.0.2.zip differ diff --git a/plugin.video.youku2/resources/settings.xml b/plugin.video.youku2/resources/settings.xml index 8475d28..2080f94 100644 --- a/plugin.video.youku2/resources/settings.xml +++ b/plugin.video.youku2/resources/settings.xml @@ -1,5 +1,4 @@ - - + diff --git a/plugin.video.youkuvideo/LICENSE b/plugin.video.youkuvideo/LICENSE deleted file mode 100644 index 80ee640..0000000 --- a/plugin.video.youkuvideo/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - 网易公开课XBMC插件 - Copyright (C) 2013 tacy - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/plugin.video.youkuvideo/README.md b/plugin.video.youkuvideo/README.md deleted file mode 100644 index 46c735c..0000000 --- a/plugin.video.youkuvideo/README.md +++ /dev/null @@ -1,2 +0,0 @@ -fork from https://github.com/XinFanTV/plugin.video.youku2 -========== diff --git a/plugin.video.youkuvideo/addon.py b/plugin.video.youkuvideo/addon.py deleted file mode 100644 index 8345fb8..0000000 --- a/plugin.video.youkuvideo/addon.py +++ /dev/null @@ -1,551 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -from xbmcswift2 import xbmc, Plugin, xbmcgui -import re -from json import loads -import gzip -import urllib -import urllib2 -import httplib -import base64 -import time -from StringIO import StringIO -from collections_backport import OrderedDict - -plugin = Plugin() -dialog = xbmcgui.Dialog() -filters = plugin.get_storage('ftcache', TTL=1440) -epcache = plugin.get_storage('epcache', TTL=1440) - -@plugin.route('/') -def showcatalog(): - """ - show catalog list - """ - url = 'http://www.youku.com/v/' - if url in epcache: return epcache[url] - result = _http(url) - catastr = re.search(r'yk-filter-panel">(.*?)yk-filter-handle', - result, re.S) - catalogs = re.findall(r'href="(.*?)".*?>(.*?)', catastr.group(1)) - menus = [{ - 'label': catalog[-1].decode('utf-8'), - 'path': plugin.url_for('showmovie', - url='http://www.youku.com{0}'.format(catalog[0])), - } for catalog in catalogs] - menus.insert(0, {'label': '【搜索视频】选择', 'path': plugin.url_for( - 'searchvideo', url='http://www.soku.com/search_video/q_')}) - menus.append({'label': '手动清除缓存【缓存24小时自动失效】', - 'path': plugin.url_for('clscache')}) - epcache[url] = menus - return menus - -@plugin.route('/searchvideo/') -def searchvideo(url): - """ - search video - """ - source = [('http://v.youku.com', 'youku'), - ('http://tv.sohu.com', 'sohu'), - ('http://v.qq.com', 'qq'), - ('http://www.iqiyi.com', 'iqiyi'), - ('http://www.letv.com', 'letv'), - ('http://v.pps.tv', 'pps'), - ('http://www.tudou.com', 'tudou')] - kb = xbmc.Keyboard('',u'请输入搜索关键字') - kb.doModal() - if not kb.isConfirmed(): return - sstr = kb.getText() - if not sstr: return - url = url + urllib2.quote(sstr) - result = _http(url) - movstr = re.findall(r'
(.*?)', result, re.S) - vitempat = re.compile( - r'{0}{1}'.format('p_link">.*?title="(.*?)".*?p_thumb.*?src="(.*?)"', - '.*?status="(.*?)"'), re.S) - menus = [] - site = None - for movitem in movstr: - if 'p_ispaid' in movitem or 'nosource' in movitem: continue - psrc = re.compile(r'pgm-source(.*?)
', re.S).search(movitem) - if not psrc: continue - for k in source: - if k[0] in psrc.group(1): - site = k - break - if not site: continue - vitem = vitempat.search(movitem) - - if 'class="movie"' in movitem: - eps = re.search(r'(%s.*?html)' % site[0], movitem, re.S).group(1) - menus.append({ - 'label': '%s【%s】(%s)' % ( - vitem.group(1), vitem.group(3), site[1]), - 'path': plugin.url_for('playsearch', url=eps, source=site[1]), - 'thumbnail': vitem.group(2),}) - - if 'class="tv"' in movitem or 'class="zy"' in movitem: - if 'class="tv"' in movitem: - epss = re.findall( - r'(%s.*?html).*?>([\w ."]+?)' % site[0], movitem, re.S) - else: - epss = re.findall(r'{0}{1}{2}'.format( - '"(?:(?:date)|(?:phases))">([\d-]+)\s+([^>]+?)<(?:(?:em)|(?:/a))(?s)'), - movitem) - epss = [(i[1], '[%s]%s' % (i[0], i[2])) for i in epss] - #epss = reversed([(k, v) for k,v in OrderedDict(reversed(epss)). - # iteritems() if '查看全部' not in v]) - epss = [(v[0], site[1], v[1]) for v in epss] - menus.append({ - 'label': '%s【%s】(%s)' % ( - vitem.group(1), vitem.group(3), site[1]), - 'path': plugin.url_for('showsearch', url=str(epss)), - 'thumbnail': vitem.group(2),}) - return menus - -@plugin.route('/showsearch/') -def showsearch(url): - """ - url: 0 is url, 1 is play site, 2 is title - """ - items = eval(url) - if len(items)>100: - items = sorted(list(set(items)), key=lambda item: int(item[2])) - menus = [{'label': item[2], - 'path': plugin.url_for('playsearch', url=item[0], source=item[1]), - } for item in items] - return menus - -@plugin.route('/movies/') -def showmovie(url): - """ - show movie list - """ - #filter key, e.g. 'http://www.youku.com/v_showlist/c90' - urlsps = re.findall(r'(.*?/[a-z]_*\d+)', url) - key = urlsps[0] - #filter movie by filters - if 'change' in url: - url = key - for k, v in filters[key].iteritems(): - if '筛选' in k: continue - fts = [m[1] for m in v] - selitem = dialog.select(k, fts) - if selitem is -1: return - url = '{0}{1}'.format(url,v[selitem][0]) - url='{0}.html'.format(url) - print '*'*80, url - - if url in epcache: return epcache[url] - - result = _http(url) - - #get catalog filter list, filter will be cache - #filters item example: - # key:'http://www.youku.com/v_olist/c_97' - # value: '{'地区':('_a_大陆', '大陆', ...)} - if key not in filters: - filterstr = re.search(r'yk-filter-panel">(.*?)yk-filter-handle', - result, re.S) - filtertypes = re.findall(r'