Skip to content

Commit adafef1

Browse files
authored
Merge pull request #99 from DesSolo/external_config
[hdrezka] add external config
2 parents a428ee2 + b894cf0 commit adafef1

8 files changed

Lines changed: 115 additions & 57 deletions

File tree

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
### Addons
33
|Icon|Name|Id|Description|Latest version|MD5|
44
|---|---|---|---|---|---|
5+
|![](addons/zip/plugin.audio.iplayer.fm/icon.png?raw=true)|iPlayer.fm|plugin.audio.iplayer.fm|iPlayer.fm - Самые популярые песни|[3.0.1](addons/zip/plugin.audio.iplayer.fm/plugin.audio.iplayer.fm-3.0.1.zip?raw=true)|`9753910a7e9079622e9a54dab95ed294`|
6+
|![](addons/zip/plugin.video.tivix.net/icon.png?raw=true)|Tivix.net|plugin.video.tivix.net|Tivix.net|[3.0.2](addons/zip/plugin.video.tivix.net/plugin.video.tivix.net-3.0.2.zip?raw=true)|`bd9dc61509274446032c7951739553e4`|
7+
|![](addons/zip/plugin.audio.music.yandex/icon.png?raw=true)|Яндекс Музыка|plugin.audio.music.yandex|Яндекс Музыка|[0.1.4](addons/zip/plugin.audio.music.yandex/plugin.audio.music.yandex-0.1.4.zip?raw=true)|`c724f61fcdc22c14aeb6035b8f224b31`|
58
|![](addons/zip/script.dandy.domain.manager/icon.png?raw=true)|Domain Manager|script.dandy.domain.manager|Domain Manager|[2.0.0](addons/zip/script.dandy.domain.manager/script.dandy.domain.manager-2.0.0.zip?raw=true)|`762fd48864965c1355cca7bf0c69a8d4`|
6-
|![](addons/zip/plugin.video.dandy.seasonvar.ru/icon.png?raw=true)|seasonvar.ru|plugin.video.dandy.seasonvar.ru|Seasovar.ru Kodi Video Addon|[2.0.7](addons/zip/plugin.video.dandy.seasonvar.ru/plugin.video.dandy.seasonvar.ru-2.0.7.zip?raw=true)|`072a947ba8f034727285793a5f6a2e59`|
7-
|![](addons/zip/context.dandy.kinopoisk.sc/icon.png?raw=true)|Kinopoisk Search Content|context.dandy.kinopoisk.sc|Kinopoisk Search Content|[3.0.1](addons/zip/context.dandy.kinopoisk.sc/context.dandy.kinopoisk.sc-3.0.1.zip?raw=true)|`2a42144752cbd501d988f7de1afee79f`|
8-
|![](addons/zip/plugin.audio.dandy.amdm.ru/icon.png?raw=true)|AmDm.ru|plugin.audio.dandy.amdm.ru|Аккорды от AmDm.ru|[2.0.2](addons/zip/plugin.audio.dandy.amdm.ru/plugin.audio.dandy.amdm.ru-2.0.2.zip?raw=true)|`1c260b3ee1d4be9983fb2a0dac324c63`|
99
|![](addons/zip/repository.dandy.kodi/icon.png?raw=true)|Dandy's Kodi Repository (Matrix)|repository.dandy.kodi|Install Add-ons from Dandy add-on repository|[2.1.0](addons/zip/repository.dandy.kodi/repository.dandy.kodi-2.1.0.zip?raw=true)|`14640627d4ee36d5e4df8f7f2e0b8bdd`|
10+
|![](addons/zip/plugin.audio.dandy.amdm.ru/icon.png?raw=true)|AmDm.ru|plugin.audio.dandy.amdm.ru|Аккорды от AmDm.ru|[2.0.2](addons/zip/plugin.audio.dandy.amdm.ru/plugin.audio.dandy.amdm.ru-2.0.2.zip?raw=true)|`1c260b3ee1d4be9983fb2a0dac324c63`|
1011
|![](addons/zip/plugin.video.kinoprosmotr.net/icon.png?raw=true)|Kinoprosmotr.net|plugin.video.kinoprosmotr.net|Kinoprosmotr.net|[3.0.0](addons/zip/plugin.video.kinoprosmotr.net/plugin.video.kinoprosmotr.net-3.0.0.zip?raw=true)|`9eb73856fc321ce9e9337914e219212a`|
1112
|![](addons/zip/script.dandy.strm.marker/icon.png?raw=true)|STRM Marker|script.dandy.strm.marker|STRM Marker|[2.0.0](addons/zip/script.dandy.strm.marker/script.dandy.strm.marker-2.0.0.zip?raw=true)|`7d560c96ff9b08e2dec0add0db0409d2`|
12-
|![](addons/zip/plugin.video.hdrezka.tv/icon.png?raw=true)|Hdrezka.tv|plugin.video.hdrezka.tv|Hdrezka.tv|[3.2.3](addons/zip/plugin.video.hdrezka.tv/plugin.video.hdrezka.tv-3.2.3.zip?raw=true)|`50e7db2259d87139d09e60ea2fdfcf21`|
13+
|![](addons/zip/plugin.video.dandy.seasonvar.ru/icon.png?raw=true)|seasonvar.ru|plugin.video.dandy.seasonvar.ru|Seasovar.ru Kodi Video Addon|[2.0.7](addons/zip/plugin.video.dandy.seasonvar.ru/plugin.video.dandy.seasonvar.ru-2.0.7.zip?raw=true)|`072a947ba8f034727285793a5f6a2e59`|
1314
|![](addons/zip/context.dandy.mediainfo/icon.png?raw=true)|Media Info|context.dandy.mediainfo|Open Media Info by current Item|[2.0.2](addons/zip/context.dandy.mediainfo/context.dandy.mediainfo-2.0.2.zip?raw=true)|`67ff00d7c54412fc6939344719ed3e1f`|
15+
|![](addons/zip/context.dandy.kinopoisk.sc/icon.png?raw=true)|Kinopoisk Search Content|context.dandy.kinopoisk.sc|Kinopoisk Search Content|[3.0.1](addons/zip/context.dandy.kinopoisk.sc/context.dandy.kinopoisk.sc-3.0.1.zip?raw=true)|`2a42144752cbd501d988f7de1afee79f`|
1416
|![](addons/zip/plugin.video.kinokong.net/icon.png?raw=true)|Kinokong.net|plugin.video.kinokong.net|Kinokong.net|[2.0.6](addons/zip/plugin.video.kinokong.net/plugin.video.kinokong.net-2.0.6.zip?raw=true)|`50d97535da18303ede230830be71fdc9`|
15-
|![](addons/zip/plugin.audio.iplayer.fm/icon.png?raw=true)|iPlayer.fm|plugin.audio.iplayer.fm|iPlayer.fm - Самые популярые песни|[3.0.1](addons/zip/plugin.audio.iplayer.fm/plugin.audio.iplayer.fm-3.0.1.zip?raw=true)|`9753910a7e9079622e9a54dab95ed294`|
16-
|![](addons/zip/plugin.video.tivix.net/icon.png?raw=true)|Tivix.net|plugin.video.tivix.net|Tivix.net|[3.0.2](addons/zip/plugin.video.tivix.net/plugin.video.tivix.net-3.0.2.zip?raw=true)|`bd9dc61509274446032c7951739553e4`|
17+
|![](addons/zip/plugin.video.hdrezka.tv/icon.png?raw=true)|Hdrezka.tv|plugin.video.hdrezka.tv|Hdrezka.tv|[3.2.4](addons/zip/plugin.video.hdrezka.tv/plugin.video.hdrezka.tv-3.2.4.zip?raw=true)|`35928977b63bfce21959bbadffdecb91`|
1718
|![](addons/zip/context.dandy.strm.generator/icon.png?raw=true)|STRM Generator|context.dandy.strm.generator|STRM Generator|[2.0.0](addons/zip/context.dandy.strm.generator/context.dandy.strm.generator-2.0.0.zip?raw=true)|`4d358fd4d806ec6c64e4fbbaa3396a32`|
18-
|![](addons/zip/plugin.audio.music.yandex/icon.png?raw=true)|Яндекс Музыка|plugin.audio.music.yandex|Яндекс Музыка|[0.1.4](addons/zip/plugin.audio.music.yandex/plugin.audio.music.yandex-0.1.4.zip?raw=true)|`c724f61fcdc22c14aeb6035b8f224b31`|
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import requests
2+
3+
import xbmcgui
4+
5+
from helpers import log, busy_dialog, dump_cookies
6+
7+
8+
def authorize(plugin):
9+
log('*** authorize')
10+
11+
with busy_dialog():
12+
login_response = plugin.make_response('POST', '/ajax/login/', data={
13+
'login_name': plugin.addon.getSetting('username'),
14+
'login_password': plugin.addon.getSetting('password'),
15+
'login_not_save': '0'
16+
})
17+
18+
data = login_response.json()
19+
if not data.get('success'):
20+
log(f'code: {login_response.status_code} text: {login_response.text}')
21+
xbmcgui.Dialog().ok('Error', data.get('message', 'Fault authorize'))
22+
return
23+
24+
cookies = login_response.cookies
25+
cookies['hdmbbs'] = '1'
26+
27+
plugin.addon.setSetting('cookies', dump_cookies(cookies))
28+
xbmcgui.Dialog().notification('Success', 'Authorization completed', xbmcgui.NOTIFICATION_INFO)
29+
30+
31+
def external_config_update(plugin):
32+
log('*** external_config_update')
33+
34+
with busy_dialog():
35+
url = plugin.addon.getSetting('external_config_url')
36+
37+
log(f'attempt fetch config from: {url}')
38+
config_response = requests.get(url)
39+
if not config_response.ok:
40+
xbmcgui.Dialog().ok('Error', f'status: {config_response.status_code}')
41+
return
42+
43+
for key, new_value in config_response.json().items():
44+
old_value = plugin.addon.getSetting(key)
45+
if old_value == new_value:
46+
continue
47+
48+
log(f'updating config key: "{key}" from: "{old_value}" to: "{new_value}"')
49+
plugin.addon.setSetting(key, new_value)
50+
51+
xbmcgui.Dialog().notification('Success', 'Updated config', xbmcgui.NOTIFICATION_INFO)

addons/plugin.video.hdrezka.tv/addon.xml

Lines changed: 1 addition & 1 deletion
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.hdrezka.tv" name="Hdrezka.tv" version="3.2.3" provider-name="MrStealth, dandy, DesSolo">
2+
<addon id="plugin.video.hdrezka.tv" name="Hdrezka.tv" version="3.2.4" provider-name="MrStealth, dandy, DesSolo">
33
<requires>
44
<import addon="xbmc.python" version="3.0.0"/>
55
<import addon="script.module.xbmc.helpers" version="3.0.0"/>

addons/plugin.video.hdrezka.tv/default.py

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
33
#
4-
# Writer (c) 2012-2021, MrStealth, dandy
4+
# Writer (c) 2012-2025, MrStealth, dandy
5+
56
import os
67
import re
78
import sys
@@ -18,10 +19,10 @@
1819

1920
import requests
2021

22+
import actions
2123
import helpers
2224
import router
2325
from voidboost import parse_streams
24-
from helpers import log, get_media_attributes, color_rating, get_subtitles, set_item_subtitles
2526

2627
common = XbmcHelpers
2728
transliterate = Translit()
@@ -77,12 +78,13 @@ def _load_proxy_settings(self):
7778
'https': proxy_protocol + '://' + proxy_url
7879
}
7980

80-
def make_response(self, method, uri, params=None, data=None, cookies=None, headers=None):
81-
return self.session.request(method, self.url + uri, params=params, data=data, headers=headers, cookies=cookies)
81+
def make_response(self, method, uri, params=None, data=None, cookies=None, headers=None, **kwargs):
82+
return self.session.request(method, self.url + uri, params=params, data=data, headers=headers, cookies=cookies, **kwargs)
83+
84+
def main(self, action):
85+
params = router.parse_uri(action)
86+
helpers.log(f'*** main params: {params}')
8287

83-
def main(self):
84-
params = router.parse_uri(sys.argv[2])
85-
log(f'*** main params: {params}')
8688
mode = params.get('mode')
8789
if mode == 'play':
8890
self.play(params.get('url'))
@@ -237,7 +239,7 @@ def index(self, uri=None, page=None, query_filter=None):
237239
title = helpers.built_title(name, country_years[i*2], **info)
238240
image = self._normalize_url(common.parseDOM(div_covers[i], "img", ret='src')[0])
239241
item_uri = router.build_uri('show', uri=router.normalize_uri(links[i]))
240-
year, country, genre = get_media_attributes(country_years[i*2])
242+
year, country, genre = helpers.get_media_attributes(country_years[i*2])
241243
item = xbmcgui.ListItem(title)
242244
item.setArt({'thumb': image, 'icon': image})
243245
item.setInfo(
@@ -276,7 +278,7 @@ def select_quality(self, streams, title, image, subtitles=None):
276278
for name, quality, url in streams:
277279
if self.quality != 'select':
278280
if (name == self.quality) or (int(self.quality.split('p')[0]) >= quality):
279-
log(f'selected quality name: {name}')
281+
helpers.log(f'selected quality name: {name}')
280282
self.play(url, subtitles)
281283
break
282284
else:
@@ -289,14 +291,14 @@ def select_quality(self, streams, title, image, subtitles=None):
289291
infoLabels={'title': film_title, 'overlay': xbmcgui.ICON_OVERLAY_WATCHED, 'playCount': 0}
290292
)
291293
item.setProperty('IsPlayable', 'true')
292-
set_item_subtitles(item, subtitles)
294+
helpers.set_item_subtitles(item, subtitles)
293295
xbmcplugin.addDirectoryItem(self.handle, item_uri, item, False)
294296

295297
def select_translator(self, content, tv_show, post_id, url, idt, action):
296298
try:
297299
div = common.parseDOM(content, 'ul', attrs={'id': 'translators-list'})[0]
298300
except Exception as ex:
299-
log(f'select_translator fault parse dom ex: {ex}')
301+
helpers.log(f'select_translator fault parse dom ex: {ex}')
300302
return tv_show, idt, None
301303
titles = common.parseDOM(div, 'li', ret='title')
302304
ids = common.parseDOM(div, 'li', ret="data-translator_id")
@@ -338,7 +340,7 @@ def select_translator(self, content, tv_show, post_id, url, idt, action):
338340
subtitles = None
339341
if action == "get_movie":
340342
playlist = [response["url"]]
341-
subtitles = get_subtitles(response)
343+
subtitles = helpers.get_subtitles(response)
342344
else:
343345
episodes = response["episodes"]
344346
playlist = common.parseDOM(episodes, "ul", attrs={"class": "b-simple_episodes__list clearfix"})
@@ -360,12 +362,12 @@ def show(self, uri):
360362
ret="data-translator_id"
361363
)[0]
362364
except Exception as ex:
363-
log(f'fault parseDOM ex: {ex}')
365+
helpers.log(f'fault parseDOM ex: {ex}')
364366
try:
365367
idt = response.text.split("sof.tv.initCDNSeriesEvents")[-1].split("{")[0]
366368
idt = idt.split(",")[1].strip()
367369
except Exception as ex:
368-
log(f'fault search CDN ex: {ex}')
370+
helpers.log(f'fault search CDN ex: {ex}')
369371
subtitles = None
370372
tv_show = common.parseDOM(response.text, "div", attrs={"id": "simple-episodes-tabs"})
371373
if tv_show:
@@ -437,34 +439,34 @@ def get_item_additional_info(self, post_id):
437439
try:
438440
additional['description'] = common.parseDOM(response.text, 'div', attrs={'class': 'b-content__bubble_text'})[0]
439441
except IndexError:
440-
log(f'fault parse description post_id: {post_id}')
442+
helpers.log(f'fault parse description post_id: {post_id}')
441443

442444
try:
443445
additional['age_limit'] = re.search(r'<b style="color: #333;">(\d+\+)</b>', response.text).group(1)
444446
except AttributeError:
445-
log(f'fault parse age_limit post_id: {post_id}')
447+
helpers.log(f'fault parse age_limit post_id: {post_id}')
446448

447449
try:
448450
site_rating = common.parseDOM(response.text, 'div', attrs={'class': 'b-content__bubble_rating'})[0]
449451
additional['rating']['site'] = common.parseDOM(site_rating, 'b')[0]
450452
except IndexError:
451-
log(f'fault parse site rating post_id: {post_id}')
453+
helpers.log(f'fault parse site rating post_id: {post_id}')
452454

453455
try:
454456
imdb_rating_block = common.parseDOM(response.text, 'span', attrs={'class': 'imdb'})[0]
455457
imdb_rating = common.parseDOM(imdb_rating_block, 'b')[0]
456458
additional['rating']['imdb'] = imdb_rating
457459
additional['description'] = f'IMDb: {helpers.color_rating(imdb_rating)}\n{additional["description"]}'
458460
except IndexError:
459-
log(f'fault parse imdb rating post_id: {post_id}')
461+
helpers.log(f'fault parse imdb rating post_id: {post_id}')
460462

461463
try:
462464
kp_rating_block = common.parseDOM(response.text, 'span', attrs={'class': 'kp'})[0]
463465
kp_rating = common.parseDOM(kp_rating_block, 'b')[0]
464466
additional['rating']['kp'] = kp_rating
465467
additional['description'] = f' Кинопоиск: {helpers.color_rating(kp_rating)}\n{additional["description"]}'
466468
except IndexError:
467-
log(f'fault parse kp rating post_id: {post_id}')
469+
helpers.log(f'fault parse kp rating post_id: {post_id}')
468470

469471
return additional
470472

@@ -495,7 +497,8 @@ def get_user_input(self):
495497
return keyword
496498

497499
def search(self, keyword, external):
498-
log(f'*** search keyword: {keyword} external: {external}')
500+
helpers.log(f'*** search keyword: {keyword} external: {external}')
501+
499502
keyword = urllib.parse.unquote_plus(keyword) if (external is not None) else self.get_user_input()
500503
if not keyword:
501504
return self.menu()
@@ -520,7 +523,7 @@ def search(self, keyword, external):
520523
title = helpers.built_title(name, country_years[i], **info)
521524
image = self._normalize_url(common.parseDOM(items[i], "img", ret='src')[0])
522525
item_uri = router.build_uri('show', uri=router.normalize_uri(links[i]))
523-
year, country, genre = get_media_attributes(country_years[i])
526+
year, country, genre = helpers.get_media_attributes(country_years[i])
524527
item = xbmcgui.ListItem(title)
525528
item.setArt({'thumb': image, 'icon': image})
526529
item.setInfo(
@@ -545,9 +548,10 @@ def search(self, keyword, external):
545548
xbmcplugin.endOfDirectory(self.handle, True)
546549

547550
def play(self, url, subtitles=None):
548-
log(f'*** play url: {url} subtitles: {subtitles}')
551+
helpers.log(f'*** play url: {url} subtitles: {subtitles}')
552+
549553
item = xbmcgui.ListItem(path=url)
550-
set_item_subtitles(item, subtitles)
554+
helpers.set_item_subtitles(item, subtitles)
551555
xbmcplugin.setResolvedUrl(self.handle, True, item)
552556

553557
def play_episode(self, url, post_id, season_id, episode_id, title, image, idt):
@@ -567,7 +571,7 @@ def play_episode(self, url, post_id, season_id, episode_id, title, image, idt):
567571
}
568572
response = self.make_response('POST', "/ajax/get_cdn_series/", data=data, headers=headers).json()
569573
data = response["url"]
570-
subtitles = get_subtitles(response)
574+
subtitles = helpers.get_subtitles(response)
571575
links = parse_streams(data)
572576
self.select_quality(links, title, image, subtitles)
573577
xbmcplugin.setContent(self.handle, 'episodes')
@@ -578,32 +582,17 @@ def _normalize_url(self, item):
578582
item = self.url + item
579583
return item
580584

581-
def correct_cookies(cookies):
582-
cookies['hdmbbs'] = '1'
583-
return cookies
584-
585-
def authorize(plugin):
586-
log('*** authorize')
587-
588-
login_response = plugin.make_response('POST', '/ajax/login/', data={
589-
'login_name': plugin.addon.getSetting('username'),
590-
'login_password': plugin.addon.getSetting('password'),
591-
'login_not_save': '0'
592-
})
593-
594-
data = login_response.json()
595-
if not data.get('success'):
596-
raise Exception('Authorization failed status: %s text: %s' % (login_response.status_code, login_response.text))
597-
598-
plugin.addon.setSetting('cookies', helpers.dump_cookies(correct_cookies(login_response.cookies)))
599585

600586
def main():
601587
plugin = HdrezkaTV()
602588

603-
if sys.argv[2] == 'authorize':
604-
authorize(plugin)
589+
action = sys.argv[2]
590+
if action == 'authorize':
591+
actions.authorize(plugin)
592+
elif action == 'external_config_update':
593+
actions.external_config_update(plugin)
605594
else:
606-
plugin.main()
595+
plugin.main(action)
607596

608597
if __name__ == '__main__':
609598
main()

addons/plugin.video.hdrezka.tv/helpers.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
import json
2+
from contextlib import contextmanager
23

34
from requests.cookies import cookiejar_from_dict
5+
46
import xbmc
57

68

9+
def log(msg, level=xbmc.LOGINFO):
10+
xbmc.log(f'hdrezka: {msg}', level)
11+
12+
@contextmanager
13+
def busy_dialog():
14+
xbmc.executebuiltin('ActivateWindow(busydialognocancel)')
15+
try:
16+
yield
17+
finally:
18+
xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
19+
20+
721
def get_media_attributes(source):
822
items = source.split(',')
923
if len(items) == 3:
@@ -37,15 +51,12 @@ def dump_cookies(cookies):
3751
def load_cookies(src):
3852
return cookiejar_from_dict(json.loads(src))
3953

40-
def log(msg, level=xbmc.LOGINFO):
41-
xbmc.log(f'hdrezka: {msg}', level)
42-
4354
def get_subtitles(response):
4455
subtitles = None
4556
try:
4657
subtitles = response["subtitle"].split(',')
4758
for si in range(len(subtitles)):
48-
parts = subtitles[si].split(']');
59+
parts = subtitles[si].split(']')
4960
subtitles[si] = parts[1].replace("\/", "/")
5061
except Exception as ex:
5162
log(f'fault decode subtitles ex: {ex}')

addons/plugin.video.hdrezka.tv/resources/settings.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@
1414
<setting id="username" type="text" label="Username" />
1515
<setting id="password" type="text" label="Password" />
1616
<setting id="cookies" type="text" visible="false" label="Authorization cookies" />
17+
<setting type="sep"/>
1718
<setting type="action" label="Authorize" action="RunScript(plugin.video.hdrezka.tv, 0, authorize)" />
1819
</category>
1920
<category label="Proxy settings">
2021
<setting id="use_proxy" type="bool" label="Use proxy settings" default="false" />
2122
<setting id="protocol" type="labelenum" label="Protocol" values="http|https|socks5" default="http"/>
2223
<setting id="proxy_url" type="text" label="URL" default="USERNAME:PASSWORD@IPADDRESS:PORT"/>
2324
</category>
25+
<category label="External config">
26+
<setting id="external_config_url" type="text" label="URL"/>
27+
<setting type="sep"/>
28+
<setting type="action" label="Update" action="RunScript(plugin.video.hdrezka.tv, 0, external_config_update)" />
29+
</category>
2430
</settings>
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
35928977b63bfce21959bbadffdecb91

0 commit comments

Comments
 (0)