{"id":13522411,"url":"https://github.com/ArabCoders/watchstate","last_synced_at":"2025-03-31T22:31:25.670Z","repository":{"id":37006731,"uuid":"457795171","full_name":"arabcoders/watchstate","owner":"arabcoders","description":"Self-hosted service to sync your plex, jellyfin and emby play state. without relying on 3rd-party external services.","archived":false,"fork":false,"pushed_at":"2024-05-27T14:20:15.000Z","size":4432,"stargazers_count":385,"open_issues_count":0,"forks_count":7,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-05-29T06:11:08.530Z","etag":null,"topics":["backup","docker","emby","jellyfin","matched","misidentified","mismatched","plex","watchstate","webhook"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arabcoders.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-10T13:39:00.000Z","updated_at":"2024-05-30T15:37:06.185Z","dependencies_parsed_at":"2023-12-26T17:03:19.346Z","dependency_job_id":"80378322-ec56-4f45-9564-525562d18429","html_url":"https://github.com/arabcoders/watchstate","commit_stats":null,"previous_names":[],"tags_count":82,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arabcoders%2Fwatchstate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arabcoders","download_url":"https://codeload.github.com/arabcoders/watchstate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246552456,"owners_count":20795823,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","docker","emby","jellyfin","matched","misidentified","mismatched","plex","watchstate","webhook"],"created_at":"2024-08-01T06:00:46.883Z","updated_at":"2025-03-31T22:31:25.661Z","avatar_url":"https://github.com/arabcoders.png","language":"PHP","readme":"# WatchState\n\n![Build Status](https://github.com/arabcoders/WatchState/actions/workflows/build.yml/badge.svg)\n![MIT License](https://img.shields.io/github/license/arabcoders/WatchState.svg)\n![Docker pull](https://img.shields.io/docker/pulls/arabcoders/watchstate.svg)\n\nThis tool primary goal is to sync your backends play state without relying on third party services,\nout of the box, this tool support `Jellyfin`, `Plex` and `Emby` media servers.\n\n## Updates\n\n### 2025-03-13\n\nWe have recently added support for plex webhooks via tautulli which you can use if you don't have PlexPass. This should help\nclose the gap with other media servers.\n\n### 2025-02-19\n\nWe have introduced new experimental feature to allow syncing watch progress for played items. This feature is still in\nearly stages, and might not work as expected. and there are probably still many bugs that we need to fix. Please report\nany issues you might face.\n\nThe feature is disabled by default, to enable it you need to run add this environment variable `WS_PROGRESS_THRESHOLD`\nwith seconds as value, the minimum value is `180` seconds. `0` seconds means it's disabled. We think reasonable value is\n`86400` or more this number is about 1day.\n\nWe are still not keen on this feature, and it might be removed in future releases if we aren't able to deal with the\nissues we are facing.\n\n### 2025-02-11\n\nWe recently have added support to generate accesstoken for external `Plex` users, i.e. `not home users`. so the\n`backends:create` command now supports generating the needed config files for external users. Beware the support for\nthis is still in early stages, and might not work as expected. report any issues you might face.\n\n### 2025-02-05\n\nWe have added initial support to browse the WebUI as sub user, it's still in early stages, only few Endpoints support\nit.\nWe have also added support to webhooks to allow sub users, you simply have to add new hooks using `user@backend`. Please\ntake look at [this FAQ](FAQ.md#how-to-add-webhooks) to learn how to use it for sub users.\n\n--- \nRefer to [NEWS](NEWS.md) for old updates.\n\n# Features\n\n* WebUI.\n* Sync backends play state (from many to many).\n* Backup your backends play state into `portable` format.\n* Receive Webhook events from media backends.\n* Find `un-matched` or `mis-matched` items.\n* Search your backend for `title` or `item id`.\n* Display and filter your play state. Can be exported as `yaml` or `json`.\n* Check if your media servers reporting same data via the parity command.\n* Sync your watch progress via webhooks or scheduled tasks.\n* Check if your media backends have stale references to old files.\n\nIf you like my work, you might also like my other project [YTPTube](https://github.com/arabcoders/ytptube), which is\nsimple and to the point yt-dlp frontend to help download content from all supported sites by yt-dlp.\n\n----\n\n# Install\n\ncreate your `compose.yaml` with the following content:\n\n```yaml\nservices:\n    watchstate:\n        image: ghcr.io/arabcoders/watchstate:latest\n        # To change the user/group id associated with the tool change the following line.\n        user: \"${UID:-1000}:${GID:-1000}\"\n        container_name: watchstate\n        restart: unless-stopped\n        ports:\n            - \"8080:8080\" # The port which will serve WebUI + API + Webhooks\n        volumes:\n            - ./data:/config:rw # mount current directory to container /config directory.\n```\n\nCreate directory called `data` next to the `compose.yaml` file. After creating your docker compose file, start\nthe container.\n\n```bash\n$ mkdir -p ./data \u0026\u0026 docker-compose pull \u0026\u0026 docker-compose up -d\n```\n\n\u003e [!IMPORTANT]\n\u003e It's really important to match the `user:` to the owner of the `data` directory, the container is rootless, as such\n\u003e it will crash if it's unable to write to the data directory. It's really not recommended to run containers as root,\n\u003e but if you fail to run the container you can try setting the `user: \"0:0\"` if that works it means you have permissions\n\u003e issues. refer to [FAQ](FAQ.md) to troubleshoot the problem.\n\n\u003e [!NOTE]\n\u003e For `Unraid` users You can install the `Community Applications` plugin, and search for `watchstate` it comes\n\u003e preconfigured. Otherwise, to manually install it, you need to add value to the `Extra Parameters` section in advanced\n\u003e tab/view. add the following value `--user 99:100`. This has to happen before you start the container, otherwise it\n\u003e will\n\u003e have the old user id, and you then have to run the following command from\n\u003e terminal `chown -R 99:100 /mnt/user/appdata/watchstate`.\n\n\u003e [!NOTE]\n\u003e To use this container with `podman` set `compose.yaml` `user` to `0:0`. it will appear to be working as root\n\u003e inside the container, but it will be mapped to the user in which the command was run under.\n\n# Management via WebUI\n\nAfter starting the container, you can access the WebUI by visiting `http://localhost:8080` in your browser.\n\nAt the start you won't see anything as the `WebUI` is decoupled from the WatchState and need to be configured to be able\nto access the API.\nIn the top right corner, you will see a cogwheel icon, click on it and then Configure the connection settings.\n\n![Connection settings](screenshots/api_settings.png)\n\nAs shown in the screenshot, to get your `API Token`, run the following command\n\n```bash\n$ docker exec -ti watchstate console system:apikey \n```\n\nCopy the random string in dark yellow, into the `API Token` field Make sure to set the `API URL` or click\nthe `current page URL` link. If everything is set, then the Status field will turn\ngreen. and `Status: OK` will be shown, and the reset of the navbar will show up. Which hopefully means everything is ok.\n\nTo add a backend, click on the `Backends` link in the navbar, then `+` button. as showing in the following screenshot\n\n![Add backend](screenshots/add_backend.png)\n\nFill the required information, if you get a green notification, then the backend is added successfully. If you get a\nred/yellow notification, Then most likely incorrect information was provided.\nYou can check the message in the notification itself to know what went wrong. Or check the logs page, Most likely an\nerror has been logged to a file named `app.YYYYMMDD.log`.\n\nIf everything went ok, you should see the backend shows up in the same page. You can then go to the Tasks page and click\non `Queue Task`, for first time import we recommend letting\nthe task run in the background, as it might take a while to import all the data.\n\nOnce you have done all for your backends, You should go back again to `Tasks` page and enable the `Import` and `Export`\ntasks. This will make sure your data is always in sync.\nTo enable/disable the task, simply click on the slider next to the task name if it's green then it's enabled, if it's\ngray then it's disabled.\n\nOnce that is done, you can let the tool do its job, and you can start using the tool to track your play state.\n\n# Management via CLI.\n\n# Adding backend\n\nAfter starting the container you should start adding your backends and to do so run the following command:\n\n\u003e [!NOTE]\n\u003e to get your plex token, please\n\u003e visit [this plex page](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/) to\n\u003e know how to extract your plex token. For jellyfin \u0026 emby. Go to Dashboard \u003e Advanced \u003e API keys \u003e then create new API\n\u003e keys.\n\n```bash\n$ docker exec -ti watchstate console config:add\n```\n\nThis command is interactive and will ask you for some questions to add your backend.\n\n# Managing backend\n\nTo edit backend settings run\n\n```bash\n$ docker exec -ti watchstate console config:manage -s backend_name\n```\n\n# Importing play state.\n\nWhat does `Import` or what does the command `state:import` means in context of watchstate?\n\nImport means, pulling data from the backends into the database while attempting to normalize the state.\n\nTo import your current play state from backends that have import enabled, run the following command:\n\n```bash\n$ docker exec -ti watchstate console state:import -v\n```\n\nThis command will pull your play state from all your backends. To import from specific backends use\nthe `[-s, --select-backend]` flag. For example,\n\n```bash\n$ docker exec -ti watchstate console state:import -v -s home_plex -s home_jellyfin \n```\n\n\u003e [!NOTE]\n\u003e Now that you have imported your current play state enable the import task by using the following command\n\n```bash\n$ docker exec -ti watchstate console system:env -k WS_CRON_IMPORT -e true\n```\n\n### Supported import methods\n\nOut of the box, we support the following import methods:\n\n* Scheduled Tasks. `Cron jobs that pull data from backends on a schedule.`\n* On demand. `Pull data from backends on demand. By running the state:import command manually`\n* Webhooks. `Receive events from backends and update the database accordingly.`\n\n\u003e [!NOTE]\n\u003e Even if all your backends support webhooks, you should keep import task enabled. This help keep healthy relationship.\n\u003e and pick up any missed events.\n\n---\n\n# Exporting play state\n\nWhat does `export` or what does the command `state:export` means in context of watchstate?\n\nExport means, sending data back to backends, while trying to minimize the network traffic. To export your current play\nstate to backends that have export enabled, run the following command:\n\n```bash\n$ docker exec -ti watchstate console state:export -v\n```\n\nThis command will export your current play state to all of your export enabled backends. To export to\nspecific backends use the `[-s, --select-backend]`flag. For example,\n\n```bash\n$ docker exec -ti watchstate console state:export -v -s home_plex -s home_jellyfin \n```\n\n\u003e [!NOTE]\n\u003e Now that you have exported your current play state, enable the export task by using the following command\n\n```bash\n$ docker exec -ti watchstate console system:env -k WS_CRON_EXPORT -e true\n```\n\n---\n\n# FAQ\n\nTake look at this [frequently asked questions](FAQ.md) page. to know more about this tool and how to enable webhook\nsupport and answers to many questions.\n\n---\n\n# Social channels\n\nIf you have short or quick questions, or just want to chat with other users, feel free to join\nmy [discord server](https://discord.gg/haUXHJyj6Y).\nkeep in mind it's solo project, as such it might take me a bit of time to reply to questions.\n\n---\n\n# Donate\n\nIf you feel like donating and appreciate my work, you can do so by donating to children charity. For\nexample [Make-A-Wish](https://worldwish.org).\nI Personally don't need the money, but I do appreciate the gesture.\n","funding_links":[],"categories":["🌌 Related"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArabCoders%2Fwatchstate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FArabCoders%2Fwatchstate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArabCoders%2Fwatchstate/lists"}