"""Offline tutorial: retain returned image positions and select one video rendition."""
from copy import deepcopy
from urllib.parse import urlsplit
import json
def positive_dimension(value):
return value if type(value) is int and value > 0 else 0
def media_array(data, name):
value = data.get(name)
if value is None:
return []
if not isinstance(value, list):
raise ValueError(f"{name} must be an array or null")
return value
def usable_url(item):
if not isinstance(item, dict) or not isinstance(item.get("url"), str):
return False
try:
parsed = urlsplit(item["url"].strip())
return parsed.scheme in {"http", "https"} and bool(parsed.hostname)
except ValueError:
return False
def preview_plan(payload):
"""For one public post; videos are assumed to be renditions of one clip."""
if not isinstance(payload, dict) or payload.get("status") != 200:
raise ValueError("Expected a successful API response envelope")
data = payload.get("data")
if not isinstance(data, dict):
raise ValueError("Expected a data object")
# Keep source positions, including gaps left by unusable entries.
images = [
{
"position": position,
"url": item["url"].strip(),
"width": positive_dimension(item.get("width")),
"height": positive_dimension(item.get("height")),
}
for position, item in enumerate(media_array(data, "images"), start=1)
if usable_url(item)
]
candidates = [
(position, item)
for position, item in enumerate(media_array(data, "videos"), start=1)
if usable_url(item)
]
def rank(candidate):
position, item = candidate
audio = item.get("hasAudio")
audio_rank = 2 if audio is True else (0 if audio is False else 1)
width = positive_dimension(item.get("width"))
height = positive_dimension(item.get("height"))
return audio_rank, width * height, height, -position
chosen = None
if candidates:
position, item = max(candidates, key=rank)
chosen = {
"source_position": position,
"url": item["url"].strip(),
"quality": item.get("quality"),
"hasAudio": item.get("hasAudio"),
}
return {"images": images, "selected_video": chosen}
# Synthetic fixtures only. example.invalid is not a real media source.
carousel = {
"status": 200,
"data": {
"platform": "tiktok",
"thumbnail": "https://example.invalid/cover.jpg",
"images": [
{"url": "https://example.invalid/image10.jpg", "width": 1080, "height": 1920},
{"url": "https://example.invalid/image2.jpg", "width": 1080, "height": 1920},
{"url": "https://example.invalid/image1.jpg", "width": 1080, "height": 1920},
],
"videos": [],
},
}
clip = {
"status": 200,
"data": {
"platform": "tiktok",
"images": [],
"videos": [
{"url": "https://example.invalid/silent-1080.mp4", "width": 1920,
"height": 1080, "quality": "1080p", "hasAudio": False},
{"url": "https://example.invalid/muxed-720.mp4", "width": 1280,
"height": 720, "quality": "720p", "hasAudio": True},
{"url": "https://example.invalid/muxed-720-alternate.mp4", "width": 1280,
"height": 720, "quality": "720p", "hasAudio": True},
],
},
}
def expect_invalid(payload):
try:
preview_plan(payload)
except ValueError:
return
raise AssertionError("Invalid envelope/array should be rejected")
# Nine checks exercise behavior, rather than making a live API request.
image_plan = preview_plan(carousel)
assert [item["url"].rsplit("/", 1)[-1] for item in image_plan["images"]] == [
"image10.jpg", "image2.jpg", "image1.jpg"
] # 1: retain returned order instead of sorting filenames
assert [item["position"] for item in image_plan["images"]] == [1, 2, 3]
assert image_plan["selected_video"] is None # 2: no invented video
video_plan = preview_plan(clip)
assert video_plan["selected_video"]["source_position"] == 2 # 3: prefer known audio
unknown_audio = deepcopy(clip)
unknown_audio["data"]["videos"][0]["hasAudio"] = None
assert preview_plan(unknown_audio)["selected_video"]["source_position"] == 2
# 4: unknown audio is not a promise of audio
gaps = deepcopy(carousel)
gaps["data"]["images"] = [
{},
{"url": "https://example.invalid/frame.jpg"},
{"url": "javascript:alert(1)"},
{"url": "https://example.invalid/frame.jpg"},
]
assert [item["position"] for item in preview_plan(gaps)["images"]] == [2, 4]
# 5: skip unusable entries without renumbering or deleting repeated positions
original = deepcopy(clip)
preview_plan(clip)
assert clip == original # 6: do not mutate the API response
assert preview_plan({"status": 200, "data": {"images": None, "videos": None}}) == {
"images": [], "selected_video": None
} # 7: null arrays can produce an empty plan
expect_invalid({"status": 401, "data": {}}) # 8: error is not an empty successful post
expect_invalid({"status": 200, "data": {"images": {"url": "bad"}}})
# 9: malformed media array is not silently accepted
print("Nine offline checks passed.")
print("Carousel preview plan:")
print(json.dumps(image_plan, indent=2))
print("One-clip rendition choice:")
print(json.dumps(video_plan, indent=2))