Merge lp:~mycompostpile/cairo-dock-plug-ins-extras/YoutubeDl into lp:~cairo-dock-team/cairo-dock-plug-ins-extras/third-party

Proposed by Brian
Status: Merged
Merged at revision: 281
Proposed branch: lp:~mycompostpile/cairo-dock-plug-ins-extras/YoutubeDl
Merge into: lp:~cairo-dock-team/cairo-dock-plug-ins-extras/third-party
Diff against target: 448 lines (+213/-66)
7 files modified
YoutubeDl/YoutubeDl (+60/-22)
YoutubeDl/YoutubeDl.conf (+6/-6)
YoutubeDl/auto-load.conf (+2/-2)
YoutubeDl/constantTypes.py (+1/-1)
YoutubeDl/fileDialogs.py (+109/-33)
YoutubeDl/getClipboardText.py (+33/-0)
YoutubeDl/myYoutubeDownloader.py (+2/-2)
To merge this branch: bzr merge lp:~mycompostpile/cairo-dock-plug-ins-extras/YoutubeDl
Reviewer Review Type Date Requested Status
Matthieu Baerts Approve
Review via email: mp+109979@code.launchpad.net

Description of the change

Added middle click selection to show up in the right click menu.

Cleaned up the handbook.

Added clipboard entry on right click if there appears to be a youtube url.
Also on left click when the list is empty added the default string to be the clipboard contents if there appears to be a youtube url.

Change the tab in the configuration file to read Configuration instead of User Interface.

Shortened the default time between updates.

Fixed the middle click not opening video folder before configuration saved.

Fixed the quick info being changed to YoutubeDl after reload.

Changed the abort to allow the next url to start downloading if user did not pause the downloads.

Added the gtk file dialogs to be the default. (still working on the gtk version of the url list editor)

To post a comment you must log in.
Revision history for this message
Matthieu Baerts (matttbe) wrote :

Hello,

I've to disapprove this change simply because it seems you've removed all other external applets :^^:

Can you move your 'YoutubeDl' directory somewhere else, delete your 'cairo-dock-plug-ins-extras' directory, re-download the branch (bzr branch lp:cairo-dock-plug-ins-extras) and commit your new features? :)

review: Needs Fixing
Revision history for this message
Matthieu Baerts (matttbe) wrote :

PS: you can push on the same branch with this command:
  $ bzr push lp:~mycompostpile/cairo-dock-plug-ins-extras/YoutubeDl --overwrite

281. By Brian

YoutubeDl: Fixed the missing applet folders

282. By Brian

YoutubeDl: attempting to fix diverge error

Revision history for this message
Brian (mycompostpile) wrote :

Upload fixed. My apologies. I thought I was doing something wrong by uploading all the applets every time I made a change. Guess I am not used to bzr yet. Thanks for your patience.

Revision history for this message
Matthieu Baerts (matttbe) wrote :

Thank you for this new version!

I just have a problem with 'getClipboardText':

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/dbus/connection.py", line 230, in maybe_handle_message
    self._handler(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/CDApplet.py", line 168, in _on_build_menu
    self.on_build_menu()
  File "./YoutubeDl", line 329, in on_build_menu
    if getClipboardText():
  File "/opt/cairo-dock_bzr/cairo-dock-plug-ins-extras/YoutubeDl/getClipboardText.py", line 13, in getClipboardText
    if text.find("youtube.com/watch") == -1:

(or with the line 16 instead of 13)
I guess text is null at this moment but I think it's not a good idea to only show this entry menu when we have a correct weblink for two reasons:
 * this feature is hidden most of the time
 * it takes time before building the menu and the size of the menu can be wrong.
Note that it can be interesting to support short youtube links (youtu.be/VIDEO_ID) and maybe to support more than one link ;)

review: Needs Fixing
283. By Brian

YoutubeDl: simplified getClipboardText; Fixed a couple of bugs in debuging code.

Revision history for this message
Matthieu Baerts (matttbe) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'YoutubeDl/YoutubeDl'
2--- YoutubeDl/YoutubeDl 2012-06-11 02:43:29 +0000
3+++ YoutubeDl/YoutubeDl 2012-06-16 03:04:23 +0000
4@@ -35,6 +35,9 @@
5 from constantTypes import PopupTypes
6 from constantTypes import menuEntries
7
8+#Get the clipboard text
9+from getClipboardText import getClipboardText
10+
11 class Applet(CDApplet):
12
13 def __init__(self):
14@@ -71,8 +74,8 @@
15 self.icon.SetQuickInfo(str(self.result[0]))
16 else:
17 self.icon.SetQuickInfo('')
18- if self.__showStatusOnIcon:
19- self.icon.SetLabel("YoutubeDl")
20+ # Uncomment the following line to trace debug actions in the console.
21+ #self.debug()
22 self.reload()
23 self.__setTimer()
24
25@@ -126,13 +129,18 @@
26 "editable" : False, })
27 self.currentDialog = PopupTypes.infoDialog
28 else:
29+ self.urlManualEntry()
30+
31+
32+ def urlManualEntry(self):
33+ defaultText = getClipboardText()
34 dialog_attributes = {
35 'message' : "Please enter URL:",
36 'use-markup' : True,
37 'buttons' : 'ok;cancel' }
38 widget_attributes = {
39 'widget-type' : 'text-entry',
40- 'initial-value' : "",
41+ 'initial-value' : defaultText,
42 'multi-lines' : False}
43 self.icon.PopupDialog (dialog_attributes, widget_attributes)
44 self.currentDialog = PopupTypes.urlManualEntry
45@@ -153,10 +161,18 @@
46
47 def on_middle_click(self):
48 if self.__actionOnMiddleClick == 'Open Video Folder':
49- subprocess.call(['xdg-open',self.__videos_directory], shell=False)
50+ if self.validVideoDirectory:
51+ subprocess.call(['xdg-open',self.__videos_directory], shell=False)
52+ else:
53+ tempString = "Error: Video Directory not writable.\n Please make sure directory is valid and writable"
54+ self.icon.PopupDialog( {"message" : tempString,
55+ "icon" : "gtk-stock-edit"},
56+ {"visible" : True,
57+ "multi-lines" : True,
58+ "editable" : False, })
59+ self.currentDialog = PopupTypes.infoDialog
60 else:
61 alerts.doUserAlert(self,self.resultSummary,4)
62-
63 return True
64
65 def reload(self):
66@@ -276,11 +292,23 @@
67 def on_build_menu(self):
68 self.messageDebug("onBuildMenu: context menu called")
69 items = []
70+ if self.validVideoDirectory:
71+ if self.__actionOnMiddleClick == 'Open Video Folder':
72+ items.append(
73+ {"label": _("Open Video Folder") + " (" + _("middle-click") + ")",
74+ "icon" : "gtk-open",
75+ "id" : menuEntries.openVideoFolder })
76+ else:
77+ items.append(
78+ {"label": _("Show Download Status") + " (" + _("middle-click") + ")",
79+ "icon" : "gtk-info",
80+ "id" : menuEntries.showDownloadStatus })
81 if self.activeDownload:
82 items.append(
83 {"label": "Abort current download",
84 "icon" : "gtk-cancel",
85- "id" : menuEntries.abortDownload })
86+ "id" : menuEntries.abortDownload,
87+ "tooltip" : _("Send abort signal to the downloader. There may be a delay") })
88 if len(self.urlList) > 0:
89 items.append(
90 {"label": "Save current URL list",
91@@ -300,6 +328,11 @@
92 {"label": "Load URL list from file",
93 "icon" : "gtk-open",
94 "id" : menuEntries.loadURLs })
95+ if getClipboardText():
96+ items.append(
97+ {"label": "Add URL from clipboard",
98+ "icon" : "gtk-edit",
99+ "id" : menuEntries.clipboardURL })
100 if self.__startDownloads:
101 items.append(
102 {"label": "Pause Downloading",
103@@ -333,6 +366,12 @@
104 self.saveURLs()
105 elif iNumEntry == menuEntries.loadURLs:
106 self.loadURLs()
107+ elif iNumEntry == menuEntries.clipboardURL:
108+ self.urlManualEntry()
109+ elif iNumEntry == menuEntries.openVideoFolder:
110+ subprocess.call(['xdg-open',self.__videos_directory], shell=False)
111+ elif iNumEntry == menuEntries.showDownloadStatus:
112+ alerts.doUserAlert(self,self.resultSummary,4)
113 elif iNumEntry == menuEntries.pauseDownload:
114 self.__startDownloads = False
115 message = "Downloading Paused"
116@@ -360,7 +399,6 @@
117 self.work_queue.put('Abort')
118 self.result = ['Aborting','Aborting','Aborting','Aborting']
119 self.icon.SetQuickInfo(str(self.result[0]))
120- self.__startDownloads = False
121 elif self.currentDialog == PopupTypes.delList:
122 self.messageDebug("onAnswerDialog: confirm delete: "+str(button)+" "+str(userResponse))
123 if button == 0:
124@@ -465,7 +503,7 @@
125 Write debug message to console.
126 """
127 if self.__debugMode:
128- print '<%s : %s>' % (self.__name, message)
129+ print '<%s : %s>' % (self.cAppletName, message)
130
131 def debug(self):
132 """
133@@ -480,21 +518,21 @@
134 """
135 Reload the configuration.
136 """
137- interval = keyfile.getint('User Interface', 'interval')
138+ interval = keyfile.getint('Configuration', 'interval')
139 self.__interval = interval * 1000 # convert in millisecondes.
140- self.__startDownloads = keyfile.getboolean('User Interface', 'startDownloads')
141- self.__showAlertStartDownloads = keyfile.getboolean('User Interface', 'showAlertStartDownloads')
142- self.__showAlertDownloadComplete = keyfile.getboolean('User Interface', 'showAlertDownloadComplete')
143- self.__showAlertDownloadAbort = keyfile.getboolean('User Interface', 'showAlertDownloadAbort')
144- self.__showAlertAddURL = keyfile.getboolean('User Interface', 'showAlertAddURL')
145- self.usePynotify = keyfile.getboolean('User Interface', 'usePynotify')
146- self.useListView = keyfile.getboolean('User Interface', 'useListView')
147- self.urlListExceeds = keyfile.getint('User Interface', 'urlListExceeds')
148- self.__actionOnMiddleClick = keyfile.get('User Interface', 'actionOnMiddleClick')
149- self.__showProgressOnIcon = keyfile.getboolean('User Interface', 'showProgressOnIcon')
150- self.__showStatusOnIcon = keyfile.getboolean('User Interface', 'showStatusOnIcon')
151- self.__videos_directory = keyfile.get('User Interface', 'videos_directory')
152- self.__urlList_directory = keyfile.get('User Interface', 'urlList_directory')
153+ self.__startDownloads = keyfile.getboolean('Configuration', 'startDownloads')
154+ self.__showAlertStartDownloads = keyfile.getboolean('Configuration', 'showAlertStartDownloads')
155+ self.__showAlertDownloadComplete = keyfile.getboolean('Configuration', 'showAlertDownloadComplete')
156+ self.__showAlertDownloadAbort = keyfile.getboolean('Configuration', 'showAlertDownloadAbort')
157+ self.__showAlertAddURL = keyfile.getboolean('Configuration', 'showAlertAddURL')
158+ self.usePynotify = keyfile.getboolean('Configuration', 'usePynotify')
159+ self.useListView = keyfile.getboolean('Configuration', 'useListView')
160+ self.urlListExceeds = keyfile.getint('Configuration', 'urlListExceeds')
161+ self.__actionOnMiddleClick = keyfile.get('Configuration', 'actionOnMiddleClick')
162+ self.__showProgressOnIcon = keyfile.getboolean('Configuration', 'showProgressOnIcon')
163+ self.__showStatusOnIcon = keyfile.getboolean('Configuration', 'showStatusOnIcon')
164+ self.__videos_directory = keyfile.get('Configuration', 'videos_directory')
165+ self.__urlList_directory = keyfile.get('Configuration', 'urlList_directory')
166 self.__setTimer()
167
168 if not self.__videos_directory:
169
170=== modified file 'YoutubeDl/YoutubeDl.conf'
171--- YoutubeDl/YoutubeDl.conf 2012-06-11 02:43:29 +0000
172+++ YoutubeDl/YoutubeDl.conf 2012-06-16 03:04:23 +0000
173@@ -1,4 +1,4 @@
174-#!en;0.0.9
175+#!en;0.1.0
176
177 #[gtk-about]
178 [Icon]
179@@ -91,8 +91,8 @@
180 fg alpha = 1
181
182
183-#User interface options
184-[User Interface]
185+#Configuration options
186+[Configuration]
187
188 #b Start downloading videos imediately? :
189 #{Otherwise use right click and enable downloads}
190@@ -101,15 +101,15 @@
191 #v
192 mySep =
193
194-#i[1;300] Time between updates:
195+#i[1;30] Time between updates:
196 #{in secondds}
197-interval = 30
198+interval = 5
199
200 #v
201 mySep =
202
203 #L[Open Video Folder;Show Status] Action on middle click:
204-actionOnMiddleClick = 0
205+actionOnMiddleClick = Open Video Folder
206
207 #v
208 mySep =
209
210=== modified file 'YoutubeDl/auto-load.conf'
211--- YoutubeDl/auto-load.conf 2012-06-11 02:43:29 +0000
212+++ YoutubeDl/auto-load.conf 2012-06-16 03:04:23 +0000
213@@ -4,13 +4,13 @@
214 author = Brian
215
216 # A short description of the applet and how to use it.
217-description = This applet allows a user to drag Youtube links from the Youtube website and drop them on the icon to download. The backend downloader is based on youtube-dl.py.\n\n If you have python-tk installed on your system saving and loading url lists will be done using a graphical dialog box, otherwise you need to set the directory path in the configuration and just enter the filename in the popup box.\n\n If you have pynotify installed on your system you have the option of letting the notification area of your desktop handle the alerts, otherwise alerts will be done using the cairo-dock popup messages. You can turn this feature on or off under the configuration.\n\nCurrently the url list is not editable from the dock but if you save the list to a file you can edit with a text editor then load the list back into the plugin. Downloading can be paused from the context menu of the icon and you can choose to have downloads start automatically in the configuration area.\n\nThe left click button on the mouse brings up the current url list and the middle button can be configured for different actions.\n\nPlease enjoy.
218+description = This applet allows a user to drag Youtube links from the Youtube website and drop them on the icon to download. The backend downloader is based on youtube-dl.py.\n\nOnly one video will be downloaded at a time and each url will be added to a list. When the video is downloaded or aborted the url will be removed from the list. The list can be saved to a file and loaded again for future use.\n\nThe middle mouse button can be configured to open the video folder or to show download status.\n\nRight clicking allows various options depending on what is happening at that time. If your video foler is not valid or not writeable then you can't download until it is corrected.\n\nIf there are no videos in the list left clicking on the icon allows you to enter a url. Otherwise the url list will be displayed.
219
220 # Category of the applet : 2 = files, 3 = internet, 4 = Desktop, 5 = accessory, 6 = fun
221 category = 3
222
223 # Version of the applet; change it everytime you change something in the config file. Don't forget to update the version both in this file and in the config file.
224-version = 0.0.9
225+version = 0.1.0
226
227 # Default icon to use if no icon has been defined by the user. If not specified, or if the file is not found, the "icon" file will be used.
228 icon =
229
230=== modified file 'YoutubeDl/constantTypes.py'
231--- YoutubeDl/constantTypes.py 2012-06-11 02:43:29 +0000
232+++ YoutubeDl/constantTypes.py 2012-06-16 03:04:23 +0000
233@@ -2,7 +2,7 @@
234 (infoDialog, confirmAbort, saveListFilename, getListFilename, delList, showUrlList, urlManualEntry) = range(7)
235
236 class menuEntries:
237- (abortDownload, saveURLs, loadURLs, pauseDownload, enableDownload, clearURLs, editURLs) = range(7)
238+ (abortDownload, saveURLs, loadURLs, pauseDownload, enableDownload, clearURLs, editURLs, clipboardURL, openVideoFolder, showDownloadStatus) = range(10)
239
240 class youtube:
241 videoFormats = {"H264 - MP4 at 480p":'18',
242
243=== modified file 'YoutubeDl/fileDialogs.py'
244--- YoutubeDl/fileDialogs.py 2012-06-09 04:13:00 +0000
245+++ YoutubeDl/fileDialogs.py 2012-06-16 03:04:23 +0000
246@@ -1,34 +1,110 @@
247 try:
248- import Tkinter, tkFileDialog
249- def openUrlFilename(initialDirectory):
250-
251- rootDialog = Tkinter.Tk()
252-
253- # define options for opening or saving a file
254- file_opt = options = {}
255- options['defaultextension'] = 'txt' # couldn't figure out how this works
256- options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
257- options['initialdir'] = initialDirectory
258- options['title'] = 'Please select a url list file to open'
259- options['parent'] = rootDialog
260- fileName = tkFileDialog.askopenfilename(**file_opt)
261- rootDialog.destroy()
262- return fileName
263-
264- def saveUrlFilename(initialDirectory):
265- rootDialog = Tkinter.Tk()
266- file_opt = options = {}
267- options['defaultextension'] = 'txt' # couldn't figure out how this works
268- options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
269- options['initialdir'] = initialDirectory
270- options['title'] = 'Please select a url list file to save'
271- options['parent'] = rootDialog
272- fileName = tkFileDialog.asksaveasfilename(**file_opt)
273- rootDialog.destroy()
274- return fileName
275-
276-except ImportError:
277- def openUrlFilename(initialDirectory):
278- return None
279- def saveUrlFilename(initialDirectory):
280- return None
281+ import pygtk
282+ pygtk.require('2.0')
283+
284+ import gtk
285+ def openUrlFilename(initialDirectory):
286+ # Check for new pygtk: this is new class in PyGtk 2.4
287+ if gtk.pygtk_version < (2,3,90):
288+ print "PyGtk 2.3.90 or later required for this example"
289+ raise SystemExit
290+
291+ dialog = gtk.FileChooserDialog("Open..",
292+ None,
293+ gtk.FILE_CHOOSER_ACTION_OPEN,
294+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
295+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
296+ dialog.set_default_response(gtk.RESPONSE_OK)
297+
298+ filter = gtk.FileFilter()
299+ filter.set_name("Text Files")
300+ filter.add_pattern("*.txt")
301+ dialog.add_filter(filter)
302+
303+ filter = gtk.FileFilter()
304+ filter.set_name("All files")
305+ filter.add_pattern("*")
306+ dialog.add_filter(filter)
307+
308+ dialog.set_current_folder(initialDirectory)
309+ response = dialog.run()
310+ if response == gtk.RESPONSE_OK:
311+ print "OK pressed: " + dialog.get_filename(), 'selected'
312+ fileName = dialog.get_filename()
313+ elif response == gtk.RESPONSE_CANCEL:
314+ print "Cancel pressed: " + dialog.get_filename(), 'selected'
315+ #print 'Closed, no files selected'
316+ fileName = ''
317+ dialog.destroy()
318+ return fileName
319+ def saveUrlFilename(initialDirectory):
320+ # Check for new pygtk: this is new class in PyGtk 2.4
321+ if gtk.pygtk_version < (2,3,90):
322+ print "PyGtk 2.3.90 or later required for this example"
323+ raise SystemExit
324+
325+ dialog = gtk.FileChooserDialog("Save..",
326+ None,
327+ gtk.FILE_CHOOSER_ACTION_SAVE,
328+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
329+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
330+ dialog.set_default_response(gtk.RESPONSE_OK)
331+
332+ filter = gtk.FileFilter()
333+ filter.set_name("Text Files")
334+ filter.add_pattern("*.txt")
335+ dialog.add_filter(filter)
336+
337+ filter = gtk.FileFilter()
338+ filter.set_name("All files")
339+ filter.add_pattern("*")
340+ dialog.add_filter(filter)
341+
342+ dialog.set_current_folder(initialDirectory)
343+ response = dialog.run()
344+ if response == gtk.RESPONSE_OK:
345+ print "OK pressed: " + str(dialog.get_filename()), 'selected'
346+ fileName = dialog.get_filename()
347+ elif response == gtk.RESPONSE_CANCEL:
348+ print "Cancel pressed: " + str(dialog.get_filename()), 'selected'
349+ #print 'Closed, no files selected'
350+ fileName = ''
351+ dialog.destroy()
352+ return fileName
353+#except ImportError:
354+except:
355+ try:
356+ import Tkinter, tkFileDialog
357+ def openUrlFilename(initialDirectory):
358+
359+ rootDialog = Tkinter.Tk()
360+
361+ # define options for opening or saving a file
362+ file_opt = options = {}
363+ options['defaultextension'] = 'txt' # couldn't figure out how this works
364+ options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
365+ options['initialdir'] = initialDirectory
366+ options['title'] = 'Please select a url list file to open'
367+ options['parent'] = rootDialog
368+ fileName = tkFileDialog.askopenfilename(**file_opt)
369+ rootDialog.destroy()
370+ return fileName
371+
372+ def saveUrlFilename(initialDirectory):
373+ rootDialog = Tkinter.Tk()
374+ file_opt = options = {}
375+ options['defaultextension'] = 'txt' # couldn't figure out how this works
376+ options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
377+ options['initialdir'] = initialDirectory
378+ options['title'] = 'Please select a url list file to save'
379+ options['parent'] = rootDialog
380+ fileName = tkFileDialog.asksaveasfilename(**file_opt)
381+ rootDialog.destroy()
382+ return fileName
383+
384+ #except ImportError:
385+ except:
386+ def openUrlFilename(initialDirectory):
387+ return None
388+ def saveUrlFilename(initialDirectory):
389+ return None
390
391=== added file 'YoutubeDl/getClipboardText.py'
392--- YoutubeDl/getClipboardText.py 1970-01-01 00:00:00 +0000
393+++ YoutubeDl/getClipboardText.py 2012-06-16 03:04:23 +0000
394@@ -0,0 +1,33 @@
395+#!/usr/bin/env python
396+
397+#try the gtk method of getting the clipboard contents first
398+try:
399+ import gtk
400+
401+ def getClipboardText():
402+ clipboard = gtk.clipboard_get()
403+ return clipboard.wait_for_text()
404+except:
405+ #next try the tkinter method of getting the clipboard contents
406+ try:
407+ import Tkinter
408+ def getClipboardText():
409+ root = Tkinter.Tk()
410+ root.withdraw() # Hide the main window (optional)
411+ return root.clipboard_get()
412+ except:
413+ #finally try the xclip method of getting the clipboard contents
414+ try:
415+ import subprocess
416+ def getClipboardText():
417+ try:
418+ p = subprocess.Popen(["xclip","-out","-selection","clipboard"],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
419+ clipText, errors = p.communicate()
420+ return clipText
421+ except:
422+ #If xclip fails return nothing
423+ return ""
424+ except:
425+ #If all fails then return nothing
426+ def getClipboardText():
427+ return ""
428
429=== modified file 'YoutubeDl/myYoutubeDownloader.py'
430--- YoutubeDl/myYoutubeDownloader.py 2012-06-01 22:55:12 +0000
431+++ YoutubeDl/myYoutubeDownloader.py 2012-06-16 03:04:23 +0000
432@@ -71,7 +71,7 @@
433 try:
434 url = self.work_queue.get()
435 self.__config.refresh()
436- videos_directory = self.__config.get('User Interface', 'videos_directory')
437+ videos_directory = self.__config.get('Configuration', 'videos_directory')
438 self.useFormat = self.__config.get('Download Options', 'useFormat')
439 self.videoFormat = self.__config.get('Download Options', 'videoFormat')
440 self.maxVideoFormat = self.__config.get('Download Options', 'maxVideoFormat')
441@@ -97,7 +97,7 @@
442 except Queue.Empty:
443 time.sleep(1)
444
445- def debug():
446+ def debug(self):
447 global doDebug
448 doDebug = True
449

Subscribers

People subscribed via source and target branches

to all changes: