This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

archiver-bot: find video file in directories, require IPFS CID for all links

+56 -16
+56 -16
5pkgs/archiver-bot/archiver_bot/__init__.py
··· 88 88 return f"{FLAX_URL}/{quote(relative)}" 89 89 90 90 91 + def find_main_video(path: str) -> str | None: 92 + """Find the main video file in a path. If path is a file, return it. If directory, find largest video.""" 93 + if os.path.isfile(path): 94 + return path 95 + if os.path.isdir(path): 96 + video_exts = {".mkv", ".mp4", ".avi", ".m4v", ".ts", ".wmv"} 97 + best = None 98 + best_size = 0 99 + for root, _dirs, files in os.walk(path): 100 + for f in files: 101 + ext = os.path.splitext(f)[1].lower() 102 + if ext in video_exts: 103 + full = os.path.join(root, f) 104 + size = os.path.getsize(full) 105 + if size > best_size: 106 + best = full 107 + best_size = size 108 + return best 109 + return None 110 + 111 + 91 112 async def compute_cid(path: str) -> str | None: 92 113 """Compute the IPFS CID for a file using ipfs add --only-hash --raw-leaves.""" 114 + video = find_main_video(path) 115 + if not video: 116 + log.warning(f"No video file found for {path}") 117 + return None 93 118 try: 94 119 ipfs_path = "/tmp/ipfs-hash-repo" 95 120 if not os.path.exists(os.path.join(ipfs_path, "config")): ··· 102 127 await init_proc.communicate() 103 128 env = {**os.environ, "IPFS_PATH": ipfs_path} 104 129 proc = await asyncio.create_subprocess_exec( 105 - IPFS_BIN, "add", "--only-hash", "--raw-leaves", "--quieter", path, 130 + IPFS_BIN, "add", "--only-hash", "--raw-leaves", "--quieter", video, 106 131 stdout=asyncio.subprocess.PIPE, 107 132 stderr=asyncio.subprocess.PIPE, 108 133 env=env, ··· 112 137 except asyncio.TimeoutError: 113 138 proc.kill() 114 139 await proc.communicate() 115 - log.warning(f"ipfs add --only-hash timed out for {path}") 140 + log.warning(f"ipfs add --only-hash timed out for {video}") 116 141 return None 117 142 if proc.returncode == 0: 118 143 cid = stdout.decode().strip() 119 144 if cid: 120 145 return cid 121 146 else: 122 - log.warning(f"ipfs add --only-hash failed for {path}: {stderr.decode().strip()}") 147 + log.warning(f"ipfs add --only-hash failed for {video}: {stderr.decode().strip()}") 123 148 except Exception as e: 124 - log.warning(f"Failed to compute CID for {path}: {e}") 149 + log.warning(f"Failed to compute CID for {video}: {e}") 125 150 return None 126 151 127 152 ··· 204 229 lines_html.append(f'🎬 Stream: <a href="{flix_link}">{flix_link}</a>') 205 230 206 231 # IPFS link (compute CID for the file) 207 - if not is_dir: 208 - cid = await compute_cid(path) 209 - if cid: 210 - ipfs_link = f"{IPFS_GATEWAY_URL}/ipfs/{cid}" 211 - lines_plain.append(f"🌐 IPFS: {ipfs_link}") 212 - lines_html.append(f'🌐 IPFS: <a href="{ipfs_link}">{ipfs_link}</a>') 213 - lines_plain.append(f" ipfs get {cid}") 214 - lines_html.append(f" <code>ipfs get {cid}</code>") 232 + cid = await compute_cid(path) 233 + if cid: 234 + ipfs_link = f"{IPFS_GATEWAY_URL}/ipfs/{cid}" 235 + lines_plain.append(f"🌐 IPFS: {ipfs_link}") 236 + lines_html.append(f'🌐 IPFS: <a href="{ipfs_link}">{ipfs_link}</a>') 237 + lines_plain.append(f" ipfs get {cid}") 238 + lines_html.append(f" <code>ipfs get {cid}</code>") 239 + else: 240 + return None 215 241 216 242 return ("\n".join(lines_plain), "<br>".join(lines_html)) 217 243 ··· 325 351 if path: 326 352 is_dir = media_type == "tv" 327 353 jf_id = await lookup_jellyfin_id(session, media_type, media_id) 328 - links_plain, links_html = await make_media_links(path, is_dir=is_dir, jellyfin_id=jf_id) 354 + links = await make_media_links(path, is_dir=is_dir, jellyfin_id=jf_id) 355 + if not links: 356 + return (f"❌ {display} is available but IPFS hash failed.", f"❌ <b>{display}</b> is available but IPFS hash failed.") 357 + links_plain, links_html = links 329 358 return (f"✅ {display} is already available!\n{links_plain}", f"✅ <b>{display}</b> is already available!<br>{links_html}") 330 359 return (f"✅ {display} is already available!", f"✅ <b>{display}</b> is already available!") 331 360 elif status in (2, 3, 4): ··· 341 370 if existing_path: 342 371 is_dir = media_type == "tv" 343 372 jf_id = await lookup_jellyfin_id(session, media_type, media_id) 344 - links_plain, links_html = await make_media_links(existing_path, is_dir=is_dir, jellyfin_id=jf_id) 373 + links = await make_media_links(existing_path, is_dir=is_dir, jellyfin_id=jf_id) 345 374 # Still send the request to Jellyseerr so it's tracked there too 346 375 await jellyseerr_request(session, "/request", method="POST", json=payload) 376 + if not links: 377 + return (f"❌ {display} is available but IPFS hash failed.", f"❌ <b>{display}</b> is available but IPFS hash failed.") 378 + links_plain, links_html = links 347 379 return (f"✅ {display} is already available!\n{links_plain}", f"✅ <b>{display}</b> is already available!<br>{links_html}") 348 380 349 381 result = await jellyseerr_request(session, "/request", method="POST", json=payload) ··· 487 519 await trigger_jellyfin_scan(http) 488 520 await asyncio.sleep(10) 489 521 jf_id = await lookup_jellyfin_id(http, "movie", tmdb_id) 490 - links_plain, links_html = await make_media_links(file_path, jellyfin_id=jf_id) 522 + links = await make_media_links(file_path, jellyfin_id=jf_id) 523 + if not links: 524 + links_plain = links_html = "❌ IPFS hash failed" 525 + else: 526 + links_plain, links_html = links 491 527 plain = f"✅ {display} has been downloaded and is now available!\n{links_plain}" 492 528 html = f"✅ <b>{display}</b> has been downloaded and is now available!<br>{links_html}" 493 529 for room_id in rooms: ··· 531 567 await trigger_jellyfin_scan(http) 532 568 await asyncio.sleep(10) 533 569 jf_id = await lookup_jellyfin_id(http, "tv", tmdb_id) 534 - links_plain, links_html = await make_media_links(folder_path, is_dir=True, jellyfin_id=jf_id) 570 + links = await make_media_links(folder_path, is_dir=True, jellyfin_id=jf_id) 571 + if not links: 572 + links_plain = links_html = "❌ IPFS hash failed" 573 + else: 574 + links_plain, links_html = links 535 575 plain = f"✅ {display}{ep_info} has been downloaded and is now available!\n{links_plain}" 536 576 html = f"✅ <b>{display}</b>{ep_info} has been downloaded and is now available!<br>{links_html}" 537 577 for room_id in rooms: