How it works¶
Two independent scripts, one catalog. Neither talks to the other; they share only the LANG setting and the compose file.
media-vtt.py: subtitles¶
- Creates
media.dbwith adownloaded_vttstable if it does not exist. - Downloads
<base>/<LANG>.json.gz, unpacks it to<LANG>.jsonin the output folder and deletes the.gz. - Reads the file line by line and keeps each object whose
typeismedia-itemand whoseo.keyPartshas an identifier (pubS, or elsedocID), atrackand aformatCode. - For each item, looks up
(identifier, track, formatCode)inmedia.db.successandfailedare skipped. - Otherwise asks
<base>?langwritten=<LANG>&track=<track>&pub=<pubS>(ordocid=<docID>) and expects JSON withfiles.<LANG>.<format>: lists of file entries. The first entry, in any format, with asubtitles.urlwins. - Downloads that URL and saves it in the output folder under the last part of the URL's path, decoded. A network error is retried after 2 and 4 seconds; the third failure records
failed. - Records
success,no_subtitles(no entry had subtitles) orfailed(no answer, or nofilesin it).
publications-epub.py: EPUBs¶
- Creates
pubs.dbwith aPublicationStatetable if it does not exist. - Opens
unit.dband reads theLanguageIdwhoseSymbolisLANG. No match stops the run. - Fetches the manifest JSON, takes its
currentfield, downloads that manifest's gzipped catalog and unpacks it tologin the output folder: a SQLite database. - Lists
TagNumber, Symbol, symfrom itsPublicationtable for that language. ATagNumberother than 0 is an issue of a periodical, fetched withpub=<sym>&issue=<TagNumber>; 0 is a single publication, fetched withpub=<Symbol>. - Skips each publication
pubs.dbalready marksprocessed. For the rest, asks for its files withfileformat=epuband expects JSON withfiles.<LANG>.EPUB[0].file.url. - Downloads that URL and saves it under the name in the server's
Content-Dispositionheader, or<Symbol>_<TagNumber>.epubwithout one. A network error is retried after 2 and 4 seconds. - Records
processed,no_epub(no EPUB listed) orfailed. Onlyprocessedis skipped next time.
State¶
The two SQLite files are the only memory between runs. Delete a row and the next run fetches that item again; delete the file and the next run starts from nothing (files already in the folder are overwritten, not duplicated, because the names come from the catalog).
What talks to what¶
Each script makes HTTPS requests to the addresses you set in the source, and to the file URLs the catalog returns. Nothing else leaves the machine. Both run as root inside their containers. The containers need no extra privileges, and nothing in them listens on a port (the EXPOSE 80 in the Dockerfiles is unused, and the compose file publishes nothing).