From b04ba3b1922b9a2750ce7c20c11f147a30329e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D1=80=D0=BE=D0=B4=D0=B8=D0=BD=20=D0=A0=D0=BE?= =?UTF-8?q?=D0=BC=D0=B0=D0=BD?= Date: Mon, 14 Mar 2022 20:39:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20Kodi=2019?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE.txt | 165 ++++++++++++++++++++++++++ README.md | 45 ++++++- __init__.py | 20 ++++ addon.xml | 44 +++++++ changelog.txt | 17 +++ default.py | 82 +++++++++++++ itv.py | 162 +++++++++++++++++++++++++ resources/icon.png | Bin 0 -> 1799 bytes resources/language/English/strings.po | 35 ++++++ resources/language/German/strings.po | 35 ++++++ resources/language/Russian/strings.po | 35 ++++++ resources/settings.xml | 10 ++ 12 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 LICENSE.txt create mode 100644 __init__.py create mode 100644 addon.xml create mode 100644 changelog.txt create mode 100644 default.py create mode 100644 itv.py create mode 100644 resources/icon.png create mode 100644 resources/language/English/strings.po create mode 100644 resources/language/German/strings.po create mode 100644 resources/language/Russian/strings.po create mode 100644 resources/settings.xml diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md index 9830773..e08bf92 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# script.video.iptv.itv +# ITV Addon for KODI +[![logo](https://raw.githubusercontent.com/kodi-iptv-addons/kodi-iptv-addons/master/script.video.iptv.itv/resources/icon.png)](https://goo.gl/LZQKVL) + + + +## Installation guide + +* Download repository zip file: [https://goo.gl/NQ4CEY](https://goo.gl/NQ4CEY) (which is a shortcut to [repository.iptv.zip](https://raw.githubusercontent.com/dmitry-vinogradov/kodi-iptv-addons/master/repository.iptv.zip)) +* In KODI's _Add-ons / Add-on browser_ select **Install from zip file** +* Navigate and choose the downloaded repository zip file **_repository.iptv.zip_** +* After installation: + * go to **Install from repository** + * select **IPTV Add-ons repository** + * open **Video Addons** + * Select and install **ITV** addon. + +## Установка + +* Скачиваем ZIP файл репозитория: [https://goo.gl/NQ4CEY](https://goo.gl/NQ4CEY) (это сокращенный URL для [repository.iptv.zip](https://raw.githubusercontent.com/dmitry-vinogradov/kodi-iptv-addons/master/repository.iptv.zip)) +* В разделе _Дополнения_ выбираем **Установить из файла ZIP** +* Выбираем скаченный ZIP файл **_repository.iptv.zip_** +* После установки репозитория: + * Выбираем пункт **Установка из репозитория** + * Выбираем репозиторий **IPTV Add-ons repository** + * Открываем **Видеодополнения** + * Выбираем и устанавливаем **ITV** дополнение. + +### Screenshots: + + + +[![screenshot](https://raw.githubusercontent.com/kodi-iptv-addons/kodi-iptv-addons/master/screenshot_01.png)](#) + + + +[![screenshot](https://raw.githubusercontent.com/kodi-iptv-addons/kodi-iptv-addons/master/screenshot_02.png)](#) + + + +[![screenshot](https://raw.githubusercontent.com/kodi-iptv-addons/kodi-iptv-addons/master/screenshot_03.png)](#) + + + +[![screenshot](https://raw.githubusercontent.com/kodi-iptv-addons/kodi-iptv-addons/master/screenshot_04.png)](#) \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..9e7cc30 --- /dev/null +++ b/__init__.py @@ -0,0 +1,20 @@ +# coding=utf-8 +# +# Copyright (C) 2018 Dmitry Vinogradov +# https://github.com/kodi-iptv-addons +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +# diff --git a/addon.xml b/addon.xml new file mode 100644 index 0000000..c5bb8d4 --- /dev/null +++ b/addon.xml @@ -0,0 +1,44 @@ + + + + + + + + video + + + + resources/icon.png + + + + all + IPTV player for ITV (itv.live) + IPTV player for ITV (itv.live) + GNU LESSER GENERAL PUBLIC LICENSE Version 3, June 2007 + https://github.com/kodi-iptv-addons + +v1.1.3 (2020-04-15) +- Minor bug fixes +v1.1.2 (2020-03-30) +- Fixed stream URL resolving +v1.1.1 (2019-01-31) +- Implemented usage of alternative EPG with program images +- Added stop on idle addon settings +v1.0.4 (2018-11-02) +- Improved error handling +v1.0.3 (2018-10-20) +- Handle authentication failures properly +v1.0.2 (2018-10-20) +- Set default value for hostname in settings to api.itv.live +v1.0.1 (2018-10-19) +- Bug fixes +v1.0.0 (2018-10-19) +- Initial release + + + diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..b4916cf --- /dev/null +++ b/changelog.txt @@ -0,0 +1,17 @@ +v1.1.3 (2020-04-15) +- Minor bug fixes +v1.1.2 (2020-03-30) +- Fixed stream URL resolving +v1.1.1 (2019-01-31) +- Implemented usage of alternative EPG with program images +- Added stop on idle addon settings +v1.0.4 (2018-11-02) +- Improved error handling +v1.0.3 (2018-10-20) +- Handle authentication failures properly +v1.0.2 (2018-10-20) +- Set default value for hostname in settings to api.itv.live +v1.0.1 (2018-10-19) +- Bug fixes +v1.0.0 (2018-10-19) +- Initial release diff --git a/default.py b/default.py new file mode 100644 index 0000000..4037c23 --- /dev/null +++ b/default.py @@ -0,0 +1,82 @@ +# coding=utf-8 +# +# Copyright (C) 2018 Dmitry Vinogradov +# https://github.com/kodi-iptv-addons +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +import builtins +import os + +setattr(builtins, 'addon_id', os.path.basename(os.path.abspath(os.path.dirname(__file__)))) + +import xbmcgui +from .itv import Itv +from iptvlib.api import ApiException +from iptvlib import * +from iptvlib.mainwindow import MainWindow + + +class Main(object): + def __init__(self): + self.main_window = MainWindow.create(self.check_settings) + self.main_window.doModal() + del self.main_window + + def check_settings(self): + # type: () -> bool + hostname = addon.getSetting("hostname") + key = addon.getSetting("key") + if hostname == "" or key == "": + + dialog = xbmcgui.Dialog() + yesno = bool( + dialog.yesno( + addon.getAddonInfo("name"), " ", + get_string(TEXT_SUBSCRIPTION_REQUIRED_ID), + get_string(TEXT_SET_CREDENTIALS_ID) + ) + ) + del dialog + if yesno is True: + addon.openSettings() + return self.check_settings() + else: + return False + + adult = addon.getSetting("adult") == 'true' or \ + addon.getSetting("adult") == True + sort_channels = addon.getSetting("sort_channels") == 'true' or \ + addon.getSetting("sort_channels") == True + + try: + self.main_window.api = Itv(hostname, key, adult, sort_channels=sort_channels) + except ApiException as ex: + if ex.code == Itv.E_HTTP_REQUEST_FAILED: + dialog = xbmcgui.Dialog() + dialog.ok( + addon.getAddonInfo("name"), + get_string(TEXT_HTTP_REQUEST_ERROR_ID) + '\n' + + ex.message + '\n' + + ex.origin_error + ) + return False + + return True + + +if __name__ == "__main__": + Main() diff --git a/itv.py b/itv.py new file mode 100644 index 0000000..89c412f --- /dev/null +++ b/itv.py @@ -0,0 +1,162 @@ +# coding=utf-8 +# +# Copyright (C) 2018 Dmitry Vinogradov +# https://github.com/kodi-iptv-addons +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +import json +from urllib.parse import quote + +from iptvlib.api import Api, ApiException +from iptvlib.models import * + + +class Itv(Api): + PROTECTED_GROUP = "Взрослый" + TEXT_ERROR_WRONG_KEY_ID = 30005 # type: int + + key = None # type: str + adult = None # type: bool + sort_channels = None # type: bool + hostname = None # type: str + _player_info = None # type: list + + def __init__(self, hostname, key, adult, **kwargs): + super(Itv, self).__init__(**kwargs) + self.hostname = hostname + self.key = self.username = key + self.adult = adult + self.auth_status = self.AUTH_STATUS_NONE + Model.API = self + + @property + def base_api_url(self): + return "http://%s/%%s" % self.hostname + + @property + def base_icon_url(self): + return "http://%s/icon/%%s" % self.hostname + + @property + def host(self): + return self.hostname + + @property + def diff_live_archive(self): + return TENSECS + + @property + def archive_ttl(self): + return TREEDAYS + + def get_cookie(self): + return "" + + def is_login_request(self, uri, payload=None, method=None, headers=None): + return uri == "" and payload.get("action") == "playerInfo" + + def login(self): + self._player_info = [] + response = self.make_request("", {"action": "playerInfo", "ukey": self.key}) + if isinstance(response, list) and len(response) and response[0].get("response") == "No Token": + raise ApiException( + addon.getLocalizedString(self.TEXT_ERROR_WRONG_KEY_ID), + Api.E_API_ERROR + ) + else: + is_error, error = Api.is_error_response(response) + if is_error: + raise ApiException(error.get("message"), error.get("code")) + + self._player_info = response + self.auth_status = self.AUTH_STATUS_OK + return response + + def get_groups(self): + if self._player_info is None: + self.login() + number = 1 + groups = OrderedDict() + channels = OrderedDict() + for channel_data in self._player_info: + if (channel_data["cat_id"] in groups) is False: + gid = str(channel_data["cat_id"]) + groups[gid] = Group( + gid=gid, + name=channel_data["cat_name"], + channels=OrderedDict(), + number=number + ) + number += 1 + group = groups[channel_data["cat_id"]] + + if self.adult is False and group.name == self.PROTECTED_GROUP: + continue + + cid = str(channel_data["ch_id"]) + channel = Channel( + cid=cid, + gid=group.gid, + name=channel_data["channel_name"], + icon=self.base_icon_url % channel_data["logo"], + epg=True, + archive=bool(channel_data.get("rec", 0)), + protected=group.name == self.PROTECTED_GROUP + ) + channel.data.update({"server": channel_data["server_cdn"], "token": channel_data["token"], "port": channel_data["port_cdn"]}) + group.channels[cid] = channels[cid] = channel + return groups + + def get_stream_url(self, cid, ut_start=None): + channel = self.channels[cid] + url = "http://%s:%s/%s/" % \ + (channel.data["server"], channel.data["port"] if channel.data["port"] != "" else "80", cid) + if ut_start is None: + url = "%smono.m3u8?token=%s" % (url, channel.data["token"]) + else: + url = "%sindex-%s-%s.m3u8?token=%s" % (url, int(ut_start), int(time_now() - ut_start), channel.data["token"]) + return self.resolve_url(url) + + def get_epg(self, cid): + # type: (str) -> OrderedDict[int, Program] + programs = self.get_epg_gh(self.channels[cid]) + if len(programs): + return programs + + obj = quote(json.dumps({"action": "epg", "chid": cid})) + response = self.make_request("epg.php?obj=%s" % obj) # type: dict[str, list[dict]] + is_error, error = Api.is_error_response(response) + if is_error: + raise ApiException(error.get("message"), error.get("code")) + + programs = OrderedDict() + prev = None + for v in response["res"]: + program = Program( + cid, + self.channels[cid].gid, + int(v["startTime"]), + int(v["stopTime"]), + v["title"], + v["desc"], + self.channels[cid].archive + ) + if prev is not None: + program.prev_program = prev + prev.next_program = program + programs[program.ut_start] = prev = program + return programs diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..585fffe206aef9d636bc4a129b5ce0fc94d7f3ba GIT binary patch literal 1799 zcmZ8hdpHwn7@sM*J9R3z&`2qhYDwi7tx3#ma_Qne3Lz_(7|AW>km%-?AzP74(Z!6> zJdTlRGAEWxXOdYnj3vqCZ0Yv&J@5B^zxVgNzwdpY_m4LfZEvk4uOSZr0F-Qw!jFmH zdGT$Nl@|NiIK?smKnjSqbFvbL0Hd>Dt21K%tD)R5zlIVF4)~2Z;p4r+NWjj(l~C*@ zhVefB6^Ijl@GE#F;ivFx-EXQDt*`h8%n#;QmE_L+4F2Y@q&nYA7}U){~AtF!Q)P$@65c!-0w6R|Ppy*OOeW z`nGHZ09Je1zz;b^z8R;*OGX}7v{3f%Y(xdH9k^fL zrG}PRin_6Vy|BHe`M`yQmKv9}k4TOpe&i!^Ohc6YwBIK*NpO9)%NnptsSGiF6}t1y z-Z9v#aDT9seZj2zL|ohkhGx3m_CZV(#Hl@S*Xv@@2E!2mEh+X|vHw8~ID4slKb0$e zg0%p6u=Xl4$ab>H=+Z!-T-b{UgntF#P5{w4CFtc*(OF7I+onDB)`u1FqM=58J}J}r zmdB?-2A00Oib=Q%NWX7>PG( z8)FLFRV09Tpy=tdef?y0KLu_gOIVIf%$m;R=bY}&|L~=gxVme0ie~y(di(nW;HefR zTVfh1pfH*cO|7bc4Q@qsFGbZlIv2gJiA5tM;C{0%?fA= zGr3_xl&g+v=+g5LDDol&-Js__P?}-Dv5qvz&Zra#4P%vre=X`YhQrM@suInP+2Ct< zIRk`|k3pO^p5`QCk7+Rug^T%;jL{|=6%wXDX_6hEVMj#k^_>bbg7cF<$C~AN-i^UE zs7A99)mZ2}b?3RBSw&0O485D@yG2`*6~tLk;XyPkTG+r~D<-RHDG$1EFO7US$lbWd zdKqyeK)5SZ&%>VC&8n&#v*mSnoDYu1h>Kh6p-n(hjuf&(Q-Sj0rX|p&;T~U38-t|s z`3Cj%aG46PGJb~$6y-_j_fnN3+~Z!I;i=*4ju465OH7Ai!F87*pZVG}piczn)=|$1 zEH|~zgc!!Bv$*zZuYm*VPXus-|CC{|3J>d<-SilbaJ5`n<)>Zh!!JEj*mn%?7b-v9 zM7O?@C$k$=9NZ6ItM})-+^Q@ey3=V3f^H+DY)$_Wf*g{y7s-l!>}Xn^(d-3C_N;la zdR4+)3SK_pvU4@XApBKC?@r~qWmokeCL{jk^LU6MCwe2MvBCqUn>1&9o`D*qROK7@ za}O?P8|6{)I_efrec9{ZfIGTrT73o=eN9DJE@JOAHBvV6*r`xKU}bpM02{o|tI(-m zNPVF-rzdan-0j@sJ_K9EWb3Y~6i$x+P18YL=|eY_*T_N_Ix5mep2~eRDeSxrh1b@K zUKB{ZtsGAw;Ev{ZnXyY;PKL_s{r$-9%f091QKt{=f|?;Mkbg&6xZe)V*&)}10Wt%q zalEa0n*dKCOMBekfwWjXR(ADLEtv^T2Iw&m^yWhUU)BIzCSXVdVsh zYQ6fk!V@k_w@Wg%6=7xax7GTd=Qm9pJX9F^3~DxQ%X}6V-O7(^x#H1}3lP*}5R+1u z5tlO{O&6Bl@)#S9{ZK>QI+pKu`fK&(JPdoMh|~!2*|5OxNfnGJkEassGjXmIvyg14 zuwC$PPRD1+qC@kH>4n7Iz44T&3O}e3X;lAWJ#NJEz4`#lh-z1g3$(z`wC?jxm{cr9 zD9n-K>z*L%if*^YQl~0M{~>FB!N^Z3SYDILxkgNmbgPp2P(4~#hs1ORt~Xb0PvNk< zof}HG9FYYj{Q>*U;XMU3kd$~~#uY6;6rB6MI={YK`Ll^Z%!>xKlE}u&9$p3WO86gr CyFX + + + + + + + + +