Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugin.video.viwx] v1.6.0 #4631

Merged
merged 1 commit into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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