From 73ca9a842d2de876501baec8a2bc5676d2103664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 May 2021 10:36:11 +0300 Subject: [PATCH 01/14] Add database access library Inspired by plexcleaner https://github.com/nap/plexcleaner/blob/853bb5b81325878071059b67a2cdad8d0b7311e5/plexcleaner/database.py --- plextraktsync/db/Database.py | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 plextraktsync/db/Database.py diff --git a/plextraktsync/db/Database.py b/plextraktsync/db/Database.py new file mode 100644 index 0000000000..634dc647c0 --- /dev/null +++ b/plextraktsync/db/Database.py @@ -0,0 +1,43 @@ +import sqlite3 + +from plextraktsync.factory import logging + + +class Database: + _uncommited = False + + def __init__(self, database_path: str): + self.logger = logging.getLogger("PlexTraktSync.Database") + try: + self.filename = database_path + self._connection = sqlite3.connect(database_path) + self._cursor = self._connection.cursor() + self._cursor.execute('ANALYZE') + + except sqlite3.OperationalError as e: + self.logger.error(e) + raise e + + except sqlite3.DatabaseError as e: + self.logger.error(e) + raise e + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if self._uncommited: + self.commit() + + self._connection.close() + + def commit(self): + self._connection.commit() + self._uncommited = False + + def rollback(self): + self._connection.rollback() + self._uncommited = False + + def has_uncommited(self): + return self._uncommited From b849e4b11378a8c58ff5b9f6965ab8534610121b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 May 2021 16:09:47 +0300 Subject: [PATCH 02/14] Export cursor --- plextraktsync/db/Database.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plextraktsync/db/Database.py b/plextraktsync/db/Database.py index 634dc647c0..c2dfcab5ff 100644 --- a/plextraktsync/db/Database.py +++ b/plextraktsync/db/Database.py @@ -22,6 +22,10 @@ def __init__(self, database_path: str): self.logger.error(e) raise e + @property + def cursor(self): + return self._cursor + def __enter__(self): return self From 857f1c2269a5dd60fb55be4da154d8bb0d7f8acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 May 2021 19:39:50 +0300 Subject: [PATCH 03/14] Use execute wrapper --- plextraktsync/db/Database.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plextraktsync/db/Database.py b/plextraktsync/db/Database.py index c2dfcab5ff..3ad6b4264f 100644 --- a/plextraktsync/db/Database.py +++ b/plextraktsync/db/Database.py @@ -35,6 +35,10 @@ def __exit__(self, exc_type, exc_val, exc_tb): self._connection.close() + def execute(self, query, *args): + self._uncommited = True + return self.cursor.execute(query, *args) + def commit(self): self._connection.commit() self._uncommited = False From 855ceadbfc88ce16945c9b6b2aae72408d292f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 12:53:58 +0300 Subject: [PATCH 04/14] Add SyncDatabase class --- plextraktsync/db/SyncDatabase.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 plextraktsync/db/SyncDatabase.py diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py new file mode 100644 index 0000000000..8263f0d260 --- /dev/null +++ b/plextraktsync/db/SyncDatabase.py @@ -0,0 +1,6 @@ +from plextraktsync.db.Database import Database + + +class SyncDatabase: + def __init__(self, con: Database): + self.con = con From 3b96e7cb8d1dc7de5389d253ac19a712990529fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:02:43 +0300 Subject: [PATCH 05/14] Create table on connection --- plextraktsync/db/SyncDatabase.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py index 8263f0d260..9d519ac664 100644 --- a/plextraktsync/db/SyncDatabase.py +++ b/plextraktsync/db/SyncDatabase.py @@ -2,5 +2,16 @@ class SyncDatabase: + table_name = 'sync' + def __init__(self, con: Database): self.con = con + with self.con as con: + self._create_table(con) + + # Initial CREATE TABLE must happen in shared connection; subsequent queries will use thread-local connections + def _create_table(self, con: Database): + con.execute(f'CREATE TABLE IF NOT EXISTS {self.table_name} ({self.schema})') + + def insert(self, record: SyncRecord): + pass From cdddc9b017576dfccf718495b352100ac54295ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:06:00 +0300 Subject: [PATCH 06/14] Set schema for sync table --- plextraktsync/db/SyncDatabase.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py index 9d519ac664..663402fdd4 100644 --- a/plextraktsync/db/SyncDatabase.py +++ b/plextraktsync/db/SyncDatabase.py @@ -2,7 +2,23 @@ class SyncDatabase: - table_name = 'sync' + table_name = "sync" + # fields: + # A. Media ID + # B. Plex timestamp watched + # C. seen on Plex sync? + # D. Trakt timestamp watched + # E. seen on Trakt sync? + # F. result + schema = """ + id PRIMARY KEY, + media_id, + plex_timestamp_watched, + seen_on_plex_sync, + trakt_timestamp_watched, + seen_on_trakt_sync, + result + """ def __init__(self, con: Database): self.con = con From 797de3d31363dc1df2a6e11daff36b36b3c6c196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:08:08 +0300 Subject: [PATCH 07/14] Add SyncRecord class --- plextraktsync/db/SyncRecord.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 plextraktsync/db/SyncRecord.py diff --git a/plextraktsync/db/SyncRecord.py b/plextraktsync/db/SyncRecord.py new file mode 100644 index 0000000000..8f85f03505 --- /dev/null +++ b/plextraktsync/db/SyncRecord.py @@ -0,0 +1,12 @@ +from dataclasses import dataclass + + +@dataclass +class SyncRecord: + id: str + media_id: str + plex_timestamp_watched: str + seen_on_plex_sync: str + trakt_timestamp_watched: str + seen_on_trakt_sync: str + result: str From a91026a7674ca6dbe1da7a48f43ea6f89218e842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:09:33 +0300 Subject: [PATCH 08/14] Add insert method --- plextraktsync/db/SyncDatabase.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py index 663402fdd4..14280e57fe 100644 --- a/plextraktsync/db/SyncDatabase.py +++ b/plextraktsync/db/SyncDatabase.py @@ -1,5 +1,12 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + from plextraktsync.db.Database import Database +if TYPE_CHECKING: + from plextraktsync.db.SyncRecord import SyncRecord + class SyncDatabase: table_name = "sync" From c0bd6332eac87fa672933a75f97d50023c2b8ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:15:51 +0300 Subject: [PATCH 09/14] Add sync_database factory --- plextraktsync/util/Factory.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plextraktsync/util/Factory.py b/plextraktsync/util/Factory.py index e16c0969ec..3064e127a8 100644 --- a/plextraktsync/util/Factory.py +++ b/plextraktsync/util/Factory.py @@ -300,6 +300,18 @@ def sync_config(self): return SyncConfig(self.config, self.server_config) + @cached_property + def sync_database(self): + from os.path import join + + from plextraktsync.db.Database import Database + from plextraktsync.db.SyncDatabase import SyncDatabase + from plextraktsync.path import cache_dir + + db_path = join(cache_dir, "sync.sqlite") + + return SyncDatabase(Database(db_path)) + @cached_property def queue(self): from plextraktsync.queue.BackgroundTask import BackgroundTask From 6e38c766cdcbe58302fc52e1af6f6dde959cdb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:19:20 +0300 Subject: [PATCH 10/14] Add sync database to sync --- plextraktsync/sync/Sync.py | 4 +++- plextraktsync/util/Factory.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plextraktsync/sync/Sync.py b/plextraktsync/sync/Sync.py index 9c36b0c58a..a8373540cf 100644 --- a/plextraktsync/sync/Sync.py +++ b/plextraktsync/sync/Sync.py @@ -11,16 +11,18 @@ from plextraktsync.plan.Walker import Walker from plextraktsync.plex.PlexApi import PlexApi from plextraktsync.trakt.TraktApi import TraktApi + from plextraktsync.db.SyncDatabase import SyncDatabase class Sync: logger = logging.getLogger(__name__) - def __init__(self, config: SyncConfig, plex: PlexApi, trakt: TraktApi): + def __init__(self, config: SyncConfig, plex: PlexApi, trakt: TraktApi, sync_state: SyncDatabase): self.config = config self.plex = plex self.trakt = trakt self.walker = None + self.sync_state = sync_state @cached_property def trakt_lists(self): diff --git a/plextraktsync/util/Factory.py b/plextraktsync/util/Factory.py index 3064e127a8..8a289fa403 100644 --- a/plextraktsync/util/Factory.py +++ b/plextraktsync/util/Factory.py @@ -140,7 +140,7 @@ def sync(self): plex = self.plex_api trakt = self.trakt_api - return Sync(self.sync_config, plex, trakt) + return Sync(self.sync_config, plex, trakt, self.sync_database) @cached_property def progressbar(self): From b0023aa5573b717d5efb554dbb7c649f05ba5541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:21:17 +0300 Subject: [PATCH 11/14] Add update method to SyncDatabase --- plextraktsync/db/SyncDatabase.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py index 14280e57fe..c34f991f5b 100644 --- a/plextraktsync/db/SyncDatabase.py +++ b/plextraktsync/db/SyncDatabase.py @@ -6,6 +6,7 @@ if TYPE_CHECKING: from plextraktsync.db.SyncRecord import SyncRecord + from plextraktsync.media import Media class SyncDatabase: @@ -38,3 +39,6 @@ def _create_table(self, con: Database): def insert(self, record: SyncRecord): pass + + def update(self, m: Media): + pass From 29bab58e52ccb2aa703977c398104fd548bf22e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:25:24 +0300 Subject: [PATCH 12/14] Do something silly in update() --- plextraktsync/db/SyncDatabase.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plextraktsync/db/SyncDatabase.py b/plextraktsync/db/SyncDatabase.py index c34f991f5b..698a3e0871 100644 --- a/plextraktsync/db/SyncDatabase.py +++ b/plextraktsync/db/SyncDatabase.py @@ -3,9 +3,9 @@ from typing import TYPE_CHECKING from plextraktsync.db.Database import Database +from plextraktsync.db.SyncRecord import SyncRecord if TYPE_CHECKING: - from plextraktsync.db.SyncRecord import SyncRecord from plextraktsync.media import Media @@ -41,4 +41,12 @@ def insert(self, record: SyncRecord): pass def update(self, m: Media): - pass + record = SyncRecord( + media_id=m.trakt_id, + plex_timestamp_watched=m.watched_on_plex, + seen_on_plex_sync=m.watched_on_plex, + trakt_timestamp_watched=m.watched_on_trakt, + seen_on_trakt_sync=m.watched_on_trakt, + result="", + ) + print(record) From 870ed7243a9a013c44850984f7a49c754491c904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:25:34 +0300 Subject: [PATCH 13/14] Mark id optional --- plextraktsync/db/SyncRecord.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plextraktsync/db/SyncRecord.py b/plextraktsync/db/SyncRecord.py index 8f85f03505..84e281f0e5 100644 --- a/plextraktsync/db/SyncRecord.py +++ b/plextraktsync/db/SyncRecord.py @@ -3,10 +3,11 @@ @dataclass class SyncRecord: - id: str media_id: str plex_timestamp_watched: str seen_on_plex_sync: str trakt_timestamp_watched: str seen_on_trakt_sync: str result: str + + id: str = None From 08ad4ea205e10703193246af7f1f85ae41bdcf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 29 Apr 2023 13:25:46 +0300 Subject: [PATCH 14/14] Just sync each media item to local db --- plextraktsync/sync/Sync.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plextraktsync/sync/Sync.py b/plextraktsync/sync/Sync.py index a8373540cf..b47fa67fb4 100644 --- a/plextraktsync/sync/Sync.py +++ b/plextraktsync/sync/Sync.py @@ -49,9 +49,11 @@ async def sync(self, walker: Walker, dry_run=False): if self.config.need_library_walk: async for movie in walker.find_movies(): + self.sync_state.update(movie) await pm.ahook.walk_movie(movie=movie, dry_run=dry_run) async for episode in walker.find_episodes(): + self.sync_state.update(episode) await pm.ahook.walk_episode(episode=episode, dry_run=dry_run) await pm.ahook.fini(walker=walker, dry_run=dry_run)