Add nice svg graphics to the playlist, based on the work of fapasv ( http://kde-look...
[amarok.git] / supplementary_scripts / amarok_live / amarok_live.py
blob2a1fca82aecf66a0181467533edd9ac59fc0af26
1 #!/usr/bin/env python
3 ############################################################################
4 # Python wrapper script for running the Amarok LiveCD remastering scripts
5 # from within Amarok. Based on the Python-Qt template script for Amarok
6 # (c) 2005 Mark Kretschmann <markey@web.de>
7 #
8 # (c) 2005 Leo Franchi <lfranchi@gmail.com>
10 # Depends on: Python 2.2, PyQt
11 ############################################################################
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
18 ############################################################################
20 import ConfigParser
21 import os
22 import sys
23 import threading
24 import signal
25 from time import sleep
27 try:
28 from qt import *
29 except:
30 os.popen( "kdialog --sorry 'PyQt (Qt bindings for Python) is required for this script.'" )
31 raise
34 # Replace with real name
35 debug_prefix = "LiveCD Remastering"
38 class ConfigDialog ( QDialog ):
39 """ Configuration widget """
41 def __init__( self ):
42 QDialog.__init__( self )
43 self.setWFlags( Qt.WDestructiveClose )
44 self.setCaption("Amarok Live! Configuration")
46 self.lay = QGridLayout( self, 3, 2)
48 self.lay.addColSpacing( 0, 300 )
50 self.isopath = QLineEdit( self )
51 self.isopath.setText( "Path to Amarok Live! iso" )
52 self.tmppath = QLineEdit( self )
53 self.tmppath.setText( "Temporary directory used, 2.5gb free needed" )
55 self.lay.addWidget( self.isopath, 0, 0 )
56 self.lay.addWidget( self.tmppath, 1, 0 )
58 self.isobutton = QPushButton( self )
59 self.isobutton.setText("Browse..." )
60 self.tmpbutton = QPushButton( self )
61 self.tmpbutton.setText("Browse..." )
63 self.cancel = QPushButton( self )
64 self.cancel.setText( "Cancel" )
65 self.ok = QPushButton( self )
66 self.ok.setText( "Ok" )
68 self.lay.addWidget( self.isobutton, 0, 1 )
69 self.lay.addWidget( self.tmpbutton, 1, 1 )
70 self.lay.addWidget( self.cancel, 2, 1 )
71 self.lay.addWidget( self.ok, 2, 0)
73 self.connect( self.isobutton, SIGNAL( "clicked()" ), self.browseISO )
74 self.connect( self.tmpbutton, SIGNAL( "clicked()" ), self.browsePath )
76 self.connect( self.ok, SIGNAL( "clicked()" ), self.save )
77 self.connect( self.ok, SIGNAL( "clicked()" ), self.unpack )
78 # self.connect( self.ok, SIGNAL( "clicked()" ), self.destroy )
79 self.connect( self.cancel, SIGNAL( "clicked()" ), self, SLOT("reject()") )
81 self.adjustSize()
83 path = None
84 try:
85 config = ConfigParser.ConfigParser()
86 config.read( "remasterrc" )
87 path = config.get( "General", "path" )
88 iso = config.get( "General", "iso")
90 if not path == "": self.tmppath.setText(path)
91 if not iso == "": self.isopath.setText(iso)
92 except:
93 pass
97 def save( self ):
98 """ Saves configuration to file """
99 self.file = file( "remasterrc", 'w' )
100 self.config = ConfigParser.ConfigParser()
101 self.config.add_section( "General" )
102 self.config.set( "General", "path", self.tmppath.text() )
103 self.config.set( "General", "iso", self.isopath.text() )
104 self.config.write( self.file )
105 self.file.close()
107 self.accept()
109 def clear():
111 self.file = file( "remasterrc", 'w' )
112 self.config = ConfigParser.ConfigParser()
113 self.config.add_section( "General" )
114 self.config.set( "General", "path", "" )
115 self.config.set( "General", "iso", "" )
116 self.config.write( self.file )
117 self.file.close()
119 def browseISO( self ):
121 path = QFileDialog.getOpenFileName( "/home",
122 "CD Images (*.iso)",
123 self,
124 "iso choose dialogr",
125 "Choose ISO to remaster")
126 self.isopath.setText( path )
128 def browsePath( self ):
130 tmp = QFileDialog.getExistingDirectory( "/home",
131 self,
132 "get tmp dir",
133 "Choose working directory",
135 self.tmppath.setText( tmp )
138 def unpack( self ):
140 # now the fun part, we run part 1
141 fd = os.popen("kde-config --prefix", "r")
142 kdedir = fd.readline()
143 kdedir = kdedir.strip()
144 scriptdir = kdedir + "/share/apps/amarok/scripts/amarok_live"
145 fd.close()
147 path, iso = self.readConfig()
148 os.system("kdesu -t sh %s/amarok.live.remaster.part1.sh %s %s" % (scriptdir, path, iso))
149 #os.wait()
150 print "got path: %s" % path
155 def readConfig( self ) :
156 path = ""
157 iso = ""
158 try:
159 config = ConfigParser.ConfigParser()
160 config.read("remasterrc")
161 path = config.get("General", "path")
162 iso = config.get("General", "iso")
163 except:
164 pass
165 return (path, iso)
169 class Notification( QCustomEvent ):
170 __super_init = QCustomEvent.__init__
171 def __init__( self, str ):
174 self.__super_init(QCustomEvent.User + 1)
175 self.string = str
177 class Remasterer( QApplication ):
178 """ The main application, also sets up the Qt event loop """
180 def __init__( self, args ):
181 QApplication.__init__( self, args )
182 debug( "Started." )
184 # Start separate thread for reading data from stdin
185 self.stdinReader = threading.Thread( target = self.readStdin )
186 self.stdinReader.start()
188 self.readSettings()
191 # ugly hack, thanks mp8 anyway
192 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add playlist to livecd\"")
193 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add selected to livecd\"")
194 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Create Remastered CD\"")
195 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Clear Music on livecd\"")
197 os.system("dcop amarok script addCustomMenuItem \"Amarok live\" \"Add playlist to livecd\"")
198 os.system("dcop amarok script addCustomMenuItem \"Amarok live\" \"Add selected to livecd\"")
199 os.system("dcop amarok script addCustomMenuItem \"Amarok live\" \"Create Remastered CD\"")
200 os.system("dcop amarok script addCustomMenuItem \"Amarok live\" \"Clear Music on livecd\"")
203 def readSettings( self ):
204 """ Reads settings from configuration file """
206 try:
207 path = config.get( "General", "path" )
209 except:
210 debug( "No config file found, using defaults." )
213 ############################################################################
214 # Stdin-Reader Thread
215 ############################################################################
217 def readStdin( self ):
218 """ Reads incoming notifications from stdin """
220 while True:
221 # Read data from stdin. Will block until data arrives.
222 line = sys.stdin.readline()
224 if line:
225 qApp.postEvent( self, Notification(line) )
226 else:
227 break
230 ############################################################################
231 # Notification Handling
232 ############################################################################
234 def customEvent( self, notification ):
235 """ Handles notifications """
237 string = QString(notification.string)
238 debug( "Received notification: " + str( string ) )
240 if string.contains( "configure" ):
241 self.configure()
242 if string.contains( "stop"):
243 self.stop()
245 elif string.contains( "customMenuClicked" ):
246 if "selected" in string:
247 self.copyTrack( string )
248 elif "playlist" in string:
249 self.copyPlaylist()
250 elif "Create" in string:
251 self.createCD()
252 elif "Clear" in string:
253 self.clearCD()
256 # Notification callbacks. Implement these functions to react to specific notification
257 # events from Amarok:
259 def configure( self ):
260 debug( "configuration" )
262 self.dia = ConfigDialog()
263 self.dia.show()
264 #self.connect( self.dia, SIGNAL( "destroyed()" ), self.readSettings )
266 def clearCD( self ):
268 self.dia = ConfigDialog()
269 path, iso = self.dia.readConfig()
271 os.system("rm -rf %s/amarok.live/music/* %s/amarok.live/playlist/* %s/amarok.live/home/amarok/.kde/share/apps/amarok/current.xml" % (path, path, path))
273 def onSignal( self, signum, stackframe ):
274 stop()
276 def stop( self ):
278 fd = open("/tmp/amarok.stop", "w")
279 fd.write( "stopping")
280 fd.close()
282 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add playlist to livecd\"")
283 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add selected to livecd\"")
284 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Create Remastered CD\"")
285 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Clear Music on livecd\"")
288 def copyPlaylist( self ):
290 self.dia = ConfigDialog()
291 path, iso = self.dia.readConfig()
292 if path == "":
293 os.system("dcop amarok playlist popupMessage 'Please run configure first.'")
294 return
296 tmpfileloc = os.tmpnam()
297 os.system("dcop amarok playlist saveM3u '%s' false" % tmpfileloc)
298 tmpfile = open(tmpfileloc)
300 import urllib
302 files = ""
303 m3u = ""
304 for line in tmpfile.readlines():
305 if line[0] != "#":
307 line = line.strip()
309 # get filename
310 name = line.split("/")[-1]
312 #make url
313 url = "file://" + urllib.quote(line)
315 #make path on livecd
316 livecdpath = "/music/" + name
318 files += url + " "
319 m3u += livecdpath + "\n"
321 tmpfile.close()
323 files = files.strip()
325 os.system("kfmclient copy %s file://%s/amarok.live/music/" % (files, path))
327 import random
328 suffix = random.randint(0,10000)
329 # os.system("mkdir %s/amarok.live/home/amarok/.kde/share/apps/amarok/playlists/" % path)
330 m3uOut = open("/tmp/amarok.live.%s.m3u" % suffix, 'w')
332 m3u = m3u.strip()
333 m3uOut.write(m3u)
335 m3uOut.close()
337 os.system("mv /tmp/amarok.live.%s.m3u %s/amarok.live/playlist/" % (suffix,path))
338 os.system("rm /tmp/amarok.live.%s.m3u" % suffix)
341 os.remove(tmpfileloc)
343 def copyTrack( self, menuEvent ):
345 event = str( menuEvent )
346 debug( event )
347 self.dia = ConfigDialog()
349 path,iso = self.dia.readConfig()
350 if path == "":
351 os.system("kdialog --sorry 'You have not specified where the Amarok live iso is. Please click configure and do so first.'")
352 else:
353 # get the list of files. yes, its ugly. it works though.
354 #files = event.split(":")[-1][2:-1].split()[2:]
355 #trying out a new one
356 #files = event.split(":")[-1][3:-2].replace("\"Amarok live!\" \"add to livecd\" ", "").split("\" \"")
357 #and another
359 files = event.replace("customMenuClicked: Amarok live Add selected to livecd", "").split()
361 allfiles = ""
362 for file in files:
363 allfiles += file + " "
364 allfiles = allfiles.strip()
365 os.system("kfmclient copy %s file://%s/amarok.live/music/" % (allfiles, path))
367 def createCD( self ):
369 self.dia = ConfigDialog()
370 path,iso = self.dia.readConfig()
371 if path == "":
372 os.system("kdialog --sorry 'You have not configured Amarok live! Please run configure.")
374 fd = os.popen("kde-config --prefix", "r")
375 kdedir = fd.readline()
376 kdedir = kdedir.strip()
377 scriptdir = kdedir + "/share/apps/amarok/scripts/amarok_live"
378 fd.close()
380 os.system("kdesu sh %s/amarok.live.remaster.part2.sh %s" % (scriptdir, path))
382 fd = open("/tmp/amarok.script", 'r')
383 y = fd.readline()
384 y = y.strip()
385 if y == "end": # user said no more, clear path
386 self.dia.clear()
387 fd.close()
390 ############################################################################
392 def onSignal( signum, stackframe ):
393 fd = open("/tmp/amarok.stop", "w")
394 fd.write( "stopping")
395 fd.close()
397 print 'STOPPING'
399 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add playlist to livecd\"")
400 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Add selected to livecd\"")
401 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Create Remastered CD\"")
402 os.system("dcop amarok script removeCustomMenuItem \"Amarok live\" \"Clear Music on livecd\"")
405 def debug( message ):
406 """ Prints debug message to stdout """
408 print debug_prefix + " " + message
410 def main():
411 app = Remasterer( sys.argv )
413 # not sure if it works or not... playing it safe
414 dia = ConfigDialog()
416 app.exec_loop()
418 if __name__ == "__main__":
420 mainapp = threading.Thread(target=main)
421 mainapp.start()
422 signal.signal(15, onSignal)
423 print signal.getsignal(15)
424 while 1: sleep(120)
426 #main( sys.argv )