Skip to content

Commit 0a3fc08

Browse files
authored
Merge pull request #122 from dimkroon/development
Version 1.5.2
2 parents be4eb55 + 1949c92 commit 0a3fc08

File tree

9 files changed

+65
-49
lines changed

9 files changed

+65
-49
lines changed

plugin.video.viwx/addon.xml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<addon id="plugin.video.viwx" name="viwX" version="1.5.1" provider-name="Dimitri Kroon">
2+
<addon id="plugin.video.viwx" name="viwX" version="1.5.2" provider-name="Dimitri Kroon">
33
<requires>
44
<import addon="xbmc.python" version="3.0.0"/>
55
<import addon="inputstream.adaptive" version="19.0.5"/>
@@ -30,18 +30,9 @@
3030
<fanart>resources/fanart.png</fanart>
3131
</assets>
3232
<news>
33-
[B]v1.5.1[/B]
33+
[B]v1.5.2[/B]
3434
[B]Fixes:[/B]
35-
* News clips failed to play with KeyError 'Brand'.
36-
* Error messages when opening an empty 'Continue Watching' list.
37-
* Stream-only FAST channels stalled in advert breaks.
38-
* Programmes are now reported as having been fully played when the user has skipped to the end while playing.
39-
* Some programmes were missing en IPTV EPG.
40-
* Search now requests the same number of items as a generic web browser does.
41-
42-
[B]New Features:[/B]
43-
* Paid items are excluded from search results based on the setting 'Hide premium content'.
44-
* On most live channels it's now possible to seek back up to 1 hour from the moment the channel is started.
35+
- Login failed with error 'Forbidden' even though email and password were correct.
4536
</news>
4637
<reuselanguageinvoker>true</reuselanguageinvoker>
4738
</extension>

plugin.video.viwx/changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
v 1.5.2
2+
Fixes:
3+
- Login failed with error 'Forbidden' even though email and password were correct.
4+
15
v 1.5.1
26
Fixes:
37
- News clips failed to play with KeyError 'Brand'.

plugin.video.viwx/resources/language/resource.language.en_gb/strings.po

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,19 @@ msgid "Signed out!"
181181
msgstr ""
182182

183183
msgctxt "#30614"
184-
msgid "User name"
184+
msgid "Email"
185185
msgstr ""
186186

187187
msgctxt "#30615"
188188
msgid "Password"
189189
msgstr ""
190190

191191
msgctxt "#30616"
192-
msgid "Invalid username"
192+
msgid "Invalid email or password"
193193
msgstr ""
194194

195195
msgctxt "#30617"
196-
msgid "Invalid password"
196+
msgid "Forbidden\nIf this error persists wait a few hours before trying again."
197197
msgstr ""
198198

199199
msgctxt "#30618"

plugin.video.viwx/resources/lib/itv_account.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import json
1111
import logging
1212

13+
from codequick import Script
1314
from codequick.support import logger_id
1415

1516
from . import utils
@@ -21,6 +22,9 @@
2122
logger = logging.getLogger(logger_id + '.account')
2223
SESS_DATA_VERS = 2
2324

25+
TXT_INVALID_EMAIL_OR_PASSW = 30616
26+
TXT_LOGIN_FORBIDDEN = 30617
27+
2428

2529
class ItvSession:
2630
def __init__(self):
@@ -123,7 +127,7 @@ def login(self, uname: str, passw: str):
123127
'sec-fetch-dest': 'empty',
124128
'sec-fetch-mode': 'cors',
125129
'sec-fetch-site': 'same-site',
126-
'priority': 'u=1',
130+
'priority': 'u=0',
127131
'te': 'trailers'
128132
},
129133
timeout=fetch.WEB_TIMEOUT
@@ -141,8 +145,8 @@ def login(self, uname: str, passw: str):
141145
status_code = e.response.status_code
142146
if status_code in (400, 403):
143147
msg = {
144-
400: 'Invalid username or password',
145-
403: 'Forbidden\nIf this error persists wait a few hours before trying again.'
148+
400: Script.localize(TXT_INVALID_EMAIL_OR_PASSW),
149+
403: Script.localize(TXT_LOGIN_FORBIDDEN)
146150
}.get(status_code, 'Sign in failed.')
147151
logger.info("Sign in failed: %r: %r", e, e.response.content)
148152
raise AuthenticationError(msg) from None

plugin.video.viwx/resources/lib/kodi_utils.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# ----------------------------------------------------------------------------------------------------------------------
2-
# Copyright (c) 2022-2023 Dimitri Kroon.
2+
# Copyright (c) 2022-2024 Dimitri Kroon.
33
# This file is part of plugin.video.viwx.
44
# SPDX-License-Identifier: GPL-2.0-or-later
55
# See LICENSE.txt
@@ -30,8 +30,6 @@
3030

3131
TXT_USERNAME = 30614
3232
TXT_PASSWORD = 30615
33-
TXT_INVALID_USERNAME = 30616
34-
TXT_INVALID_PASSWORD = 30617
3533
TXT_TRY_AGAIN = 30618
3634
TXT_RESUME_FROM = 30619
3735
TXT_PLAY_FROM_START = 30620
@@ -88,11 +86,6 @@ def show_login_result(success: bool, message: str = None):
8886
def ask_login_retry(reason):
8987
"""Show a message that login has failed and ask whether to try again."""
9088

91-
if reason.lower() == 'invalid username':
92-
reason = Script.localize(TXT_INVALID_USERNAME)
93-
elif reason.lower() == 'invalid password':
94-
reason = Script.localize(TXT_INVALID_PASSWORD)
95-
9689
msg = '\n\n'.join((reason, Script.localize(TXT_TRY_AGAIN)))
9790

9891
dlg = xbmcgui.Dialog()

plugin.video.viwx/resources/lib/telemetry_data.py

Lines changed: 20 additions & 11 deletions
Large diffs are not rendered by default.

test/support/fixtures.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# ----------------------------------------------------------------------------------------------------------------------
77

88
import os
9+
import sys
910
from typing import Dict, List, Tuple
1011

1112
from unittest.mock import patch
@@ -100,6 +101,10 @@ def set_credentials(session=None) -> None:
100101
credentials_set = s.refresh()
101102
if credentials_set is False:
102103
credentials_set = s.login(account_login.UNAME, account_login.PASSW)
104+
if not credentials_set:
105+
import traceback
106+
traceback.print_exc()
107+
sys.exit(1)
103108

104109

105110
def setup_web_test(*args):

test/web/test_itvx_api.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,10 @@ def check_vnd_user_content_v1_json(self, data):
342342
# Some episodes' series and/or episode number are None, e.g. episodes of The Chase
343343
object_checks.has_keys(item, 'seriesNumber', 'episodeNumber')
344344

345-
if item['contentType'] in ('FILM', 'SPECIAL'):
345+
if item['contentType'] == 'FILM':
346346
self.assertIsNotNone(utils.iso_duration_2_seconds(item['duration']))
347+
elif item['contentType'] == 'SPECIAL':
348+
self.assertTrue(utils.iso_duration_2_seconds(item['duration']) or item['duration'] is None)
347349
else:
348350
self.assertIsNone(item['duration'])
349351

@@ -699,8 +701,8 @@ def test_get_playlist_catchup(self):
699701

700702
def test_get_playlist_premium_catchup(self):
701703
"""Request a premium stream without a premium account."""
702-
# 2Point4 Children S1E1
703-
resp = self.get_playlist_catchup('https://magni.itv.com/playlist/itvonline/ITV/10_0848_0006.001')
704+
# Judge John Deed S1E1
705+
resp = self.get_playlist_catchup('https://magni.itv.com/playlist/itvonline/ITV/10_5323_0001.001')
704706
object_checks.has_keys(resp, 'Message', 'TransactionId')
705707
self.assertTrue('message: User does not have entitlements' in resp['Message'])
706708

test/web/test_itvx_html.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ def check_programme(self, progr_data):
115115
has_keys(progr_data, 'title', 'image', 'longDescription', 'description',
116116
'encodedProgrammeId', 'titleSlug', 'tier', 'visuallySigned',
117117
obj_name=obj_name)
118-
expect_keys(progr_data, 'categories', 'programmeId')
118+
expect_keys(progr_data, 'programmeId')
119+
misses_keys(progr_data, 'categories')
119120
# Only programme details pages (like episodes, specials, films) still have this field.
120121
# Its presence is specifically checked in their tests.
121122
expect_misses_keys(progr_data, 'imagePresets')
@@ -124,7 +125,8 @@ def check_programme(self, progr_data):
124125
self.assertTrue(is_not_empty(progr_data['longDescription'], str))
125126
self.assertTrue(is_not_empty(progr_data['description'], str))
126127
self.assertTrue(is_url(progr_data['image']))
127-
self.assertTrue(is_not_empty(progr_data['categories'], list))
128+
self.assertTrue(is_not_empty(progr_data['genres'], list))
129+
has_keys(progr_data['genres'][0], 'id', 'name')
128130
self.assertTrue(is_not_empty(progr_data['titleSlug'], str))
129131
self.assertTrue(is_tier_info(progr_data['tier']))
130132
if 'numberOfAvailableSeries' in progr_data:
@@ -149,7 +151,7 @@ def check_series(self, series, parent_name):
149151
def check_title(self, title, parent_name):
150152
obj_name = '{}-title-{}'.format(parent_name, title['episodeTitle'])
151153
has_keys(title, 'accessibilityTags', 'audioDescribed', 'availabilityFrom', 'availabilityUntil', 'broadcastDateTime',
152-
'categories', 'contentInfo', 'dateTime', 'description',
154+
'genres', 'contentInfo', 'dateTime', 'description',
153155
'duration', 'encodedEpisodeId', 'episodeTitle', 'genres', 'guidance', 'image', 'longDescription',
154156
'notFormattedDuration', 'playlistUrl', 'productionType', 'premium', 'tier', 'series', 'visuallySigned',
155157
'subtitled', 'audioDescribed',
@@ -164,12 +166,18 @@ def check_title(self, title, parent_name):
164166
self.assertTrue(is_iso_utc_time(title['availabilityFrom']))
165167
self.assertTrue(is_iso_utc_time(title['availabilityUntil']))
166168
self.assertTrue(is_iso_utc_time(title['broadcastDateTime']) or title['broadcastDateTime'] is None)
167-
self.assertIsInstance(title['categories'], list)
169+
self.assertTrue(is_not_empty(title['genres'], list))
170+
has_keys(title['genres'][0], 'id', 'name')
168171
self.assertIsInstance(title['contentInfo'], str) # can be empty in films, specials, or episodes in sections like 'latest episodes'.
169-
self.assertTrue(is_iso_utc_time(title['dateTime']))
172+
self.assertTrue(is_iso_utc_time(title['dateTime']) or title['dateTime'] is None)
170173
self.assertTrue(is_not_empty(title['description'], str))
171-
self.assertTrue(is_not_empty(title['duration'], str))
172-
self.assertFalse(title['duration'].startswith('P')) # duration is not in iso format
174+
self.assertTrue(is_not_empty(title['duration'], str) or title['duration'] is None)
175+
if title['duration'] is not None:
176+
self.assertFalse(title['duration'].startswith('P')) # duration is not in iso format
177+
if title['notFormattedDuration'] is None:
178+
self.assertIsNone(title['duration'])
179+
else:
180+
self.assertTrue(title['notFormattedDuration'].startswith('PT'))
173181
self.assertTrue(is_encoded_episode_id(title['encodedEpisodeId']))
174182
self.assertTrue(is_not_empty(title['episodeTitle'], str) or title['episodeTitle'] is None)
175183
check_genres(self, title['genres'])
@@ -336,11 +344,11 @@ def check_item_type_brand(testcase, item, parent_name):
336344
has_keys(item, 'title', 'contentType', 'titleSlug', 'description', 'genres', 'dateTime', 'imageTemplate',
337345
'numberOfAvailableSeries', 'series', 'programmeId', 'encodedProgrammeId', 'contentInfo', 'isPaid',
338346
obj_name=name)
339-
expect_keys(item, 'partnership', 'contentOwner','categories', 'channel', 'ccid', obj_name=name)
347+
expect_keys(item, 'partnership', 'contentOwner', 'channel', 'ccid', obj_name=name)
348+
misses_keys(item, 'categories')
340349
testcase.assertTrue(is_not_empty(item['title'], str))
341350
testcase.assertTrue(is_not_empty(item['titleSlug'], str))
342351
testcase.assertTrue(is_not_empty(item['description'], str))
343-
testcase.assertTrue(is_not_empty(item['categories'], list))
344352
check_genres(testcase, item['genres'], name)
345353
testcase.assertTrue(item['dateTime'] is None or is_iso_utc_time(item['dateTime']))
346354
testcase.assertTrue(is_url(item['imageTemplate']))

0 commit comments

Comments
 (0)