igstats reads the followers and following files out of an Instagram data export — as JSON, as pasted text, or as the whole ZIP — and works out mutuals, accounts you follow that do not follow back, and followers you do not follow, each dated from the timestamp in the export. Nothing is kept: the application defines no database model, and the upload is read in memory and discarded with the request.
Instagram will hand you your own data, and then the export is two JSON files nobody wants to read. This does the set arithmetic: following minus followers, followers minus following, and the intersection, with the date each relationship began pulled from the timestamps the export includes.
You can hand it the ZIP straight from the export, the two JSON files individually, or paste their contents. The ZIP path searches the archive for the two filenames at any depth, because the folder layout has moved between export versions.
The app defines no models. Not "the models are unused" — the models module is empty, so there is no table for an upload to land in. The archive is opened in memory, the two files are parsed, the result is rendered into the response, and the request ends. The only thing the session cookie carries is the chosen language.
For a tool whose entire input is a list of the people someone follows, that property is the product. It is also the kind of claim that is only worth making if a reader can check it, which is why the repository is public.
Instagram has revised its export shape at least twice, and old exports still exist. In earlier files the username sits in a value field; in later ones that field is gone and the username is the entry title. When neither is present, it is still recoverable from the profile URL — and that URL has two forms of its own, one with a plain handle and one with an intermediate path segment.
Username extraction therefore tries four sources in order and returns the first that yields something. That is not elegant, but the alternative is telling a visitor their perfectly valid export is unreadable.
Eight languages, chosen by an explicit parameter, then the session, then the browser Accept-Language header, then the default. Regional variants are mapped down to the language actually translated, so a visitor asking for one Chinese or Spanish variant is not silently dropped back to English.