Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TV Time Out to Simkl importer

Use at your own risk. This tool can write to or delete data from your Simkl library; PRs are welcome.

Small JBang importer that converts a TV Time Out export into Simkl /sync/history requests.

It reads the tvtime-series-<date>.json and tvtime-movies-<date>.json files from a TV Time Out zip, extracted directory, or individual JSON file. TV Time Out exports are produced by the separate TV Time Out by Refract browser extension; this importer is not affiliated with TV Time, Simkl, Refract, or that extension. Dry-run is the default so the generated payload can be inspected before anything is sent to Simkl.

Watched history, watchlist-only items, and watched special episodes are imported by default.

Running with JBang

Install JBang using the official installation instructions.

Run the local checkout:

jbang SimklTvTimeOutImporter.java --help

JBang can also run the script directly from a GitHub repository URL:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java --help

For repeatable imports, prefer a tag or commit SHA instead of master:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/<tag-or-commit>/SimklTvTimeOutImporter.java \
  --input 2026-07-05-tvtimeout-export.zip

See JBang's remote execution documentation for URL execution and trust prompts.

Simkl Set up

Before any use, it is required to setup your SIMKL API key.

  1. Navigate to the developper settings : https://simkl.com/settings/developer/
  2. Click Get API keys
  3. Add a new key for a new app
    • Name: simkl-tvtimeout-importer or whatever you wish to put there
    • Description: whatever you want
    • Redirect URI: urn:ietf:wg:oauth:2.0:oob, this one is important to allow the PIN authentication.

1Password secrets

Do not put SIMKL_CLIENT_ID or SIMKL_CLIENT_SECRET literal values in the shell command. Shell history will record the command line.

The default flow is Simkl PIN login. Keep the app credentials from the Simkl developer page somewhere safe (e.g 1Password):

Prefer passing the developer credentials with op item get command substitutions. The literal secret values are not written to shell history, and the PIN URL remains plain clickable terminal output:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --help

This opens a link on SIMKL where you are asked to paste a code,mwhich will give access to this program.

This keeps literal secrets out of shell history, note command substitutions expand before jbang starts. A local process running as the same user may be able to inspect process arguments while the command is running.

Alternatively, if using 1Password, there's op run --env-file .env.1password -- ... which wraps the process and keep the env var protected. It uses the op://... references in the env file, however it's draw back is that it will prevent the printed PIN URL from being linkified by the terminal. So you have to manually edit the link pasted in the browser.

Advanced

If you deliberately store a user OAuth access token, set SIMKL_ACCESS_TOKEN and pass --use-access-token. Do not point SIMKL_ACCESS_TOKEN at client-secret; the client secret belongs in SIMKL_CLIENT_SECRET. The tool also accepts --use-access-token=<token>, but prefer the environment variable form because command arguments can be visible to other local processes.

Stored-token mode example:

SIMKL_ACCESS_TOKEN="$(op item get simkl --fields access-token --reveal)" \
jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --input 2026-07-05-tvtimeout-export.zip \
  --use-access-token \
  --apply

Dry run

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --input 2026-07-05-tvtimeout-export.zip \
  --output simkl-history-payload.json

Import

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --input 2026-07-05-tvtimeout-export.zip \
  --apply

--apply posts batches to https://api.simkl.com/sync/history with skip_auto_watching=yes. The importer sends watched movies and watched TV episodes with TVDB/IMDb IDs and normalized GMT watched_at timestamps.

Backup and restore

Save the current Simkl state before importing:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --backup-current simkl-backup.json

Or make a backup immediately before a live import:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --input 2026-07-05-tvtimeout-export.zip \
  --backup-before-apply simkl-backup-before-import.json \
  --apply

Preview a restore payload from a saved backup:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --restore simkl-backup.json \
  --output simkl-restore-payload.json

Apply a restore. This deletes the current Simkl library first, then replays the backup:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --restore simkl-backup.json \
  --backup-before-apply simkl-backup-before-restore.json \
  --apply \
  --confirm-restore-delete

An empty or whitespace-only restore file is treated as an empty backup. With --apply --confirm-restore-delete, that means the current Simkl library is deleted and nothing is replayed.

To remove everything directly, preview the delete payload first:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --remove-everything \
  --output simkl-delete-payload.json

Apply the wipe only with an explicit confirmation flag:

jbang https://github.com/bric3/simkl-tvtimeout-importer/blob/master/SimklTvTimeOutImporter.java \
  --client-id="$(op item get simkl --fields client-id --reveal)" \
  --client-secret="$(op item get simkl --fields client-secret --reveal)" \
  --remove-everything \
  --backup-before-apply simkl-backup-before-delete.json \
  --apply \
  --confirm-remove-everything

If SIMKL_ACCESS_TOKEN is set, the importer still ignores it by default. Add --use-access-token when you explicitly want stored-token mode instead of PIN login.

Backups store Simkl's raw per-type all-items responses plus metadata. Restore is best-effort for the fields Simkl exposes through that API: IDs, statuses, watched episodes, watched timestamps, ratings, memos, and watchlist add dates.

Simkl sync-guide compliance:

  • Backup and delete discovery reads /sync/all-items/shows, /sync/all-items/movies, and /sync/all-items/anime sequentially.
  • Live write batches wait at least 1.1 seconds between POST requests.
  • This tool does not run a continuous sync loop or background polling.

Useful options:

  • --source-zone Europe/Paris: timezone for TV Time Out episode timestamps that have no offset.
  • --watched-only: skips unwatched movies and shows.
  • --skip-specials: skips watched season 0/special episodes. Specials are included by default.
  • --batch-size 20: changes top-level movies/shows per API call.

Rewatch counts are reported but not imported. TV Time Out only provides counts, while Simkl rewatch history needs explicit rewatch sessions and safer timestamp handling.

License

This project is licensed under the Mozilla Public License 2.0. The official MPL 2.0 text is also available from Mozilla.

About

Import you TvTime out export to simkl via the API

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages