clive bzw cclive auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
superthorsten
User
Beiträge: 7
Registriert: Mittwoch 4. Februar 2015, 13:19

Hey Leute,

ich will für dieses tolle Programm clive, mit dem man youtube-videos runter laden kann, gerade eine GUI programmieren. Hab auch schon ewas Funktionierendes, aber ich will die Prozentangabe noch in Tkinter daneben schreiben. Also ich rufe über Bash cclive auf und der läd mir das Video herunter und zeigt in der shell ständig den aktuellen Stand an. Normalerweise kann man ja die Ausgabe umleiten, zum Beispiel in eine Textdatei mit

Code: Alles auswählen

 Befehl > Textdatei.txt 


Bei Clive wäre das:

Code: Alles auswählen

clive <URL>  > <Datei.txt> 
Das geht aber irgendwie nicht, vermutlich weil die Ausgabe ständig aktualisiert wird oder weiß der Geier. Vielleicht gibts ja auch ne Pythonlösung die Ausgabe auszulesen, die wäre mir aber nicht bekannt. Wäre in Bash, wenns denn klappen würde, am elgegantesten, so glaube ich zumindest.

Hat jemand eine Idee ?

Grüße
Thorsten
BlackJack

@superthorsten: Du suchst wahrscheinlich das `subprocess`-Modul.
superthorsten
User
Beiträge: 7
Registriert: Mittwoch 4. Februar 2015, 13:19

Ja genau, damit versuche ich es gerade. Folgendermaßen sieht mein Code aus:

Code: Alles auswählen


#!/usr/bin/python
# coding: utf8
import os
import subprocess

sub="cclive https://www.youtube.com/watch?v=HECa3bAFAYk" #Katzenvideo herunterladen
p = subprocess.Popen(sub, shell=True,bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#Alternative 1 Start
Nachrichten=p.communicate()[0]
print Nachrichten	
p.stdin.close()
# Alternative 1 Ende 

Code: Alles auswählen

#Alternative 2 Start
file=open("/dev/stdout","r")
Nachrichten=eval(file.read())
print Nachrichten
file.close()
#Alternative 2 Ende
Alternative 2 habe ich mit einem einfachen Shell-Befehl getestet, mit dem Echo-Befehl. Damit klappt es. Aber nicht mit cclive. Hier wird eine leere Zeile ausgegeben. Das liegt vermutlich daran, dass erst nach beenden des Programmes die ausgabe erfolgt, welche dann eben leer ist. Aber ich will ja die laufende Ausgabe haben.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du tust wohl wirklich alles, um dir selbst in den Fuß zu schießen :lol:

Schau dir mal die Dokumentation zum subprocess-Modul genauer an. Popen wird kein einzelner String als Kommando übergeben, sondern die einzelnen Argument in einer Liste:

Code: Alles auswählen

subprocess.Popen(["cclive", url])
Dann kannst du auch das gefährliche ``shell=True`` weglassen, vor dem "ganz unauffällig" in einer roten Box in der Dokumentation gewarnt wird ;-)

Zu deinem zweiten Ansatz: Vergiss sofort wieder, dass es "eval" gibt. Damit lässt sich beliebiger Code ausführen, was eigentlich immer in böses Ende nimmt. Besonders dann, wenn man über die ankommenden Daten keine Kontrolle hat.

Und bitte wirf einen Blick auf PEP 8.
Das Leben ist wie ein Tennisball.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@superthorsten: zusätzlich zu dem was EyDu schreibt, wenn Du communicate benutzt, brauchst Du Dich nicht wundern, dass nichts passiert, bis cclive fertig ist, weil communicate auf das Ende des Programms wartet.
BlackJack

Ich habe mir cclive mal angeschaut und es scheint als wenn man da nicht viel machen kann, das puffert seine Ausgabe wenn es nicht direkt mit einem Terminal verbunden ist. Man müsste dem Prozess also ein Terminal vortäuschen. Zum Beispiel mit dem `pexpect`-Modul.
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Alternativvorschlag: Kann cclive irgendetwas, was youtube-dl nicht kann? Letzteres ist in Python geschrieben, sodass du es in dein eigenes Skript einbinden könntest. https://github.com/rg3/youtube-dl/blob/ ... youtube-dl
superthorsten
User
Beiträge: 7
Registriert: Mittwoch 4. Februar 2015, 13:19

Das mit youtube-dl ist ne gute Idee. Ich habe mir die Manpage nicht richtig durchgelesen von cclive. Womöglich hätte ich mir viel rumprobiererei gespart. Hier ist die Version mit youtube-dl, die auch funktioniert:

Code: Alles auswählen

#!/usr/bin/python
# coding: utf8
import subprocess

p=subprocess.Popen(["youtube-dl","https://www.youtube.com/watch?v=NJX7pFqOZsU"],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

while True:
	line = p.stdout.readline()
	if line != '':
		print "test:", line.rstrip()
	else:
		break
Danke für die Hilfe
BlackJack

@superthorsten: Das sieht ein wenig zu kompliziert aus. Man kann direkt über ein Dateiobjekt iterieren und bekommt dann die Zeilen. Damit wird das zu einer einfachen ``for``-Schleife bei der man dann auch keine Abbruchbedingung mehr prüfen muss.

Es ist auch keine gute Idee einfach so alle Standardfiles zu „pipen”. Die Eingabe wird überhaupt nicht benötigt, und die Fehlerausgabe kann Probleme verursachen weil Du die überhaupt nicht ausliest. Sollte der externe Prozess da tatsächlich Daten hineinschreiben, dann blockiert das wenn der Puffer beim Empfänger voll ist bis in alle Ewigkeit und Dein Programm hängt.
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

superthorsten hat geschrieben:Das mit youtube-dl ist ne gute Idee. Ich habe mir die Manpage nicht richtig durchgelesen von cclive. Womöglich hätte ich mir viel rumprobiererei gespart. Hier ist die Version mit youtube-dl, die auch funktioniert:
[...]
Danke für die Hilfe
Allerdings war es so gedacht, dass youtube-dl als Modul eingebunden wird; dass das geht, ist ja gerade der Vorteil. Der Weg über subprocess dürfte in diesem Fall eher suboptimal sein.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@superthorsten: Wie nezzcarth schon geschrieben hat, ist youtube-dl ein Pythonmodul. Du brauchst also nicht einen Extra-Prozess starten und umständlich die Ausgabe parsen, sondern kannst die Download-Routine direkt importieren und aufrufen.
superthorsten
User
Beiträge: 7
Registriert: Mittwoch 4. Februar 2015, 13:19

Zurück mit der Behauptung, es würde funktionieren. Leider klappts nicht mit der Augabe des Downloadfortschritts. Genau bis dahin wirds ausgegeben und klappt wunderbar. Wenn der Download beginnt, aber nicht mehr. Naja, gleiches Problem wie bei clive bzw cclive nehme ich an. Die Information über die Gesamtgröße des Videos kann man wohl auch nicht mit youtube-dl ausgeben, zumindest habe ich da nichts gefunden. Dann muss wohl doch die Shell simuliert werden.

Ich lasse das Problem jetzt erstmal ruhen und schreibe hier nochmal was rein, wenn ich mich wieder mit dem Problem beschäftige und ne Lösung gefunden habe.

Grüße
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@superthorsten: vielleicht hast Du nezzcarths oder meinen Beitag nicht gelesen. youtube-dl ist ein Pythonmodul. Importiere es direkt und nutze die bereitgestellte API. Es gibt Callbacks, die den Fortschritt melden.
superthorsten
User
Beiträge: 7
Registriert: Mittwoch 4. Februar 2015, 13:19

Hey,

das mit den Callbacks und den APIs versuche ich mal. Leider fehlt es mir hier an Wissen. Zum Beispiel scheitere ich bereits daran, den Quellcode von youtube-dl auf meiner Festplatte zu finden. Die Datei youtube-dl beinhaltet das hier:

Code: Alles auswählen

#! /usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'youtube-dl==2013.11.11','console_scripts','youtube-dl'
__requires__ = 'youtube-dl==2013.11.11'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('youtube-dl==2013.11.11', 'console_scripts', 'youtube-dl')()
    )
Damit kann ich nichts anfangen. Dann muss ich noch schauen was Callbacks sind und wie man die APIs nutzt. Da das hier für mich eine Prokrastinationsarbeit ist, muss ich es aber erstmal dabei belassen. Aber Danke erstmal für die Hilfe.
BlackJack

@superthorsten: Mach in einer Python-Shell einfach mal ein ``import youtube_dl``. Wenn Du das Modul-Objekt dann mal mit ``print`` ausgibst oder einfach auch nur so mal den Wert in der Shell ausgeben lässt, weisst Du wo die Dateien liegen.
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

superthorsten hat geschrieben:Dann muss ich noch schauen was Callbacks sind und wie man die APIs nutzt. Da das hier für mich eine Prokrastinationsarbeit ist, muss ich es aber erstmal dabei belassen. Aber Danke erstmal für die Hilfe.
Auf der Seite, die ich oben verlinkt hatte, gibt es doch schon ein funktionsfähiges Beispiel, das du leicht anpassen kannst. Callback bedeutet im konkreten Fall, dass du der Methode, die den Download startet eine Funktion übergeben kannst, die bei Veränderungen des Downloadfortschritts ausgeführt wird. Diese Funktion bekommt als Parameter ein Dictionary, das diverse Informationen über den Downloadzustand enthält. Damit müsste es sehr einfach sein, eine Progressbar zu steuern, wie du es vorhattest.

Extern Shelltools zu starten und sich durch deren Output zu wühlen, kann man machen, wenn es sonst keine Alternative gibt, ansonsten ist das meiner Meinung nach nicht empfehlenswert.
Antworten