Astroport.ONE/templates/.kodi/addons/plugin.video.francetv/resources/lib/addon.py

261 lines
8.2 KiB
Python

# coding: utf-8
#
# Copyright © 2020 melmorabity
#
# 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.
from __future__ import unicode_literals
import logging
import os
import re
try:
from typing import Dict
from typing import Optional
from typing import Text
except ImportError:
pass
try:
from urllib.parse import parse_qsl
from urllib.parse import quote
except ImportError:
from urlparse import parse_qsl
from urllib import quote
from inputstreamhelper import Helper # pylint: disable=import-error
import xbmc # pylint: disable=import-error
from xbmcaddon import Addon # pylint: disable=import-error
from xbmcgui import Dialog # pylint: disable=import-error
from xbmcgui import ListItem # pylint: disable=import-error
import xbmcplugin # pylint: disable=import-error
from resources.lib.api import FranceTV
from resources.lib.api import ParsedItem
import resources.lib.kodilogging
from resources.lib.utils import update_url_params
from resources.lib.video import FranceTVVideo
from resources.lib.video import FranceTVVideoException
resources.lib.kodilogging.config()
_LOGGER = logging.getLogger(__name__)
_KODI_VERSION = int(xbmc.getInfoLabel("System.BuildVersion").split(".")[0])
# pylint: disable=too-few-public-methods
class FranceTVAddon:
_ADDON_ID = "plugin.video.francetv"
_ADDON = Addon()
_ADDON_DIR = xbmc.translatePath(_ADDON.getAddonInfo("path"))
_ADDON_MEDIA_DIR = os.path.join(_ADDON_DIR, "resources", "media")
_ADDON_FANART = Addon().getAddonInfo("fanart")
_USER_AGENT = (
"Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:85.0) Gecko/20100101 "
"Firefox/85.0"
)
def __init__(self, base_url, handle, params):
# type: (Text, int, Text) -> None
self._base_url = base_url
self._handle = handle
self._params = self._params_to_dict(params)
self._api = FranceTV()
@staticmethod
def _params_to_dict(params):
# type: (Optional[Text]) -> Dict[Text, Text]
# Parameter string starts with a '?'
return dict(parse_qsl(params[1:])) if params else {}
def _localize(self, label):
# type: (Text) -> Text
return re.sub(
r"\$LOCALIZE\[(\d+)\]",
lambda m: self._ADDON.getLocalizedString(int(m.group(1))),
label,
)
def _add_listitem(self, parsed_item):
# type: (ParsedItem) -> None
is_folder = parsed_item.url.get("mode") != "watch"
_LOGGER.debug("Add ListItem %s", parsed_item)
listitem = ListItem(
label=self._localize(parsed_item.label), offscreen=True
)
listitem.setInfo("video", parsed_item.info)
# Set fallback fanart
parsed_item.art.setdefault("fanart", self._ADDON_FANART)
listitem.setArt(parsed_item.art)
for key, value in list(parsed_item.properties.items()):
listitem.setProperty(key, value)
xbmcplugin.addDirectoryItem(
self._handle,
update_url_params(self._base_url, **parsed_item.url),
listitem,
isFolder=is_folder,
)
def _mode_collection(self, path):
# type: (Text) -> None
xbmcplugin.setContent(self._handle, "videos")
xbmcplugin.addSortMethod(
self._handle, xbmcplugin.SORT_METHOD_UNSORTED, label2Mask="%Z"
)
level = None # type: Optional[int]
if self._params.get("level"):
try:
level = int(self._params["level"])
except ValueError:
pass
for item in self._api.get_collection(path, level):
self._add_listitem(item)
def _mode_watch(self):
# type: () -> None
video_id = self._params["id"]
is_helper = Helper("mpd")
use_dash = bool(is_helper.check_inputstream())
video_url = FranceTVVideo().get_video_url(video_id, use_dash)
# Workaround for
# https://github.com/melmorabity/plugin.video.francetv/issues/2
headers = "User-Agent={}".format(self._USER_AGENT)
listitem = ListItem(
path="{}|{}".format(video_url, headers),
offscreen=True,
)
# Use DASH if possible for better subtitle management
if use_dash and ".mpd" in video_url:
listitem.setMimeType("application/dash+xml")
listitem.setProperty("inputstream.adaptive.manifest_type", "mpd")
if _KODI_VERSION >= 19:
listitem.setProperty(
"inputstream", is_helper.inputstream_addon
)
else:
listitem.setProperty(
"inputstreamaddon", is_helper.inputstream_addon
)
listitem.setProperty(
"inputstream.adaptive.stream_headers", headers
)
xbmcplugin.setResolvedUrl(self._handle, True, listitem)
def _mode_search(self):
# type: () -> None
search = Dialog().input(self._ADDON.getLocalizedString(30005))
self._mode_collection(
"apps/search?term={}&filters=with-lives,with-collections".format(
quote(search, safe="")
)
)
def _mode_default(self):
# type: () -> None
self._add_listitem(
ParsedItem(
self._ADDON.getLocalizedString(30001),
{"mode": "collection", "path": "apps/page/_"},
{},
{"icon": os.path.join(self._ADDON_MEDIA_DIR, "home.png")},
{},
)
)
self._add_listitem(
ParsedItem(
self._ADDON.getLocalizedString(30002),
{"mode": "collection", "path": "generic/directs"},
{},
{"icon": os.path.join(self._ADDON_MEDIA_DIR, "live-tv.png")},
{},
)
)
self._add_listitem(
ParsedItem(
self._ADDON.getLocalizedString(30003),
{"mode": "collection", "path": "generic/channels"},
{},
{"icon": os.path.join(self._ADDON_MEDIA_DIR, "channels.png")},
{},
)
)
self._add_listitem(
ParsedItem(
self._ADDON.getLocalizedString(30004),
{"mode": "collection", "path": "generic/categories"},
{},
{
"icon": os.path.join(
self._ADDON_MEDIA_DIR, "categories.png"
)
},
{},
)
)
self._add_listitem(
ParsedItem(
self._ADDON.getLocalizedString(30005),
{"mode": "search"},
{},
{"icon": os.path.join(self._ADDON_MEDIA_DIR, "search.png")},
{},
)
)
def run(self):
# type: () -> None
mode = self._params.get("mode")
_LOGGER.debug("Addon params = %s", self._params)
succeeded = True
try:
if mode == "collection" and self._params.get("path"):
self._mode_collection(self._params["path"])
elif mode == "watch" and self._params.get("id"):
self._mode_watch()
elif mode == "search":
self._mode_search()
else:
self._mode_default()
except FranceTVVideoException as ex:
_LOGGER.error(ex)
Dialog().ok(self._ADDON.getLocalizedString(30201), ex.args[1])
succeeded = False
finally:
xbmcplugin.endOfDirectory(self._handle, succeeded=succeeded)