Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
# run: echo "${{toJson(github)}}"

- name: Run make release
run: cd $HOME/work/kodi/kodi/ && make release
run: cd $GITHUB_WORKSPACE && make release

- uses: stefanzweifel/git-auto-commit-action@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
|![](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`|
|![](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.9](addons/zip/plugin.video.dandy.seasonvar.ru/plugin.video.dandy.seasonvar.ru-2.0.9.zip?raw=true)|`b4137559b24671d1ee4ca9025bae1725`|
|![](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`|
|![](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`|
|![](addons/zip/plugin.video.hdrezka.tv/icon.png?raw=true)|Hdrezka.tv|plugin.video.hdrezka.tv|Hdrezka.tv|[3.2.5](addons/zip/plugin.video.hdrezka.tv/plugin.video.hdrezka.tv-3.2.5.zip?raw=true)|`5fae038ff39c380103bce65e7f66a166`|
|![](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`|
|![](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`|
|![](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`|
Expand Down
4 changes: 2 additions & 2 deletions addons/addons.xml
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,15 @@
</extension>
</addon>

<addon id="plugin.video.hdrezka.tv" name="Hdrezka.tv" version="3.2.4" provider-name="MrStealth, dandy, DesSolo">
<addon id="plugin.video.hdrezka.tv" name="Hdrezka.tv" version="3.2.5" provider-name="MrStealth, dandy, DesSolo">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.xbmc.helpers" version="3.0.0"/>
<import addon="script.module.translit" version="3.0.0"/>
<import addon="script.module.dandy.search.history" version="3.0.0"/>
<import addon="script.module.requests"/>
</requires>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py">>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
Expand Down
2 changes: 1 addition & 1 deletion addons/addons.xml.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e7baf6dbe3760b0b524ca3d0de83b080
36423869b6df52787ca949073a106421
5 changes: 2 additions & 3 deletions addons/plugin.video.hdrezka.tv/addon.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.hdrezka.tv" name="Hdrezka.tv" version="3.2.4" provider-name="MrStealth, dandy, DesSolo">
<addon id="plugin.video.hdrezka.tv" name="Hdrezka.tv" version="3.2.5" provider-name="MrStealth, dandy, DesSolo">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.xbmc.helpers" version="3.0.0"/>
<import addon="script.module.translit" version="3.0.0"/>
<import addon="script.module.dandy.search.history" version="3.0.0"/>
<import addon="script.module.requests"/>
</requires>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py">>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
Expand All @@ -21,4 +21,3 @@
</assets>
</extension>
</addon>

3 changes: 3 additions & 0 deletions addons/plugin.video.hdrezka.tv/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
3.2.5
[fix] voidboost obfuscation

3.0.0
[upd] Kodi 19

Expand Down
113 changes: 102 additions & 11 deletions addons/plugin.video.hdrezka.tv/voidboost.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import re
import base64
import logging
from operator import itemgetter
from typing import List, Tuple, Optional

logger = logging.getLogger(__name__)

BK_SEP = '//_//'
BK_BLOCKS = [
Expand All @@ -11,15 +15,102 @@
'JCQjISFAIyFAIyM='
]

# Компилируем один раз
QUALITY_PATTERN = re.compile(r'\[((\d+)[^]]+)].+?(http.+?mp4)', re.DOTALL)


def parse_streams(data: str) -> List[Tuple[str, int, str]]:
"""
Парсит потоки из обфусцированной или plain text строки.
Сохраняет оригинальную логику: берет первый URL после качества.

Returns:
[(quality_name, quality_int, url), ...] отсортировано по качеству desc

Raises:
ValueError: Если нет валидных потоков
"""
if not isinstance(data, str) or not data.strip():
raise ValueError("Input must be non-empty string")

# Шаг 1: Очистка (как в оригинале)
cleaned = _clean_obfuscation(data)

# Шаг 2: Декодирование с автоопределением формата
decoded = _decode(cleaned)
if not decoded:
raise ValueError("Failed to decode streams data")

# Шаг 3: Парсинг (оригинальная логика)
streams = _parse_quality_blocks(decoded)

if not streams:
logger.warning(f"No streams parsed from: {decoded[:200]}...")
raise ValueError("No streams found in decoded data")

# Шаг 4: Сортировка (оригинальная)
return sorted(streams, key=itemgetter(1), reverse=True)


def _clean_obfuscation(data: str) -> str:
"""Удаляет escape-символы и мусорные блоки."""
result = data.replace('\\', '')
for block in BK_BLOCKS:
result = result.replace(BK_SEP + block, '')
return result


def _decode(data: str) -> Optional[str]:
"""
Определяет формат и декодирует.
Plain text: начинается с [
Base64: остальное
"""
# Plain text (новый формат без обфускации)
if data.startswith('['):
logger.debug("Detected plain text format")
return data

# Base64 (старый формат)
try:
# Проверяем минимальную длину для base64
if len(data) < 4:
return None

decoded_bytes = base64.b64decode(data[2:])
return decoded_bytes.decode('utf-8')
except (ValueError, UnicodeDecodeError) as e:
logger.debug(f"Base64 decode failed: {e}")
return None


def _parse_quality_blocks(decoded: str) -> List[Tuple[str, int, str]]:
"""
Парсит блоки [quality]url.
Сохраняет оригинальное поведение: берет первый http...mp4 после [quality].
"""
streams = []

for match in QUALITY_PATTERN.finditer(decoded):
quality_name = match.group(1) # "1080p" или "1080p Ultra"
quality_num = int(match.group(2)) # 1080
url = match.group(3) # http...mp4 (первый найденный после [quality])

# Валидация URL
if _is_valid_url(url):
# Очистка HLS-суффикса для совместимости
clean_url = url.replace(':hls:manifest.m3u8', '')
streams.append((quality_name, quality_num, clean_url))
else:
logger.warning(f"Invalid URL parsed: {url[:100]}...")

return streams


def parse_streams(salted):
salted = salted.replace('\\', '')
for bk in BK_BLOCKS:
salted = salted.replace(BK_SEP + bk, '')
decoded_streams = base64.b64decode(salted[2:]).decode('utf-8')
parsed_streams = []
for name, quality, url in re.findall(r'\[((\d+)[^]]+)].+?(http.+?mp4)', decoded_streams):
parsed_streams.append((
name, int(quality), url
))
return sorted(parsed_streams, key=itemgetter(1), reverse=True)
def _is_valid_url(url: str) -> bool:
"""Проверяет что URL начинается с http и содержит домен."""
return (
url.startswith(('http://', 'https://')) and
len(url) > 10 and
'.' in url[8:] # после http:// или https://
)
3 changes: 3 additions & 0 deletions addons/zip/plugin.video.hdrezka.tv/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
3.2.5
[fix] voidboost obfuscation

3.0.0
[upd] Kodi 19

Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5fae038ff39c380103bce65e7f66a166