Skip to content

Commit

Permalink
Merge pull request #4631 from dimkroon/matrix-viwx-1.6.0
Browse files Browse the repository at this point in the history
[plugin.video.viwx] v1.6.0
  • Loading branch information
basrieter authored Feb 15, 2025
2 parents 5d8865c + ae00b75 commit 7b01500
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 57 deletions.
18 changes: 9 additions & 9 deletions plugin.video.viwx/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.viwx" name="viwX" version="1.5.3" provider-name="Dimitri Kroon">
<addon id="plugin.video.viwx" name="viwX" version="1.6.0" provider-name="Dimitri Kroon">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="inputstream.adaptive" version="19.0.5"/>
Expand Down Expand Up @@ -30,15 +30,15 @@
<fanart>resources/fanart.png</fanart>
</assets>
<news>
[B]v1.5.3[/B]
[B]v 1.6.0[/B]
[B]Fixes:[/B]
- Show a proper geo-blocked message again.
- All catchup played in low resolution.
- Sometimes a message to login was shown when the actual issue was a connection error.
[B]Changes:[/B]
- Added support for hero items of type 'episode'.
- Hero items of type 'series' now navigate directly into the intended series folder.
If the programme has more than 1 series the items has a context menu entry 'view all episodes' to navigate to the whole programme.
- 'Continue watching' items could sometimes have and incorrect resume point.
- Another attempt to fix issues with signing in with email and password.

[B]New Features:[/B]
- Possibility to import authentication tokens copied from a web browser or another instance of
viwX as an alternative method to authenticate when signing in with email and password fails.
Visit https://github.com/dimkroon/itvx-for-kodi/wiki/Sign-in-to-your-ITV-account for more info.
</news>
<reuselanguageinvoker>true</reuselanguageinvoker>
</extension>
Expand Down
9 changes: 9 additions & 0 deletions plugin.video.viwx/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
v 1.6.0
Fixes:
- 'Continue watching' items could sometimes have and incorrect resume point.
- Another attempt to fix issues singing in with email and password.

New Features:
- Possibility to import authentication tokens copied from a web browser or another instance of
viwX as an alternative to authenticate.

v 1.5.3
Fixes:
- Show a proper geo-blocked message again.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ msgctxt "#30203"
msgid "Show password"
msgstr ""

msgctxt "#30204"
msgid "Import authentication tokens"
msgstr ""

msgctxt "#30205"
msgid "Export authentication tokens"
msgstr ""

# Help texts

msgctxt "#30302"
Expand Down Expand Up @@ -157,6 +165,16 @@ msgid "Show password in plain text while you type.\n"
"If disabled the password will be masked with '*' characters, making your password invisible to others, and yourself."
msgstr ""

msgctxt "#30404"
msgid "An alternative way to sign in - import tokens from another Kodi device or from a web browser.\n"
"Visit https://github.com/dimkroon/itvx-for-kodi/wiki for more info."
msgstr ""

msgctxt "#30405"
msgid "Export the authentication tokens from this device so you can import them on another device.\n"
"Visit https://github.com/dimkroon/itvx-for-kodi/wiki for ore info."
msgstr ""

# Script texts

# Texts in dialogs
Expand Down Expand Up @@ -198,7 +216,9 @@ msgid "Invalid email or password"
msgstr ""

msgctxt "#30617"
msgid "Forbidden\nIf this error persists wait a few hours before trying again."
msgid "Forbidden\n"
"If this error persists wait a few hours before trying again.\n"
"Visit https://github.com/dimkroon/itvx-for-kodi/wiki for alternative log in methods."
msgstr ""

msgctxt "#30618"
Expand All @@ -221,6 +241,30 @@ msgctxt "#30622"
msgid "This stream is only available to users with an itvX premium account"
msgstr ""

msgctxt "#30623"
msgid "Cannot to export tokens.\nNo user is currently signed in."
msgstr ""

msgctxt "#30624"
msgid "Export succeeded.\nData saved to:\n{file_path}."
msgstr ""

msgctxt "#30625"
msgid "Export failed.\nMake sure the folder is writable."
msgstr ""

msgctxt "#30626"
msgid "Import succeeded.\nYou are now signed in as '{nickname}'."
msgstr ""

msgctxt "#30627"
msgid "Import failed.\nThe file has invalid data."
msgstr ""

msgctxt "#30628"
msgid "Cookie import succeeded, but signing in failed.\nCheck the log for more info"
msgstr ""

# Generic button texts
msgctxt "#30790"
msgid "OK"
Expand Down
4 changes: 2 additions & 2 deletions plugin.video.viwx/resources/lib/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@


WEB_TIMEOUT = (3.5, 12)
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0'
USER_AGENT_VERSION = '127.0'
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0'
USER_AGENT_VERSION = '135.0'


logger = logging.getLogger('.'.join((logger_id, __name__.split('.', 2)[-1])))
Expand Down
3 changes: 1 addition & 2 deletions plugin.video.viwx/resources/lib/itv_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ def refresh(self):
session_data = self.account_data['itv_session']
session_data.update(new_tokens)
sess_cookie_str = build_cookie(session_data)
logger.debug("New Itv.Session cookie: %s" % sess_cookie_str)
self.account_data['cookies']['Itv.Session'] = sess_cookie_str
self.account_data['refreshed'] = time.time()
self._user_id, self._user_nickname, self._expire_time = parse_token(session_data.get('access_token'))
Expand Down Expand Up @@ -269,7 +268,7 @@ def fetch_authenticated(funct, url, login=True, **kwargs):
raise AuthenticationError

try:
if account.account_data['refreshed'] < time.time() - 4 * 3600:
if account.account_data.get('refreshed', 0.0) < time.time() - 4 * 3600:
# renew tokens periodically
logger.debug("Token cache time has expired.")
raise AuthenticationError
Expand Down
16 changes: 12 additions & 4 deletions plugin.video.viwx/resources/lib/kodi_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ----------------------------------------------------------------------------------------------------------------------
# Copyright (c) 2022-2024 Dimitri Kroon.
# Copyright (c) 2022-2025 Dimitri Kroon.
# This file is part of plugin.video.viwx.
# SPDX-License-Identifier: GPL-2.0-or-later
# See LICENSE.txt
Expand Down Expand Up @@ -121,10 +121,18 @@ def ask_play_from_start(title=None):
Script.localize(TXT_PLAY_FROM_START))


def msg_dlg(msg, title=None):
if not isinstance(msg, str) or not isinstance(title, (type(None), str)):
def msg_dlg(msg, title=None, **kwargs):
if not isinstance(msg, (str, int)) or not isinstance(title, (type(None), str, int)):
logger.error("Invalid argument passed to message dialog: '%s', '%s'", msg, title)
raise ValueError('Arguments must be of type string')
raise ValueError('Arguments must be of type string or int')

if isinstance(msg, int):
msg = Script.localize(msg)
if kwargs:
msg = msg.format(**kwargs)

if isinstance(title, int):
title = Script.localize(title)

dlg = xbmcgui.Dialog()
if title is None:
Expand Down
90 changes: 89 additions & 1 deletion plugin.video.viwx/resources/lib/settings.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@

# ----------------------------------------------------------------------------------------------------------------------
# Copyright (c) 2022-2024 Dimitri Kroon.
# Copyright (c) 2022-2025 Dimitri Kroon.
# This file is part of plugin.video.viwx.
# SPDX-License-Identifier: GPL-2.0-or-later
# See LICENSE.txt
# ----------------------------------------------------------------------------------------------------------------------

import logging
import json

import xbmcgui
import xbmcvfs
from codequick import Script
from codequick.support import addon_data, logger_id

Expand All @@ -19,6 +22,14 @@
logger = logging.getLogger('.'.join((logger_id, __name__)))


TXT_EXPORT_NOT_SINGED_IN = 30623
TXT_EXPORT_SUCCESS = 30624
TXT_EXPORT_FAIL = 30625
TXT_IMPORT_SUCCESS = 30626
TXT_IMPORT_INVALID_DATA = 30627
TXT_IMPORT_FAILED_REFRESH = 30268


@Script.register()
def login(_=None):
"""Ask the user to enter credentials and try to sign in to ITVX.
Expand Down Expand Up @@ -62,6 +73,83 @@ def logout(_):
xbmc.executebuiltin('Container.Refresh')


@Script.register()
def import_tokens(_):
"""Import authentication tokens from a web browser or an existing viwx session file."""
session = itv_account.itv_session()

file_path = xbmcgui.Dialog().browseSingle(1, 'Open cookie file', 'files')
if not file_path:
logger.info("Importing browser cookie canceled.")
return

logger.info("Importing browser cookie from %s.", file_path)
with xbmcvfs.File(file_path, 'r') as f:
data = f.read()

data = data.strip()
try:
if data.startswith('Itv.Session:"{"tokens":'):
logger.info("Found Firefox cookie data...")
data = data[13:-1]
session_data = json.loads(data)['tokens']['content']
elif data.startswith('{"tokens":'):
logger.info("Found Chromium cookie data...")
session_data = json.loads(data)['tokens']['content']
else:
logger.info("Expecting viwX data...")
session_data = json.loads(data)['itv_session']
# Just to check its presence
_ = session_data['refresh_token']
except (json.JSONDecodeError, KeyError, TypeError):
logger.error("Invalid auth cookie data:\n", exc_info=True)
kodi_utils.msg_dlg(TXT_IMPORT_INVALID_DATA)
return

logger.debug('Successfully read auth cookie file.')

session.account_data['itv_session'] = session_data
session.account_data['cookies'] = {}
if session.refresh():
kodi_utils.msg_dlg(TXT_IMPORT_SUCCESS, nickname=session.user_nickname)
else:
session.save_account_data()
kodi_utils.msg_dlg(TXT_IMPORT_FAILED_REFRESH)


@Script.register()
def export_tokens(_):
import datetime
import os
from resources.lib import utils

# Check if a user is logged in
user_id = itv_account.itv_session().user_id
if not user_id:
logger.info("Nothing to export, user_id = '%s'.", user_id)
kodi_utils.msg_dlg(TXT_EXPORT_NOT_SINGED_IN)
return

session_file = os.path.join(utils.addon_info.profile, "itv_session")
dest_dir = xbmcgui.Dialog().browseSingle(0, 'Choose directory', 'files')
if not dest_dir:
return
filename = datetime.datetime.now().strftime('viwx_tokens_%Y-%m-%d_%H-%M-%S.txt')
logger.info("Selected destination directory: %s", dest_dir)
sep = '' if dest_dir[-1] in ('/', '\\') else '/'
dest_path = sep.join((dest_dir, filename))
logger.info("Exporting session data to '%s'.", dest_path)
xbmcvfs.copy(session_file, dest_path)

# Both copy() and File.write() return True when writing to an un-writable destination
# Check if the file exists to ensure copy succeeded.
if xbmcvfs.exists(dest_path):
kodi_utils.msg_dlg(TXT_EXPORT_SUCCESS, file_path=dest_path)
else:
kodi_utils.msg_dlg(TXT_EXPORT_FAIL)
return


@Script.register()
def change_logger(_):
"""Callback for settings->generic->log_to.
Expand Down
Loading

0 comments on commit 7b01500

Please sign in to comment.