diff --git a/jellyfin_kodi/database/__init__.py b/jellyfin_kodi/database/__init__.py
index d8c30650..2e51357c 100644
--- a/jellyfin_kodi/database/__init__.py
+++ b/jellyfin_kodi/database/__init__.py
@@ -263,6 +263,10 @@ def reset_kodi():
if name not in ["version", "videoversiontype"]:
videodb.cursor.execute("DELETE FROM " + name)
+ # Delete the custom videoversiontype entries
+ if name == "videoversiontype":
+ videodb.cursor.execute("DELETE from videoversiontype WHERE id > 40800 AND owner = 1")
+
if settings("enableMusic.bool") or dialog("yesno", "{jellyfin}", translate(33162)):
with Database("music") as musicdb:
@@ -427,3 +431,17 @@ def get_item(kodi_id, media):
return
return item
+
+def get_item_by_file_id(file_id, media):
+ """Get jellyfin item based on kodi file id and media."""
+ with Database("jellyfin") as jellyfindb:
+ item = jellyfin_db.JellyfinDatabase(jellyfindb.cursor).get_item_by_file_id(
+ file_id, media
+ )
+
+ if not item:
+ LOG.debug("Not an jellyfin item")
+
+ return
+
+ return item
diff --git a/jellyfin_kodi/database/jellyfin_db.py b/jellyfin_kodi/database/jellyfin_db.py
index 5201e932..9708aa89 100644
--- a/jellyfin_kodi/database/jellyfin_db.py
+++ b/jellyfin_kodi/database/jellyfin_db.py
@@ -61,6 +61,15 @@ class JellyfinDatabase:
return self.cursor.fetchall()
+ def get_item_by_file_id(self, *args):
+
+ try:
+ self.cursor.execute(QU.get_item_by_file_id, args)
+
+ return self.cursor.fetchone()[0]
+ except TypeError:
+ return
+
def get_item_by_kodi_id(self, *args):
try:
diff --git a/jellyfin_kodi/database/queries.py b/jellyfin_kodi/database/queries.py
index 41a59cda..715ba7db 100644
--- a/jellyfin_kodi/database/queries.py
+++ b/jellyfin_kodi/database/queries.py
@@ -23,7 +23,7 @@ WHERE parent_id = ?
AND media_type = ?
"""
get_item_by_media_folder = """
-SELECT jellyfin_id, jellyfin_type
+SELECT jellyfin_id, jellyfin_type, jellyfin_parent_id
FROM jellyfin
WHERE media_folder = ?
"""
@@ -39,6 +39,12 @@ FROM jellyfin
WHERE jellyfin_id LIKE ?
"""
get_item_by_wild_obj = ["{Id}"]
+get_item_by_file_id = """
+SELECT jellyfin_id, parent_id, media_folder, jellyfin_type, checksum
+FROM jellyfin
+WHERE kodi_fileid = ?
+AND media_type = ?
+"""
get_item_by_kodi = """
SELECT jellyfin_id, parent_id, media_folder, jellyfin_type, checksum
FROM jellyfin
diff --git a/jellyfin_kodi/downloader.py b/jellyfin_kodi/downloader.py
index 147efece..47fb909d 100644
--- a/jellyfin_kodi/downloader.py
+++ b/jellyfin_kodi/downloader.py
@@ -328,7 +328,9 @@ class GetItemWorker(threading.Thread):
result = self.server.http.request(request, s)
for item in result["Items"]:
-
+ # Force Jellyfin to treat version as a movie to get the right metadata
+ if settings("useVersions") == "true" and item["Type"] == "Video":
+ item["Type"] = "Movie"
if item["Type"] in self.output:
self.output[item["Type"]].put(item)
except HTTPException as error:
diff --git a/jellyfin_kodi/entrypoint/service.py b/jellyfin_kodi/entrypoint/service.py
index 8702be88..e1b6da21 100644
--- a/jellyfin_kodi/entrypoint/service.py
+++ b/jellyfin_kodi/entrypoint/service.py
@@ -80,6 +80,7 @@ class Service(xbmc.Monitor):
LOG.info("Platform: %s", settings("platformDetected"))
LOG.info("Python Version: %s", sys.version)
LOG.info("Using dynamic paths: %s", settings("useDirectPaths") == "0")
+ LOG.info("Syncing video versions: %s", settings("useVersions") == "true")
LOG.info("Log Level: %s", self.settings["log_level"])
verify_kodi_defaults()
diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py
index 1448028a..47a72794 100644
--- a/jellyfin_kodi/full_sync.py
+++ b/jellyfin_kodi/full_sync.py
@@ -359,7 +359,9 @@ class FullSync(object):
for x in items:
if x[0] not in current and x[1] == "Movie":
- obj.remove(x[0])
+ # Parent ID tied to main version so check it before removing
+ if x[2] not in current:
+ obj.remove(x[0])
@progress()
def tvshows(self, library, dialog):
diff --git a/jellyfin_kodi/helper/api.py b/jellyfin_kodi/helper/api.py
index dfa05a7e..a0689cb2 100644
--- a/jellyfin_kodi/helper/api.py
+++ b/jellyfin_kodi/helper/api.py
@@ -236,6 +236,11 @@ class API(object):
elif self.item["Container"] == "bluray":
path = "%s/BDMV/index.bdmv" % path
+ # Loop through configured path replacements searching for a match prior to slash correction
+ for local_path in self.path_data.keys():
+ if local_path in path:
+ path = path.replace(local_path, self.path_data[local_path])
+
path = path.replace("\\\\", "\\")
if "\\" in path:
@@ -245,11 +250,6 @@ class API(object):
protocol = path.split("://")[0]
path = path.replace(protocol, protocol.lower())
- # Loop through configured path replacements searching for a match
- for local_path in self.path_data.keys():
- if local_path in path:
- path = path.replace(local_path, self.path_data[local_path])
-
return path
def get_user_artwork(self, user_id):
diff --git a/jellyfin_kodi/helper/playutils.py b/jellyfin_kodi/helper/playutils.py
index d881101e..d86d6180 100644
--- a/jellyfin_kodi/helper/playutils.py
+++ b/jellyfin_kodi/helper/playutils.py
@@ -95,7 +95,7 @@ class PlayUtils(object):
break
- elif not self.is_selection(info) or len(info["MediaSources"]) == 1:
+ elif not self.is_selection(info) or len(info["MediaSources"]) == 1 or settings("useVersions") == "true":
LOG.info("Skip source selection.")
sources.append(info["MediaSources"][0])
diff --git a/jellyfin_kodi/jellyfin/api.py b/jellyfin_kodi/jellyfin/api.py
index 88087f7a..d40fad5b 100644
--- a/jellyfin_kodi/jellyfin/api.py
+++ b/jellyfin_kodi/jellyfin/api.py
@@ -142,6 +142,9 @@ class API(object):
def get_media_folders(self):
return self.users("/Items")
+ def get_extras(self, item_id):
+ return self.users("/Items/%s/SpecialFeatures" % item_id)
+
def get_item(self, item_id):
return self.users("/Items/%s" % item_id)
diff --git a/jellyfin_kodi/objects/actions.py b/jellyfin_kodi/objects/actions.py
index ced4751e..72ce3103 100644
--- a/jellyfin_kodi/objects/actions.py
+++ b/jellyfin_kodi/objects/actions.py
@@ -3,6 +3,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
#################################################################################################
+import os
import threading
import sys
import json
@@ -935,6 +936,29 @@ def on_play(data, server):
return
item = server.jellyfin.get_item(item[0])
+
+ # If using Video Versions, need to match the actual file as the kodi_id is always the primary
+ if settings("useVersions") == "true":
+ # Addon Mode matches the jellyfin_id's properly automatically
+ # This may need to be done elsewhere as well until Kodi exposes versions properly
+
+ # Check the playing file against the primary file; if no match get the right one
+ playing_file = os.path.basename(file)
+ primary_file = os.path.basename(item["Path"])
+ if playing_file != primary_file:
+ from .kodi import Movies
+
+ # If not, search kodi database for the filename and get kodi fileid
+ with database.Database("video") as videodb:
+ path_id = Movies(videodb.cursor).get_path(file.replace(playing_file, ""))
+ file_id = Movies(videodb.cursor).get_file(path_id, playing_file)
+
+ # Get the proper jellyfin_id for this file
+ newitem = database.get_item_by_file_id(file_id, media)
+
+ # Get the correct item now with the new id
+ item = server.jellyfin.get_item(newitem)
+
item["PlaybackInfo"] = {"Path": file}
playutils.set_properties(
item,
diff --git a/jellyfin_kodi/objects/kodi/kodi.py b/jellyfin_kodi/objects/kodi/kodi.py
index 94698267..68776fac 100644
--- a/jellyfin_kodi/objects/kodi/kodi.py
+++ b/jellyfin_kodi/objects/kodi/kodi.py
@@ -86,21 +86,13 @@ class Kodi(object):
def remove_path(self, *args):
self.cursor.execute(QU.delete_path, args)
- def add_file(self, filename, path_id):
+ def add_file(self, *args):
+ file_id = self.get_file(*args)
- try:
- self.cursor.execute(
- QU.get_file,
- (
- filename,
- path_id,
- ),
- )
- file_id = self.cursor.fetchone()[0]
- except TypeError:
+ if file_id is None:
file_id = self.create_entry_file()
- self.cursor.execute(QU.add_file, (file_id, path_id, filename))
+ self.cursor.execute(QU.add_file, (file_id,) + args)
return file_id
@@ -113,6 +105,15 @@ class Kodi(object):
if path_id is not None:
self.cursor.execute(QU.delete_file_by_path, (path_id,) + args)
+ def get_file(self, *args):
+
+ try:
+ self.cursor.execute(QU.get_file, args)
+
+ return self.cursor.fetchone()[0]
+ except TypeError:
+ return
+
def get_filename(self, *args):
try:
diff --git a/jellyfin_kodi/objects/kodi/movies.py b/jellyfin_kodi/objects/kodi/movies.py
index da959806..808093bb 100644
--- a/jellyfin_kodi/objects/kodi/movies.py
+++ b/jellyfin_kodi/objects/kodi/movies.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals
+import os
+import re
from sqlite3 import DatabaseError
##################################################################################################
-from ...helper import LazyLogger
+from ...helper import LazyLogger, settings
from .kodi import Kodi
from . import queries as QU
@@ -63,6 +65,58 @@ class Movies(Kodi):
if self.cursor.fetchone()[0] == 1:
self.cursor.execute(QU.add_video_version, args)
+ def update_videoversion(self, *args):
+ self.cursor.execute(QU.check_video_version)
+ if self.cursor.fetchone()[0] == 1:
+ self.cursor.execute(QU.update_video_version, args)
+
+ def check_videoversion(self, *args):
+ self.cursor.execute(QU.count_video_version, args)
+ return self.cursor.fetchone()[0]
+
+ def get_or_create_videoversiontype(self, name, filepath, extra=False):
+ """Retrieve or create a video version type based on the Jellyfin version name or filename."""
+ # If versions are disabled, always return the standard edition
+ if settings("useVersions") != "true":
+ return 40400
+
+ # Change itemtype for extras. If other types added in the future, need to adjust.
+ itemtype = self.itemtype + 1 if extra else self.itemtype
+
+ # Get the filename without extension
+ filename = os.path.splitext(os.path.basename(filepath))[0]
+
+ # Remove Jellyfin-added suffixes--may need to add others
+ test_name = re.sub(r"/(3D|DVD|Bluray)$", "", name)
+
+ # If the Jellyfin version name matches the filename completely, a good version name
+ # wasn't created automatically, so extract it, or set to Standard Edition
+ if not extra and test_name == filename:
+ # Check for ' - XXXX' at end of the name to use for version name
+ match = re.search(r" - (.+)$", name)
+ if match:
+ name = match.group(1).strip()
+ else:
+ name = None
+
+ # Set Standard Edition for empty names or DVD/Bluray folders
+ if not name or filename.lower() in ("index", "video_ts"):
+ return 40400
+
+ # Remove */3D suffixes that Jellyfin adds (ie '.mvc/3D') as long as 3D in the name already
+ if '3D' in name[:-2]:
+ name = re.sub(r'\.(\w{3,4})/3D$', lambda m: ' ' + m.group(1).upper(), name)
+
+ # Check if this version type already exists and return it
+ self.cursor.execute(QU.get_video_version_type, (name, itemtype,))
+ row = self.cursor.fetchone()
+ if row:
+ return row[0]
+
+ # Create a new version type and return the id
+ self.cursor.execute(QU.add_video_version_type, (name, 1, itemtype))
+ return self.cursor.lastrowid
+
def update(self, *args):
self.cursor.execute(QU.update_movie, args)
@@ -72,7 +126,39 @@ class Movies(Kodi):
self.cursor.execute(QU.delete_file, (file_id,))
self.cursor.execute(QU.check_video_version)
if self.cursor.fetchone()[0] == 1:
+ # Cleanup version types
+ versions = self.get_videoversions(kodi_id)
+ type_id = next((row[0] for row in versions if row[1] == file_id), None)
self.cursor.execute(QU.delete_video_version, (file_id,))
+ self.delete_unused_version_type(type_id)
+
+ # Remove all other versions; Jellyfin creates a new base entry if other versions are left
+ for row in versions:
+ self.delete_video_version(row[1], row[0])
+
+ def delete_video_version(self, file_id, type_id):
+ """Remove video version file and cleanup version type if unused."""
+ self.cursor.execute(QU.delete_file, (file_id,))
+ self.cursor.execute(QU.delete_video_version, (file_id,))
+ self.delete_unused_version_type(type_id)
+
+ def delete_unused_version_type(self, type_id):
+ """Delete video version type if no references exist, and its not a builtin type."""
+ if type_id and type_id > 40800:
+ self.cursor.execute(QU.count_video_version_type, (type_id,))
+ if self.cursor.fetchone()[0] == 0:
+ self.cursor.execute(QU.delete_video_version_type, (type_id,))
+
+ def get_videoversions(self, kodi_id):
+ self.cursor.execute(QU.get_video_versions, (kodi_id,))
+ return self.cursor.fetchall()
+
+ def check_movie_file_primary(self, kodi_id, file_id):
+ """Return True if the movie row with idMovie matches the provided idFile."""
+ self.cursor.execute(QU.check_movie_file_primary, (kodi_id, file_id))
+ row = self.cursor.fetchone()
+
+ return row is not None
def get_rating_id(self, *args):
diff --git a/jellyfin_kodi/objects/kodi/queries.py b/jellyfin_kodi/objects/kodi/queries.py
index 86b0b8ba..0ebb84a8 100644
--- a/jellyfin_kodi/objects/kodi/queries.py
+++ b/jellyfin_kodi/objects/kodi/queries.py
@@ -70,12 +70,13 @@ FROM files
WHERE idPath = ?
AND strFilename = ?
"""
-get_file_obj = ["{FileId}"]
+get_file_obj = ["{PathId}", "{Filename}"]
get_filename = """
SELECT strFilename
FROM files
WHERE idFile = ?
"""
+get_filename_obj = ["{FileId}"]
get_all_people = """
SELECT name, actor_id
FROM actor
@@ -416,8 +417,30 @@ add_video_version_obj = [
"{MovieId}",
"movie",
"{VideoVersionItemType}",
- 40400,
+ "{VideoVersionTypeId}",
]
+update_video_version = """
+UPDATE videoversion
+SET idMedia = ?, media_type = ?, itemType = ?, idType = ?
+WHERE idFile = ?
+"""
+update_video_version_obj = [
+ "{MovieId}",
+ "movie",
+ "{VideoVersionItemType}",
+ "{VideoVersionTypeId}",
+ "{FileId}",
+]
+count_video_version = """
+SELECT COUNT(*) FROM videoversion WHERE idFile = ? AND idMedia = ? AND idType = ?
+"""
+count_video_version_obj = ["{FileId}", "{MovieId}", "{VideoVersionTypeId}"]
+count_video_version_type = """
+SELECT COUNT(*) FROM videoversion WHERE idType = ?
+"""
+get_video_versions = """
+SELECT DISTINCT idType, idFile FROM videoversion WHERE idMedia = ?
+"""
get_videoversion_itemtype = """
SELECT itemType FROM videoversiontype WHERE id = ?
"""
@@ -425,6 +448,18 @@ get_videoversion_itemtype_obj = ["{VideoVersionId}"]
check_video_version = """
SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='videoversion'
"""
+get_video_version_type = """
+SELECT id FROM videoversiontype WHERE name = ? and itemType = ?
+"""
+add_video_version_type = """
+INSERT INTO videoversiontype(name, owner, itemType) VALUES (?, ?, ?)
+"""
+get_max_video_version_type = """
+SELECT MAX(id) FROM videoversiontype
+"""
+check_movie_file_primary = """
+SELECT 1 FROM movie WHERE idMovie = ? AND idFile = ? LIMIT 1
+"""
add_musicvideo = """
INSERT INTO musicvideo(idMVideo, idFile, c00, c04, c05, c06, c07, c08, c09, c10,
c11, c12, premiered)
@@ -801,6 +836,11 @@ delete_video_version = """
DELETE FROM videoversion
WHERE idFile = ?
"""
+delete_video_version_type = """
+DELETE FROM videoversiontype
+WHERE id = ?
+AND owner = 1
+"""
delete_set = """
DELETE FROM sets
WHERE idSet = ?
diff --git a/jellyfin_kodi/objects/movies.py b/jellyfin_kodi/objects/movies.py
index e155af9e..f989761a 100644
--- a/jellyfin_kodi/objects/movies.py
+++ b/jellyfin_kodi/objects/movies.py
@@ -16,6 +16,7 @@ from ..helper import (
jellyfin_item,
values,
Local,
+ settings,
)
from ..helper import LazyLogger
from ..helper.utils import find_library
@@ -66,6 +67,11 @@ class Movies(KodiDb):
obj["PathId"] = e_item[2]
obj["LibraryId"] = e_item[6]
obj["LibraryName"] = self.jellyfin_db.get_view_name(obj["LibraryId"])
+
+ if settings("useVersions") == "true":
+ # Only process primary movie files, not versions and extras; those are processed in add_versions.
+ if not self.check_movie_file_primary(obj["MovieId"], obj["FileId"]):
+ return
except TypeError:
update = False
LOG.debug("MovieId %s not found", obj["Id"])
@@ -127,6 +133,7 @@ class Movies(KodiDb):
tags.append("Favorite movies")
obj["Tags"] = tags
+ obj["media_sources"] = item.get("MediaSources")
if update:
self.movie_update(obj)
@@ -142,10 +149,80 @@ class Movies(KodiDb):
self.add_people(*values(obj, QU.add_people_movie_obj))
self.add_streams(*values(obj, QU.add_streams_obj))
self.artwork.add(obj["Artwork"], obj["MovieId"], "movie")
+ self.artwork.add(obj["Artwork"], obj["FileId"], "videoversion")
self.item_ids.append(obj["Id"])
+ self.current_type_ids = set()
+ self.add_versions(API, obj)
+ self.add_versions(API, obj, True) # Add extras as versions
+ self.cleanup_versions(obj)
return not update
+ def add_versions(self, API, obj, extra=False):
+ """Add all additional media sources as Kodi versions."""
+ if settings("useVersions") != "true" or (extra and settings("useExtras") != "true"):
+ return
+
+ sources = self.server.jellyfin.get_extras(obj["Id"]) if extra else obj["media_sources"]
+ for source in sources:
+ if obj["Id"] == source["Id"]:
+ # Found primary version, so skip
+ continue
+
+ # Extras already in the right format from get_extras, but versions need to be pulled
+ jfitem = source if extra else self.server.jellyfin.get_item(source["Id"])
+ version = self.objects.map(jfitem, "Movie")
+ version["MovieId"] = obj["MovieId"]
+ version["LibraryId"] = obj["LibraryId"]
+ version["JellyfinParentId"] = obj["Id"]
+
+ # Version specific metadata
+ version["DateAdded"] = Local(version["DateAdded"]).split(".")[0].replace("T", " ")
+ version["Resume"] = API.adjust_resume((version["Resume"] or 0) / 10000000.0)
+ version["Runtime"] = round(float((version["Runtime"] or 0) / 10000000.0), 6)
+ version["PlayCount"] = API.get_playcount(version["Played"], version["PlayCount"])
+ version["Video"] = API.video_streams(version["Video"] or [], version["Container"])
+ version["Audio"] = API.audio_streams(version["Audio"] or [])
+ version["Streams"] = API.media_streams(version["Video"], version["Audio"], version["Subtitles"])
+ version["Artwork"] = API.get_all_artwork(self.objects.map(jfitem, "Artwork"))
+ if version["DatePlayed"]:
+ version["DatePlayed"] = Local(version["DatePlayed"]).split(".")[0].replace("T", " ")
+
+ version["Path"] = API.get_file_path(version["Path"])
+ self.get_path_filename(version)
+ version["PathId"] = self.add_path(*values(version, QU.add_path_obj))
+
+ # Find the correct version name for this source
+ version_type_id = self.get_or_create_videoversiontype(source.get("Name"), version["SourceFilename"], extra)
+ version["VideoVersionTypeId"] = version_type_id
+ version["VideoVersionItemType"] = self.itemtype + 1 if extra else self.itemtype
+ self.current_type_ids.add(version_type_id)
+
+ version["FileId"] = self.get_file(*values(version, QU.get_file_obj))
+ if version["FileId"]:
+ # Version already exists
+ self.update_videoversion(*values(version, QU.update_video_version_obj))
+ self.jellyfin_db.update_reference(*values(version, QUEM.update_reference_obj))
+ else:
+ # Add the version file and version type
+ version["FileId"] = self.add_file(*values(version, QU.add_file_obj))
+ self.add_videoversion(*values(version, QU.add_video_version_obj))
+ self.jellyfin_db.add_reference(*values(version, QUEM.add_reference_movie_obj))
+
+ self.update_file(*values(version, QU.update_file_obj))
+ self.add_playstate(*values(version, QU.add_bookmark_obj))
+ self.add_streams(*values(version, QU.add_streams_obj))
+ self.artwork.add(version["Artwork"], version["FileId"], "videoversion")
+
+ def cleanup_versions(self, obj):
+ """Cleanup versions that are no longer in Jellyfin"""
+ versions = self.get_videoversions(obj["MovieId"])
+ for row in versions:
+ type_id = row[0]
+ file_id = row[1]
+ if file_id != obj["FileId"] and type_id not in self.current_type_ids:
+ self.delete_video_version(file_id, type_id)
+
def movie_add(self, obj):
"""Add object to kodi."""
obj["RatingId"] = self.create_entry_rating()
@@ -158,6 +235,15 @@ class Movies(KodiDb):
obj["FileId"] = self.add_file(*values(obj, QU.add_file_obj))
obj["VideoVersionItemType"] = self.itemtype
+ version_name = None
+ for source in obj["media_sources"]:
+ # First media source isn't always the main version, so find the correct version name for the primary
+ if obj["Id"] == source["Id"]:
+ version_name = source.get("Name")
+ break
+ version_type_id = self.get_or_create_videoversiontype(version_name, obj["SourceFilename"])
+ obj["VideoVersionTypeId"] = version_type_id
+
self.add(*values(obj, QU.add_movie_obj))
self.add_videoversion(*values(obj, QU.add_video_version_obj))
self.jellyfin_db.add_reference(*values(obj, QUEM.add_reference_movie_obj))
@@ -217,6 +303,7 @@ class Movies(KodiDb):
if "\\" in obj["Path"]
else obj["Path"].rsplit("/", 1)[1]
)
+ obj["SourceFilename"] = obj["Filename"]
if self.direct_path:
@@ -225,18 +312,20 @@ class Movies(KodiDb):
obj["Path"] = obj["Path"].replace(obj["Filename"], "")
+ sl = "\\" if "\\" in obj["Path"] else "/"
"""check dvd directories and point it to ./VIDEO_TS/VIDEO_TS.IFO"""
if validate_dvd_dir(obj["Path"] + obj["Filename"]):
- obj["Path"] = obj["Path"] + obj["Filename"] + "/VIDEO_TS/"
+ obj["Path"] = obj["Path"] + obj["Filename"] + sl + "VIDEO_TS" + sl
obj["Filename"] = "VIDEO_TS.IFO"
LOG.debug("DVD directory %s", obj["Path"])
"""check bluray directories and point it to ./BDMV/index.bdmv"""
if validate_bluray_dir(obj["Path"] + obj["Filename"]):
- obj["Path"] = obj["Path"] + obj["Filename"] + "/BDMV/"
+ obj["Path"] = obj["Path"] + obj["Filename"] + sl + "BDMV" + sl
obj["Filename"] = "index.bdmv"
LOG.debug("Bluray directory %s", obj["Path"])
+ obj["SourceFilename"] = obj["Filename"]
else:
obj["Path"] = "plugin://plugin.video.jellyfin/%s/" % obj["LibraryId"]
params = {
diff --git a/jellyfin_kodi/objects/tvshows.py b/jellyfin_kodi/objects/tvshows.py
index ee6dbd7c..d76f1cd8 100644
--- a/jellyfin_kodi/objects/tvshows.py
+++ b/jellyfin_kodi/objects/tvshows.py
@@ -616,7 +616,7 @@ class TVShows(KodiDb):
temp_obj = dict(obj)
temp_obj["Filename"] = self.get_filename(
- *values(temp_obj, QU.get_file_obj)
+ *values(temp_obj, QU.get_filename_obj)
)
temp_obj["Path"] = "plugin://plugin.video.jellyfin/"
self.remove_file(*values(temp_obj, QU.delete_file_obj))
@@ -625,7 +625,7 @@ class TVShows(KodiDb):
temp_obj = dict(obj)
temp_obj["Filename"] = self.get_filename(
- *values(temp_obj, QU.get_file_obj)
+ *values(temp_obj, QU.get_filename_obj)
)
temp_obj["PathId"] = self.get_path("plugin://plugin.video.jellyfin/")
temp_obj["FileId"] = self.add_file(*values(temp_obj, QU.add_file_obj))
diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po
index 62ddb511..ff121ea9 100644
--- a/resources/language/resource.language.en_gb/strings.po
+++ b/resources/language/resource.language.en_gb/strings.po
@@ -1257,3 +1257,10 @@ msgctxt "#33261"
msgid "Off"
msgstr "Off"
+msgctxt "#30900"
+msgid "Sync video versions"
+msgstr "Sync video versions"
+
+msgctxt "#30901"
+msgid "Sync video extras"
+msgstr "Sync video extras"
diff --git a/resources/language/resource.language.en_us/strings.po b/resources/language/resource.language.en_us/strings.po
index 84f63066..5a4a742e 100644
--- a/resources/language/resource.language.en_us/strings.po
+++ b/resources/language/resource.language.en_us/strings.po
@@ -1180,3 +1180,11 @@ msgstr "16.0 Mbps"
msgctxt "#33239"
msgid "96"
msgstr "96"
+
+msgctxt "#30900"
+msgid "Sync video versions"
+msgstr "Sync video versions"
+
+msgctxt "#30901"
+msgid "Sync video extras"
+msgstr "Sync video extras"
diff --git a/resources/settings.xml b/resources/settings.xml
index bd83d8e4..fe01420c 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -108,6 +108,19 @@
+
+ 0
+ false
+
+
+