A commandline based tool to sync watch state between different media servers

Overview

Warning

This is an early release version, expect bugs and edge cases that we haven't encountered. Please keep that in mind before running this tool. while its works for me, it might not work for your setup.

Watch State Sync (Early Preview)

A commandline based tool to sync watch state between different media servers.

Introduction

Ever wanted to sync your watch state without having to rely on 3rd party service like trakt.tv? then this tool is for you. I had multiple problems with Plex trakt.tv plugin which led to my account being banned at trakt.tv, and on top of that the plugin no longer supported. And I like to keep my own data locally if possible.

Supported Media servers.

  • Plex
  • Emby
  • Jellyfin

Install

create your docker-compose.yaml file

version: '3.3'
services:
    watchstate:
        image: arabcoders/watchstate:latest
        container_name: watchstate
        restart: unless-stopped
        environment:
            WS_UID: ${UID:-1000} # Set container operation user id.
            WS_GID: ${GID:-1000} # Set container operation group id.
            WS_WEBHOOK_ENABLE: 0 # Enable webhook listening server. Disabled by default.
            WS_CRON_IMPORT: 0 # Enable manual pulling of watch state from servers. Disabled by default.
            WS_CRON_EXPORT: 1 # Enable manual push of watch state back to servers. Disabled by default.
        ports:
            - "8081:80" # webhook listener port
        volumes:
            - ./:/config:rw # mount current directory to container /config directory.

After creating your docker-compose file, start the container.

docker-compose up -d

First time

You have to set up your servers in config/servers.yaml you will have examples inside the file, after editing the file remove the unused servers examples.

after configuring your servers at config/servers.yaml you should import your current watch state by running the following command.

docker exec -ti watchstate console state:import -vvrm

TIP

To see the whole sync operation information you could run the command with -vvvr it will show all debug information, be careful it might crash your terminal depending on how many servers and media you have. the output is excessive.


Pull watch state.

now that you have imported your watch state, you can stop manually running the command again. and rely on the webhooks to update the watch state.

To enable webhook listening server, Edit the WS_WEBHOOK_ENABLE variable by setting its value to 1. If the variable does not exist or is set to value other than 1 it will not start the included caddy server.

If you don't want to use webhook events to update the watch state, and want to rely on manual polling the servers for state change, then set the value of WS_CRON_IMPORT to 1. By default, we run import every hour. However, you can change the schedule by adding another variable WS_CRON_IMPORT_AT and set it value to valid cron timing. for example, 0 */2 * * * it will run every two hours instead of 1 hour.

Push watch state

To manually push your watch state back to servers you can run the following command

docker exec -ti watchstate console state:export -vvr 

to sync specific server/s, use the --servers-filter which accept comma seperated list of server names.

docker exec -ti watchstate console state:export -vvr --servers-filter 'server1,server2' 

If you want to automate the pushing of your watch state back to servers, set the value of WS_CRON_EXPORT to 1. By default, we run export every 90 minutes. However, you can change the schedule by adding another variable called WS_CRON_EXPORT_AT and set it value to valid cron timing. for example, 0 */3 * * * it will run every three hours instead of 90 minutes.

Memory usage (Import)

The default mapper we use is called MemoryMapper this mapper store the entire state in memory during import operation, by doing so we gain massive speed up. However, this approach has drawbacks mainly large memory usage. Depending on your media count, it might use 1GB+ or more of memory. Tests done on 2k movies and 70k episodes and 4 servers. Ofc the memory will be freed as as as the comparison is done.

However, If you are on a memory constraint system, there is an alternative mapper implementation called DirectMapper , this implementation works directly via db the only thing stored in memory is the api call body. which get removed as soon as it's parsed. The drawback for this mapper is it's like really slow for large libraries. It has to do 3x call to db for each time.

To see memory usage during the operation run the import command with following flags. -vvvrm these flags will redirect logger output, log memory usage and print them to the screen.

bash docker exec -ti watchstate console state:import -vvvrm

How to change Import mapper.

Set the environment variable WS_IMPORT_MAPPER to DirectMapper or edit the config/config.yaml and add the following lines

mapper:
    import:
        type: DirectMapper

Servers.yaml

Example of working server with all options. You can have as many servers as you want.

my_home_server:
    type: jellyfin|emby|plex # Choose one
    url: 'https://mymedia.example.com' # The URL for the media server api
    # User API Token.
    # Jellyfin: Create API token via (Dashboard > Advanced > API keys > +)
    # Emby: Create API token via (Manage Emby server > Advanced > API keys > + New Api Key)
    # Plex: see on how to get your plex-token https://support.plex.tv/articles/204059436
    token: user-api-token
    # Get your user ID. For Jellyfin/emby only.
    # Jellyfin : Dashboard > Server > Users > click your user > copy the userId= value
    # Emby: Manage Emby server > Server > Users > click your user > copy the userId= value
    # Plex: for plex managed users the X-Plex-Token acts as userId.
    user: user-id
    export:
        enabled: true # Enable export.
    import:
        enabled: true # Enable import.
    options:
        http2: false # Enable HTTP/2 support for faster http requests (server must support http 2.0).
        importUnwatched: false # By default, We do not import unwatched state to enable it set to true. 
        exportIgnoreDate: false # By default, we respect the server watch date. To override the check, set this to true.

Start Webhook Server.

The default container includes webserver to listen for webhook events, to enable the server. edit your docker-compose.yaml file, and set the environment variable WS_WEBHOOK_ENABLE to 1.

View the contents of your config/config.yaml and take note of the webhook.apikey. if the apikey does not exist run the following command.

docker exec -ti watchstate console config:generate 

it should populate your config.yaml with randomly generated key, and it will be printed to your screen. Adding webhook to your server the url will be dependent on how you expose the server, but typically it will be like this:

http://localhost:8081/?type=[SERVER_TYPE]&apikey=[YOUR_API_KEY]

[SERVER_TYPE]

Change the parameter to one of supported backends. e.g. emby, plex or jellyfin. it should match the server type that you are adding the link to, Each server type has different webhook payload.

[YOUR_API_KEY]

Change this parameter to your api key you can find it by viewing config/config.yaml under the key of webhook.apikey.

Configuring Media servers to send webhook events.

Jellyfin (Free)

go to your jellyfin dashboard > plugins > Catalog > install: Notifications > Webhook, restart your jellyfin. After that go back again to dashboard > plugins > webhook. Add A Add Generic Destination,

Webhook Name:

Choose whatever name you want.

Webhook Url:

http://localhost:8081/?type=jellyfin&apikey=[YOUR_API_KEY]

Notification Type:

Select the following events

  • Item Added
  • User Data Saved

Click save

Emby (you need emby premiere to use webhooks)

Go to your Manage Emby Server > Server > Webhooks > (Click Add Webhook)

Webhook Url:

http://localhost:8081/?type=emby&apikey=[YOUR_API_KEY]

Webhook Events

Select the following events

  • Playback events
  • User events

Click Add Webhook

Plex (you need PlexPass to use webhooks)

Go to your plex WebUI > Settings > Your Account > Webhooks > (Click ADD WEBHOOK)

URL:

http://localhost:8081/?type=plex&apikey=[YOUR_API_KEY]

Click Save Changes

Finally

after making sure everything is running smoothly, edit your docker-compose.yaml file and enable the exporting of your watch state back to servers. by setting the value of WS_CRON_EXPORT to 1.

restart your docker container for changes to take effect.

FAQ


Q1: How to update new server watched state without overwriting the existing watch state?

Add the server, disable the import operation, and enable export. Then run the following commands.

docker exec -ti watchstate console state:export -vvrm --ignore-date --force-full --servers-filter [SERVER_NAME]

[SERVER_NAME]

Replace [SERVER_NAME] with what you have chosen to name your server in config e.g. my_home_server

this command will force export your current database state back to the selected server. If the operation is successful you can then enable the import feature if you want.

Q2: Is there support for Multi-user setup?

No, Not at this time. The database design centered on single user. However, It's possible to run container for each user.

Note: for Plex managed users you can log in via managed user and then extract the user x-plex-token (this token acts as userId for plex)

For jellyfin/emby, you can use same api-token and just replace the userId.

Comments
  • [Import] Jellyfin : Strange syncing issues...

    [Import] Jellyfin : Strange syncing issues...

    For some reason WatchState stopped syncing a few days ago, so I removed the container and started again from scratch. This is on Debian 11 with Docker. However, it suddenly marked thousands of random episodes as watched. I checked the import log and it constantly updates the same entries.

    I'm also noticing some weird renaming such as

    [2022-06-03T10:08:50.241361-07:00] logger.NOTICE: plex: Updating 'Dark Angel (2000) - 01x004'. State changed. {(guids: [ (guid_imdb: [ (old: tt0554559), (new: tt0554566) ]) ])}

    Also it doesn't seem to sync in between services. Any idea what could be wrong? As always, thanks :)

    Jellyfin Backend Upstream Bug 
    opened by TechPerplexed 40
  • Plex XBMCnfoTVImporter GUIDs

    Plex XBMCnfoTVImporter GUIDs

    I'm having issues with nothing from Plex getting imported, and only a small fraction of Jellyfin episodes. Jellyfin movies seem fine.

    In Plex, I use a local agent since I write my own NFO files for my owned media, and their agents don't support local NFO files out of the box. I suspect this may be causing issues if some column isn't being populated for records when imported that watchstate relies on?

    In Jellyfin, I use local NFO files, but that's supported out of the box. And it's working for all Movies and a few TV shows.

    Here's the initial import command I tried:

    ~/projects/watchstate$ sudo mv db/watchstate.db db/watchstate.db.bak ; docker exec -ti watchstate console state:import -vvvrm -f > log.txt
    
    [2022-04-22T13:49:40+00:00] logger.INFO: [M: 3.10M] Preloading all mapper data.
    [2022-04-22T13:49:40+00:00] logger.INFO: [M: 8.89M] Finished preloading mapper data.
    [2022-04-22T13:49:40+00:00] logger.INFO: [M: 8.89M] Single transaction mode
    [2022-04-22T13:49:40+00:00] logger.NOTICE: [M: 9.82M] Importing 'plex' play state changes since '2022-04-22T13:44:59+00:00'.
    [2022-04-22T13:49:40+00:00] logger.NOTICE: [M: 11.46M] Importing 'jellyfin' play state changes since '2022-04-22T13:44:59+00:00'.
    [2022-04-22T13:49:40+00:00] logger.NOTICE: [M: 11.57M] Waiting on (5) HTTP Requests.
    

    Then it scrolls through all of my Plex entries, but nothing at all gets imported. Example (which are confirmed watched under my user in Plex):

    ~/projects/watchstate$ sudo mv db/watchstate.db db/watchstate.db.bak ; docker exec -ti watchstate console state:import -vvvrm -s plex -f > log-plex.txt
    
    [2022-04-22T13:50:30+00:00] logger.NOTICE: [M: 14.22M] Ignoring plex - (Movies) - (movie:2) - [Invaders from Mars (1986)]. No valid GUIDs. [(0: {"id":"com.plexapp.agents.xbmcnfo://tt0091276?lang=xn"})]
    [2022-04-22T13:50:30+00:00] logger.NOTICE: [M: 14.22M] Ignoring plex - (Movies) - (movie:2) - [Koko: A Talking Gorilla (1978)]. No valid GUIDs. [(0: {"id":"com.plexapp.agents.xbmcnfo://tt0076097?lang=xn"})]
    
    [2022-04-22T14:10:55+00:00] logger.DEBUG: [M: 6.72M] Parsing Legacy plex content agent. [(guid: com.plexapp.agents.xbmcnfotv://79089/1/1?lang=xn)]
    [2022-04-22T14:10:55+00:00] logger.NOTICE: [M: 6.72M] Ignoring plex - (TV Shows) - (episode:1) - [Samurai Champloo - (1x1) - Tempestuous Temperaments]. No valid GUIDs. [(0: {"id":"com.plexapp.agents.xbmcnfotv://79089/1/1?lang=xn"})]
    [2022-04-22T14:10:55+00:00] logger.DEBUG: [M: 6.72M] Parsing Legacy plex content agent. [(guid: com.plexapp.agents.xbmcnfotv://79089/1/2?lang=xn)]
    [2022-04-22T14:10:55+00:00] logger.NOTICE: [M: 6.72M] Ignoring plex - (TV Shows) - (episode:1) - [Samurai Champloo - (1x2) - Redeye Reprisal]. No valid GUIDs. [(0: {"id":"com.plexapp.agents.xbmcnfotv://79089/1/2?lang=xn"})]
    

    Then it scrolls through all of my Jellyfin entries, but only a fraction of the show/episodes imported. This one is definitely in a watched state via the jellyfin gui:

    ~/projects/watchstate$ sudo mv db/watchstate.db db/watchstate.db.bak ; docker exec -ti watchstate console state:import -vvvrm -s jellyfin -f > 
    log-jellyfin.txt
    
    [2022-04-22T14:13:04+00:00] logger.NOTICE: [M: 7.31M] Ignoring jellyfin - (TV Shows) - (episode:767bffe4f11c93ef34b805451a696a4e) - [The Handmaid's Tale - (1x1) - Offred]. No valid GUIDs.
    

    Then I marked a single episode as watched and re-ran the import without "-f" option, but it was not imported. Most shows/episodes seem broken. The ones listed as "updating episode" were not updated, and these are marked as updating every time i run import no matter what:

    [2022-04-22T14:29:31+00:00] logger.NOTICE: [M: 11.40M] Finished waiting HTTP Requests.
    [2022-04-22T14:29:31+00:00] logger.NOTICE: [M: 11.40M] Committing (2) Changes.
    [2022-04-22T14:29:31+00:00] logger.INFO: [M: 11.40M] Updating database with '2' changes.
    [2022-04-22T14:29:31+00:00] logger.DEBUG: [M: 11.40M] Updating episode [(id: 26)]
    [2022-04-22T14:29:31+00:00] logger.DEBUG: [M: 11.41M] Updating episode [(id: 706)]
    

    Jellyfin Movies seem fine, however. I updated a single movie as watched and re-ran without the "-f" option for jellyfin. It successfully imported the one I marked as watched, but it was odd that it updated 2 other episodes (and does the same ones every time i re-run):

    [2022-04-22T14:20:22+00:00] logger.NOTICE: [M: 11.40M] Finished waiting HTTP Requests.
    [2022-04-22T14:20:22+00:00] logger.NOTICE: [M: 11.40M] Committing (3) Changes.
    [2022-04-22T14:20:22+00:00] logger.INFO: [M: 11.40M] Updating database with '3' changes.
    [2022-04-22T14:20:22+00:00] logger.DEBUG: [M: 11.40M] Updating episode [(id: 26)]
    [2022-04-22T14:20:22+00:00] logger.DEBUG: [M: 11.41M] Updating episode [(id: 706)]
    [2022-04-22T14:20:22+00:00] logger.DEBUG: [M: 11.41M] Adding movie [(via: jellyfin), (title: Rudy), (year: 1993), (date: 1993-09-17)]
    
    enhancement 
    opened by almightiest 29
  • Nothing updated, entity state is tainted.

    Nothing updated, entity state is tainted.

    Thanks for creating this project, it's what I have been wanting for years now - can't wait for the Trakt integration as well!

    I'm having an issue with the webhooks I hope you can help with. As soon I start playing something on any of the services, I'm getting the following error on Emby both when I start playing something and when it finishes:

    127.0.0.1 -  17/Apr/2022:20:48:25 +0000 "POST /index.php" 200
    response_status: 200 - response_text: "Nothing updated, entity state is tainted." - request_key: "-" - http_request: "POST /?&apikey=xxxxx HTTP/1.1":5 - user_ip: 172.18.0.6 - http_host: watchstate - user_agent: "Emby Server/4.6.7.0"
    
    

    Jellyfin:

    127.0.0.1 -  17/Apr/2022:22:39:13 +0000 "POST /index.php" 200
    response_status: 200 - response_text: "Nothing updated, entity state is tainted." - request_key: "xxxxx" - http_request: "POST / HTTP/1.1":5 - user_ip: 172.18.0.8 - http_host: watchstate - user_agent: "Jellyfin-Server/10.7.7"
    
    

    With Plex, I'm getting a different error:

    2022/04/17 20:55:55 [crit] 58#58: *1654 open() "/var/lib/nginx/tmp/client_body/0000000006" failed (13: Permission denied), client: 172.18.0.14, server: , request: "POST /?&apikey=xxxxx HTTP/1.1", host: "watchstate"
    response_status: 500 - response_text: "-" - request_key: "-" - http_request: "POST /?&apikey=xxxxx HTTP/1.1":170 - user_ip: 172.18.0.14 - http_host: watchstate - user_agent: "PlexMediaServer/1.25.9.5721-965587f64"
    

    Obviously it's talking to the Webhook because it registers the start/stop action, but what does it mean that the entity state is tainted? And any idea why Plex is giving a permission denied error? Thanks so much :)

    Edit: forgot to mention that manually running the import and export commands runs just fine!

    bug good first issue 
    opened by TechPerplexed 29
  • No supported GUID

    No supported GUID

    Adding in Jellyfin server and getting error. Have done the initial syncs.

    [2022-04-16T10:55:06.564015+00:00] logger.ERROR: JellyfinServer: No supported GUID was given. [] {"file":"/app/src/Libs/Servers/JellyfinServer.php","line":303} []
    127.0.0.1 -  16/Apr/2022:10:55:06 +0000 "POST /index.php" 400
    
    invalid 
    opened by ikolsteren 29
  • Plex Pass issue

    Plex Pass issue

    Hi, like the project, I've been meaning to explore this approach myself, as I have different plex servers in different location and want to keep all the users watch state sync.

    Slightly problem, with the approach for plex. A user only gets access to the webhook capability, if they personally have a plex pass. This means, buying for every family member, also doesn't work for managed user.

    The documentation is a little vague on whether the server owner's webhook is hit for shared users media.* appear to be yes for playback.started but not for the others.

    The plex-token is only available to the owner of the server and any viewCount retrieved via the api is for the uid 1 (the server owner account) which is going to make things a lot harder.

    I'm not sure how you retrieve the viewCount for 'shared users' which includes plex account holder accessing the library as a shared library or managed users. The question is how do they authenticate, when logged in as these user types you can't retrieve the token as you don't have access to the xml info.

    opened by ChrisPates 24
  • Can't sync to Plex?

    Can't sync to Plex?

    Hey, First of all thank you for this nice project!

    I have an Emby server and am now switching to Plex. I would like to take over the current "seen/unseen" data for my users. I was able to successfully import the data from Emby, but failing to export to Plex.

    root@Server /docker/media-server # docker exec -ti watchstate console state:export -v --select-backends 'plex'
    [2022-10-27T18:01:34+00:00] NOTICE: DATABASE: Loading changed items since [2022-10-27 18:01:34 UTC].
    [2022-10-27T18:01:34+00:00] NOTICE: SYSTEM: Using push mode for [0] backends and export mode for [1] backends.
    [2022-10-27T18:01:34+00:00] NOTICE: Export mode start.
    [2022-10-27T18:01:34+00:00] NOTICE: SYSTEM: Preloading DirectMapper data.
    [2022-10-27T18:01:34+00:00] NOTICE: SYSTEM: Preloading DirectMapper data is complete.
    [2022-10-27T18:01:34+00:00] NOTICE: SYSTEM: Exporting play state to [plex].
    [2022-10-27T18:01:35+00:00] ERROR: Request for [plex] libraries returned with unexpected [401] status code.
    [2022-10-27T18:01:35+00:00] WARNING: SYSTEM: Not updating last export date. [plex] report an error.
    [2022-10-27T18:01:35+00:00] NOTICE: SYSTEM: Sending [0] play state comparison requests.
    [2022-10-27T18:01:35+00:00] NOTICE: SYSTEM: Sent [0] play state comparison requests.
    [2022-10-27T18:01:35+00:00] NOTICE: Export mode ends.
    [2022-10-27T18:01:35+00:00] NOTICE: SYSTEM: No play state changes detected.
    [2022-10-27T18:01:35+00:00] WARNING: SYSTEM: Not updating last export date for [plex]. Backend reported an error.
    

    I can't find my error, maybe I can get some help here?

    Investigating 
    opened by Skyfay 19
  • [BUG] Not importing all items from Plex

    [BUG] Not importing all items from Plex

    Describe the bug

    syncing Plex > Jellyfin.

    For some reason, Watchstate isn't detecting all shows/Γ©pisodes/movies in my Plex library.

    I noticed this because in Jellyfin I had a bunch of shows that didn't have all episodes marked as watched.

    When I looked at the backend for Plex using backend:search:query the episodes just aren't there, but they ARE watched in Plex. It's very inconsistent. Like the same show may have some episodes of a season marked as watched and others not when they are all watched in Plex.

    I also notice the Plex import only makes 73 calls to the backend but I have about 1400 shows and 15000+ episodes. There aren't any errors running with -vvv other than some external IDs that can't be found (which is normal for some of the obscure shows I have).

    To Reproduce Not sure πŸ€”

    Expected behavior All shows and episodes would appear in the watchstate database.

    ** Tool Version:** WatchState 068d935

    Investigating info-needed 
    opened by stokkes 15
  • Error parsing plex tv library - Malformed UTF-8 characters, possibly incorrectly encoded '}' At position 0.

    Error parsing plex tv library - Malformed UTF-8 characters, possibly incorrectly encoded '}' At position 0.

    Hi

    When I try to execute the first command to pull watchstate.. I get the following error. Unable to proceed further.

    docker-compose exec watchstate console state:import -vvrm -s plx
    [2022-04-22T01:41:59+00:00] logger.INFO: [M: 3.10M] Preloading all mapper data.
    [2022-04-22T01:41:59+00:00] logger.INFO: [M: 7.33M] Finished preloading mapper data.
    [2022-04-22T01:41:59+00:00] logger.INFO: [M: 7.33M] Single transaction mode
    [2022-04-22T01:41:59+00:00] logger.NOTICE: [M: 9.19M] Importing 'plx' play state changes since beginning.
    [2022-04-22T01:41:59+00:00] logger.NOTICE: [M: 9.40M] Waiting on (3) HTTP Requests.
    [2022-04-22T01:42:00+00:00] logger.INFO: [M: 9.69M] Parsing Successful plx - (Movies) - (movie:3) response.
    [2022-04-22T01:42:01+00:00] logger.INFO: [M: 11.20M] Finished Parsing plx - (Movies) - (movie:3) (1011 objects) response.
    [2022-04-22T01:42:01+00:00] logger.INFO: [M: 11.19M] Parsing Successful plx - (Movies 4K) - (movie:2) response.
    [2022-04-22T01:42:01+00:00] logger.INFO: [M: 11.21M] Finished Parsing plx - (Movies 4K) - (movie:2) (7 objects) response.
    [2022-04-22T01:42:03+00:00] logger.INFO: [M: 11.23M] Parsing Successful plx - (TV Shows) - (episode:4) response.
    
    In Parser.php line 368:
                                                                                   
      [JsonMachine\Exception\SyntaxErrorException]                                 
      Malformed UTF-8 characters, possibly incorrectly encoded '}' At position 0.  
                                                                                   
    
    Exception trace:
      at /app/vendor/halaxa/json-machine/src/Parser.php:368
     JsonMachine\Parser->error() at /app/vendor/halaxa/json-machine/src/Parser.php:220
     JsonMachine\Parser->getIterator() at /app/src/Libs/Servers/PlexServer.php:631
     App\Libs\Servers\PlexServer->App\Libs\Servers\{closure}() at /app/src/Commands/State/ImportCommand.php:252
     App\Commands\State\ImportCommand->process() at /app/src/Commands/State/ImportCommand.php:96
     App\Commands\State\ImportCommand->App\Commands\State\{closure}() at /app/src/Command.php:84
     App\Command->single() at /app/src/Commands/State/ImportCommand.php:96
     App\Commands\State\ImportCommand->runCommand() at /app/src/Command.php:22
     App\Command->execute() at /app/vendor/symfony/console/Command/Command.php:291
     Symfony\Component\Console\Command\Command->run() at /app/vendor/symfony/console/Application.php:989
     Symfony\Component\Console\Application->doRunCommand() at /app/vendor/symfony/console/Application.php:299
     Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:171
     Symfony\Component\Console\Application->run() at /app/src/Libs/Initializer.php:117
     App\Libs\Initializer->runConsole() at /app/console:66
    
    state:import [-r|--redirect-logger] [-m|--memory-usage] [-f|--force-full] [--proxy PROXY] [--no-proxy NO-PROXY] [--timeout TIMEOUT] [-s|--servers-filter [SERVERS-FILTER]] [--import-unwatched] [--stats-show] [--stats-filter [STATS-FILTER]] [--mapper-direct] [-c|--config CONFIG]
    
    bug 
    opened by MagnuM2K 15
  • Exception: Unexpected content type during parsing.

    Exception: Unexpected content type during parsing.

    Hi,

    thanks ahead for this nice app, what makes me wonder

    i setup plex and emby as backends, i get the following error when i import or export changes to emby ...

    here 2 sample

    [2022-09-06T04:25:05.940987+02:00] logger.ERROR: Unhandled exception was thrown during handling of [emby] [Serien] [%(item.title)] export. {"library":{"id":"43cfe12fe7d9d8d21251e0964e0232e2","type":"tvshows","totalRecords":1930,"url":"http://emby:8096/Users/7dee1d34dd2942b3beec4245ff55c3db/items/?parentId=43cfe12fe7d9d8d21251e0964e0232e2&recursive=false&enableUserData=false&enableImages=false&fields=ProviderIds%2CDateCreated%2COriginalTitle%2CSeasonUserData%2CDateLastSaved%2CPremiereDate%2CProductionYear%2CPath&excludeLocationTypes=Virtual"},"segment":{"number":1,"of":1},"exception":{"file":"/opt/app/src/Backends/Jellyfin/Action/Export.php","line":43,"kind":"UnhandledMatchError","message":"Unhandled match case '...'","trace":[]}} []
    
    [2022-09-06T04:32:23.974484+02:00] logger.ERROR: Unhandled exception was thrown during handling of [emby] [Serien] [%(item.title)] import. {"library":{"id":"43cfe12fe7d9d8d21251e0964e0232e2","type":"tvshows","totalRecords":1930,"url":"http://emby:8096/Users/7dee1d34dd2942b3beec4245ff55c3db/items/?parentId=43cfe12fe7d9d8d21251e0964e0232e2&recursive=false&enableUserData=false&enableImages=false&fields=ProviderIds%2CDateCreated%2COriginalTitle%2CSeasonUserData%2CDateLastSaved%2CPremiereDate%2CProductionYear%2CPath&excludeLocationTypes=Virtual"},"segment":{"number":1,"of":1},"exception":{"file":"/opt/app/src/Backends/Jellyfin/Action/Import.php","line":726,"kind":"InvalidArgumentException","message":"Invalid Content type was given.","trace":[]}} []
    
    

    what really wonders me when i tried debugging, i see file":"/opt/app/src/Backends/Jellyfin/... instead /Emby/... may thats the issue ?

    from my servers.yaml

    image

    may an idea what could be wrong here ?

    enhancement 
    opened by alturismo 14
  • Other users updating synced user

    Other users updating synced user

    Users that are not the user that is setup are having their play status' updated on the user setup for sync User X is setup on two plex servers and for both the match user and uuid set for true snippet from servers.yaml file

      user: 375432
      import:
        enabled: true
        lastSync: 1650036504
      export:
        enabled: true
        lastSync: 1650036644
      webhook:
        import: true
        push: true
        match:
          user: true
          uuid: true
        token: *********************************
      persist: {  }
    

    When users Y or Z watch something and its completed user X watch status sets that they have watched the same episode

    bug Plex Backend 
    opened by ikolsteren 14
  • 404 Error on Import, Config Pulls in Usernames fine so is talking.

    404 Error on Import, Config Pulls in Usernames fine so is talking.

    Hi wowkise

    Ive created the docker and it pulled in my user accounts so defo talking to my current plex backend (ByteSized Hosting)

    When i try run an 'import' to pull the current watchstate of Plex i get the following

    [2022-10-27T16:43:45+01:00] ERROR: Request for [bytesized] libraries returned with unexpected [404] status code.
    
    apps@ubuntu-unraid:~/docker/core$ docker exec -ti watchstate console state:import -v
    
    [2022-10-27T16:45:27+01:00] NOTICE: SYSTEM: Preloading MemoryMapper data.
    
    [2022-10-27T16:45:27+01:00] NOTICE: SYSTEM: Preloading MemoryMapper data is complete.
    
    [2022-10-27T16:45:27+01:00] NOTICE: SYSTEM: Importing [bytesized] METADATA & PLAY STATE changes.
    
    [2022-10-27T16:45:27+01:00] ERROR: Request for [bytesized] libraries returned with unexpected [404] status code.
    
    [2022-10-27T16:45:27+01:00] WARNING: SYSTEM: Not updating last import date. [bytesized] reported an error.
    
    [2022-10-27T16:45:27+01:00] NOTICE: SYSTEM: Waiting on [0] requests.
    
    [2022-10-27T16:45:27+01:00] NOTICE: SYSTEM: Finished waiting on [0] requests.
    
    [2022-10-27T16:45:27+01:00] NOTICE: MAPPER: No changes detected.
    
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”
    
    β”‚ Type β”‚ Added β”‚ Updated β”‚ Failed β”‚
    
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
    
    β”‚ Movie β”‚ 0 β”‚ 0 β”‚ 0 β”‚
    
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
    
    β”‚ Episode β”‚ 0 β”‚ 0 β”‚ 0 β”‚
    
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    

    Im trying to 'backup' the watchstate from Plex on Bytesized to a Locally Hosted Unraid setup.

    In your context

    import = pull data from 'source' Plex

    export = push data to destination Plex.

    Any Assistance appreciated.

    Thanks

    invalid 
    opened by TheWood1978 13
  • TODO list

    TODO list

    TODO

    • [ ] now that the main code is stable, we should start writing more tests.

    Long term goals

    • [ ] add duplicate db records detector.
    • [ ] We need some sort of confidence vote for updating global external ids. This idea to combat incorrect external ids being reported by media servers.
    • [ ] since we have the data we may be able to generate possible mismatches using local data, however the accuracy of this decrease if there are less than 3 backends to be accurate i think we should enforce 3 backends as minimum. with optional flag to enable it for 2 servers. with clear warning that data is probably not accurate.

    Possible v2 features.

    • [ ] Make it easier to handle multiuser import/export #136
    • [ ] Sync currently playing item progress. see #99
    • [ ] check if graph database make sense for v2 if we going to support multi user.

    Done

    • [x] #287
    • [x] #251
    • [x] #227
    • [x] Add an access.log for webhooks instead of relying on frontend proxy to do the logging. #170
    • [x] Separate server:remote options into their own sub commands for example backend:library:list backend:library:mismatch etc. instead of being being listed under server:remote options.
    • [x] For search mismatch we should look compare filename as well not just directory as some people have their movies in one giant directory.
    • [x] For search mismatch we should compare the provided year against the year in filename or directory if available.
    • [x] on webhook request we should request metadata directly from server, as the info given via webhook payload sometimes is less then what we need. case in point jellyfin webhook payload is so sparse.
    • [x] Add Parent id / library id to metadata field.
    • [x] Implement sanity check for external ids and reject invalid ids. looking at you jellyfin! #141
    • [x] add a way to import metadata from backend without affecting play state. basically fill the metadata if it's exists in the storage already.
    • [x] Add date to log file. log.(Ymd).log so we can prune older logs.
    • [x] Add logs viewer.
    • [x] In webhook context add support for metadata import only as well.
    • [x] Update servers:manage to add an option of enabling metadata import if user disabled import from backend but have export enabled.
    • [x] remove servers.yaml webhook.import webhook.push and rely on just import.enabled and export.enabled.
    • [x] rename config:* command namespace to system:*
    • [x] force user id selection for Plex regardless if there are multiple users or not in servers:manage, Users should still be able to toggle whether they want strict user match or not. the servers.yaml key user: should not be empty or null. "the empty or null check for plex should only start throwing errors on v1 release, as there are users who already have working setup".
    • [x] Allow export to use push mode if import.enabled or options.IMPORT_METADATA_ONLY are enabled.
    • [x] In export context, We need to check changed items metadata and see if all export targets has registered metadata. otherwise, fallback to full export mode #150
    • [x] In webhook context. update the extra column as well if we are only updating metadata.
    • [x] Support dual mode in export run. #152.
    • [x] Add info to the extra column on Task Scheduler to indicate how the metadata has been updated. #153
    • [x] for db:list allow sorting on multiple column. #154
    • [x] Add query retry incase of database is locked. #159
    • [x] Backend clients classes are getting larger as we add more features, we need to start separating actions. #168
    • [x] change Inspect Request attributes injection values into nested array instead of current k/v list. #171
    • [x] #173
    • [x] #174
    • [x] All exception catchers MUST implements a trace mode support. to help diagnose problems. #176
    • [x] #180
    • [x] #184
    • [x] #185
    • [x] #186
    • [x] #187
    • [x] New scheduled task to allow backing up backends play states.
    • [x] Stop referring to database as storage, instead call it database.
    • [x] Make sure to check external id expected type, as some backends fails to do so.
    • [x] User servers should be referenced as backend as we are hopefully expanding to beyond just media servers.
    • [x] Start updating old commands help doc.
    • [x] for backend:library:mismatch/unmatched, add option to run on all libraries.
    • [x] #191
    • [x] #192
    • [x] #201
    • [x] #205
    • [x] Add windows docker compose documentation.
    • [x] Change docker build to switch user context.
    • [x] #210
    enhancement 
    opened by ArabCoders 0
Releases(v0.0.20-alpha)
Owner
Abdulmohsen
Loves to learn new things everyday, long time PHP Developer.
Abdulmohsen
A simple tool to backup data & db from a web server to Google Drive.

PHP Google Drive backup - A (very) simple CLI tool that I used to backup my www directory and my database from OVH to Google Drive, in a cronjob.

Alex 18 Jan 4, 2023
PHP CLI tool which allows publishing zipped MODX extra to modstore.pro marketplace

MODX Extra Publisher PHP CLI tool which allows publishing zipped MODX extra to modstore.pro marketplace. Installation global? local? To install packag

Ivan Klimchuk 3 Aug 6, 2021
πŸ‘¨πŸ»β€πŸš€ A command-line tool that gives you the Alpine Day 2021 schedule in your timezone. πŸš€

Alpine Day Schedule a command-line tool that gives you the Alpine Day 2021 schedule in your timezone. ?? Quick start Requires PHP 7.4+ # First, instal

Nuno Maduro 11 Jun 10, 2021
PHP Interminal is a command-line tool that gives you access to PHP Internals discussions in your terminal.

PHP Interminal is a command-line tool that gives you access to PHP Internals discussions in your terminal. ??

Nuno Maduro 32 Dec 26, 2022
Patrol is an elegant command-line tool that keeps your PHP Project's dependencies in check.

Patrol is an elegant command-line tool that keeps your PHP Project's dependencies in check. Installation / Usage Requires PHP 8.0+ First, install Patr

Nuno Maduro 237 Nov 14, 2022
A PHP command line tool used to install shlink

Shlink installer A PHP command line tool used to install shlink. Installation Install this tool using composer.

null 8 Nov 3, 2022
Laracon Schedule a command-line tool that gives you the Laracon Online schedule in your timezone.

Laracon Schedule a command-line tool that gives you the Laracon Online schedule in your timezone. ?? Quick start Requires PHP 7.4+ # First, install: c

Nuno Maduro 101 Sep 16, 2022
A simple command-line tool whose aim is to facilitate the continous delivery of PHP apps

Deployer Simple command-line tool that aims to facilitate the continous delivery of PHP apps, particularly Laravel apps. Imagine you want to update yo

Fernando Bevilacqua 4 Sep 8, 2021
A PHP Command Line tool that makes it easy to compile, concat, and minify front-end Javascript and CSS/SCSS dependencies.

Front End Compiler A PHP Command Line tool that makes it easy to compile, concat, and minify front-end Javascript and CSS/SCSS dependencies. The minif

Happy Medium 2 Nov 12, 2021
Simple command-line tool to access HiWeb account information

Simple command-line tool to access HiWeb account information.

Milad Nekofar 2 Dec 26, 2022
πŸ’₯ Collision is a beautiful error reporting tool for command-line applications

Collision was created by, and is maintained by Nuno Maduro, and is a package designed to give you beautiful error reporting when interacting with your

Nuno Maduro 4.2k Jan 5, 2023
A CLI tool to check whether a specific composer package uses imported symbols that aren't part of its direct composer dependencies

A CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package. This will prevent you from using "soft" dependencies that are not defined within your composer.json require section.

Matthias Glaub 722 Dec 30, 2022
Takeout is a CLI tool for spinning up tiny Docker containers, one for each of your development environment dependencies.

Takeout Takeout is a CLI tool for spinning up tiny Docker containers, one for each of your development environment dependencies. It's meant to be pair

Tighten 1.4k Jan 2, 2023
A tool to generate boilerplate code, interact with and debug Drupal.

Table of Contents generated with DocToc Drupal Console Required PHP version Drupal Console documentation Download Drupal Console Run Drupal Console Co

Hecho en Drupal 929 Jan 5, 2023
A Cli tool to save you time, and gives you the power to scaffold all of your models,controllers,commands

A Cli tool to save you time, and gives you the power to scaffold all of your models,controllers,commands... at once Installation You can install the p

Coderflex 16 Nov 11, 2022
A powerful command line application framework for PHP. It's an extensible, flexible component, You can build your command-based application in seconds!

CLIFramework CLIFramework is a command-line application framework, for building flexiable, simple command-line applications. Commands and Subcommands

Yo-An Lin 428 Dec 13, 2022
ReactPHP Shell, based on the Symfony Console component.

Pecan Event-driven, non-blocking shell for ReactPHP. Pecan (/pΙͺˈkɑːn/) provides a non-blocking alternative to the shell provided in the Symfony Consol

Michael Crumm 43 Sep 4, 2022
Import data from and export data to a range of different file formats and media

Ddeboer Data Import library This library has been renamed to PortPHP and will be deprecated. Please use PortPHP instead. Introduction This PHP library

David de Boer 570 Dec 27, 2022
This Laravel Nova package allows you to manage media and media fields

Nova Media Hub This Laravel Nova package allows you to manage media and media fields. Requirements php: >=8.0 laravel/nova: ^4.0 Features Media Hub UI

outl1ne 25 Dec 22, 2022
This tool gives you the ability to set the default collapse state for Nova 4.0 menu items.

Nova Menu Collapsed This tool gives you the ability to set the default collapse state for Nova 4.0 menu items. Requirements php: >=8.0 laravel/nova: ^

Artem Stepanenko 10 Nov 17, 2022