build_catalog.sh: add cover field (=movie.jpg), bencode hash extraction
This commit is contained in:
1 parent
942ba97850
commit
b6d339e9c1
1 file changed
+74
-7
+74
-7
@@ -14,7 +14,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MOVIES_DIR="/data/coolify/applications/e9ghwyp5n5kyfshk55krbhki/movies"
|
||||
MOVIES_DIR="${MOVIES_DIR:-/data/coolify/applications/e9ghwyp5n5kyfshk55krbhki/movies}"
|
||||
OUT="$MOVIES_DIR/catalog.json"
|
||||
|
||||
[[ -d "$MOVIES_DIR" ]] || { echo "Нет папки $MOVIES_DIR"; exit 1; }
|
||||
@@ -25,6 +25,50 @@ import sys, os, json, datetime
|
||||
movies_dir, out = sys.argv[1], sys.argv[2]
|
||||
movies = []
|
||||
|
||||
def decode_bencode(b, pos):
|
||||
"""Minimal bencode decoder. Returns (value, new_pos)."""
|
||||
c = b[pos:pos+1]
|
||||
if c == b'd':
|
||||
pos += 1; dd = {}
|
||||
while b[pos:pos+1] != b'e':
|
||||
kk, pos = decode_bencode(b, pos)
|
||||
vv, pos = decode_bencode(b, pos)
|
||||
dd[kk] = vv
|
||||
return dd, pos+1
|
||||
if c == b'l':
|
||||
pos += 1; ll = []
|
||||
while b[pos:pos+1] != b'e':
|
||||
vv, pos = decode_bencode(b, pos)
|
||||
ll.append(vv)
|
||||
return ll, pos+1
|
||||
if c == b'i':
|
||||
e = b.index(b'e', pos)
|
||||
return int(b[pos+1:e]), e+1
|
||||
# string: <len>:<bytes> -- read the length digits first, then ':'
|
||||
co = pos
|
||||
while b[co:co+1] != b':':
|
||||
co += 1
|
||||
n = int(b[pos:co])
|
||||
s = b[co+1:co+1+n]
|
||||
return s, co+1+n
|
||||
|
||||
def encode_bencode(obj):
|
||||
"""Re-encode a decoded bencode value back to bytes (canonical)."""
|
||||
if isinstance(obj, int):
|
||||
return b'i' + str(obj).encode('ascii') + b'e'
|
||||
if isinstance(obj, bytes):
|
||||
return str(len(obj)).encode('ascii') + b':' + obj
|
||||
if isinstance(obj, str):
|
||||
b = obj.encode('utf-8')
|
||||
return str(len(b)).encode('ascii') + b':' + b
|
||||
if isinstance(obj, list):
|
||||
return b'l' + b''.join(encode_bencode(x) for x in obj) + b'e'
|
||||
if isinstance(obj, dict):
|
||||
keys = sorted(obj.keys())
|
||||
return b'd' + b''.join(encode_bencode(k) + encode_bencode(obj[k]) for k in keys) + b'e'
|
||||
raise TypeError(obj)
|
||||
|
||||
|
||||
for entry in sorted(os.listdir(movies_dir)):
|
||||
d = os.path.join(movies_dir, entry)
|
||||
if not os.path.isdir(d) or entry.startswith('.'):
|
||||
@@ -33,7 +77,7 @@ for entry in sorted(os.listdir(movies_dir)):
|
||||
# читаем meta.txt
|
||||
metafile = os.path.join(d, 'meta.txt')
|
||||
if os.path.exists(metafile):
|
||||
for line in open(metafile, encoding='utf-8'):
|
||||
for line in open(metafile, encoding='utf-8', errors='replace'):
|
||||
line = line.strip()
|
||||
if not line or ':' not in line:
|
||||
continue
|
||||
@@ -47,13 +91,23 @@ for entry in sorted(os.listdir(movies_dir)):
|
||||
meta['rating'] = float(v)
|
||||
elif k in ('title', 'original_title', 'description'):
|
||||
meta[k] = v
|
||||
# обложка
|
||||
poster = None
|
||||
for f in os.listdir(d):
|
||||
if f.lower().endswith(('.jpg', '.jpeg', '.png', '.webp')):
|
||||
poster = f; break
|
||||
# обложка: poster.* для карточки, movie.* для модалки торрента
|
||||
imgs = [f for f in os.listdir(d) if f.lower().endswith(('.jpg', '.jpeg', '.png', '.webp'))]
|
||||
def first(prefix):
|
||||
for f in imgs:
|
||||
if f.lower().startswith(prefix):
|
||||
return f
|
||||
return None
|
||||
poster = first('poster.') or (imgs[0] if imgs else None)
|
||||
movie = first('movie.') or poster
|
||||
if poster:
|
||||
meta['poster'] = f"movies/{entry}/{poster}"
|
||||
if movie:
|
||||
meta['img'] = f"movies/{entry}/{movie}"
|
||||
# cover: та же картинка, что и фон (img/movie.jpg), для режима 'обложка' в Lampa
|
||||
cover = movie or poster
|
||||
if cover:
|
||||
meta['cover'] = f"movies/{entry}/{cover}"
|
||||
# торрент
|
||||
torrent = None
|
||||
for f in os.listdir(d):
|
||||
@@ -61,6 +115,19 @@ for entry in sorted(os.listdir(movies_dir)):
|
||||
torrent = f; break
|
||||
if torrent:
|
||||
meta['torrent'] = f"movies/{entry}/{torrent}"
|
||||
# extract info-hash -> magnet (native Lampa torrent playback needs torrent_hash)
|
||||
try:
|
||||
import hashlib
|
||||
tdata = open(os.path.join(d, torrent), 'rb').read()
|
||||
parsed, _ = decode_bencode(tdata, 0) # parse whole file from the start
|
||||
info = parsed[b'info']
|
||||
# re-encode the info dict to get the exact bencoded bytes for hashing
|
||||
encoded = encode_bencode(info)
|
||||
h = hashlib.sha1(encoded).hexdigest()
|
||||
meta['hash'] = h
|
||||
meta['magnet'] = f"magnet:?xt=urn:btih:{h}"
|
||||
except Exception as e:
|
||||
print(' ! hash error for', entry, e)
|
||||
# fallback title
|
||||
if 'title' not in meta:
|
||||
meta['title'] = entry
|
||||
|
||||
Reference in new issue
Block a user