Erste Erkenntnis....
json.load ist was anderes als json.loads
Das eine liest von einer Datei und das andere von einem String. Das muss man erstmal wissen
Erste Erkenntnis....
json.load ist was anderes als json.loads
Das eine liest von einer Datei und das andere von einem String. Das muss man erstmal wissen
Vielleicht kannst du hier schon mal unterstützen
import xbmc
import xbmcaddon
import xbmcgui
import datetime
import json
addon = xbmcaddon.Addon()
addonname = addon.getAddonInfo('name')
now = datetime.datetime.now()
#kodi_time = now.strftime("%Y-%m-%d %H:%M:%S")
kodi_time="2022-03-07 17:09:54"
response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : [ "lastplayed", "playcount" ], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}')
data = json.loads(response)
single_movie = str(data['result']['movies'][0]['label'])
# kodi lists the total of its movie in its json-output (thankfully)
# let..s save that for the usage in range(x)
total=data['result']['limits']['end']
# for every item in the total of the movies
# that..s not the movie-id
for i in range(total):
# get lastplayed date
last_p=(data['result']['movies'][i]['lastplayed'])
# get playcount (probably not needed yet)...note, that..s an int
playcount=(data['result']['movies'][i]['playcount'])
# get current movie-id
movieid=data['result']['movies'][i]['movieid']
# get current movie label
label=data['result']['movies'][i]['label']
# if lastplayed value is not empty
if last_p != "":
# format string to date
last_date = datetime.datetime.strptime(last_p, "%Y-%m-%d %H:%M:%S")
# add 365 to lasteplayed date
lastp_plus_year = last_date + datetime.timedelta(days=365)
# check if lastplayed + 365 is lower than then the current date
if str(lastp_plus_year) < str(kodi_time):
ans = str(label)
#print("Reset playcount and lastplayed for movieid: " + str(movieid))
xbmcgui.Dialog().ok(addonname, ans)
Alles anzeigen
Das funktioniert soweit und durch die Anpassung des Datums (habe ich halt in dem Fall mal hart eingetragen) bekomme ich in einem Dialog auch nur einen einzigen Film aus meiner Dateibank angezeigt.
Soweit so gut....führe ich das Script aber nun ein 2. Mal aus, dann bekomme ich eine Notification angezeigt welche mir sagt, dass ich das Logfile anschauen soll. Da steht dann:
https://paste.kodi.tv/osotugazax
Und das verstehe ich gerade nicht, warum das nur beim 2. Durchlauf der Fall ist.
Starte ich Kodi neu, dann läuft das einwandfrei wieder für 1 Mal durch. Es klingt für mich irgendwie so, als gäbe es ein Problem mit einer der Variablen, dass die nicht aufgerufen werden können. Ich verstehe halt nur nicht warum.
Danke im Voraus.
@PvD (sorry, wenn ich dich so oft pinge....)
Ich habe noch ein wenig geforscht und ein paar Logmessages ins Kodi Log gehauen. Mir fällt auf, dass o. g. Fehler nur dann auftritt, wenn
Der Hase liegt also tatsächlich irgendwo in Zeile 38 im Pfeffer
Und ich verstehe es tatsächlich immer noch nicht. Ich schreibe einen String in last_p und lasse den in Zeile 38 in ein Datumsformat wandeln. Warum klappt das beim ersten Mal und warum ist es beim 2. Mail ein "NoneType"?
datetime.datetime.strptime() unter Python ist mehr oder weniger kaputt. Es liegt nicht - wie man evtl. vermutet - an der Variablen last_p, sondern (unter ganz bestimmnten Laufzeitbedingungen) am datetime-Modul.
Das führt Dich dahin (auch mit einer Lösung): https://stackoverflow.com/questions/4039…e-in-python-3-4
Bugreport: https://bugs.python.org/issue27400
Selbst Google ist nicht davor gefeit. Das oauth-Modul besitzt das gleich Issue, weswegen es bei uns im Repo ein gefixtes oauth gibt. Trotz Bugreport ist sich Google aber zu fein, das in Ihren APIs zu fixen. Pech gehabt.
Lange Rede kurzer Sinn, versuche mal anstelle von:
Quellcode
Awesome thanks.
Das schaue ich mir heute nachmittag an. Vielen vielen Dank
Nicht vergessen, dass man time dann natürlich auch noch importieren muss.
Nachdem der Fehler jetzt gelöst ist (das Problem kannte ich noch gar nicht), würde ich ein paar Verbesserungen am Code vorschlagen:
Statt import datetime würde ich direkt from datetime import datetime importieren. Dann wird weniger importiert, was das Ganze minimal schneller machen sollte und man spart sich etwas Schreibarbeit, weil man z.B. in Zeile 10 statt datetime.datetime.now() jetzt datetime.now() nutzen kann. Wenn man sehr schreibfaul ist (wie ich), kann man auch from datetime import datetime as dt machen und dann dt.now() nutzen.
Bei der for-Schleife würde ich so was versuchen:
Dann brauchst du auch die Variable total gar nicht.
In Zeile 36 würde ich dann gleich 2 Änderungen machen:
Du überprüfst hier nur, ob last_p ein leerer String ist, oder nicht. Um den Code robuster zu machen, könntest du noch andere Fälle abdecken, indem du einfach nur if last_p: nutzt. Ein leerer String wird nämlich als False interpretiert, genau so wie eine 0 oder None. Alles andere wird als True gewertet (evtl. gibt es noch eine Ausnahme, die mir gerade nicht einfällt).
Und es ist weniger Schreibarbeit
Insgesamt hast du in den letzten Zeilen ziemlich viel Einrückung. So etwas mache ich gerne etwas flacher, indem ich die Logik bei Conditions umdrehe. Also statt
if last_p:
# format string to date
last_date = datetime.datetime.strptime(last_p, "%Y-%m-%d %H:%M:%S")
#...
Würde ich schreiben
if not last_p:
continue
# format string to date
last_date = datetime.datetime.strptime(last_p, "%Y-%m-%d %H:%M:%S")
#...
continue bedeutet, dass die for-Schleife mit dem nächsten Element weiter machen soll. Alles darunter wird also nicht mehr ausgeführt, sondern erst wieder mit dem nächsten i bzw. movie
In Zeile 42 vergleichst du zwei Daten, indem du beide in einen String umwandelst. Das kann schnell zu Fehlern führen. Ich würde lieber if lastp_plus_year < now: machen. Für deine Tests müsstest du now dann eben erzeugen wie bei last_date, also mit strptime von datetime oder time.
Zu guter Letzt die Variable ans:
Die wird mit jedem Schritt der for-Schleife wieder überschrieben und enthält am Ende nur den label-Wert des letzten Films. Ich vermute du willst eher eine Liste, d.h. vor die Schleife (Z. 25) kommt ans = list() und in Zeile 43 dann ans.append(str(label))
Vermutlich musst du aus ans dann in Zeile 46 wieder einen String machen, da weiß ich nicht wie xbmcgui.Dialog().ok() mit einer Liste umgehen würde.
Vermutlich musst du aus ans dann in Zeile 46 wieder einen String machen, da weiß ich nicht wie xbmcgui.Dialog().ok() mit einer Liste umgehen würde.
Ja, das wusste ich sogar schon ;). Aber vielen Dank
Statt import datetime würde ich direkt from datetime import datetime importieren.
Das hatte ich schon probiert. Ich konnte dann aber [tt]strptime[/tt| nicht verwenden, wenn ich richtig liege. Das muss ich mir aber nochmal anschauen.
Vielen Dank für die Hinweise. Ich werds heute Abend umsetzen
So...das meiste ist umgesetzt und funktioniert auch schon. Jetzt muss ich noch ein wenig kreativ beim Icon werden und vielleicht baue ich noch ein Setting für die Tage ein.
Falls jemand noch ne Idee hat, was man noch implementieren könnte, dann bin ich für Vorschläge offen. Werd's dann nachher noch in mein Git pushen
Habe zwar keinen Anwendungsfall hierfür, aber warum nur Tage bei den Settings anbieten?
Macht doch drei Variablen rein Tage, Monate und Jahre. So kann dann wirklich jeder nach seinem Geschmack auswählen wann etwas als ungesehen markiert werden soll.
Muss ich mir anschauen. Wenn ich nicht ganz falsch liege, dann bietet mir "Timedelta" (was offensichtlich für das hinzufügen von Tagen verantwortlich ist) die Einheit "Tage" als Maximum an.
Vielleicht kann ich ein anderes Modul verwenden.
Was ich noch mit einbauen werde, sind Episoden.
Ja, das ist klar. Ich kann eine Berechnung machen. Die kann ich entweder im Script machen oder es dem User überlassen, welchen Wert er da eintragen möchte und das als Setting verfügbar machen.
Ich kann dem User aber keine Möglichkeit geben eine bestimmte Anzahl an Monaten zu definieren, da ich nur Tage berechnen kann und jeder Monat unterschiedliche Anzahl an Tagen hat. Ich könnte einen Monatsdurchschnitt berechnen: 365 / 12, was dann 30,4166666667 Tage wären und so könnte ich dann einen Montag berechen:
(Ich glaube die Klammern bei dtnow() sind nicht korrekt....zumindest wirft es mit einen Fehler, wenn ich dein Script oben kopiere und ausführe ohne die Klammern klappt es)
Das finde ich aber ziemlich ungenau.
Und ja...das ich "timedelta" zusätzlich importieren muss, habe ich auch schon gemerkt ;). Daher habe ich auch einfach "datetime" komplett importiert.
Weiter ist das Problem, welches ich habe (weswegen ich es vielleicht so umständlich geschrieben habe), dass ich verschiedene Typen bekomme:
in deinem Beispiel oben ist "dtnow" ein Typ <class 'datetime.datetime'> und gibt mir bei einer Ausgabe auch Millisekunden mit, die ich zum Vergleich nicht brauche/möchte. Also muss ich die einmal wandeln (mit strftime). Nach der Wandlung ist es dann aber ein Typ "str".
Aus dem JSON bekomme ich einen Typ "str"...um damit Berechnungen via "timedelta" machen zu können muss ich den String erst wieder zurück zu einem Typ "<class 'datetime.datetime'>" machen (via "strptime")
Ich werde auf jeden Fall mal den import anpassen....datetime und timedelta von datetime schein tatsächlich ausreichend zu sein
In der Zeile 42 kann ich mit wahrscheinlich einen "str" im Vergleich sparen, da kodi_time schon ein "str" ist (entweder weil ich es so rein schreibe bzw. durch die Wandlung mit "strftime"). In jedem Fall muss es auf beiden Seiten ein String sein, damit ich es vergleichen kann. So zumindest mein Verständnis bisher
In jedem Fall muss es auf beiden Seiten ein String sein, damit ich es vergleichen kann. So zumindest mein Verständnis bisher
Nein. Datetime-Objekte kann man direkt vergleichen. Ein Stringvergleich kann gehörig in die Hose gehen, z.B. ergibt print('01.12.2020' < '30.11.2020') True, was aber bezogen auf das Datum nicht stimmt. Der Stringvergleich vergleicht zeichenweise von Anfang beginnend beide Zeichenketten und da ist '0' schonmal kleiner als '3'. Ein direkter Vergleich der Datetimeobjekte macht das richtig (dazu sind sie ja da).
Ok...ist es dann beim Vergleich egal ob es Millisekunden hat oder nicht? Denn dann würde ich nur den JSON Wert zu einem datetime-Objekt wandeln und könnte so dann diese Werte miteinander vergleichen.
Vom JSON bekomme ich halt nur "YYYY-mm-dd HH:MM:SS" als String
Denn dann würde ich nur den JSON Wert zu einem datetime-Objekt wandeln und könnte so dann diese Werte miteinander vergleichen.
Das ist der richtige Weg. Das JSON-Format würe ich als Konstante nach den Imports definieren, dann hast Du weniger Schreibkram: JSON_TIME_FMT = '%Y-%m-%d %H:%M:%S', bei der Umwandlung in datetime einfach nur (Zeile 38): last_date = datetime.datetime.strptime(last_p, JSON_TIME_FMT)
Ich habe mal noch den Formatkram oben geändert. Es ist noch früh und mein Hirn arbeitet noch mechanisch...
print('01.12.2020' < '30.11.2020')
Deutsche Schreibweise ist halt doof
'2020-12-01' < '2020-11-30'
Es geht um den Stringvergleich ansich und nicht um die deutsche Schreibweise eines Datums.
ja schon klar das man Datum nicht als String vergleichen sollte, aber bei der Deuschen Schreibweise gehts halt gar nicht.
Bei der chinesischen auch nicht und selbst bei der amerikanischen mit '2020/01/12' oder '2020/12/01' kann man sich nicht sicher sein.
Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!