Oh sorry, bis zu tools.c bin ich gar nicht gekommen
Verstehe ich es richtig: der Dateiname im System ist bei dir nach dem Verschieben kodiert?
Und du benutzt json?
Oh sorry, bis zu tools.c bin ich gar nicht gekommen
Verstehe ich es richtig: der Dateiname im System ist bei dir nach dem Verschieben kodiert?
Und du benutzt json?
Einige Sonderzeichen werden kodiert. :? Usw.
Ja, ich nutze json.
Hm, das sind die, aus denen der VDR beim anlegen der Aufnahme diese völlig kryptischen Verzeichnisse macht.
Ich nutze xml. Da habe ich jetzt mal mit "unCut~Quarks & Co: Wem nützt Krebsvorsorge?~%Moderation: Ranga Yogeshwar" probiert und das klappt auch nicht so richtig.
Da wurde bei unCut~Quarks_ einfach abgeschnitten
im Dateisystem heissen die Verzeichnisse QYRKZ3~G und _D6CFZ~6
Funktioniert das bei dir den mit Live?
Das wäre mein Vorschlag gewesen
/* move or copy recording */
void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
QueryHandler q("/recordings/move", request);
string source = q.getBodyAsString("source");
string target = q.getBodyAsString("target");
string directory = q.getBodyAsString("directory");
bool copy_only = q.getBodyAsBool("copy_only");
if (!copy_only)
cThreadLock RecordingsLock(&Recordings);
if (source.length() > 0 && target.length() > 0) {
if (access(source.c_str(), F_OK) == 0) {
cRecording* recording = Recordings.GetByName(source.c_str());
string filename = directory.empty() ? target : StringExtension::replace(directory, "/", "~") + "~" + target;
if (recording && !VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(filename.c_str(), true), copy_only)) {
LOG_ERROR_STR(source.c_str());
reply.httpReturn(503, "File copy failed!");
} else {
Recordings.Update(false);
}
} else {
reply.httpReturn(504, "Recording not found or path is invalid!");
}
} else {
reply.httpReturn(404, "Missing file name!");
}
}
Alles anzeigen
aber jetzt würde ich doch gerne das mit den : und ? auch noch in den Griff bekommen...
Hm, das sind die, aus denen der VDR beim anlegen der Aufnahme diese völlig kryptischen Verzeichnisse macht.
Ich nutze xml. Da habe ich jetzt mal mit "unCut~Quarks & Co: Wem nützt Krebsvorsorge?~%Moderation: Ranga Yogeshwar" probiert und das klappt auch nicht so richtig.
Da wurde bei unCut~Quarks_ einfach abgeschnitten
im Dateisystem heissen die Verzeichnisse QYRKZ3~G und _D6CFZ~6
Funktioniert das bei dir den mit Live?
So, da bin ich wieder
Der Fehler oben lag am &, wenn ich das mit %26 ersetze funktioniert das via xml wie es soll!
Ich kann im target alles (ausser &) un-kodiert verwenden, auch : und ?. Zumindest mach ich dafür nichts weiter.
Der VDR erstellt dann die 'kryptischen Verzeichnisse', so wie es sein soll.
im Dateisystem heissen die Verzeichnisse QYRKZ3~G und _D6CFZ~6
Das sieht mir nach Samba aus... Hast Du mal auf dem VDR selbst nachgesehen, wie die Verzeichnisse da aussehen?
Bei meiner Version kann ich alles einfach so rüberschicken, um die Parameterkodierung kümmert sich jQuery. Nutzt Du keine JS Bibliothek?
Wenn ich z.B.
in
umbenennen möchte, schickt jQuery diesen String los
source=%2Fmedia%2Fdaten%2FFilme%2FAufnahmen%2FDokus%2F3D%2FBig_Bugs_-_Kleine_Krabbler_ganz_gro%C3%9F_%26_klein%2322%235C~%233A%232A%233F%237C%233C%233E%2323bla%2F2013-12-30.04.18.780-0.rec&target=Dokus~3D~Big_Bugs_-_Kleine_Krabbler_ganz_gro%C3%9F_%26_klein%22%5C%2F%3A*%3F%7C%3C%3E%23+
Du musst deine Parameter mit encodeURIComponent genauso kodieren, falls das nicht bereits passiert. Ich entnehme deinem Posts aber, das du keine Urlkodierung verwendest.
Konkret geht es um diese Zeichen:
(vdr/recording.c)
Diese Zeichen und auch der Slash und die Tilde werden durch die Methode VdrExtension::FileSystemExchangeChars korrekt verarbeitet. Die ruft die VDR Methode ExchangeChars aus recording.c auf, die sich um alles kümmert. Daher musst du gar nichts ersetzen. Die Zeile 14 in deinem Beitrag von Gestern 21:46 ist nicht nötig, IMO sogar falsch. Wenn ich nun in meinem Verzeichnissen einen Slash verwenden will, geht das nicht mehr, da die Slashes vor der Konvertierung bereits in Tilde umgewandelt wurden. So hast du aus zwei verschiedenen Zeichen eines gemacht. Ohne die Zeile funktioniert das aber. Anwendungsbeispiel wäre z.B. das ich eine Serienstaffel so benennen möchte:
Moin,
Ja, das mit den Zeichen wird wohl Samba sein.
source schicke ich kodiert mit encodeURIComponent.
target kommt unkodieret, da mache ich aber vor dem verschicken noch target=target.replace(/'/g, "%27").replace(/&/g, "%26").replace(/ /g, "_");
Und das funktioniert ganz gut.
Ich probiere gleich aber noch, wie die Verzeichnisse aussehen wenn ich das target auch kodieren lasse.
ZitatDie Zeile 14 in deinem Beitrag von Gestern 21:46 ist nicht nötig, IMO sogar falsch.
Nö, die ist super so. Am target wird ja nichts verändert, genau so wie du es wolltest.
Wenn directory nicht leer ist, wird es vor das target gesetzt und / werden zu ~, aber nur im directory.
In deinem Fall lässt du also directory einfach leer.
habe ich eben getestet.
Im OSD gibt das dann:
-Breaking Bad
--Staffel (1/5)
--*Der Einsteiger (1/7)
Test-string
codiert mit "target=target.replace(/'/g, "%27").replace(/&/g, "%26").replace(/ /g, "_");" und abgeschickt via xml ergibt das Verzeichnis
Test-string
codiert mit encodeURIComponent und abgeschickt via xml ergibt das Verzeichnis
wenn das bei dir mit json so nicht funktioniert, müsste es eigentlich am getJsonString liegen.
Das du einen extra Parameter directory verwendest habe ich irgendwie übersehen.
Nö, die ist super so.
Klar... Sie tut was sie soll
Das passiert doch aber alles bereits in recording.c ExchangeChars. Ich verstehe nicht, warum du die Extra Umwandlung benötigst, das ist doch doppeltgemoppelt.
Ich nehme an, du möchtest Slashes als Verzeichnis delimiter übergeben.
VDR definiert aber die Tilde als Verzeichnis delimiter.
Mein Vorschlag wäre also, den Parameter directory wegzulassen, die Extra umwandlung herauszunehmen und als Verzeichnis delimiter die Tilde zu übergeben, wie vorgesehen.
Mein Vorschlag wäre also, den Parameter directory wegzulassen, die Extra umwandlung herauszunehmen und als Verzeichnis delimiter die Tilde zu übergeben, wie vorgesehen.
Es ist jetzt wie vorgesehen
Das mit dem directory ist ja nicht auf meinem Mist gewachsen, sondern kommt vom live-plugin.
Da ist das wohl wegen dem Verzeichnis Select. So ein Select habe ich bei mir auch eingebaut...
Es ist jetzt wie vorgesehen
Super
Das mit dem directory ist ja nicht auf meinem Mist gewachsen, sondern kommt vom live-plugin.
Da ist das wohl wegen dem Verzeichnis Select. So ein Select habe ich bei mir auch eingebaut...
Ah OK... Ich dachte, Du hättest den Parameter zusätzlich eingefügt.
Ich habe auch so einen Dir Selector gebaut. Wenn ich einen Ordner hinzufügen möchte, muss ich das allerdings im Dateinamen machen. Macht Live z.B. ja auch so.
Was hältst Du denn von der Rückantwort? Ich dachte mir, dann muss ich die Logik, die im VDR den Dateinamen baut im Client nicht zusätzlich implementieren.
Schaden tut es ja niemanden. Der Vorteil ist der, das ich im Client den Datenbestand Fehlerfrei aktualisieren kann, ohne die Aufnahmen erneut zu laden.
Hast du das mit der Kodierung mal getestet bzw funktioniert das jetzt?
Schaden tut es ja niemanden. Der Vorteil ist der, das ich im Client den Datenbestand Fehlerfrei aktualisieren kann, ohne die Aufnahmen erneut zu laden.
Ich hatte beim probieren aber einen Fehler 502 weil ich die .xml Endung nicht dabei hatte !!! Nur Spass
Das mit dem leeren String finde ich zwar irgendwie uncool aber es soll ja nur funktionieren...
Ausgehend von deinen Änderungen in tools.c/.h
/* move or copy recording */
void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
QueryHandler q("/recordings/move", request);
StreamExtension s(&out);
string source = q.getBodyAsString("source");
string target = q.getBodyAsString("target");
string directory = q.getBodyAsString("directory");
bool copy_only = q.getBodyAsBool("copy_only");
if (!copy_only)
cThreadLock RecordingsLock(&Recordings);
if (source.length() > 0 && target.length() > 0) {
if (access(source.c_str(), F_OK) == 0) {
cRecording* recording = Recordings.GetByName(source.c_str());
if (recording) {
string filename = directory.empty() ? target : StringExtension::replace(directory, "/", "~") + "~" + target;
string newname = VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(filename.c_str(), true), copy_only);
if (newname.length() > 0) {
Recordings.Update(false); // <- muss das hier überhaupt gemacht werden?
cRecording* new_recording = Recordings.GetByName( newname.c_str() );
if (q.isFormat(".html")) {
reply.addHeader("Content-Type", "text/html; charset=utf-8");
s.writeHtmlHeader("New Filename");
s.write(new_recording->FileName());
s.write("</body></html>");
} else if (q.isFormat(".json")) {
reply.addHeader("Content-Type", "application/json; charset=utf-8");
cxxtools::JsonSerializer serializer(out);
serializer.serialize(StringExtension::encodeToJson(new_recording->FileName()), "filename");
serializer.finish();
} else if (q.isFormat(".xml")) {
reply.addHeader("Content-Type", "text/xml; charset=utf-8");
s.write("<recordings xmlns=\"http://www.domain.org/restfulapi/2011/recordings-xml\">\n");
s.write(cString::sprintf(" <param name=\"filename\">%s</param>\n", StringExtension::encodeToXml(new_recording->FileName()).c_str()));
s.write("</recordings>");
} else {
reply.httpReturn(502, "Only the following formats are supported: .xml, .json and .html");
}
} else {
LOG_ERROR_STR(source.c_str());
reply.httpReturn(503, "File copy failed!");
}
} else {
reply.httpReturn(504, "Recording not found!");
}
} else {
reply.httpReturn(504, "Path is invalid!");
}
} else {
reply.httpReturn(404, "Missing file name!");
}
}
Alles anzeigen
Ein weiterer Entwurf, leider passt die Nummer so noch nicht. Wenn man die noch wüsste...
/* move or copy recording */
void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
QueryHandler q("/recordings/move", request);
StreamExtension s(&out);
string source = q.getBodyAsString("source");
string target = q.getBodyAsString("target");
string directory = q.getBodyAsString("directory");
bool copy_only = q.getBodyAsBool("copy_only");
if (!copy_only)
cThreadLock RecordingsLock(&Recordings);
if (source.length() > 0 && target.length() > 0) {
if (access(source.c_str(), F_OK) == 0) {
cRecording* recording = Recordings.GetByName(source.c_str());
if (recording) {
string filename = directory.empty() ? target : StringExtension::replace(directory, "/", "~") + "~" + target;
string newname = VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(filename.c_str(), true), copy_only);
if (newname.length() > 0) {
Recordings.Update(false); // <- muss das hier überhaupt gemacht werden?
cRecording* new_recording = Recordings.GetByName(newname.c_str());
if (new_recording) {
RecordingList* recordingList;
bool read_marks = false;
if ( q.isFormat(".json") ) {
reply.addHeader("Content-Type", "application/json; charset=utf-8");
recordingList = (RecordingList*)new JsonRecordingList(&out, read_marks);
} else if ( q.isFormat(".html") ) {
reply.addHeader("Content-Type", "text/html; charset=utf-8");
recordingList = (RecordingList*)new HtmlRecordingList(&out, read_marks);
} else if ( q.isFormat(".xml") ) {
reply.addHeader("Content-Type", "text/xml; charset=utf-8");
recordingList = (RecordingList*)new XmlRecordingList(&out, read_marks);
} else {
reply.httpReturn(502, "Resources are not available for the selected format. (Use: .json, .xml or .html)");
return;
}
recordingList->init();
cThreadLock RecordingsLock(&Recordings);
recordingList->addRecording(new_recording, 1); // <- hier sollte eigentlich die Nummer übergeben werden
recordingList->setTotal(1);
recordingList->finish();
delete recordingList;
}
} else {
LOG_ERROR_STR(source.c_str());
reply.httpReturn(503, "File copy failed!");
}
} else {
reply.httpReturn(504, "Recording not found!");
}
} else {
reply.httpReturn(504, "Path is invalid!");
}
} else {
reply.httpReturn(404, "Missing file name!");
}
}
Alles anzeigen
Hast du das mit der Kodierung mal getestet bzw funktioniert das jetzt?
Bei mir funktioniert das einwandfrei. Ich habe ja auch keinen directory Parameter und wandele auch nichts um bzw. lass VDR das machen
string filename = directory.empty() ? target : StringExtension::replace(directory, "/", "~") + "~" + target;
Davon lässt du dich nicht abbringen, oder?
Ein weiterer Entwurf, leider passt die Nummer so noch nicht. Wenn man die noch wüsste...
Ist halt die Frage, ob man die Nummer überhaupt braucht. Bisher ist die nur nötig gewesen, wenn ich eine Aufnahme löschen will. Da du die Methode deleteRecordingByName implementiert hast, kann man ja jetzt den Dateinamen als ID verwenden, was eh viel besser ist. Ich würde die Methode deleteRecording sogar ersetzen wollen aber man will ja kompatibel bleiben.
Außer dem Dateinamen ändert sich in der Methode moveRecording an der Aufnahme eh nichts.
Insofern: Vergiss doch die Nummer.... Der Client muss sein Objekt im Moment der Änderung sowieso kennen und kann das dann Updaten. Assuerdem kann sich die Nummer auch ändern, wenn der VDR eine Aufnahme beginnt oder eine Aufnahme mit der FB gelöscht wird, oder?
Wie funktioniert denn deleteRecordingByName genau? Übergebe ich file_name, relative_file_name oder name aus dem Recordings Objekt?
Ich tippe auf file_name... Wichtig wäre hier nur, das das Verzeichnis mit dem Timestamp übergeben werden muss, damit er mir bei mehreren Aufnahmen von z.B. einer Sereinepisode auch nur eine einzelne löscht und nicht alle, wenn die unter dem gleichen Namen abgelegt wurden.
Bei mir funktioniert das einwandfrei. Ich habe ja auch keinen directory Parameter und wandele auch nichts um bzw. lass VDR das machen
Na, du hast doch weiter oben geschrieben, das
ZitatDas mache ich wegen Sonderzeichen wie z.B. ':' Die sind dann ja irgendwie kodiert: Name "Dino Planet: T-Rex und seine Brüder (2/3)" = Dateiname "Dino-Planet#3A_T-Rex_und_seine_Brüder_(2~3)"
und bei mir wird da kein #3A sondern ein : im Dateisystem.
Die Nummer:
//recordingList->addRecording(new_recording, 1);
for (int i = 0; i < Recordings.Count(); i++) {
cRecording* tmp_recording = Recordings.Get(i);
if (strcmp (new_recording->FileName(), tmp_recording->FileName()) == 0)
recordingList->addRecording(tmp_recording, i);
}
im ganzen dann
/* move or copy recording */
void RecordingsResponder::moveRecording(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
{
QueryHandler q("/recordings/move", request);
StreamExtension s(&out);
string source = q.getBodyAsString("source");
string target = q.getBodyAsString("target");
string directory = q.getBodyAsString("directory");
bool copy_only = q.getBodyAsBool("copy_only");
if (!copy_only)
cThreadLock RecordingsLock(&Recordings);
if (source.length() > 0 && target.length() > 0) {
if (access(source.c_str(), F_OK) == 0) {
cRecording* recording = Recordings.GetByName(source.c_str());
if (recording) {
string filename = directory.empty() ? target : StringExtension::replace(directory, "/", "~") + "~" + target;
string newname = VdrExtension::MoveRecording(recording, VdrExtension::FileSystemExchangeChars(filename.c_str(), true), copy_only);
if (newname.length() > 0) {
//Recordings.Update(false);
cRecording* new_recording = Recordings.GetByName(newname.c_str());
if (new_recording) {
RecordingList* recordingList;
bool read_marks = false;
if ( q.isFormat(".json") ) {
reply.addHeader("Content-Type", "application/json; charset=utf-8");
recordingList = (RecordingList*)new JsonRecordingList(&out, read_marks);
} else if ( q.isFormat(".html") ) {
reply.addHeader("Content-Type", "text/html; charset=utf-8");
recordingList = (RecordingList*)new HtmlRecordingList(&out, read_marks);
} else if ( q.isFormat(".xml") ) {
reply.addHeader("Content-Type", "text/xml; charset=utf-8");
recordingList = (RecordingList*)new XmlRecordingList(&out, read_marks);
} else {
reply.httpReturn(502, "Resources are not available for the selected format. (Use: .json, .xml or .html)");
return;
}
recordingList->init();
cThreadLock RecordingsLock(&Recordings);
//recordingList->addRecording(new_recording, 1);
for (int i = 0; i < Recordings.Count(); i++) {
cRecording* tmp_recording = Recordings.Get(i);
if (strcmp (new_recording->FileName(), tmp_recording->FileName()) == 0)
recordingList->addRecording(tmp_recording, i);
}
recordingList->setTotal(1);
recordingList->finish();
delete recordingList;
} else {
LOG_ERROR_STR(newname.c_str());
}
} else {
LOG_ERROR_STR(source.c_str());
reply.httpReturn(503, "File copy failed!");
}
} else {
reply.httpReturn(504, "Recording not found!");
}
} else {
reply.httpReturn(504, "Path is invalid!");
}
} else {
reply.httpReturn(404, "Missing file name!");
}
}
Alles anzeigen
ZitatWie funktioniert denn deleteRecordingByName genau? Übergebe ich file_name...
filename (wie source beim moveRecording)
<param name="filename">/srv/vdr/video.00/unCut/Quarks_&_Co:_Wem_nützt_Krebsvorsorge?/2014-04-06.19.16.21-0.rec</param>
ZitatWichtig wäre hier nur, das das Verzeichnis mit dem Timestamp übergeben werden muss, damit er mir bei mehreren Aufnahmen von z.B. einer Sereinepisode auch nur eine einzelne löscht und nicht alle, wenn die unter dem gleichen Namen abgelegt wurden.
2014-04-06.19.16.21-0.rec -> was soll da schief gehen?
und bei mir wird da kein #3A sondern ein : im Dateisystem.
Das hängt davon ab, mit welchen Optionen man den VDR startet. Mit
ersetzt der VDR alle kritischen Zeichen, die bei Windows-Dateisystemen nicht vorkommen dürfen.
Alles anzeigenNa, du hast doch weiter oben geschrieben, das
Zitat
Das mache ich wegen Sonderzeichen wie z.B. ':' Die sind dann ja irgendwie kodiert: Name "Dino Planet: T-Rex und seine Brüder (2/3)" = Dateiname "Dino-Planet#3A_T-Rex_und_seine_Brüder_(2~3)"
und bei mir wird da kein #3A sondern ein : im Dateisystem.
Echt? Das kann ich ja gar nicht glauben...Das macht mein VDR schon so lange ich ihn kenne... Wegen NTFS...
Siehe: https://github.com/flensrocker…b/master/recording.c#L556 und ff.
2014-04-06.19.16.21-0.rec -> was soll da schief gehen?
Eben... Ich wusste nur nicht, ob man das nun mit übergeben muss oder nicht.
@Seahawk
Ich starte VDR nicht mit --dirnames=,,1 und er ersetzt die Zeichen trotzdem... zumindest taucht der Parameter in der Prozessliste nicht auf
Echt? Das kann ich ja gar nicht glauben...Das macht mein VDR schon so lange ich ihn kenne... Wegen NTFS...
ich@yavdr:/srv/vdr/video.00$ ls
Baron_Münchhausen Grey's_Anatomy_-_Die_jungen_Ärzte Lucky:_Test8 Sofia_die_Erste_-_Auf_einmal_Prinzessin unCut
Breaking_Bad Karlsson_auf_dem_Dach Quarks_~:_&_'_was_geht?_(hier_ab)_-_*Teil1! Spielfilme Wickie_und_die_starken_Männer
Der_kleine_Rabe_Socke Kinderfilme_HD Ritter_Rost_-_Eisenhart_und_voll_verbeult Spielfilme_HD
Die_Brüder_Löwenherz Lotte_and_the_Moonstone_Secret Safe_-_Todsicher Summer_Wars
Dokumentationen Lucky:_Test7 Serien Toy_Story_II
... aber ich nutze auch kein ntfs
ihmo ist das dann wohl alles ok so...
Ich starte VDR nicht mit --dirnames=,,1 und er ersetzt die Zeichen trotzdem... zumindest taucht der Parameter in der Prozessliste nicht auf
Es gibt auch noch das mit einer ähnlichen Funktion:
Ach ja... --vfat da war doch was.
Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!