Skip to content
This repository was archived by the owner on May 2, 2026. It is now read-only.

Commit e1272dd

Browse files
authored
Merge pull request #171 from axtrat/provider/animeunity
2 parents 5f7e10a + 5fe59e1 commit e1272dd

4 files changed

Lines changed: 60 additions & 8 deletions

File tree

viu_media/libs/provider/anime/animeunity/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@
1111
# Server Specific
1212
AVAILABLE_VIDEO_QUALITY = ["1080", "720", "480"]
1313
VIDEO_INFO_REGEX = re.compile(r"window.video\s*=\s*(\{[^\}]*\})")
14+
VIDEO_INFO_CLEAN_REGEX = re.compile(r'(?<!["\'])(\b\w+\b)(?=\s*:)')
15+
DOWNLOAD_FILENAME_REGEX = re.compile(r"[?&]filename=([^&]+)")
16+
QUALITY_REGEX = re.compile(r"/(\d{3,4}p)")
1417
DOWNLOAD_URL_REGEX = re.compile(r"window.downloadUrl\s*=\s*'([^']*)'")
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import logging
2+
3+
from .constants import (
4+
DOWNLOAD_FILENAME_REGEX,
5+
DOWNLOAD_URL_REGEX,
6+
QUALITY_REGEX,
7+
VIDEO_INFO_CLEAN_REGEX,
8+
VIDEO_INFO_REGEX,
9+
)
10+
11+
logger = logging.getLogger(__name__)
12+
13+
14+
def extract_server_info(html_content: str, episode_title: str | None) -> dict | None:
15+
"""
16+
Extracts server information from the VixCloud/AnimeUnity embed page.
17+
Handles extraction from both window.video object and download URL.
18+
"""
19+
video_info = VIDEO_INFO_REGEX.search(html_content)
20+
download_url_match = DOWNLOAD_URL_REGEX.search(html_content)
21+
22+
if not (download_url_match and video_info):
23+
return None
24+
25+
info_str = VIDEO_INFO_CLEAN_REGEX.sub(r'"\1"', video_info.group(1))
26+
27+
# Use eval context for JS constants
28+
ctx = {"null": None, "true": True, "false": False}
29+
try:
30+
info = eval(info_str, ctx)
31+
except Exception as e:
32+
logger.error(f"Failed to parse JS object: {e}")
33+
return None
34+
35+
download_url = download_url_match.group(1)
36+
info["link"] = download_url
37+
38+
# Extract metadata from download URL if missing in window.video
39+
if filename_match := DOWNLOAD_FILENAME_REGEX.search(download_url):
40+
info["name"] = filename_match.group(1)
41+
else:
42+
info["name"] = f"{episode_title or 'Unknown'}"
43+
44+
if quality_match := QUALITY_REGEX.search(download_url):
45+
# "720p" -> 720
46+
info["quality"] = int(quality_match.group(1)[:-1])
47+
else:
48+
info["quality"] = 0 # Fallback
49+
50+
return info

viu_media/libs/provider/anime/animeunity/mappers.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ def map_to_server(
9999
translation_type=MediaTranslationType(translation_type),
100100
mp4=True,
101101
)
102-
for quality in AVAILABLE_VIDEO_QUALITY
102+
for quality in sorted(
103+
list(set(AVAILABLE_VIDEO_QUALITY + [str(info["quality"])])),
104+
key=lambda x: int(x),
105+
reverse=True,
106+
)
103107
if int(quality) <= info["quality"]
104108
],
105109
episode_title=episode.title,

viu_media/libs/provider/anime/animeunity/provider.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
from ..utils.debug import debug_provider
99
from .constants import (
1010
ANIMEUNITY_BASE,
11-
DOWNLOAD_URL_REGEX,
1211
MAX_TIMEOUT,
1312
REPLACEMENT_WORDS,
1413
TOKEN_REGEX,
15-
VIDEO_INFO_REGEX,
1614
)
15+
from .extractor import extract_server_info
1716
from .mappers import (
1817
map_to_anime_result,
1918
map_to_search_result,
@@ -158,14 +157,10 @@ def episode_streams(self, params: EpisodeStreamsParams):
158157
video_response = self.client.get(url=response.text.strip(), timeout=MAX_TIMEOUT)
159158
video_response.raise_for_status()
160159

161-
video_info = VIDEO_INFO_REGEX.search(video_response.text)
162-
download_url_match = DOWNLOAD_URL_REGEX.search(video_response.text)
163-
if not (download_url_match and video_info):
160+
if not (info := extract_server_info(video_response.text, episode.title)):
164161
logger.error(f"Failed to extract video info for episode {episode.id}")
165162
return None
166163

167-
info = eval(video_info.group(1).replace("null", "None"))
168-
info["link"] = download_url_match.group(1)
169164
yield map_to_server(episode, info, params.translation_type)
170165

171166

0 commit comments

Comments
 (0)