Post

SubSyncForPlex + Home Assistant - Sync Plex Subtitles and Refresh Playback

Learn how I solved the subtitle syncing problem in Plex by building SubSyncForPlex and integrating it with Home Assistant for seamless syncing, notifications, and automatic playback refresh.

SubSyncForPlex + Home Assistant - Sync Plex Subtitles and Refresh Playback

One of the small but frustrating problems in my Plex setup used to be subtitle syncing.
I use Bazarr to automatically download subtitles whenever I add new items to my Plex collection.
While Bazarr works great for downloading, the subtitle sync plugin gave me mixed results, sometimes it would sync properly, but other times it would delete parts of the subtitle file or just make things worse.

Plex has since added automatic subtitle syncing built into the server, and it has improved the experience a lot.
But it’s still not perfect — sometimes it doesn’t kick in, or the timing can still feel just a little bit off.

And usually, it’s my wife who notices first. We’ll be halfway into a movie or show when she points out that the subtitles are a little out of sync — and I have to admit, once she points it out, I can’t unsee it either.

Originally, fixing it meant grabbing my laptop, manually running subsync, and reloading the file.
It got annoying fast.

At first, I tried to automate it with a PowerShell script triggered by HASS.Agent on a Windows VM running in my home lab. That worked…until Windows decided to reboot itself for updates — leaving me to log in and restart everything manually again.

I needed something more reliable — something that could run independently and fit into my Home Assistant setup.

That’s why I built SubSyncForPlex:
A lightweight Python service that automatically syncs subtitles using subsync with a simple webhook — no more grabbing the laptop.

In this post, I’ll walk you through:

  • What SubSyncForPlex does
  • How I integrated it with Home Assistant to make syncing seamless
  • How you can set up a button to sync and refresh your playback

What is SubSyncForPlex?

At a high level, SubSyncForPlex:

  • Accepts webhook requests containing a Plex media ID
  • Locates the media file and associated subtitle file using the Plex API
  • Uses subsync to realign subtitle timing
  • Sends webhook notifications back to Home Assistant (optional)

You can run it standalone or inside a Docker container. I personally run it in Docker for easier management alongside my Home Assistant setup.

Full installation instructions and configuration details are available in the SubSyncForPlex README.

Docker compose example

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
  subsyncforplex:
    image: 'ghcr.io/chrishansentech/subsyncforplex:latest'
    environment:
      - HOME_ASSISTANT_WEBHOOK_URL=<optional_webhook_url>
      - DEFAULT_SUB_LANG=en #optional defaults to en
      - DEFAULT_AUDIO_LANG=en #optional defaults to en
      - PLEX_URL=<your_plex_server_url>
      - PLEX_TOKEN=<your_plex_token>
    volumes:
      - '/path/to/media:/media'
    ports:
      - '8000:8000'

Make sure the /media path inside the container matches the structure of your Plex library as seen by the Plex API. For example, if the Plex API returns a path like /Plex/Movies/WarGames (1983)/WarGames (1983).mkv, then your volume mount should be set to:

/path/to/plex/media:/media/Plex

This ensures that the file paths returned by the API can be resolved correctly within the container.

Output from SubSyncForPlex Output Example

Extending SubSyncForPlex with Home Assistant

While SubSyncForPlex can run on its own, it gets a lot more powerful when you integrate it with Home Assistant. Here’s the flow I built:

  1. Home Assistant Script:
    • Sends a webhook request to SubSyncForPlex containing the current playing media’s ID and Plex media player entity ID.
  2. Home Assistant Automation:
    • Sends a push notification to your phone when syncing starts.
    • Sends another notification when it succeeds or fails.
    • If successful, it checks if you’re still watching the same media, and refreshes the playback to reload the updated subtitles.

This flow uses the Home Assistant Plex Media Server integration to retrieve the media_content_id and refresh playback through Plex media_player entities.

REST Command

Create a rest_command in your config.yaml to send the sync request to SubSyncForPlex like this:

1
2
3
4
5
6
7
8
9
10
11
rest_command:
  plex_subsync_sync:
    url: "http://YOUR_SUBSYNCFORPLEX_SERVER:8000/subsync"
    method: POST
    headers:
      Content-Type: "application/json"
    payload: |
      {
        "media_id": {{ media_id }},
        "entity_id": "{{ entity_id }}"
      }

Replace YOUR_SUBSYNCFORPLEX_SERVER with the actual IP or hostname where you’re running SubSyncForPlex.

If you want to specify the language for the audio and subtitle files, you can update your rest_command to include "audio_lang": "LANGUAGE_CODE" and "sub_lang": "LANGUAGE_CODE" in the payload. You can mix and match languages, as SubSync supports translations.

Script to Trigger SubSyncForPlex

This script grabs the media_content_id from a Plex integration media_player entity, and sends it to the SubSyncForPlex webhook.

1
2
3
4
5
6
7
8
9
10
11
12
alias: "Sync Plex Subtitles"
fields:
  media_player:
    description: "Plex media player entity"
    example: "media_player.plex_living_room_tv"
sequence:
  - variables:
      media_id: "{{ state_attr(media_player, 'media_content_id') }}"
  - service: rest_command.plex_subsync_sync
    data:
      media_id: "{{ media_id }}"
      entity_id: "{{ media_player }}"

Example button configuration to call script:

1
2
3
4
5
6
7
8
9
10
11
- type: button
  show_icon: true
  show_name: true
  icon: mdi:subtitles
  entity: script.sync_plex_subtitles
  tap_action:
    action: perform-action
    perform_action: script.sync_plex_subtitles
    target: {}
    data:
      media_player: media_player.plex_living_room_tv

Automations for Notifications and Playback Refresh

Here’s an automation that:

  • Sends a notification when the sync starts
  • Sends another notification when it succeeds or fails
  • If successful and you’re still watching the same item, it restarts playback (to reload the updated subtitles).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
alias: "Handle SubSyncForPlex Status"
triggers:
  - trigger: webhook
    webhook_id: SubSyncForPlex_status
    local_only: true
    allowed_methods:
      - POST
condition: []
actions:
  - variables:
      stage: "{{ trigger.json.stage }}"
      message: "{{ trigger.json.message }}"
      media_id: "{{ trigger.json.media_id }}"
      entity_id: "{{ trigger.json.entity_id }}"
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ stage == 'sync-started' }}"
        sequence:
          - action: notify.mobile_your_device
            data:
              title: Subtitle Sync
              message: "{{ message }}"
      - conditions:
          - condition: template
            value_template: "{{ stage == 'sync-success' }}"
        sequence:
          - action: notify.mobile_your_device 
            data:
              title: Subtitle Sync
              message: "{{ message }}"
          - delay: 2
          - condition: template
            value_template: >-
              {{ state_attr(entity_id, 'media_content_id') == media_id }}
          - action: media_player.play_media
            target:
              entity_id: "{{ entity_id }}"
            data:
              media_content_id: "{{ media_id }}"
              media_content_type: video
      - conditions:
          - condition: template
            value_template: "{{ stage == 'sync-failed' }}"
        sequence:
          - action: notify.mobile_your_device 
            data:
              title: Subtitle Sync Failed
              message: "{{ message }}"

You’ll need to configure your Home Assistant webhook trigger to listen for webhook payloads from SubSyncForPlex (webhook_id: SubSyncForPlex_status) and set up a webhook URL in the SubSyncForPlex config (HOME_ASSISTANT_WEBHOOK_URL).

Example:
http://homeassistant.local:8123/api/webhook/SubSyncForPlex_status

How it Works Together

  • Start sync manually from a dashboard button using the script.
  • Get notified immediately when the sync begins.
  • Receive success/failure notifications as soon as it finishes.
  • Automatically refresh playback after syncing if you’re still watching the same media on the same Plex client

This has made subtitle syncing basically effortless at my house — and no more resyncing subtitles manually using my laptop on the couch.

Final Thoughts

If you always have subtitles on like we do, SubSyncForPlex with Home Assistant makes subtitle syncing easy, fast, and reliable.
It’s a simple project but has a big impact on the everyday experience of using Plex.

You can find the code and contribute to the project here:
ChrisHansenTech/SubSyncForPlex on GitHub

If you have any suggestions, issues, or improvements, feel free to reach out or open a PR.
Happy syncing!

This post is licensed under CC BY-SA 4.0 by the author.