diff --git a/addons.xml b/addons.xml index db048f2..6bad2ca 100644 --- a/addons.xml +++ b/addons.xml @@ -586,11 +586,11 @@ - + diff --git a/addons.xml.md5 b/addons.xml.md5 index 8bf928e..b610c34 100644 --- a/addons.xml.md5 +++ b/addons.xml.md5 @@ -1 +1 @@ -6f950d4432087aab00f1b0eb54b6a958 addons.xml +6f1710fee0aa7e01cd890dba04021db5 addons.xml diff --git a/plugin.video.5ivdo/resources/settings.xml b/plugin.video.5ivdo/resources/settings.xml index 918cfec..2b98044 100644 --- a/plugin.video.5ivdo/resources/settings.xml +++ b/plugin.video.5ivdo/resources/settings.xml @@ -1,4 +1,4 @@ - + diff --git a/plugin.video.baiduyun/resources/settings.xml b/plugin.video.baiduyun/resources/settings.xml index 50a13aa..6006ab0 100644 --- a/plugin.video.baiduyun/resources/settings.xml +++ b/plugin.video.baiduyun/resources/settings.xml @@ -1,4 +1,4 @@ - + diff --git a/plugin.video.cntv-video/addon.xml b/plugin.video.cntv-video/addon.xml index 3de8161..2246ae2 100644 --- a/plugin.video.cntv-video/addon.xml +++ b/plugin.video.cntv-video/addon.xml @@ -1,7 +1,7 @@ diff --git a/plugin.video.cntv-video/lib/tudou.py b/plugin.video.cntv-video/lib/tudou.py index 2d5b3b1..34e3cf3 100644 --- a/plugin.video.cntv-video/lib/tudou.py +++ b/plugin.video.cntv-video/lib/tudou.py @@ -1,76 +1,76 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- +#!/usr/bin/env python -import re +from xml.dom.minidom import parseString from json import loads -from common import get_html, r1 - - -HOST_URL = 'http://www.tudou.com' +from common import get_html, match1, r1 class Tudou(): - def video_from_iid(self, iid, **kwargs): - url = 'http://www.tudou.com/outplay/goto/getItemSegs.action?iid=%s' - html = get_html(url % iid) - data = loads(html) - - keys = data.keys() - for key in keys: - if data[key][0].get('size'): - vids = [t['k'] for t in data[key]] - break + def tudou_download_by_iid(self, iid, title, **kwargs): + data = loads(get_html('http://www.tudou.com/outplay/goto/getItemSegs.action?iid=%s' % iid)) + temp = max([data[i] for i in data if 'size' in data[i][0]], key=lambda x:sum([part['size'] for part in x])) + vids, size = [t["k"] for t in temp], sum([t["size"] for t in temp]) urls = [] for vid in vids: - html = get_html('http://cnc.v2.tudou.com/f?id=%d&jp=1' % vid) - y = re.compile('(http.+?)<\/f>').findall(html) - if len(y) < 1: - break - y = y[0].replace('&', '&') - urls.append(y.strip()) + for i in parseString(get_html('http://ct.v2.tudou.com/f?id=%s' % vid)).getElementsByTagName('f'): + urls.append(i.firstChild.nodeValue.strip()) + return urls - def video_from_id(self, id, **kwargs): + def tudou_download_by_id(self, id, title, **kwargs): html = get_html('http://www.tudou.com/programs/view/%s/' % id) iid = r1(r'iid\s*[:=]\s*(\S+)', html) - return self.video_from_iid(iid, **kwargs) - - def parse_plist(url): - html = get_html(url) - lcode = r1(r"lcode:\s*'([^']+)'", html) - plist_info = loads(get_html('http://www.tudou.com/crp/plist.action?lcode=' + lcode)) - return ([(item['kw'], item['iid']) for item in plist_info['items']]) - - def download_playlist(self, url, **kwargs): - videos = parse_plist(url) - urls = [] - for i, (title, id) in enumerate(videos): - print('Processing %s of %s videos...' % (i + 1, len(videos))) - urls += self.video_from_iid(id) + try: + title = r1(r'kw\s*[:=]\s*[\'\"]([^\n]+?)\'\s*\n', html).replace("\\'", "\'") + except AttributeError: + title = '' + return self.tudou_download_by_iid(iid, title, **kwargs) def video_from_url(self, url, **kwargs): # Embedded player - id = r1(r'http://www.tudou.com/v/([^/]+)/', url) + id = r1(r'.tudou.com/v/([^/]+)/', url) if id: - return self.video_from_id(id, **kwargs) - + return self.tudou_download_by_id(id, title='') + html = get_html(url) - + try: + title = r1(r'\Wkw\s*[:=]\s*[\'\"]([^\n]+?)\'\s*\n', html).replace("\\'", "\'") + assert title + title = unescape_html(title) + except AttributeError: + title = match1(html, r'id=\"subtitle\"\s*title\s*=\s*\"([^\"]+)\"') + if title is None: + title = '' + vcode = r1(r'vcode\s*[:=]\s*\'([^\']+)\'', html) if vcode is None: vcode = match1(html, r'viden\s*[:=]\s*\"([\w+/=]+)\"') if vcode: - from youku import video_from_vid - return video_from_vid(vcode, **kwargs) - + print "vcode", vcode + from youku import Youku + return Youku().video_from_vid(vcode, **kwargs) + iid = r1(r'iid\s*[:=]\s*(\d+)', html) if not iid: - return self.download_playlist(url) + return self.tudou_download_playlist(url, **kwargs) else: - return self.video_from_iid(iid, **kwargs) + return self.tudou_download_by_iid(iid, title, **kwargs) + + def parse_plist(self, url): + html = get_html(url) + lcode = r1(r"lcode:\s*'([^']+)'", html) + plist_info = loads(get_html('http://www.tudou.com/crp/plist.action?lcode=' + lcode)) + return ([(item['kw'], item['iid']) for item in plist_info['items']]) + def tudou_download_playlist(url, **kwargs): + videos = self.parse_plist(url) + for i, (title, id) in enumerate(videos): + print('Processing %s of %s videos...' % (i + 1, len(videos))) + self.tudou_download_by_iid(id, title, **kwargs) site = Tudou() -video_from_iid = site.video_from_iid +video_from_url = site.video_from_url + +#print video_from_url('http://video.tudou.com/v/XMzE3OTYyNjE0MA==.html?spm=a2h28.8313471.pl.dlink_1_21') diff --git a/plugin.video.cntv-video/plugin.video.cntv-video-1.0.8.zip b/plugin.video.cntv-video/plugin.video.cntv-video-1.0.9.zip similarity index 93% rename from plugin.video.cntv-video/plugin.video.cntv-video-1.0.8.zip rename to plugin.video.cntv-video/plugin.video.cntv-video-1.0.9.zip index c0a860d..a58c051 100644 Binary files a/plugin.video.cntv-video/plugin.video.cntv-video-1.0.8.zip and b/plugin.video.cntv-video/plugin.video.cntv-video-1.0.9.zip differ diff --git a/plugin.video.funshion/resources/settings.xml b/plugin.video.funshion/resources/settings.xml index 8692322..6e0e6ac 100644 --- a/plugin.video.funshion/resources/settings.xml +++ b/plugin.video.funshion/resources/settings.xml @@ -1,4 +1,4 @@ - + diff --git a/plugin.video.iqiyi/resources/settings.xml b/plugin.video.iqiyi/resources/settings.xml index b137987..23e9e45 100644 --- a/plugin.video.iqiyi/resources/settings.xml +++ b/plugin.video.iqiyi/resources/settings.xml @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/plugin.video.letv/resources/settings.xml b/plugin.video.letv/resources/settings.xml index 1bf38a2..68ab8f5 100644 --- a/plugin.video.letv/resources/settings.xml +++ b/plugin.video.letv/resources/settings.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/plugin.video.rrsp/icon.png b/plugin.video.rrsp/icon.png index 3cbaeba..aa66ac4 100644 Binary files a/plugin.video.rrsp/icon.png and b/plugin.video.rrsp/icon.png differ diff --git a/plugin.video.rrsp/plugin.video.rrsp-1.0.0.zip b/plugin.video.rrsp/plugin.video.rrsp-1.0.0.zip index f119985..3a3be2a 100644 Binary files a/plugin.video.rrsp/plugin.video.rrsp-1.0.0.zip and b/plugin.video.rrsp/plugin.video.rrsp-1.0.0.zip differ diff --git a/plugin.video.rrsp/resources/settings.xml b/plugin.video.rrsp/resources/settings.xml index db54d32..50920ab 100644 --- a/plugin.video.rrsp/resources/settings.xml +++ b/plugin.video.rrsp/resources/settings.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/plugin.video.rrys/LICENSE b/plugin.video.rrys/LICENSE new file mode 100644 index 0000000..ece019f --- /dev/null +++ b/plugin.video.rrys/LICENSE @@ -0,0 +1,340 @@ + 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. + + {description} + Copyright (C) {year} {fullname} + + 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.rrys/addon.py b/plugin.video.rrys/addon.py new file mode 100644 index 0000000..864e24e --- /dev/null +++ b/plugin.video.rrys/addon.py @@ -0,0 +1,80 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- + +from xbmcswift2 import Plugin, ListItem, xbmc +from urlparse import parse_qsl +from urllib import urlencode +from json import loads +from bs4 import BeautifulSoup +from common import get_html + +HOST = 'http://www.renrenyingshi.com' +CATE = [ + '爱情', + '剧情', + '喜剧', + '科幻', + '动作', + '犯罪', + '冒险', + '家庭', + '战争', + '悬疑', + '恐怖', + '历史', + '伦理', + '罪案', + '警匪', + '惊悚', + '奇幻', + '魔幻', + '青春', + '都市', + '搞笑', + '纪录片', + '时装', + '动画', + '音乐'] + +plugin = Plugin() +url_for = plugin.url_for + + +def previous_page(endpoint, page, total_page, **kwargs): + if int(page) > 1: + page = str(int(page) - 1) + return [{'label': u'上一页 - {0}/{1}'.format(page, str(total_page)), 'path': url_for(endpoint, page=page, **kwargs)}] + else: + return [] + + +def next_page(endpoint, page, total_page, **kwargs): + if int(page) < int(total_page): + page = str(int(page) + 1) + return [{'label': u'下一页 - {0}/{1}'.format(page, str(total_page)), 'path': url_for(endpoint, page=page, **kwargs)}] + else: + return [] + + +@plugin.route('/sublist/') +def sublist(url): + if not url.startswith('http'): + url = HOST + url + pass + +# main entrance +@plugin.route('/') +def index(): + page = get_html(HOST) + tree = BeautifulSoup(page, 'html.parser') + soup = tree.find_all('ul', {'id': 'nav'}) + soups = soup[0].find_all('li', {'class': 'nav-item'}) + for item in soups[1:]: + yield { + 'label': item.text, + 'path': url_for('sublist', url=item.a['href']) + } + + +if __name__ == '__main__': + plugin.run() diff --git a/plugin.video.rrys/addon.xml b/plugin.video.rrys/addon.xml new file mode 100644 index 0000000..e0c11a9 --- /dev/null +++ b/plugin.video.rrys/addon.xml @@ -0,0 +1,21 @@ + + + + + + + + video + + + 来自人人影视(renrenyingshi.com)的视频 + 人人影视(renrenyinyshi.com) + + https://github.com/yfang1644/kodi_plugins/plugin.video.rrys + yfang1644@gmail.com + all + + diff --git a/plugin.video.rrys/changelog.txt b/plugin.video.rrys/changelog.txt new file mode 100644 index 0000000..0a3dafc --- /dev/null +++ b/plugin.video.rrys/changelog.txt @@ -0,0 +1,2 @@ +v1.0.0 (2017.11.27, for my daughter) +- 人人影视 initial diff --git a/plugin.video.rrys/icon.png b/plugin.video.rrys/icon.png new file mode 100644 index 0000000..3cbaeba Binary files /dev/null and b/plugin.video.rrys/icon.png differ diff --git a/plugin.video.rrys/plugin.video.rrys-1.0.0.zip b/plugin.video.rrys/plugin.video.rrys-1.0.0.zip new file mode 100644 index 0000000..170cec2 Binary files /dev/null and b/plugin.video.rrys/plugin.video.rrys-1.0.0.zip differ diff --git a/plugin.video.rrys/resources/settings.xml b/plugin.video.rrys/resources/settings.xml new file mode 100644 index 0000000..15cb4f7 --- /dev/null +++ b/plugin.video.rrys/resources/settings.xml @@ -0,0 +1,3 @@ + + + diff --git a/plugin.video.tudou/addon.py b/plugin.video.tudou/addon.py new file mode 100644 index 0000000..0eb3162 --- /dev/null +++ b/plugin.video.tudou/addon.py @@ -0,0 +1,306 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import xbmc +from xbmcswift2 import Plugin, xbmcgui +from urllib import quote_plus +import re +from bs4 import BeautifulSoup +from common import get_html, r1 +from youku import Youku +from tudou import Tudou + +plugin = Plugin() +url_for = plugin.url_for + +######################################################################## +# 土豆 www.tudou.com +######################################################################## + + +HOST_URL = 'http://www.tudou.com' + +BANNER = '[COLOR yellow]【%s】[/COLOR]' +BANNER_FMT = '[COLOR green]【%s】[/COLOR]' +TIMER_FMT = '[COLOR FF8040C0](%s)[/COLOR]' +INDENT_FMT0 = '[COLOR FFDEB887] %s[/COLOR]' +INDENT_FMT1 = '[COLOR FFDEB8FF] %s[/COLOR]' + + +def httphead(url): + if len(url) < 2: + return url + if url[0:2] == '//': + url = 'http:' + url + elif url[0] == '/': + url = HOST_URL + url + + return url + + +############################################################################ +@plugin.route('/playvideo/') +def playvideo(url): + level = int(plugin.addon.getSetting('resolution')) + + if level == 4: + dialog = xbmcgui.Dialog() + level = dialog.select('清晰度选择', ['流畅', '高清', '超清', '1080P']) + level = max(0, level) + + if 'youku' in url: + urls = Youku().video_from_url(httphead(url), level=level) + elif 'tudou' in url: + urls = Tudou().video_from_url(httphead(url), level=level) + + stack_url = 'stack://' + ' , '.join(urls) + plugin.set_resolved_url(stack_url) + + +def gettudoulist(url): + html = get_html(httphead(url)) + tree = BeautifulSoup(html, 'html.parser') + + items = [] + + soup = tree.find_all('div', {'class': 'td-listbox__list__item--show'}) + for item in soup: + soup2str = str(item) + title = re.compile('title=\"(.+?)\"').findall(soup2str) + if not title: + title = re.compile('title=\'(.+?)\'').findall(soup2str) + thumb = re.compile('src="(.+?)"').findall(soup2str) + purl = re.compile(' href="(.+?)"').findall(soup2str) + if not (title and thumb and purl): continue + + items.append({ + 'label': title[0], + 'path': url_for('playvideo', url=purl[0]), + 'is_playable': True, + 'thumbnail': thumb[0], + 'info': {'title': title[0]} + }) + return items + + +def getyoukulist(url): + html = get_html(httphead(url)) + tree = BeautifulSoup(html, 'html.parser') + + items = [] + progs = tree.find_all('div', {'class': 'program'}) + if len(progs) < 1: + title = tree.find('meta', {'name': 'title'})['content'] + desc = tree.find_all('meta', {'name': 'description'}) + info = desc[0]['content'] + items.append({ + 'label': title, + 'path': url_for('playvideo', url=url), + 'is_playable': True, + }) + else: + for item in progs: + title = item['title'] + href = httphead(item.a['href']) + img = item.img['src'] + t = item.find('span', {'class': 'c-time'}) + time = t.text + items.append({ + 'label': title + '(' + time + ')', + 'path': url_for('playvideo', url=item.a['href']), + 'is_playable': True, + 'thumbnail': item.img['src'], + }) + + soup = tree.find_all('div', {'class': 'items clearfix'}) + if not soup: + return items + + soups = soup[0].find_all('div', {'class': 'item'}) + for item in soups: + desc = item.find('div', {'class': 'show_aspect'}) + info = desc.text if desc is not None else '' + try: + title = item['title'] + except: + continue + items.append({ + 'label': item['title'].encode('utf-8'), + 'path': url_for('playvideo', url=item.a['href']), + 'is_playable': True, + 'info': {'title': item['title'], 'plot': info}, + }) + return items + + +@plugin.route('/movielist/') +def episodelist(url): + plugin.set_content('video') + if 'youku' in url: + items = getyoukulist(url) + elif 'tudou' in url: + items = gettudoulist(url) + + return items + + +@plugin.route('/videolist/') +def videolist(url): + html = get_html(httphead(url)) + + items = [] + + tree = BeautifulSoup(html, 'html.parser') + soup = tree.find_all('div', {'class': 'td__category__filter__panel__item'}) + + for item in soup: + si = item.find_all('li') + for subitem in si: + if 'current' in subitem.get('class', ''): + subtitle = '[B]{}[/B]'.format(subitem.text.encode('utf-8')) + key = item.label.text.encode('utf-8') + items.append({ + 'label': BANNER % (key+subtitle), + 'path': url_for('select', url=url, filter=key) + }) + + tree = BeautifulSoup(html, 'html.parser') + soup = tree.find_all('div', {'class': 'v-pack--p'}) + + for item in soup: + items.append({ + 'label': item.a['title'], + 'path': url_for('episodelist', url=item.a['href']), + 'thumbnail': item.img['src'] + }) + + # page list + soup = tree.find_all('div', {'class': 'yk-pager'}) + pages = soup[0].find_all('li') + for page in pages: + try: + href = page.a['href'] + except: + continue + items.append({ + 'label': page.a.text.encode('utf-8'), + 'path': url_for('videolist', url=href.encode('utf-8')) + }) + + return items + + +@plugin.route('/select//') +def select(url, filter): + html = get_html(httphead(url)) + tree = BeautifulSoup(html, 'html.parser') + soup = tree.find_all('div', {'class': 'td__category__filter__panel__item'}) + + dialog = xbmcgui.Dialog() + color = '[COLOR FF00FF00]%s[/COLOR]' + for item in soup: + if filter != item.label.text.encode('utf-8'): + continue + si = item.find_all('li') + list = [] + i = 0 + for subitem in si: + title = subitem.text + if 'current' in subitem.get('class', ''): + title = '[B]{}[/B]'.format(title.encode('utf-8')) + mark = i + list.append(title) + i += 1 + sel = dialog.select(item.label.text, list) + + if sel >= 0: + url = si[sel].a['href'] + return videolist(url.encode('utf-8')) + + +@plugin.route('/search') +def search(): + plugin.set_content('video') + keyboard = xbmc.Keyboard('', '请输入搜索内容') + + xbmc.sleep(1500) + keyboard.doModal() + if not keyboard.isConfirmed(): + return [] + + keyword = keyboard.getText() + p_url = 'http://www.soku.com/nt/search/q_' + url = p_url + quote_plus(keyword) + page = get_html(url) + tree = BeautifulSoup(page, 'html.parser') + soup = tree.find_all('div', {'class': 's_base'}) + items = [] + for item in soup: + title = item.a['_log_title'] + href = item.a['href'] + info = item.find('div', {'class': 'info-cont'}) + info = info.span['data-text'] if info else '' + + items.append({ + 'label': title, + 'path': url_for('playvideo', url=href), + 'is_playable': True, + 'info': {'title': title, 'plot': info}, + }) + soup = tree.find_all('ul', {'class': 'clearfix'}) + soups = soup[0].find_all('li') + for item in soups: + try: + items.append({ + 'label': item.a['_log_title'] + item.span.text, + 'path': url_for('playvideo', url=item.a['href']), + 'is_playable': True, + }) + except: + continue + return items + + +@plugin.route('/') +def index(): + yield { + 'label': BANNER % '土豆视频 - 搜索', + 'path': url_for('search') + } + + url = HOST_URL + '/category' + + html = get_html(url) + tree = BeautifulSoup(html, 'html.parser') + soup = tree.find_all('div', {'class': 'td__category__filter__nav__item'}) + + for prog in soup[1:]: + cur = prog['class'] + if len(cur) > 1: + href = url + else: + href = prog.a['href'] + nametype = href.split('/')[-1][:3] + + yield { + 'label': prog.text, + 'path': url_for('videolist', url=href) + } + + +# main programs goes here ######################################### +if __name__ == '__main__': + plugin.run() + +runlist = { + None: 'mainMenu()', + 'videolist': 'listSubMenu(params)', + 'videolist1': 'listSubMenu1(params)', + 'videolist2': 'listSubMenu2(params)', + 'albumlist': 'albumList(params)', + 'codelist': 'relatedPlayList(params)', + 'playvideo': 'PlayVideo(params)', + 'search': 'searchInTudou(params)', + 'select': 'normalSelect(params)' +} + diff --git a/plugin.video.tudou/addon.xml b/plugin.video.tudou/addon.xml index b6ae2f5..63f1234 100644 --- a/plugin.video.tudou/addon.xml +++ b/plugin.video.tudou/addon.xml @@ -1,14 +1,15 @@ - + + + + point="xbmc.python.pluginsource" library="addon.py"> video diff --git a/plugin.video.tudou/changelog.txt b/plugin.video.tudou/changelog.txt index 0c9119c..d3526eb 100644 --- a/plugin.video.tudou/changelog.txt +++ b/plugin.video.tudou/changelog.txt @@ -1,3 +1,5 @@ -V1.0.0 (2017.04.19) +V1.0.1 (2017.11.28) + +V1.0.0 (2017.04.19) - initial diff --git a/plugin.video.tudou/default.py b/plugin.video.tudou/default.py deleted file mode 100644 index 2dc894c..0000000 --- a/plugin.video.tudou/default.py +++ /dev/null @@ -1,908 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -import xbmc -from xbmcgui import Dialog, DialogProgress, ListItem -import xbmcplugin -import xbmcaddon -from urlparse import parse_qsl -from urllib import quote_plus -import re -import sys -import os -from json import loads -from bs4 import BeautifulSoup -from common import get_html, r1 -from youku import video_from_vid -from tudou import video_from_iid - -######################################################################## -# 土豆 www.tudou.com -######################################################################## - -# Plugin constants -__addon__ = xbmcaddon.Addon() -__addonid__ = __addon__.getAddonInfo('id') -__addonname__ = __addon__.getAddonInfo('name') -__addonicon__ = os.path.join(__addon__.getAddonInfo('path'), 'icon.png') -__profile__ = xbmc.translatePath(__addon__.getAddonInfo('profile')) -__m3u8__ = xbmc.translatePath(os.path.join(__profile__, 'temp.m3u8')).decode("utf-8") -cookieFile = __profile__ + 'cookies.tudou' - - -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' - -HOST_URL = 'http://new.tudou.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]' -CFRAGMAX = [10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500] - - -########################################################################### -# LeTv player class -########################################################################### -class LetvPlayer(xbmc.Player): - def __init__(self): - xbmc.Player.__init__(self) - - def play(self, name, thumb, v_urls=None): - self.name = name - self.thumb = thumb - self.v_urls_size = 0 - self.curpos = 0 - self.is_active = True - self.load_url_sync = False - self.xbmc_player_stop = False - self.title = name - self.mCheck = True - self.LOVS = 0 - - self.v_urls = v_urls - if (v_urls): # single video file playback - self.curpos = int(__addon__.getSetting('video_fragmentstart')) * 10 - self.v_urls_size = len(v_urls) - else: # ugc playlist playback - self.curpos = int(name.split('.')[0]) - 1 - # Get the number of video items in PlayList for ugc playback - self.playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) - self.psize = self.playlist.size() - - self.videoplaycont = __addon__.getSetting('video_vplaycont') - self.maxfp = CFRAGMAX[int(__addon__.getSetting('video_cfragmentmax'))] - - # Start filling first buffer video and start playback - self.geturl() - - def geturl(self): - if (self.v_urls and (self.curpos < self.v_urls_size)): - # Use double buffering for smooth playback - x = (self.curpos / self.maxfp) % 2 - self.videourl = __profile__ + 'vfile-' + str(x) + '.ts' - fs = open(self.videourl, 'wb') - - endIndex = min((self.curpos + self.maxfp), self.v_urls_size) - self.title = "%s - 第(%s~%s)/%s节" % (self.name, str(self.curpos+1), str(endIndex), str(self.v_urls_size)) - # print "### Preparing: " + self.title - self.listitem = ListItem(self.title, thumbnailImage=self.thumb) - self.listitem.setInfo(type="Video", infoLabels={"Title": self.title}) - - for i in range(self.curpos, endIndex): - # Stop further video loading and terminate if user stop playback - if (self.xbmc_player_stop or pDialog.iscanceled()): - self.videourl = None - i = self.v_urls_size - break - - if (not self.isPlayingVideo()): - pDialog.create('视频缓冲', '请稍候。下载视频文件 ....') - pDialog.update(((i - self.curpos) * 100 / self.maxfp), line2="### " + self.title) - else: - pDialog.close() - - v_url = self.v_urls[i] - bfile = get_html(v_url, binary=True) - # give another trial if playback is active and bfile is invalid - if ((len(bfile) < 30) and self.isPlayingVideo()): - bfile = get_html(v_url, binary=True) - fs.write(bfile) - - # Start playback after fetching 4th video files, restart every 4 fetches if playback aborted unless stop by user - if (not self.isPlayingVideo() and (i < self.v_urls_size) and (((i - self.curpos) % 4) == 3)): - pDialog.close() - # Must stop sync loading to avoid overwritten current video when onPlayerStarted - self.load_url_sync = False - xbmc.Player.play(self, self.videourl, self.listitem) - # give some time to xmbc to upate its player status before continue - xbmc.sleep(100) - # Only reset fragment start after successful playback - __addon__.setSetting('video_fragmentstart', '0') - - fs.close() - # print "### Last video file download fragment: " + str(i) - # set self.curpos to the next loading video index - self.curpos = i + 1 - - # Last of video segment loaded, enable play once only - if (self.curpos == self.v_urls_size): - self.LOVS = 1 - else: # reset - self.LOVS = 0 - - # Start next video segment loading if sync loading not enable - if (not self.load_url_sync and (self.curpos < self.v_urls_size)): - # Reset to sync loading on subsequent video segment - self.load_url_sync = True - self.playrun() - - # ugc auto playback - elif ((self.v_urls is None) and (self.curpos < self.psize)): - if (self.mCheck and not self.isPlayingVideo()): - pDialog.create('匹配视频', '请耐心等候! 尝试匹配视频文件 ...') - - # find next not play item in ugc playlist - for idx in range(self.curpos, self.psize): - p_item = self.playlist.__getitem__(idx) - p_url = p_item.getfilename(idx) - # p_url auto replaced with self.videourl by xbmc after played. To refresh, back and re-enter - if "http:" in p_url: - p_list = p_item.getdescription(idx) - self.listitem = p_item # pass all li items including the embedded thumb image - self.listitem.setInfo(type="Video", infoLabels={"Title":p_list}) - self.curpos = idx - break - - x = self.curpos % 2 - self.videourl = __profile__ + 'vfile-' + str(x) + '.ts' - fs = open(self.videourl, 'wb') - - v_urls = decrypt_url(p_url, self.mCheck) - self.v_urls_size = len(v_urls) - self.title = "UGC list @ %s (size = %s): %s" % (str(self.curpos), str(self.v_urls_size), p_list) - # print "### Preparing: " + self.title - - for i, v_url in enumerate(v_urls): - if (self.xbmc_player_stop or pDialog.iscanceled()): - self.videourl = None - i = self.v_urls_size - break - - if (not self.isPlayingVideo()): - pDialog.create('视频缓冲', '请稍候。下载视频文件 ....') - pDialog.update((i * 100 / self.v_urls_size), line2=self.title) - else: - pDialog.close() - - bfile = get_html(v_url, True, True) - fs.write(bfile) - - # Start playback after fetching 4th video files, restart every 4 fetches if playback aborted unless stop by user - if (not self.isPlayingVideo() and (i < self.v_urls_size) and ((i % 4) == 3)): - pDialog.close() - # Must stop sync loading to avoid overwritten current video when onPlayerStarted - self.load_url_sync = False - xbmc.Player.play(self, self.videourl, self.listitem) - # give some time to xmbc to upate its player status before continue - xbmc.sleep(100) - fs.close() - # print "### Last video file download total fragment: %s ==> %s" % (str(i), self.title) - # set self.curpos to the next loading ugc index - self.curpos += 1 - - # Last of video segment loaded, enable play once only - if (self.curpos == self.psize): - self.LOVS = 1 - else: # reset - self.LOVS = 0 - - # Start next video segment loading if sync loading not enable - if (not self.load_url_sync and (self.curpos < self.psize)): - # Do not display dialog on subsequent UGC list loading - self.mCheck = False - - # Reset to sync loading on subsequent ugc item - self.load_url_sync = True - self.playrun() - - # close dialog on all mode when fetching end - pDialog.close() - - def playrun(self): - if (self.videourl and not self.isPlayingVideo()): - # print "### Player resume: %s \n### %s" % (self.title, self.videourl) - pDialog.close() - # Next video segment loading must wait until player started to avoid race condition - self.load_url_sync = True - xbmc.Player.play(self, self.videourl, self.listitem) - xbmc.sleep(100) - elif ((self.curpos < self.v_urls_size) or self.videoplaycont): - # print "### Async fetch next video segment @ " + str(self.curpos) - self.geturl() - - def onPlayBackStarted(self): - # may display next title to playback due to async - # print "### onPlayBackStarted Callback: " + self.title - pDialog.close() - if (self.load_url_sync): - if ((self.curpos < self.v_urls_size) or self.videoplaycont): - # print "### Sync fetch next video segment @ " + str(self.curpos) - self.geturl() - xbmc.Player.onPlayBackStarted(self) - - def onPlayBackSeek(self, time, seekOffset): - # print "### Player seek forward: %s / %s" % (str(time), str(seekOffset)) - xbmc.Player.onPlayBackSeek(self, time, seekOffset) - - def onPlayBackSeekChapter(self, chapter): - # no effect, valid on playlist playback by xmbc - self.curpos += 1 - # print "### Player seek next chapter: " + str(self.curpos) - xbmc.Player.onPlayBackSeek(self, chapter) - - def onPlayBackEnded(self): - # Do not restart resume playback if video aborted due to starve network data - if (self.videourl and self.load_url_sync): - # if (self.videourl): - # print "### onPlayBackEnded callback: Continue next video playback !!! " + str(self.LOVS) - if (self.LOVS < 2): - self.playrun() - else: # reset - self.LOVS = 0 - # set flag to play last video segment once only - if (self.LOVS == 1): - self.LOVS += 1 - else: - # print "### onPlayBackEnded callback: Ended-Deleted !!!" - ## self.delTsFile(10) - xbmc.Player.onPlayBackEnded(self) - - def onPlayBackStopped(self): - # print "### onPlayBackStopped callback - Ending playback!!!" - self.is_active = False - self.xbmc_player_stop = True - - def delTsFile(self, end_index): - for k in range(end_index): - tsfile = __profile__ + 'vfile-' + str(k) + '.ts' - if os.path.isfile(tsfile): - try: - os.remove(tsfile) - except: - pass - - -############################################################################ -def PlayVideo(params): - title = params.get('title', '') - thumb = params.get('thumb') - level = int(__addon__.getSetting('resolution')) - - if level == 4: - dialog = Dialog() - level = dialog.select('清晰度选择', ['流畅', '高清', '超清', '1080P']) - level = max(0, level) - - vcode = params.get('vcode') - iid = params.get('iid') - - if vcode: - urls = video_from_vid(vcode, stream_id=level) - ulen = len(urls) - if ulen > 0: - playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) - playlist.clear() - for i in range(ulen): - name = title + '(%d/%d)' % (i + 1, ulen) - listitem = ListItem(name, thumbnailImage=thumb) - listitem.setInfo(type="Video", infoLabels={"Title": name}) - playlist.add(urls[i], listitem) - - xbmc.Player().play(playlist) - elif iid: - urls = video_from_iid(iid) - ulen = len(urls) - if ulen > 0: - playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) - playlist.clear() - for i in range(ulen): - name = title + '(%d/%d)' % (i + 1, ulen) - listitem = ListItem(name, thumbnailImage=thumb) - listitem.setInfo(type="Video", infoLabels={"Title": name}) - playlist.add(urls[i], listitem) - - xbmc.Player().play(playlist) - - ''' - pDialog.create('匹配视频', '请耐心等候! 尝试匹配视频文件 ...') - pDialog.close() - if len(urls) > 0: - xplayer.play(title, thumb, urls) - - # need xmbc.sleep to make xbmc callback working properly - while xplayer.is_active: - xbmc.sleep(100) - ''' - else: - Dialog().ok(__addonname__, '未匹配到VID') - return - - -def httphead(url): - if len(url) < 2: - return url - if url[0:2] == '//': - url = 'http:' + url - elif url[0] == '/': - url = HOST_URL + url - - return url - - -def buildParams(params): - str = '' - for item in params: - str += '&%s=' % item + quote_plus(params[item]) - return str - - -def mainMenu(): - li = ListItem('[COLOR FF00FF00] 【土豆视频 - 搜索】[/COLOR]') - u = sys.argv[0] + '?mode=search' - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - url = HOST_URL + '/category/c_97.html' - - html = get_html(url) - tree = BeautifulSoup(html, 'html.parser') - soup = tree.find_all('div', {'class': 'td__category__filter__nav__item'}) - - for prog in soup: - title = prog.text - cur = prog['class'] - if len(cur) > 1: - href = url - else: - href = prog.a['href'] - href = httphead(href) - nametype = href.split('/')[-1][:3] - mode = 'videolist' - - li = ListItem(title) - u = sys.argv[0] + '?url=%s&mode=%s&name=%s' % (href, mode, title) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def listSubMenu(params): - name = params['name'] - url = params['url'] - html = get_html(url) - filter = params.get('filter', '') - - li = ListItem(BANNER_FMT % (name+'(分类过滤)' + filter)) - u = sys.argv[0] + '?url=' + quote_plus(url) - u += '&mode=select&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - tree = BeautifulSoup(html, 'html.parser') - soup = tree.find_all('div', {'class': 'v-pack--p'}) - - for item in soup: - thumb = item.img['src'] - href = httphead(item.a['href']) - title = item.a['title'] - li = ListItem(title, - iconImage=thumb, thumbnailImage=thumb) - u = sys.argv[0] + '?url=' + href - u += '&name=' + quote_plus(name) - u += '&thumb=' + quote_plus(thumb) - u += '&title=' + title - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - soup = tree.find_all('div', {'class': 'yk-pager'}) - pages = soup[0].find_all('li') - print '======================', pages - for page in pages: - try: - href = httphead(page.a['href']) - except: - continue - title = page.a.text - u = sys.argv[0] + '?url=' + href - u += '&name=' + quote_plus(name) - u += '&mode=videolist&title=' + title - li = ListItem(title) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'movies') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def findTags(string): - group = re.compile('(a|b|c|d|e|f|g|h|i|j|k|l|m|n)(\d+)').findall(string) - return dict(group) - - -def mergeTags(tags): - str = '' - for x in tags: - str += '&tags=' + tags[x] - return str - - -def listSubMenu1(params): - # http://www.tudou.com/list/ach3a-2b-2c-2d-2e-2f1003g-2h-2i-2j-2k-2l-2m-2n1sort2.html - # http://www.tudou.com/list/ach3a42b55c324d-2e-2f1003g-2h-2i-2j-2k-2l-2m-2n-2sort2.html - # a42:地区 - # b55:类型 - # c324:状态 - # dxx:年代 - # exxx:付费 - # f1002:清晰度 - # &tags=&tags=.... - # sort1:最新 sort2: 人气 - name = params['name'] - url = params['url'] - filter = params.get('filter', '') - urlpage = get_html(url) - page = params.get('pageNo', '1') - piece = url.split('/')[-1] - tagId = re.compile('ch(\d+)').findall(piece)[0] - tags = findTags(piece) - - if tags.get('n'): - AtoZ = chr(int(tags['n']) + 64) - del(tags['n']) - else: - AtoZ = '' - - params = {'name': name, - 'pageSize': '30', - 'app': 'mainsitepc', - 'deviceType': '1', - 'tagType': '3', - 'firstTagId': tagId, - 'areaCode': '', - 'initials': AtoZ, # 首字母 nXXsort2 - 'hotSingerId': '', - 'pageNo': page - } - # 'tags': '', # 地区类型...清晰度 , etc. - strparam = buildParams(params) - strparam = '?' + strparam[1:] + mergeTags(tags) - - list_api = 'http://www.tudou.com/s3portal/service/pianku/data.action' - html = get_html(list_api + strparam) - jsdata = loads(html) - items = jsdata['items'] - total = jsdata['total'] - - li = ListItem(BANNER_FMT % (name+'(第%s页|分类过滤)' % page + filter)) - u = sys.argv[0] + '?url=' + quote_plus(url) - u += '&mode=select&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - tree = BeautifulSoup(urlpage, 'html.parser') - soup = tree.find_all('select', {'id': 'selectOps'}) - field = soup[0].find_all('option') - link = re.compile('var CONFIG.+?urls:(.+])').findall(urlpage) - link = eval(link[0]) - for i in range(len(field)): - title = field[i].text - if field[i].has_attr('selected'): - li = ListItem(INDENT_FMT0 % title) - currentPage = link[i] - else: - li = ListItem(INDENT_FMT1 % title) - - href = HOST_URL + '/list/' + link[i] - nametype = link[i][:3] - if nametype == 'ach': - mode = 'videolist1' - else: - mode = 'videolist2' - - u = sys.argv[0] + '?url=' + quote_plus(href) - u += '&name=' + quote_plus(name) - u += '&mode=' + mode + '&title=' + title - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - for item in items: - title = item['title'] - href = item['playUrl'] - info = item['albumShortDesc'] - img = item['picUrl_200x112'] - pay = item['needMoney'] - info = item['updateInfo'] - if pay is True: - info += '|付费'.decode('utf-8') - albumId = item['albumId'] - aid = item['aid'] - li = ListItem(title + TIMER_FMT % info, - iconImage=img, thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - u = sys.argv[0] + '?url=' + href - u += '&mode=albumlist&albumId=%d' % albumId - u += '&name=' + quote_plus(name) - u += '&thumb=' + quote_plus(img) - u += '&title=' + title - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - if currentPage[:3] == 'ach': - mode = 'videolist1' - else: - mode = 'videolist2' - if int(page) > 1: - li = ListItem(BANNER_FMT % '上一页') - u = sys.argv[0] + '?url=' + url - u += '&mode=videolist1&pageNo=%d' % (int(page)-1) - u += '&name=' + quote_plus(name) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - if int(page) <= total // 30: - li = ListItem(BANNER_FMT % '下一页') - u = sys.argv[0] + '?url=' + url - u += '&mode=videolist1&pageNo=%d' % (int(page)+1) - u += '&name=' + quote_plus(name) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'movies') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def listSubMenu2(params): - name = params['name'] - url = params['url'] - filter = params.get('filter', '') - urlpage = get_html(url) - page = params.get('page', '1') - piece = url.split('/')[-1] - tagId = re.compile('ch(\d+)').findall(piece)[0] - tags = findTags(piece) - - if tags.get('n'): - AtoZ = chr(int(tags['n']) + 64) - del(tags['n']) - else: - AtoZ = '' - - params = {'name': name, - 'pageSize': '30', - 'sort': '2', - 'tagType': '1', - 'firstTagId': tagId, - 'areaCode': '', - 'initials': AtoZ, # 首字母 2n2sort2 - 'hotSingerId': '', - 'page': page - } - # 'tags': '', # 地区类型...清晰度 , etc. - strparam = buildParams(params) - strparam = '?' + strparam[1:] + mergeTags(tags) - - list_api = 'http://www.tudou.com/list/itemData.action' - html = get_html(list_api + strparam) - - li = ListItem(BANNER_FMT % (name+'(第%s页|分类过滤)' % page + filter)) - u = sys.argv[0] + '?url=' + quote_plus(url) - u += '&mode=select&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - tree = BeautifulSoup(urlpage, 'html.parser') - soup = tree.find_all('select', {'id': 'selectOps'}) - field = soup[0].find_all('option') - link = re.compile('var CONFIG.+?urls:(.+])').findall(urlpage) - link = eval(link[0]) - for i in range(len(field)): - title = field[i].text - if field[i].has_attr('selected'): - li = ListItem(INDENT_FMT0 % title) - currentPage = link[i] - else: - li = ListItem(INDENT_FMT1 % title) - - href = HOST_URL + '/list/' + link[i] - nametype = link[i][:3] - if nametype == 'ach': - mode = 'videolist1' - else: - mode = 'videolist2' - u = sys.argv[0] + '?url=' + quote_plus(href) - u += '&name=' + quote_plus(name) - u += '&mode=%s&title=%s' % (mode, title) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - jsdata = loads(html) - items = jsdata['data'] - - for item in items: - title = item['title'] - iid = item['itemId'] - img = item['bigPicUrl'] - time = item['totalTimeStr'] - href = HOST_URL + '/programs/view/%s/' % item['code'] - li = ListItem(title + TIMER_FMT % time, - iconImage=img, thumbnailImage=img) - u = sys.argv[0] + '?mode=albumlist' - u += '&name=' + quote_plus(name) - u += '&thumb=' + img + '&url=' + href - u += '&title=' + title - u += '&iid=%d' % (iid) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - if currentPage[:3] == 'ach': - mode = 'videolist1' - else: - mode = 'videolist2' - if int(page) > 1: - li = ListItem(BANNER_FMT % '上一页') - u = sys.argv[0] + '?url=' + url - u += '&mode=videolist2&page=%d' % (int(page)-1) - u += '&name=' + name - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - if int(page) <= 2000: - li = ListItem(BANNER_FMT % '下一页') - u = sys.argv[0] + '?url=' + url - u += '&mode=videolist2&page=%d' % (int(page)+1) - u += '&name=' + name - 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') - surl = url.split('/') - purl = surl[-1] - if len(purl) < 10: - purl = purl[:-5] + 'a-2b-2c-2d-2e-2f-2g-2h-2i-2j-2k-2l-2m-2n-2sort2.html' - filter = params.get('filter', '') - - html = get_html(url) - tree = BeautifulSoup(html, 'html.parser') - soup = tree.find_all('div', {'class': 'category_item fix'}) - - dialog = Dialog() - color = '[COLOR FF00FF00]%s[/COLOR]' - for iclass in soup: - si = iclass.find_all('li') - list = [] - i = 0 - for subitem in si: - title = subitem.text - if subitem.get('class'): - title = color % title - mark = i - list.append(title) - i += 1 - sel = dialog.select(iclass.h3.text, list) - - if sel < 0: - continue - filter += '|' + iclass.h3.text + '(' + si[sel].text + ')' - if sel == mark: - continue - - seurl = si[sel].a['href'].split('/')[-1] - p = re.compile('(a|b|c|d|e|f|g|h|i|j|k|l|m|n)(\d+)').findall(seurl[3:]) - for x in p: - purl = re.sub(x[0] + '\d+', x[0] + x[1], purl) - purl = re.sub(x[0] + '\-2', x[0] + x[1], purl) - - surl[-1] = purl - params['url'] = '/'.join(surl) - params['filter'] = filter.encode('utf-8') - - if purl[0] == 'a': - listSubMenu1(params) - else: - listSubMenu2(params) - - -def relatedAlbumList(params): - aid = params.get('albumId') - title = params.get('title') - img = params.get('thumb', '') - url = params.get('url') - if url: - html = get_html(url) - iid = re.compile('iid: (\d+)').findall(html) - vcode = re.compile('youkuCode: "(.+?)"').findall(html) - u = sys.argv[0] + '?mode=playvideo&iid=%s&vcode=%s' % (iid[0], vcode[0]) - u += '&title=' + quote_plus(title) - u += '&thumb=' + img - - else: - u = sys.argv[0] + '?mode=albumlist&albumId=%s' % aid - u += '&title=' + title + '&thumb=' + img - - li = ListItem(BANNER_FMT % title, - iconImage=img, thumbnailImage=img) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - - album_api = 'http://www.tudou.com/crp/alist.action?a=%s' - jspage = get_html(album_api % aid, decoded=True) - - jsdata = loads(jspage.encode('utf-8')) - jsdata = jsdata['items'] - - for item in jsdata: - title = item['kw'] - info = item.get('comments', '') - if info is None: - info = '' - time = item['time'] - if time is None: - time = '' - - img = item['pic'] - if img is None: - img = '' - vcode = item['vcode'] - iid = item['iid'] - u = sys.argv[0] + '?mode=playvideo' - u += '&title=' + title - u += '&thumb=' + img - u += '&vcode=%s&iid=%d' % (vcode, iid) - li = ListItem(title + '(' + time + ')', - iconImage=img, thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - - rel_list = 'http://www.tudou.com/crp/getRelativeContent.action?a=%s' - - jspage = get_html(rel_list % aid) - jsdata = loads(jspage) - headings = jsdata['data']['catList'] - heading = [x['name'] for x in headings] - title = '|'.join(heading).encode('utf-8') - - u = sys.argv[0] + '?mode=albumlist&albumId=%s' % aid - u += '&title=' + quote_plus(title) - li = ListItem(BANNER_FMT % title) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - items = jsdata['data']['playAlbumInfoList'] - for item in items: - aid = item['albumId'] - img = item['albumPicUrl'] - title = item['albumName'] - extra = item['update'] - info = item['albumShortDesc'] - li = ListItem(title + '(' + extra + ')', - iconImage=img, thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - u = sys.argv[0] + '?mode=albumlist' - u += '&title=%s&albumId=%d' % (title, aid) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'episodes') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def relatedPlayList(params): - url = params.get('url') - title = params.get('title') - img = params.get('thumb') - iid = [params.get('iid')] - if url: - html = get_html(url) - iid = re.compile('iid: (\d+)').findall(html) - vcode = re.compile('youkuCode: "(.+?)"').findall(html) - - u = sys.argv[0] + '?mode=playvideo&thumb=' + img - if iid: - u += '&iid=' + iid[0] - if vcode: - u += '&vcode=' + vcode[0] - u += '&title=' + quote_plus(title) - li = ListItem(title, iconImage=img, thumbnailImage=img) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - - rel_list = 'http://www.tudou.com/crp/getRelatedPlaylists.action?iid=%s' - - jspage = get_html(rel_list % iid[0]) - jsdata = loads(jspage) - items = jsdata['data']['pList'] - - u = sys.argv[0] + '?mode=codelist&iid=%s' % iid[0] - u += '&title=' + '相关视频'.decode('utf-8') - li = ListItem(BANNER_FMT % '相关视频') - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - - for item in items: - title = item['name'] - img = item['picUrl'] - info = item['description'] - code = item['code'] - li = ListItem(title, iconImage=img, thumbnailImage=img) - li.setInfo(type='Video', infoLabels={'Title': title, 'Plot': info}) - u = sys.argv[0] + '?mode=codelist' - u += '&title=%s&code=%s' % (title, code) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - code = items[0]['code'] - - rel_list = 'http://www.tudou.com/crp/plist.action?lcode=%s' - - jspage = get_html(rel_list % code) - jsdata = loads(jspage) - items = jsdata['items'] - - u = sys.argv[0] + '?mode=codelist&iid=%s' % iid - u += '&title=' + '主题视频'.decode('utf-8') - li = ListItem(BANNER_FMT % '主题视频') - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, False) - - for item in items: - title = item['kw'] - img = item['pic'] - time = item['time'] - iid = item['iid'] - li = ListItem(title + '(' + time + ')', - iconImage=img, thumbnailImage=img) - u = sys.argv[0] + '?mode=playvideo' - u += '&title=%s&thumb=%s&iid=%d' % (title, img, iid) - xbmcplugin.addDirectoryItem(int(sys.argv[1]), u, li, True) - - xbmcplugin.setContent(int(sys.argv[1]), 'episodes') - xbmcplugin.endOfDirectory(int(sys.argv[1])) - - -def albumList(params): - aid = params.get('albumId') - title = params.get('title', '') - img = params.get('thumb', '') - iid = params.get('iid') - - if aid: - relatedAlbumList(params) - elif iid: - relatedPlayList(params) - - -def searchInTudou(params): - keyboard = xbmc.Keyboard('', '请输入搜索内容') - - xbmc.sleep(1500) - keyboard.doModal() - if (keyboard.isConfirmed()): - keyword = keyboard.getText() - p_url = 'http://so.tv.sohu.com/mts?chl=&tvType=-2&wd=' - url = p_url + quote_plus(keyword.decode('utf-8').encode('gbk')) - params['url'] = url - params['keyword'] = keyword - params['page'] = '1' - - -# main programs goes here ######################################### -xplayer = LetvPlayer() -pDialog = DialogProgress() -params = sys.argv[2][1:] -params = dict(parse_qsl(params)) - -mode = params.get('mode') -if mode is not None: - del(params['mode']) - -runlist = { - None: 'mainMenu()', - 'videolist': 'listSubMenu(params)', - 'videolist1': 'listSubMenu1(params)', - 'videolist2': 'listSubMenu2(params)', - 'albumlist': 'albumList(params)', - 'codelist': 'relatedPlayList(params)', - 'playvideo': 'PlayVideo(params)', - 'search': 'searchInTudou(params)', - 'select': 'normalSelect(params)' -} - -exec(runlist[mode]) diff --git a/plugin.video.tudou/plugin.video.tudou-1.0.0.zip b/plugin.video.tudou/plugin.video.tudou-1.0.1.zip similarity index 86% rename from plugin.video.tudou/plugin.video.tudou-1.0.0.zip rename to plugin.video.tudou/plugin.video.tudou-1.0.1.zip index 953b4df..c9b6992 100644 Binary files a/plugin.video.tudou/plugin.video.tudou-1.0.0.zip and b/plugin.video.tudou/plugin.video.tudou-1.0.1.zip differ diff --git a/plugin.video.tudou/resources/language/Chinese (Simple)/strings.xml b/plugin.video.tudou/resources/language/Chinese (Simple)/strings.xml deleted file mode 100644 index fdb7cd2..0000000 --- a/plugin.video.tudou/resources/language/Chinese (Simple)/strings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - 刷新 - 中文 - - - 默认播放清晰度 - 连续视频播放 - 代理服务器(IP:端口)- 空白,如果不是必需的 - 片段连续 - 存储量成正比 - 片段的开始 - 视频服务器选择 - 直接播放m3u8 - 输入键盘 - Kodi内置键盘 - 中文输入插件 - - - 标清 - 高清 - 超清 - - 随意 - 1 - 2 - 3 - diff --git a/plugin.video.tudou/resources/language/English/strings.xml b/plugin.video.tudou/resources/language/English/strings.xml deleted file mode 100644 index 4cd574d..0000000 --- a/plugin.video.tudou/resources/language/English/strings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - Refresh - Chinese - - - Default Playback Resolution - Continuous Video Playback - Proxy (ip:port) - leave blank if not required - Video Fragments Concatenate - proportional to disk size - Video Fragment Start # - Video Server Selection - Play m3u8 directly - Input keyboard - Kodi internal keyboard - Chinese keyboard add-on - - - LD: Low Defination - SD: Standard Defination - HD: High Definition - - Auto - 1 - 2 - 3 - diff --git a/plugin.video.tudou/resources/settings.xml b/plugin.video.tudou/resources/settings.xml index 46a481f..3ccee32 100644 --- a/plugin.video.tudou/resources/settings.xml +++ b/plugin.video.tudou/resources/settings.xml @@ -1,9 +1,6 @@ - - - - + diff --git a/plugin.video.youkutv/resources/settings.xml b/plugin.video.youkutv/resources/settings.xml index b15b618..07f9d39 100644 --- a/plugin.video.youkutv/resources/settings.xml +++ b/plugin.video.youkutv/resources/settings.xml @@ -1,11 +1,10 @@ - - - - - - - - - - - + + + + + + + + + +