-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support rewatch feature #631
base: main
Are you sure you want to change the base?
Changes from 3 commits
309f444
be33a6a
c058028
50de3cb
e35e7fb
1269a1e
b96afcd
695a3e2
dd8d70b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -165,11 +165,13 @@ def kodiRpcToTraktMediaObject(type, data, mode='collected'): | |
data['ids'] = utilities.guessBestTraktId(id, type)[0] | ||
|
||
if 'lastplayed' in data: | ||
episode['watched_at'] = utilities.convertDateTimeToUTC( | ||
data['lastplayed']) | ||
episode['last_watched_at'] = utilities.to_iso8601_datetime( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The key There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kodi's timestamps were in a different format from those the Trakt.py library provides so this was updated. |
||
utilities.from_datetime(data['lastplayed']) | ||
) | ||
if 'dateadded' in data: | ||
episode['collected_at'] = utilities.convertDateTimeToUTC( | ||
data['dateadded']) | ||
episode['collected_at'] = utilities.to_iso8601_datetime( | ||
utilities.from_datetime(data['dateadded']) | ||
) | ||
if 'runtime' in data: | ||
episode['runtime'] = data['runtime'] | ||
episode['rating'] = data['userrating'] if 'userrating' in data and data['userrating'] > 0 else 0 | ||
|
@@ -184,11 +186,13 @@ def kodiRpcToTraktMediaObject(type, data, mode='collected'): | |
if checkExclusion(data.pop('file')): | ||
return | ||
if 'lastplayed' in data: | ||
data['watched_at'] = utilities.convertDateTimeToUTC( | ||
data.pop('lastplayed')) | ||
data['last_watched_at'] = utilities.to_iso8601_datetime( | ||
utilities.from_datetime(data.pop('lastplayed')) | ||
) | ||
if 'dateadded' in data: | ||
data['collected_at'] = utilities.convertDateTimeToUTC( | ||
data.pop('dateadded')) | ||
data['collected_at'] = utilities.to_iso8601_datetime( | ||
utilities.from_datetime(data.pop('dateadded')) | ||
) | ||
if data['playcount'] is None: | ||
data['plays'] = 0 | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,9 +208,11 @@ def __traktLoadShows(self): | |
int(y), line2=kodiUtilities.getString(32102) % (i, x)) | ||
|
||
# will keep the data in python structures - just like the KODI response | ||
show = show.to_dict() | ||
|
||
showsWatched['shows'].append(show) | ||
show_dict = show.to_dict() | ||
# reset_at is not included when calling `.to_dict()` | ||
# but needed for watched shows to know whether to reset the watched state | ||
show_dict['reset_at'] = utilities.to_iso8601_datetime(show.reset_at) if hasattr(show, 'reset_at') else None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
showsWatched['shows'].append(show_dict) | ||
|
||
i = 0 | ||
x = float(len(traktShowsRated)) | ||
|
@@ -425,6 +427,10 @@ def __addEpisodesToKodiWatched(self, traktShows, kodiShows, kodiShowsCollected, | |
updateKodiTraktShows = copy.deepcopy(traktShows) | ||
updateKodiKodiShows = copy.deepcopy(kodiShows) | ||
|
||
if kodiUtilities.getSettingAsBool('kodi_episode_reset'): | ||
utilities.updateTraktLastWatchedBasedOnResetAt( | ||
updateKodiTraktShows, updateSpecials=kodiUtilities.getSettingAsBool('kodi_episode_reset_specials')) | ||
|
||
kodiShowsUpdate = utilities.compareEpisodes(updateKodiTraktShows, updateKodiKodiShows, kodiUtilities.getSettingAsBool( | ||
"scrobble_fallback"), watched=True, restrict=True, collected=kodiShowsCollected) | ||
|
||
|
@@ -446,7 +452,7 @@ def __addEpisodesToKodiWatched(self, traktShows, kodiShows, kodiShowsCollected, | |
for season in show['seasons']: | ||
for episode in season['episodes']: | ||
episodes.append({'episodeid': episode['ids']['episodeid'], 'playcount': episode['plays'], | ||
"lastplayed": utilities.convertUtcToDateTime(episode['last_watched_at'])}) | ||
"lastplayed": utilities.to_datetime(utilities.from_iso8601_datetime(episode['last_watched_at']))}) | ||
|
||
# split episode list into chunks of 50 | ||
chunksize = 50 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
import dateutil.parser | ||
from datetime import datetime | ||
from dateutil.tz import tzutc, tzlocal | ||
import arrow | ||
razzeee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# make strptime call prior to doing anything, to try and prevent threading | ||
# errors | ||
|
@@ -181,40 +182,49 @@ def findEpisodeMatchInList(id, seasonNumber, episodeNumber, list, idType): | |
return {} | ||
|
||
|
||
def convertDateTimeToUTC(toConvert): | ||
if toConvert: | ||
dateFormat = "%Y-%m-%d %H:%M:%S" | ||
try: | ||
naive = datetime.strptime(toConvert, dateFormat) | ||
except TypeError: | ||
naive = datetime(*(time.strptime(toConvert, dateFormat)[0:6])) | ||
|
||
try: | ||
local = naive.replace(tzinfo=tzlocal()) | ||
utc = local.astimezone(tzutc()) | ||
except ValueError: | ||
logger.debug( | ||
'convertDateTimeToUTC() ValueError: movie/show was collected/watched outside of the unix timespan. Fallback to datetime utcnow') | ||
utc = datetime.utcnow() | ||
return str(utc) | ||
else: | ||
return toConvert | ||
|
||
|
||
def convertUtcToDateTime(toConvert): | ||
if toConvert: | ||
dateFormat = "%Y-%m-%d %H:%M:%S" | ||
try: | ||
naive = dateutil.parser.parse(toConvert) | ||
utc = naive.replace(tzinfo=tzutc()) | ||
local = utc.astimezone(tzlocal()) | ||
except ValueError: | ||
logger.debug( | ||
'convertUtcToDateTime() ValueError: movie/show was collected/watched outside of the unix timespan. Fallback to datetime now') | ||
local = datetime.now() | ||
return local.strftime(dateFormat) | ||
else: | ||
return toConvert | ||
def to_datetime(value): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I replaced the existing datetime transformation methods with these 4 new ones, the iso8601 methods come from the trakt.py library. |
||
if not value: | ||
return None | ||
|
||
return value.strftime('%Y-%m-%d %H:%M:%S') | ||
|
||
|
||
def from_datetime(value): | ||
if not value: | ||
return None | ||
|
||
if arrow is None: | ||
raise Exception('"arrow" module is not available') | ||
|
||
# Parse datetime | ||
dt = arrow.get(value, 'YYYY-MM-DD HH:mm:ss') | ||
|
||
# Return datetime object | ||
return dt.datetime | ||
|
||
|
||
def to_iso8601_datetime(value): | ||
if not value: | ||
return None | ||
|
||
return value.strftime('%Y-%m-%dT%H:%M:%S') + '.000-00:00' | ||
|
||
|
||
def from_iso8601_datetime(value): | ||
if not value: | ||
return None | ||
|
||
if arrow is None: | ||
raise Exception('"arrow" module is not available') | ||
|
||
# Parse ISO8601 datetime | ||
dt = arrow.get(value, 'YYYY-MM-DDTHH:mm:ss.SZZ') | ||
|
||
# Convert to UTC | ||
dt = dt.to('UTC') | ||
|
||
# Return datetime object | ||
return dt.datetime | ||
|
||
|
||
def createError(ex): | ||
|
@@ -412,6 +422,12 @@ def compareEpisodes(shows_col1, shows_col2, matchByTitleAndYear, watched=False, | |
if season in season_col2: | ||
b = season_col2[season] | ||
diff = list(set(a).difference(set(b))) | ||
for key in a: | ||
# update lastplayed in KODI if they don't match trakt | ||
if not key in b or a[key]['last_watched_at'] != b[key]['last_watched_at']: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a 100% sure is this is the correct solution. This will update any out of date timestamps not just ones to be removed. |
||
diff.append(key) | ||
# make unique | ||
diff = list(set(diff)) | ||
if playback: | ||
t = list(set(a).intersection(set(b))) | ||
if len(t) > 0: | ||
|
@@ -571,3 +587,17 @@ def _fuzzyMatch(string1, string2, match_percent=55.0): | |
s = difflib.SequenceMatcher(None, string1, string2) | ||
s.find_longest_match(0, len(string1), 0, len(string2)) | ||
return (difflib.SequenceMatcher(None, string1, string2).ratio() * 100) >= match_percent | ||
|
||
|
||
def updateTraktLastWatchedBasedOnResetAt(traktShows, updateSpecials=False): | ||
for show in traktShows['shows']: | ||
if show['reset_at']: | ||
reset_at = from_iso8601_datetime(show['reset_at']) | ||
for season in show['seasons']: | ||
if not updateSpecials and season['number'] == 0: | ||
continue | ||
for episode in season['episodes']: | ||
last_watched = from_iso8601_datetime(episode['last_watched_at']) | ||
if last_watched and last_watched < reset_at: | ||
episode['last_watched_at'] = None | ||
episode['plays'] = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I generate the correct po files and add the missing translations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The base translation file is
en_gb
so you should only be editing thatThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm noticing errors in git due to there being a
en_US
anden_us
language folder for example.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's probably a windows thing