god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Hallo
Ich glaube, dann habe ich da etwas Grundsätzliches nicht verstanden.
- ich dachte bisher, dass die rhythmdb.xml eine lokale Liste wäre, in der alle gespielten Titel verzeichnet sind. Ist das nicht so?
Ja, das ist meines wissens auch so.
Ok, dann scheint es also keine "falsche Art Tags" zu geben, sondern das Problem liegt woanders.
→ Vielleicht sollten wir mal der Fehlermeldung folgen, und den Datensatz 3275 mal genauer betrachten ?
Ich bin im Augenblick nicht an meinem Heimrechner, aber ich weiß, dass Rhythmbox bei verschiedenen Datensätzen abgestürzt ist. Bye Marcus
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Hallo
seahawk1986 ich habe mal nachfolgenden Befehl versucht:
| python merge_rhythmdb_playcount.py --output rhythmdp-merge.xml rhythmdb_alt.xml rhythmdb.xml
|
und bekomme folgende Fehlermeldung:
Traceback (most recent call last):
File "merge_rhythmdb_playcount.py", line 27, in <module>
matches = root.findall(searchstring)
File "src/lxml/lxml.etree.pyx", line 1563, in lxml.etree._Element.findall (src/lxml/lxml.etree.c:61450)
File "/usr/lib/python2.7/dist-packages/lxml/_elementpath.py", line 304, in findall
return list(iterfind(elem, path, namespaces))
File "/usr/lib/python2.7/dist-packages/lxml/_elementpath.py", line 277, in iterfind
selector = _build_path_iterator(path, namespaces)
File "/usr/lib/python2.7/dist-packages/lxml/_elementpath.py", line 260, in _build_path_iterator
selector.append(ops[token[0]](_next, token))
File "/usr/lib/python2.7/dist-packages/lxml/_elementpath.py", line 214, in prepare_predicate
raise SyntaxError("invalid predicate")
SyntaxError: invalid predicate Bye
Marcus
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ah - unter Ubuntu 16.04 musst man statt python3 statt python nehmen, damit er den richtigen Interpreter nimmt (ich hatte das unter Arch Linux ausprobiert, da ist python3 der Standard).
Kannst du eventuell mal die beiden xml-Dateien anhängen? Dann hätte ich das passende Material, um nachzuvollziehen, was da genau schiefgeht.
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Hallo seahawk1986 danke schonmal für deine Bemühungen.
Ich kenne mich leider nicht mit Python aus.
War der Syntax meines letzten Befehls denn richtig ?
Hier noch ein Versuch: | python3 merge_rhythmdb_playcount.py --output rhythmdp-merge.xml rhythmdb_alt.xml rhythmdb.xml
|
Fehlermeldung:
Traceback (most recent call last):
File "merge_rhythmdb_playcount.py", line 30, in <module>
(int(entry.find('./play-count').text) for entry in matches)
File "merge_rhythmdb_playcount.py", line 30, in <genexpr>
(int(entry.find('./play-count').text) for entry in matches)
AttributeError: 'NoneType' object has no attribute 'text' Die rhytmdbs sind je 28MB groß. Wie soll ich sie denn anhängen ?
Möchtes du sie als Email haben ? Bye Marcus
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ok, da hat ein Eintrag keinen play-count und das Skript rechnet damit, dass der existiert - probier es mal so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | #!/usr/bin/env python3
import argparse
from copy import deepcopy
import lxml.etree
parser = argparse.ArgumentParser(
description='merge play-count of multiple rhythmbox databases by file location')
parser.add_argument('files', metavar='FILE', type=str, nargs='+',
help='rhythmbox databases to parse')
parser.add_argument('--output', '-o', metavar='OUTPUT', default=None,
help="file to write the result to")
args = parser.parse_args()
xml_tree = lxml.etree.parse(args.files[0])
root = xml_tree.getroot()
for additional_file in args.files[1:]:
add_file = lxml.etree.parse(additional_file)
# copy additional nodes to root
root.extend([deepcopy(el) for el in add_file.getroot().getchildren()])
locations = set((t.text for t in root.findall("entry/location")))
for location in locations:
searchstring = "entry/[location='%s']" % location
matches = root.findall(searchstring)
if len(matches) > 1:
play_count = sum(
(int(e.text) for e in (
entry.find('.play-count') for entry in matches)
if e is not None)
)
play_count_element = matches[0].find('.play-count')
if play_count_element is None:
play_count_element = lxml.etree.Element('play-count')
matches[0].append(play_count_element)
play_count_element.text = str(play_count)
for element in matches[1:]:
root.remove(element)
if args.output:
xml_tree.write(args.output)
else:
print(lxml.etree.tostring(root, pretty_print=True).decode())
|
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Ok, da hat ein Eintrag keinen play-count und das Skript rechnet damit, dass der existiert - probier es mal so:
Habe den neuen Code in die merge_rhythmdb_playcount.py kopiert und ausgeführt:
| python3 merge_rhythmdb_playcount.py --output rhythmdp-merge.xml rhythmdb_alt.xml rhythmdb.xml
|
Fehlermeldung:
Traceback (most recent call last):
File "merge_rhythmdb_playcount.py", line 27, in <module>
matches = root.findall(searchstring)
File "src/lxml/lxml.etree.pyx", line 1563, in lxml.etree._Element.findall (src/lxml/lxml.etree.c:61450)
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 304, in findall
return list(iterfind(elem, path, namespaces))
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 277, in iterfind
selector = _build_path_iterator(path, namespaces)
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 260, in _build_path_iterator
selector.append(ops[token[0]](_next, token))
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 214, in prepare_predicate
raise SyntaxError("invalid predicate")
SyntaxError: invalid predicate zur Info:
Ausgabe:
-rw-rw-r-- 1 marcus marcus 1586 Aug 22 21:18 merge_rhythmdb_playcount.py
-rw-rw-r-- 1 marcus marcus 27095547 Apr 24 13:38 rhythmdb_alt.xml
-rw-rw-r-- 1 marcus marcus 27991092 Aug 21 20:10 rhythmdb.xml
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Wie groß sind denn die xml-Dateien, wenn du sie in einzelne Archive packst und komprimierst?
XZ_OPT=-9e tar -cJf rhythmdb_alt.tar.xz rhythmdb_alt.xml
XZ_OPT=-9e tar -cJf rhythmdb.tar.xz rhythmdb.xml
ls -lsh rhythmdb*.tar.xz
Ich glaube die Grenze für die Nachrichtentgröße inkl. Anhang liegt bei meinem E-Mail Konto bei 25 MB.
Falls du einen Cloud-Service wie Dropbox oder einen eigenen Webserver hast, mit dem man die Dateien verteilen könnte, wäre das natürlich einfacher.
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Hatte nicht dran gedach, dass das ja Textdateien sind, die sich gut komprimieren lassen. ls -lsh rhythmdb*.tar.xz
1,2M -rw-rw-r-- 1 marcus marcus 1,2M Aug 22 22:48 rhythmdb_alt.tar.xz
1,2M -rw-rw-r-- 1 marcus marcus 1,2M Aug 22 22:49 rhythmdb.tar.xz Macht das Sinn die Dateien als Private Nachricht zu senden ? Webserver und Dropbox habe ich nicht. Und UbuntuOne ist ja leider nicht mehr. Bye
Marcus
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Da hat Guns N' Roses mit einfachen Anführungszeichen im Dateipfad doch tatsächlich den Suchstring durcheinander gebracht - als Gegenmaßnahme kann man die doppelten und die einfachen Anführungszeichen im Python-Skript vertauschen:
searchstring = 'entry/[location="%s"]' % location Was mir in den XML-Dateien auch noch aufgefallen ist, ist dass da sehr viele Einträge (3111) in der rhythmdb.xml das Attribut type="ignore" und damit keinerlei Metadaten haben - spricht etwas dagegen, die einfach zu löschen?
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Die Einträge mit dem Attribut type="ignore" scheinen Eintrage für nicht-Musikdateien zu sein, die sich aber in den Verzeichnissen der Musik befinden, wie z.B. cover.jpg, *.cue, *.m3u, etc.
Ich nehme an, Rhythmbox wird diese Eintrage beim nächsten Aktualisierung der Musiksammlung wieder erstellen.
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Ich habe den searchstring ersetzt und
| python3 merge_rhythmdb_playcount.py --output rhythmdb-merge.xml rhythmdb_alt.xml rhythmdb.xml
|
ausgeführt. Ist das so i.O ? Es gibt keine Anzeige im Terminal, noch wird eine rhythmdb-merge.xml erstellt.
Ich hab das Programm für heute Nacht erstmal abgebrochen, meine CPU scheint zu heiß zu werden. Ich muß wohl mal morgen den Lüfter reinigen. Immer gleiche Anzeige nach Abbruch des Programms: ^CTraceback (most recent call last):
File "merge_rhythmdb_playcount.py", line 27, in <module>
matches = root.findall(searchstring)
File "src/lxml/lxml.etree.pyx", line 1563, in lxml.etree._Element.findall (src/lxml/lxml.etree.c:61450)
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 304, in findall
return list(iterfind(elem, path, namespaces))
File "/usr/lib/python3/dist-packages/lxml/_elementpath.py", line 176, in select
if "".join(e.itertext()) == value:
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ja, das ist ein ziemlich rechenintensiver Prozess mit den ellenlangen Stringvergleichen (wegen den Pfaden als Vergleichkriterium) - immerhin läuft er da vielfach über die ca. 70.000 Einträge aus den zwei Dateien (für gut 34.200 Songs) und so wie es geschrieben ist, kann es nur einen Kern nutzen (Threading dürfte mit Python in dem Fall auch wenig bringen, weil das ganze nicht durch I/O-Operationen limitiert wird und dann limitiert der Global Interpreter Lock) - da man das ganze vermutlich nicht mehr als ein einziges Mal benötigt, lasse ich anderen den Vortritt beim Optimieren 😉 Die Datei mit dem Ergebnis wird erst ganz am Ende geschrieben, wenn das Programm alles abgearbeitet hat.
Wenn du den Prozess abbrichst, ist es ganz normal, dass er dir zeigt, was er als letztes gemacht hat.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ok, eine Nacht drüber Schlafen bringt einiges - man kann sich Unmengen Zeit sparen, wenn man nur einmal über alle Elemente iteriert und den Pfad als Key in einem Dictionary nutzt, statt Strings zu matchen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 | #!/usr/bin/env python3
import argparse
from copy import deepcopy
from xml.etree import ElementTree as ET
parser = argparse.ArgumentParser(
description='merge play-count of multiple rhythmbox databases by file location')
parser.add_argument('files', metavar='FILE', type=str, nargs='+',
help='rhythmbox databases to parse')
parser.add_argument('--output', '-o', metavar='OUTPUT', default=None,
help="file to write the result to")
args = parser.parse_args()
xml_tree = ET.parse(args.files[0])
root = xml_tree.getroot()
for additional_file in args.files[1:]:
add_file = ET.parse(additional_file)
# copy additional nodes to root
root.extend([deepcopy(el) for el in add_file.getroot().getchildren()])
d = {}
for entry in root.findall("entry[location]"):
location = entry.find('location').text
play_count_tag = entry.find('.play-count')
play_count = int(play_count_tag.text) if play_count_tag is not None else 0
if not location in d:
if play_count_tag is None:
play_count_tag = ET.Element('play-count')
play_count_tag.text = str(play_count)
entry.append(play_count_tag)
d[location] = entry
else:
play_count_in_entry = d[location].find('.play-count')
play_count_in_entry.text = str(int(play_count_in_entry.text) + play_count)
root.remove(entry)
# delete all <play-count>0</play-count> Tags
for entry in root.findall('entry[play-count]'):
play_count = entry.find('.play-count')
if play_count.text == "0":
entry.remove(play_count)
if args.output:
xml_tree.write(args.output, encoding='utf-8', xml_declaration=True)
else:
print(ET.tostring(root, encoding='unicode'))
|
Damit sinkt die Laufzeit in meiner VM auf unter eine Minute.
|
god_of_emptiness
(Themenstarter)
Anmeldungsdatum: 31. Mai 2007
Beiträge: 186
|
Das Skript läuft und führt die beiden rhythmdb.xml zusammen.
Die playcounts werden aber nicht aufsummiert. Leider stürzt Rhythmbox auch wieder mit der zusammengeführten rhythmdb.xml ab ☹ : (rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): Gtk-WARNING **: Duplicate child name in GtkStack: Zur Wiedergabeliste hinzufügen
(rhythmbox:8695): RhythmDB-CRITICAL **: rhythmdb_entry_get_entry_type: assertion 'entry != NULL' failed
Speicherzugriffsfehler (Speicherabzug geschrieben) Was bedeutet denn die Letzte Zeile ? Bedeutet das, dass es einen entry=NULL in der rhythmdb.xml gibt und das das Problem sein könnte ?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
rhythmdb_entry_get_entry_type: assertion 'entry != NULL' failed
bedeutet übersetzt: "die Annahme, dass die Eingabe != NULL (also nicht leer) ist, ist schief gegangen. Mit anderen Worten: ein Eingabefeld, das niemals leer sein darf ist dort doch leer. Ob das jetzt echt so in der rhythmdb.xml drinsteht oder nur so erscheint (z.B. weil das Programm spinnt) weiß ich von hierher natürlich nicht. Ziemlich weit oben hatte ich deshalb ja schon die Frage aufgeworfen, ob in der XML-Datei "giftige" Einträge vorkommen. Sonst wüsste ich ja auch nicht, wie man den Fehler weiter eingrenzen könnte. Auf die Bitte, Dir genau die angemeckerten Einträge mal genauer anzuschauen, bist Du dort allerdings nicht weiter eingegangen ... Vielleicht solltest Du das doch mal tun ? LG, track
|