SEARCH

Enter your search query in the box above ^, or use the forum search tool.

You are not logged in.

#26 2011-07-14 20:51:50

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 12,783
Website

Re: the ultimate pipe menu thread

jmbarnes wrote:

As always Anonymous comes through.  This works perfectly.

And being a true genius he prefers to remain anonymous.  lol

I gotta take a look at this.

Offline

Help fund CrunchBang, donate to the project!

#27 2011-07-15 04:06:59

johnraff
nullglob
From: Nagoya, Japan
Registered: 2009-01-07
Posts: 3,030
Website

Re: the ultimate pipe menu thread

jmbarnes wrote:

Known bugs:

  • Doesn't handle characters like '&' well because Openbox's XML doesn't much like them.

You have to escape '&' as '&amp;', also > < " or ' if they should appear in a filename (unlikely, agreed) need to be escaped as
&lt; &gt; &quot; or &apos; respectively. The places menu does it in bash with:

case "$path" in    # only escape if string needs it
*\&*|*\<*|*\>*|*\"*|*\'*) pathe=$(sed "s/\&/\&amp;/g;s/</\&lt;/g;s/>/\&gt;/g;s/\"/\&quot;/g;s/'/\&apos;/g;") <<XXX
$path
XXX
;;
*)pathe=$path;;
esac

where $path is the path to the file, and $pathe is the escaped version. I can't offer any help with python though. sad


John
--------------------
( a boring Japan blog , idle twitterings  and GitStuff )
#! forum moderator

Offline

#28 2011-07-15 18:24:03

jmbarnes
#! Junkie
Registered: 2009-05-04
Posts: 250

Re: the ultimate pipe menu thread

johnraff wrote:

I can't offer any help with python though. sad

Perhaps not, but you led me in the right direction. I've added support for handling '&'s into the script. Seems to work quite well now -- at least for my uses. The updated version also includes a few cleanups and additional comments for anyone interested in modifying it.

So here it is, a python pipemenu for recursive listing of recently modified files:
http://crunchbanglinux.org/pastebin/1129

EDIT: Fixed a bug to avoid hanging on non-existing directories (helpful with network mounts that are missing.) Also cleaned up  / slimmed down a good deal.

Last edited by jmbarnes (2011-07-19 00:58:51)


IRC: PizzaAndWine     Script bits: Incremental Backup | Sleep Timer

Offline

#29 2011-09-08 22:57:50

h8uthemost
#! Junkie
Registered: 2011-08-09
Posts: 300

Re: the ultimate pipe menu thread

Just wanted to thanks anonymous for posting the MoC script. If I didn't read this thread I wouldn't have known about MoC. Just installed it and fired it up and works beautifully. Light and fast music player. Very cool. Just might end up dumping DeadBeef for this one.

The script will come in handy for a console based media player. Thanks anon.

Last edited by h8uthemost (2011-09-08 23:03:03)


We are a nice, friendly community here and I hope we stay that way.

Offline

#30 2011-10-26 14:34:18

jazzerit
New Member
Registered: 2011-10-26
Posts: 4

Re: the ultimate pipe menu thread

I made a devices pipe menu. It shows you the mountpoint and device file it corresponds to. It also lets you open it in a file manager (default thunar) or device manager (default palimpsest). If you have any optical disks, it will show you the type of disk (cd, dvd etc.) and lets you open it in the default file manager or eject it. It will also show any loop devices: it shows mountpoint and source directory (if needed, the end is shortened to fit the entry). In it's sub-menu, it shows the name of the source image and device file, and lets you open the mountpoint or source directory. On the bottom, it has a link to the recycle bin.

(I've almost finished describing it, I promise!) It has a load of configuration options at the top of the script. It lets you choose the default file manager, the disk manager, eject command  and recycle bin command, and lets you choose whether to show the recycle bin in the menu, and whether to show the disk manager, and whether to show the eject command.

Maybe a screenshot would show it better... so:
2011102613196390661440x.png

The only bug I've noticed is that the first time you start it when you log on, it takes a long time to show anything, and freezes openbox. But after ~10 seconds, it works fine again, and is quite fast any time after that in the same session.
Script:

#!/bin/bash



##############################################################################
##############################################################################
##########CONFIGURATION#######################################################
##############################################################################
##############################################################################
filemanager='thunar '  #points to your favoured file manager. If this isn't working, try removing or deleting a space as applicable on this variable.
diskmanager='palimpsest --show-volume=' #points to your favoured disk manager. If this isn't working, try removing or deleting a space as applicable on this variable.
##############################################################################
showbin='true' #set as either true or false (defaults to true). Sets whether to link to the rubbish bin in the menu or not.
bincommand='thunar trash://' #the command to use to open the rubbish bin. Not needed if showbin=false.
##############################################################################
showeject='true' #set as either true or false (defaults to true). Sets whether to show an eject option for optical disks.
ejectcommand='eject -T' #points to the command to use for ejecting disks
##############################################################################
showdm='true' #set as either true or false (defaults to true). Sets whether to show a disk management option for block devices.
##############################################################################
mediaplayer='vlc' #sets the media player to be used. Bear in mind, the media player has to be able to accept block devices on the command line
showmp='true' #set as either true or false (defaults to true). Sets whether to show a media player in the optical disk menus
##############################################################################
##############################################################################
##########END CONFIGURATION###################################################
##############################################################################
##############################################################################




echo "<openbox_pipe_menu>" #start of pipemenu


###############
#block devices#
###############
list=$(ls /sys/block | grep -v sr0 | grep -v scd0 | grep -v ram* | grep -v loop* | grep -v fd* | while read line; do ls /dev | grep -e "$line"; done)
devs=$(echo "$list" | while read line; do blkid /dev/$line; done)
echo "$devs" | while read line; do
  device=${line%%:*}
  devline=$(mount | grep $device)
  devlinepass1=${devline##/dev/*on }
  mountpoint=${devlinepass1%% type *}
  devlinepass1=
  devline=
  if [ -n "$mountpoint" ]; then
    echo "<menu id=\"$device\" label=\"$device mounted at $mountpoint\">"
    echo "<item label=\"open in file manager\"><action name=\"Execute\"><execute>$filemanager\"$mountpoint\"</execute></action></item>"
    if [ ! "$showdm" = "false" ]; then
      echo "<item label=\"open in disk utility\"><action name=\"Execute\"><execute>$diskmanager$device</execute></action></item>"
    fi
    echo "</menu>"
  fi
done


###############
#optical disks#
###############
ls /sys/block | grep -e 'sr\|scd' | while read optdisks; do
  line=$(udisks --show-info /dev/$optdisks | grep -e "has media:" | column -t | grep -w 1)
  if [ -n "$line" ]; then
    media1=$(udisks --show-info /dev/$optdisks | grep -e "media:" | column -t | grep -v rotational | grep -v "has" | column -t | tr '_' ' ')
    media=${media1##media:}
    echo "<separator/>"
    echo "<menu id=\"device\" label=\"$media\">"
        if [ ! "$showmp" = "false" ]; then
            echo "<item label=\"Open in VLC\"><action name=\"Execute\"><execute>$mediaplayer \"/dev/$optdisks\"</execute></action></item>"
        fi
    echo "<item label=\"Open in file manager\"><action name=\"Execute\"><execute>$filemanager\"/media/cdrom0\"</execute></action></item>"
    if [ ! "$showeject" = "false" ]; then
      echo "<item label=\"eject disk\"><action name=\"Execute\"><execute>$ejectcommand</execute></action></item>"
    fi
    echo "</menu>"
  fi
done


##############
#loop devices#
##############
mount | grep -e "/dev/loop[[:digit:]]" | while read line; do
device=${line// on*}
infodmp=$(udisks --show-info $device | grep -e "filename" | tr -s ' ')
source1=${infodmp//*filename: }
name=$(basename "$source1")
source=$(dirname "$source1" | head -c 30)...
pass1=${line//$device on }
mountpoint=${pass1// type*}
  if [ -n "$mountpoint" ]; then
    echo "<separator/>"
    echo "<menu id=\"$source\" label=\"$source on $mountpoint\">"
        echo "<separator label=\"$name ($device)\" />"
    echo "<item label=\"Open in file manager\"><action name=\"Execute\"><execute>$filemanager\"$mountpoint\"</execute></action></item>"
    echo "<item label=\"Open source directory in file manager\"><action name=\"Execute\"><execute>$filemanager\"$source\"</execute></action></item>"
    echo "</menu>"
  fi
done

#############
#rubbish bin#
#############
if [ ! "$showbin" = "false" ]; then
  echo "<separator/>"
  echo "<item label=\"Rubbish bin\"><action name=\"Execute\"><execute>$bincommand</execute></action></item>"
fi


echo "</openbox_pipe_menu>" #end of pipemenu

Last edited by jazzerit (2011-10-29 14:37:13)

Offline

#31 2011-11-30 11:04:35

jelloir
#! CrunchBanger
From: Outside the garden wall
Registered: 2009-08-21
Posts: 212

Re: the ultimate pipe menu thread

For device management there is also obdevicemenu

Offline

#32 2012-01-23 19:20:15

jmad2011
#! Junkie
From: newton falls ohio
Registered: 2011-12-25
Posts: 344

Re: the ultimate pipe menu thread

benj1 wrote:

ok ive just discovered the joys of pipe menus
and as there doesnt seem to be a crunchbang forum thread so i thought i would start one.

ok heres mine, used for controlling MPD


#!/usr/bin/env python
#
# Author: Ben Holroyd <holroyd.ben@gmail.com>
# License: GPL 3.0+
#
# This script requires python-mpd
#
# Usage:
# Put an entry in ~/.config/openbox/menu.xml:
# <menu id="mpd" label="MPD" execute="~/.config/openbox/scripts/ompb.py" />
#
import mpd, os, sys, socket
mpdport = 6600
musicfolder ='/home/ben/music/'
filelist = True  #potentially slow and unwieldy with a large collection of music
playlist = True #same for this
program = sys.argv[0]

client = mpd.MPDClient()  
try:
    client.connect("localhost", mpdport)    
except socket.error:
    print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
    print "<openbox_pipe_menu>"
    print "  <item label=\"MPD not running, click to start\">"
    print "    <action name=\"Execute\"><execute>mpd</execute></action>"
    print "  </item>"
    print "</openbox_pipe_menu>"
    sys.exit(0)    

song = client.currentsong()                      
stats = client.stats()
status = client.status() 

def play():
    if status['state'] == "stop" or status['state'] == "pause":
        client.play()
    elif status['state'] == "play":
        client.pause()
    
def volume(vol):
    if vol == "up":
        client.setvol(int(status['volume'])+10)
    elif vol == "down":
        client.setvol(int(status['volume'])-10)
           
try:
    if (sys.argv[1] == "play"):       play()
    elif (sys.argv[1] == "stop"):     client.stop()
    elif (sys.argv[1] == "prev"):     client.previous()
    elif (sys.argv[1] == "next"):     client.next()
    elif (sys.argv[1] == "add"):      client.add(sys.argv[2]); client.play()
    elif (sys.argv[1] == "clear"):    client.clear()
    elif (sys.argv[1] == "volume"):   volume(sys.argv[2])
    elif (sys.argv[1] == "playlist"): 
        client.delete(client.playlist().index(sys.argv[2]))
    elif sys.argv[1] == "random":
        client.random(int(not int(client.status()['random'])and True or False))
    elif sys.argv[1] == "repeat":
        client.repeat(int(not int(client.status()['repeat'])and True or False))
except IndexError:
    pass

def item_entry(indent, label, option = '', song = ''):
    """label = label on menu, option = play/pause/stop etc, song = path to song  """
    print "%s<item label=\"%s\">"%(indent, label)
    print "%s  <action name=\"Execute\"><execute>%s %s '%s'</execute></action>" % (indent, program, option, song)
    print "%s</item>" % (indent)
    
def file_walk(dir,indent):
    """ walks through music directory building a menu to view albums"""
    files = os.listdir(dir)
    files.sort()
    for file in files:
        path = os.path.join(dir,file)
        if os.path.isdir(path):
            print "%s<menu id=\"%s\" label=\"%s\">"%(indent, file, file)
            item_entry(indent+'  ','Add all to playlist','add' ,path.replace(musicfolder,''))
            print "%s  <separator />" % indent
            file_walk(path,indent+'  ')
            print "%s</menu>" % indent
        else:
            item_entry(indent,file,'add',path.replace(musicfolder,''))          
    indent = indent[2:]

def track_info(label):
    print "  <menu id=\"%s\" label=\"%s\">"%(label,label)
    print "    <item label=\"Artist: %s\"/>" % song['artist']
    print "    <item label=\"Album: %s\"/>" % song['album']
    print "    <item label=\"Tracklength: %.2f\"/>" % ((int(song['time'])/60)+(int(song['time'])%60.0/100))  
    print "    <item label=\"Track: %s\"/>" % song['track']
    print "    <item label=\"filetype: %s\"/>" % song['file'][song['file'].rfind('.')+1:]
    #print "    <item label=\"Genre: %s\"/>" % song['genre']
    print "  </menu>"


print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
print "<openbox_pipe_menu>"
if status['state'] != "stop":
    track_info("Playing: %s - " % song['artist'])
    track_info(song['title'])
    print "  <separator />"
print "  <item label=\"Status: %s\"/>" % {'play':'Playing','pause':'Paused','stop':'Stopped'}[status['state']]    
print "  <separator />"
item_entry('  ', 'Play/Pause', 'play')    
item_entry('  ', 'Stop', 'stop')
item_entry('  ', 'Prev', 'prev')
item_entry('  ', 'Next', 'next')
print "  <separator />"
if filelist == True:
    print "  <menu id=\"Albums\" label=\"Albums\">"
    file_walk(musicfolder,'  ')
    print "  </menu>"
    print "  <separator />"
if playlist == True:
    print "  <menu id=\"Playlist\" label=\"Playlist\">"
    print "    <item label=\"Click to remove from playlist\"/>"
    print "    <separator />"
    for entries in client.playlist():
        item_entry('    ', entries, 'playlist', entries)
    print "  </menu>"
    print "  <separator />"
item_entry('  ', 'Clear Playlist', 'clear')
item_entry('  ', 'Random %s' % (int(status['random']) and '[On]' or '[Off]'), 'random')    
item_entry('  ', 'Repeat %s' % (int(status['repeat']) and '[On]' or '[Off]'), 'repeat')    
print "  <menu id=\"volume\" label=\"Volume [%s]\">" % (int(status['volume']) > 0 and status['volume']+'%' or 'mute') 
item_entry('    ', 'Volume + 10\% ', 'volume up')
item_entry('    ', 'Volume - 10\%', 'volume down')
print "  </menu>"
print "  <separator />"
print "  <menu id=\"stats\" label=\"Database Stats\">"
print "    <item label=\"Artists in database: %s\"/>" % stats['artists']
print "    <item label=\"Albums in database: %s\"/>" % stats['albums']
print "    <item label=\"Songs in database: %s\"/>" % stats['songs']
print "  </menu>"
print "</openbox_pipe_menu>"

to use you need to add an entry to ~/.config/openbox/menu.xml
(also accessible through the menu preferences-->openbox config --> edit menu.xml)
something like

<menu id="mpd" label="MPD" execute="path/to/ompb.py"/>

 

Invalid Output from menu is all i keep getting


Say your prayer's,Eat your vitamins....AND WHAT YOU GONNA DO BROTHA

Offline

#33 2012-07-03 14:30:06

nabu
Member
Registered: 2011-03-30
Posts: 27

Re: the ultimate pipe menu thread

Can anyone please post the menu.xml from the Statler latest buid - I did overwrite with an older one and now I have entries that don't fit the system. Or if enyone knows how to extract the file from usb installer I would appreciate it.

Thanks

Offline

#34 2012-07-03 16:05:13

pvsage
Internal Affairs
From: North Carolina
Registered: 2009-10-18
Posts: 12,777

Re: the ultimate pipe menu thread

Look in /etc/skel - you should find default user files there, including menu.xml.


I'm a moderator here.  How are we doing?  Feedback is encouraged.

Offline

#35 2012-07-03 22:44:50

nabu
Member
Registered: 2011-03-30
Posts: 27

Re: the ultimate pipe menu thread

pvsage wrote:

Look in /etc/skel - you should find default user files there, including menu.xml.

Didn't know about that folder.

Thanks pvsage, you've really saved my day!

Offline

#36 2012-11-05 02:57:23

mosesgunn
#! CrunchBanger
Registered: 2012-10-20
Posts: 133

Re: the ultimate pipe menu thread

jmad2011 - I'm getting a similar error.

benj1 - could it be something in the code?

Offline

#37 2012-11-07 15:40:11

mosesgunn
#! CrunchBanger
Registered: 2012-10-20
Posts: 133

Re: the ultimate pipe menu thread

I am starting to enter into the world of pipemenus!  But I have not been able to get one particular pipemenu working, a python mpd script.
I made a ,py file with the code o found on benj1's ultimate pipemenu thread.  I made it executable and made a pipemenu entry using the ob gui editor - and I am getting the following error when I try to access the pipemenu.

    Failed to execute command for pipe-menu "home/manning/bin/mpd-menu.py": Failed to execute child process for pipe-menu "home/manning/bin/mpd-menu.py" (Permission Denied)

Here is the code I am using:

#!/usr/bin env python
#
# Author: Ben Holroyd <holroyd.ben@gmail.com>
# License: GPL 3.0+
#
# This script requires python-mpd
#
# Usage:
# Put an entry in ~/.config/openbox/menu.xml:
# <menu id="mpd" label="MPD" execute="~/.config/openbox/scripts/ompb.py" />
#
import mpd, os, sys, socket
mpdport = 6600
musicfolder ='/home/manning/music'
filelist = True  #potentially slow and unwieldy with a large collection of music
playlist = True #same for this
program = sys.argv[0]

client = mpd.MPDClient() 
try:
    client.connect("localhost", mpdport)   
except socket.error:
    print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
    print "<openbox_pipe_menu>"
    print "  <item label=\"MPD not running, click to start\">"
    print "    <action name=\"Execute\"><execute>mpd</execute></action>"
    print "  </item>"
    print "</openbox_pipe_menu>"
    sys.exit(0)   

song = client.currentsong()                     
stats = client.stats()
status = client.status()

def play():
    if status['state'] == "stop" or status['state'] == "pause":
        client.play()
    elif status['state'] == "play":
        client.pause()
   
def volume(vol):
    if vol == "up":
        client.setvol(int(status['volume'])+10)
    elif vol == "down":
        client.setvol(int(status['volume'])-10)
           
try:
    if (sys.argv[1] == "play"):       play()
    elif (sys.argv[1] == "stop"):     client.stop()
    elif (sys.argv[1] == "prev"):     client.previous()
    elif (sys.argv[1] == "next"):     client.next()
    elif (sys.argv[1] == "add"):      client.add(sys.argv[2]); client.play()
    elif (sys.argv[1] == "clear"):    client.clear()
    elif (sys.argv[1] == "volume"):   volume(sys.argv[2])
    elif (sys.argv[1] == "playlist"):
        client.delete(client.playlist().index(sys.argv[2]))
    elif sys.argv[1] == "random":
        client.random(int(not int(client.status()['random'])and True or False))
    elif sys.argv[1] == "repeat":
        client.repeat(int(not int(client.status()['repeat'])and True or False))
except IndexError:
    pass

def item_entry(indent, label, option = '', song = ''):
    """label = label on menu, option = play/pause/stop etc, song = path to song  """
    print "%s<item label=\"%s\">"%(indent, label)
    print "%s  <action name=\"Execute\"><execute>%s %s '%s'</execute></action>" % (indent, program, option, song)
    print "%s</item>" % (indent)
   
def file_walk(dir,indent):
    """ walks through music directory building a menu to view albums"""
    files = os.listdir(dir)
    files.sort()
    for file in files:
        path = os.path.join(dir,file)
        if os.path.isdir(path):
            print "%s<menu id=\"%s\" label=\"%s\">"%(indent, file, file)
            item_entry(indent+'  ','Add all to playlist','add' ,path.replace(musicfolder,''))
            print "%s  <separator />" % indent
            file_walk(path,indent+'  ')
            print "%s</menu>" % indent
        else:
            item_entry(indent,file,'add',path.replace(musicfolder,''))         
    indent = indent[2:]

def track_info(label):
    print "  <menu id=\"%s\" label=\"%s\">"%(label,label)
    print "    <item label=\"Artist: %s\"/>" % song['artist']
    print "    <item label=\"Album: %s\"/>" % song['album']
    print "    <item label=\"Tracklength: %.2f\"/>" % ((int(song['time'])/60)+(int(song['time'])%60.0/100)) 
    print "    <item label=\"Track: %s\"/>" % song['track']
    print "    <item label=\"filetype: %s\"/>" % song['file'][song['file'].rfind('.')+1:]
    #print "    <item label=\"Genre: %s\"/>" % song['genre']
    print "  </menu>"


print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
print "<openbox_pipe_menu>"
if status['state'] != "stop":
    track_info("Playing: %s - " % song['artist'])
    track_info(song['title'])
    print "  <separator />"
print "  <item label=\"Status: %s\"/>" % {'play':'Playing','pause':'Paused','stop':'Stopped'}[status['state']]   
print "  <separator />"
item_entry('  ', 'Play/Pause', 'play')   
item_entry('  ', 'Stop', 'stop')
item_entry('  ', 'Prev', 'prev')
item_entry('  ', 'Next', 'next')
print "  <separator />"
if filelist == True:
    print "  <menu id=\"Albums\" label=\"Albums\">"
    file_walk(musicfolder,'  ')
    print "  </menu>"
    print "  <separator />"
if playlist == True:
    print "  <menu id=\"Playlist\" label=\"Playlist\">"
    print "    <item label=\"Click to remove from playlist\"/>"
    print "    <separator />"
    for entries in client.playlist():
        item_entry('    ', entries, 'playlist', entries)
    print "  </menu>"
    print "  <separator />"
item_entry('  ', 'Clear Playlist', 'clear')
item_entry('  ', 'Random %s' % (int(status['random']) and '[On]' or '[Off]'), 'random')   
item_entry('  ', 'Repeat %s' % (int(status['repeat']) and '[On]' or '[Off]'), 'repeat')   
print "  <menu id=\"volume\" label=\"Volume [%s]\">" % (int(status['volume']) > 0 and status['volume']+'%' or 'mute')
item_entry('    ', 'Volume + 10\% ', 'volume up')
item_entry('    ', 'Volume - 10\%', 'volume down')
print "  </menu>"
print "  <separator />"
print "  <menu id=\"stats\" label=\"Database Stats\">"
print "    <item label=\"Artists in database: %s\"/>" % stats['artists']
print "    <item label=\"Albums in database: %s\"/>" % stats['albums']
print "    <item label=\"Songs in database: %s\"/>" % stats['songs']
print "  </menu>"
print "</openbox_pipe_menu>"
exit 0

Thanks for any input!!  I am diggin this crunchbang community!!!

Offline

#38 2012-11-23 16:47:16

sohaeb
New Member
Registered: 2012-11-12
Posts: 9

Re: the ultimate pipe menu thread

Can you guys update this thread ? for example mdp is not woking form and the batter script is also not working.

Offline

#39 2013-08-19 21:31:14

jpope
#! Junkie
From: USA
Registered: 2009-09-20
Posts: 281
Website

Re: the ultimate pipe menu thread

After three and a half years of the last update, I updated my #! Forums pipemenu: Link

2013-08-19--1376947051_1366x768_scrot.thumbnail.png

Enjoy! wink

2013.08.19: Updated script and link to pastebin
2013.08.20: Another update to script and pastebin link

Last edited by jpope (2013-08-20 17:09:03)


--
...old school #! user now mostly running Arch
jpope.org

Offline

#40 2013-09-10 02:19:02

mw
New Member
Registered: 2013-09-09
Posts: 7

Re: the ultimate pipe menu thread

jmad2011 wrote:
benj1 wrote:

ok ive just discovered the joys of pipe menus
and as there doesnt seem to be a crunchbang forum thread so i thought i would start one.

ok heres mine, used for controlling MPD


#!/usr/bin/env python
#
# Author: Ben Holroyd <holroyd.ben@gmail.com>
# License: GPL 3.0+
#
# This script requires python-mpd
#
# Usage:
# Put an entry in ~/.config/openbox/menu.xml:
# <menu id="mpd" label="MPD" execute="~/.config/openbox/scripts/ompb.py" />
#
import mpd, os, sys, socket
mpdport = 6600
musicfolder ='/home/ben/music/'
filelist = True  #potentially slow and unwieldy with a large collection of music
playlist = True #same for this
program = sys.argv[0]

client = mpd.MPDClient()  
try:
    client.connect("localhost", mpdport)    
except socket.error:
    print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
    print "<openbox_pipe_menu>"
    print "  <item label=\"MPD not running, click to start\">"
    print "    <action name=\"Execute\"><execute>mpd</execute></action>"
    print "  </item>"
    print "</openbox_pipe_menu>"
    sys.exit(0)    

song = client.currentsong()                      
stats = client.stats()
status = client.status() 

def play():
    if status['state'] == "stop" or status['state'] == "pause":
        client.play()
    elif status['state'] == "play":
        client.pause()
    
def volume(vol):
    if vol == "up":
        client.setvol(int(status['volume'])+10)
    elif vol == "down":
        client.setvol(int(status['volume'])-10)
           
try:
    if (sys.argv[1] == "play"):       play()
    elif (sys.argv[1] == "stop"):     client.stop()
    elif (sys.argv[1] == "prev"):     client.previous()
    elif (sys.argv[1] == "next"):     client.next()
    elif (sys.argv[1] == "add"):      client.add(sys.argv[2]); client.play()
    elif (sys.argv[1] == "clear"):    client.clear()
    elif (sys.argv[1] == "volume"):   volume(sys.argv[2])
    elif (sys.argv[1] == "playlist"): 
        client.delete(client.playlist().index(sys.argv[2]))
    elif sys.argv[1] == "random":
        client.random(int(not int(client.status()['random'])and True or False))
    elif sys.argv[1] == "repeat":
        client.repeat(int(not int(client.status()['repeat'])and True or False))
except IndexError:
    pass

def item_entry(indent, label, option = '', song = ''):
    """label = label on menu, option = play/pause/stop etc, song = path to song  """
    print "%s<item label=\"%s\">"%(indent, label)
    print "%s  <action name=\"Execute\"><execute>%s %s '%s'</execute></action>" % (indent, program, option, song)
    print "%s</item>" % (indent)
    
def file_walk(dir,indent):
    """ walks through music directory building a menu to view albums"""
    files = os.listdir(dir)
    files.sort()
    for file in files:
        path = os.path.join(dir,file)
        if os.path.isdir(path):
            print "%s<menu id=\"%s\" label=\"%s\">"%(indent, file, file)
            item_entry(indent+'  ','Add all to playlist','add' ,path.replace(musicfolder,''))
            print "%s  <separator />" % indent
            file_walk(path,indent+'  ')
            print "%s</menu>" % indent
        else:
            item_entry(indent,file,'add',path.replace(musicfolder,''))          
    indent = indent[2:]

def track_info(label):
    print "  <menu id=\"%s\" label=\"%s\">"%(label,label)
    print "    <item label=\"Artist: %s\"/>" % song['artist']
    print "    <item label=\"Album: %s\"/>" % song['album']
    print "    <item label=\"Tracklength: %.2f\"/>" % ((int(song['time'])/60)+(int(song['time'])%60.0/100))  
    print "    <item label=\"Track: %s\"/>" % song['track']
    print "    <item label=\"filetype: %s\"/>" % song['file'][song['file'].rfind('.')+1:]
    #print "    <item label=\"Genre: %s\"/>" % song['genre']
    print "  </menu>"


print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
print "<openbox_pipe_menu>"
if status['state'] != "stop":
    track_info("Playing: %s - " % song['artist'])
    track_info(song['title'])
    print "  <separator />"
print "  <item label=\"Status: %s\"/>" % {'play':'Playing','pause':'Paused','stop':'Stopped'}[status['state']]    
print "  <separator />"
item_entry('  ', 'Play/Pause', 'play')    
item_entry('  ', 'Stop', 'stop')
item_entry('  ', 'Prev', 'prev')
item_entry('  ', 'Next', 'next')
print "  <separator />"
if filelist == True:
    print "  <menu id=\"Albums\" label=\"Albums\">"
    file_walk(musicfolder,'  ')
    print "  </menu>"
    print "  <separator />"
if playlist == True:
    print "  <menu id=\"Playlist\" label=\"Playlist\">"
    print "    <item label=\"Click to remove from playlist\"/>"
    print "    <separator />"
    for entries in client.playlist():
        item_entry('    ', entries, 'playlist', entries)
    print "  </menu>"
    print "  <separator />"
item_entry('  ', 'Clear Playlist', 'clear')
item_entry('  ', 'Random %s' % (int(status['random']) and '[On]' or '[Off]'), 'random')    
item_entry('  ', 'Repeat %s' % (int(status['repeat']) and '[On]' or '[Off]'), 'repeat')    
print "  <menu id=\"volume\" label=\"Volume [%s]\">" % (int(status['volume']) > 0 and status['volume']+'%' or 'mute') 
item_entry('    ', 'Volume + 10\% ', 'volume up')
item_entry('    ', 'Volume - 10\%', 'volume down')
print "  </menu>"
print "  <separator />"
print "  <menu id=\"stats\" label=\"Database Stats\">"
print "    <item label=\"Artists in database: %s\"/>" % stats['artists']
print "    <item label=\"Albums in database: %s\"/>" % stats['albums']
print "    <item label=\"Songs in database: %s\"/>" % stats['songs']
print "  </menu>"
print "</openbox_pipe_menu>"

to use you need to add an entry to ~/.config/openbox/menu.xml
(also accessible through the menu preferences-->openbox config --> edit menu.xml)
something like

<menu id="mpd" label="MPD" execute="path/to/ompb.py"/>

 

Invalid Output from menu is all i keep getting

None of the strings in the above code are escaped so wrapping the variables at the end of string replacements (lines containing %s) in a xml quoting function might help. Ideally someone could try and rewrite the whole script using an XML builder, but that's just my 2 cents..

Offline

#41 2013-11-03 18:53:58

Yajmon#!
New Member
Registered: 2013-11-03
Posts: 7

Re: the ultimate pipe menu thread

I've wondered about a pipe menu similar to the built in "Desktops" one, except to give you more options.

I've made one that seems to do much of the building and up to the actions* ...so my first question is does something like that already exist (and if not is there a good reason).

The second is to ask for any suggestions for actions for different applications, (I've already got it sending key presses to VLC to start and stop it).  As I imagine that will affect a rewrite.

The third will be to submit it here (the code attached at the moment is for curiosity it now much more reliable and functional, almost fit for purpose).

*I was pleasantly surprised how quick it did everything (I'd cludged it up trying to be more 'efficient' as it's starts each time-I've started to put it slightly more right).

I've put the code below (in case it helps answer questions before raised), but it's decidedly not fit for purpose (and has some odd effects).
<edit: it now seems to work partially adequately (at least here, and enough for a prototype) one critical bug:
some names (unicode or escape sequences) break it (only when shown but mean you need some other way of selecting windows e.g. alt-tab)

other things that would be nice:
Minimizing (which it doesn't do).
Selecting window options based on window state
It's not as customization friendly as it ought to be, partly because I forgot the rule about premature optimization, partly because I was still working out what worked.
I want to have icons (I believe I can get the pixmaps)
>

#! /usr/bin/python
import socket
import sys

def debugMarker():
	#this function can be added to any built in action to assist debugging (it shows the window type&name as well as a bastardised Address)
	#e.g. [vlc,Vlc],[AAACAAAP]				any suggestions for the simplest unique object?
	pass

#You can call python (prog) to see what the root menu looks like
#You can call python (prog) AAACAAAP to see what the menu for a given window looks like (look up the code via the first call or by putting the debug marker somewhere appropriate)
#You can call python (prog) AAACAAAP .... to try an action for a given window


#****************************************Space to Customize*********************************
#   (remember don't get rid of alternative method till certain it works [at the moment some task names will break it!!!])

# Actions are in the form of a list containing (Name, {Action})
# actions include WM messages-the atom name to be sent to _NET_WM_STATE_
# 			and   KY messages- a list of key presses (the keycode and modifiers are converted to Hexadecimal starting at 'A')
#Known keycodes
# AK="1" BA="7" CA="o" CH="s" DA="'" DN="/" EB=" "

def MakeListOfActions():
	builtInActions={}
	#This gets called for all actions
	builtInActions[None]= [debugMarker,("Focus","CM0+_NET_ACTIVE_WINDOW"),("Maximize","CM2+_NET_WM_STATE+_NET_WM_STATE_MAXIMIZED_VERT+_NET_WM_STATE_NET_WM_STATE_MAXIMIZED_HORZ"),
	("Maximize V","CM2+_NET_WM_STATE+_NET_WM_STATE_MAXIMIZED_VERT"),("Maximize H","CM2+_NET_WM_STATE+_NET_WM_STATE_MAXIMIZED_HORZ"),
	("Shade","CM2+_NET_WM_STATE+_NET_WM_STATE_SHADED"),("Minimize","CM0+WM_CHANGE_STATE"),
	]
	#******Change here*********
	builtInActions["Vlc"]=[("Play","KYEBAAAA"),("Stop","KYCHAAAA"),("Next","KYDJAAAA"),("Prev","KYCBAAAA")]
	builtInActions["Geany"]=[]
	return builtInActions




#************************************FUNCTIONAL BIT OF THE PROGRAM*********************************


#tries to get rid of anything that makes openbox cry
def filterUnicode(string):
	specialChars="\"'&<>"
	result=""
	i=0	
	while i<len(string):
		if ord(string[i])<32:
			if ord(string[i])==27:i=i+2 #escape character
			i=i+1
		elif string[i] in specialChars:
			result+="&#"+str(ord(string[i]))+";"
			i=i+1
		elif ord(string[i])>128+64:
			#give up skip to end
			val=ord(string[i])
			msb=128			
			while msb&val!=0: msb=msb/2		#search for break in continious bits
			val=val%msb
			i=i+1
			while i<len(string) and ord(string[i])>127:
				val=val*64+ord(string[i])%64
				i=i+1
			result+="&#"+str(val)+";"
		elif ord(string[i])>128:
			result+="&#"+str(ord(string[i]))+";"
			i=i+1
		else:
			result+=string[i]
			i=i+1
	return result

#This is a condensed utility class to connect to an X-Server and do minimal set of actions neccessary
class LXServerQuery:
	def __init__(this):
		this.rootID=None #set in try connect
		this.socket=None #set in try connect
		this.tryConnect()
		this.atomCache={}

	#converts 300,4 to "/0/0/255/45"
	def numberToCharList(this,number,size):
		result=""
		for i in range(0,size):
			result=chr(number%256)+result
			number=number/256
		return result
	#reverts the above
	def charListToNumber(this,number):
		return reduce(lambda y,x:y*256+ord(x),number,0)
	#converts "/5/6 to "EF" for easy transmission
	def charListToAlphaList(this, orig):
		result=""
		for c in orig:
			result=result+chr(ord(c)/16+65)+chr(ord(c)%16+65)
		return result
	#and back again
	def alphaListToCharList(this,orig):
		result=""
		for i in range(0, len(orig),2):
			result=result+chr(16*(ord(orig[i])-65)+ord(orig[i+1])-65)
		return result		
	#Connects to the X Server (anything not required tried to be stripped out)
	#Compare message to that defined
	def tryConnect(this):
			i=0
			this.socket=socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
			this.socket.connect('/tmp/.X11-unix/X'+str(i))
			openingMessage="B"+chr(0)+chr(0)+chr(11)+chr(0)*8		
			this.socket.send(openingMessage)
			message=this.getMessage()
			if message[0]!=chr(1): return None
			lenVendor=ord(message[24])*256+ord(message[25])
			if (lenVendor%4)!=0:
				paddedV=lenVendor-(lenVendor%4)+4
			else:
				paddedV=lenVendor
			screenCount=ord(message[28])
			numFormats=ord(message[29])
			
			screenIndex=40+paddedV+8*numFormats
			this.rootID=message[screenIndex:screenIndex+4]
	#waits for a message back from the XServer
	def getMessage(this):
			message=""
			while message=="":
				try:
					message=message+this.socket.recv(10000)
				except Exception:
					pass #message unchanged, continue waiting
			if message[0]==chr(0):
				print "Error Message Received: Error="+str(ord(message[1]))+"@"+str(map(ord,message[4:8]))
			return message

	#This returns the 4 character 'ATOM' that represents a instruction
	def getEWMHkey(this,key):
		if key in this.atomCache: return this.atomCache[key]
		if(len(key)%4!=0):
			message=key+chr(0)*(4-len(key)%4)
		else:
			message=key
		message=chr(0)+chr(len(key))+chr(0)+chr(0)+message
		message=chr(16)+chr(1)+chr(0)+chr(1+len(message)/4)+message
		this.socket.send(message)
		message=this.getMessage()
		this.atomCache[key]=message[8:12]
		return message[8:12]

	#Sends a message to find a property, returns the length, the format, and the data
	def getProperty(this,window,key):
		message=window    #root num
		message=message+key
		message=message+chr(0)*4	#no fixed type
		message=message+chr(0)*4	#no offset
		message=message+chr(0)*3+chr(255)	#no length limit
		message=chr(20)+chr(0)+chr(0)+chr(6)+message		   #op 20 get property 6*4 bytes
		this.socket.send(message)
		result=this.getMessage()
		length=this.charListToNumber(result[16:20])
		return (length, ord(result[1]), result[32:32+length*ord(result[1])/8])
	#wraps an event in a client message
	def sendEvent(this,destWindow, propogate,mask, event):			
			this.socket.send(chr(25)+chr(propogate)+chr(0)+chr(11)+destWindow+this.numberToCharList(mask,4)+event)		
				
	def close(this):
		this.socket.close()



#This is used when called with a given window and argument
class WindowCommand:
	#Gets the action and tells it to do something
	def __init__(this,window,action):		
			query=LXServerQuery()
			window=query.alphaListToCharList(window)
			print action[0:2]
			if action[0:2]=="CM":
				print "HERE"
				data0=int(action[2])
				actions=action[4:].split("+")
				if len(actions)==3:
					this.sendStateEvent(query, window, data0,query.getEWMHkey(actions[0]), query.getEWMHkey(actions[1]), query.getEWMHkey(actions[2]))
				elif len(actions)==2:
					this.sendStateEvent(query, window, data0,query.getEWMHkey(actions[0]),query.getEWMHkey(actions[1]), chr(0)*4)					
				elif len(actions)==1:
					this.sendStateEvent(query, window, data0,query.getEWMHkey(actions[0]),chr(0)*4,chr(0)*4)					
			elif action[0:2]=="KY":
				for i in range(2,len(action),7):					
					#send key press event format "KKMMMM "
					this.sendKeyEvent(query, window,query.alphaListToCharList(action[i:i+2]),query.alphaListToCharList(action[i+2:i+6]))
	#I think this section is doing things in the wrongish way as can't minimize, etc...
	def sendStateEvent(this, query, targetWindow, data0,m1, p1, p2):
		event=chr(33)+chr(32)+chr(0)+chr(0)+targetWindow+m1
		event=event+chr(0)*3+chr(data0)+p1+p2+chr(0)*4
		event=event+chr(0)*4
		query.sendEvent(query.rootID,0,0x00180000,event) #Structure Notify Redirect
		print "Sent client message"
	def sendKeyEvent(this, query, targetWindow, keyCode, keyMod):
		event=keyCode+chr(0)+chr(0)
		event=event+chr(0)*4+query.rootID+targetWindow+chr(0)*4+chr(0)*4+chr(0)*4+keyMod+chr(1)+chr(0)
		query.sendEvent(targetWindow,1,1,chr(2)+event) #key down
		query.sendEvent(targetWindow,1,2,chr(3)+event) #key up
		
#This is used when called with a given window it provides a pipe menu to Do Stuff
class WindowOptions:
		#calculates the options could prob improve later
		def __init__(this, programLocation, window):	
			this.programLocation=programLocation
			this.builtInActions=MakeListOfActions()
			this.printablewindow=window
			query=LXServerQuery()
			this.window=query.alphaListToCharList(window)
			this.actionNames=[]+this.builtInActions[None]
			programtype=query.getProperty(this.window, query.getEWMHkey("WM_CLASS"))[2].split(chr(0))
			if len(programtype)>1 :				
				if programtype[1] in this.builtInActions:
					this.actionNames=this.actionNames+this.builtInActions[programtype[1]]
			if debugMarker in this.actionNames:
					this.actionNames=this.actionNames+[(",".join(programtype),"Test"),(window,"")]
					this.actionNames.remove(debugMarker)
		#produces the openbox menu
		def toMenu(this):
			result= '<openbox_pipe_menu>\n'
			for aname in this.actionNames:				
					result=result+"			<item label='"+aname[0]+"'>\n"
					result=result+"				<action name='Execute'><command>"
					result=result+this.programLocation+" "+this.printablewindow+" "+aname[1]+""
					result=result+"</command></action>\n"
					result=result+"			</item>\n"
			result=result+ '</openbox_pipe_menu>'
			return result
			
			


#This is used when called with no arguments it provides a pipe menu of all windows
class Task:
	def __init__(this,window,query):
		this.window=window
		this.name=filterUnicode(query.getProperty(window, query.getEWMHkey("WM_NAME"))[2])
		this.icon=query.getProperty(window, query.getEWMHkey("_NET_WM_ICON_NAME"))[2]
		this.desktop=ord(query.getProperty(window, query.getEWMHkey("_NET_WM_DESKTOP"))[2][3]) #fails if more than 254 desktops	(not likely)
		this.printableWindow=query.charListToAlphaList(this.window)
	def __str__(this):
		return this.toMenu(0,sys.argsv[0])
	#produces pipe menu fragment
	def toMenu(this,uid,programLocation):
		result="		<menu id='/Taskbar/"+str(uid)+"' label='"+this.name+"'  execute='"+programLocation+" "+this.printableWindow+"'>\n"
		result=result+"		</menu>\n"
		return result

class TaskList:
	def __init__(this, programLocation):
		query=LXServerQuery()
		this.programLocation=programLocation
		this.desktopnames,this.tasks=this.getWindowList(query)
	#gets active tasks and puts them into desktops
	def getWindowList(this,query):
		desktopnames=query.getProperty(query.rootID,query.getEWMHkey("_NET_DESKTOP_NAMES"))[2]
		desktopnames=map(filterUnicode,desktopnames.split('\0'))[:-1]
		tasks=[]
		windowIDs=query.getProperty(query.rootID,query.getEWMHkey("_NET_CLIENT_LIST_STACKING"))[2]
		for i in range(0,len(windowIDs),4):			
			tasks.append(Task(windowIDs[i:i+4],query))
		return desktopnames,tasks
	#produces pipe menu
	def toMenu(this):
		result= '<openbox_pipe_menu>\n'
		uid=0
		for i,desktop in enumerate(this.desktopnames):
			result=result+"	<menu id='/TaskbarDesktop/"+desktop+"' label='D"+desktop+"'>\n"
			for item in this.tasks:
				if item.desktop==i or item.desktop==255:
					result=result+item.toMenu(uid,this.programLocation)
					uid=uid+1
			result=result+"	</menu>\n"
		result=result+ '</openbox_pipe_menu>'
		return result

if len(sys.argv)==1:
	t=TaskList(sys.argv[0],)
	print t.toMenu()
elif len(sys.argv)==2:
	w=WindowOptions(sys.argv[0],sys.argv[1])
	print w.toMenu()
elif len(sys.argv)==3:
	w=WindowCommand(sys.argv[1],sys.argv[2])
else:
	print "Odd number of arg",sys.argv

Last edited by Yajmon#! (2013-11-13 22:11:26)

Offline

#42 2013-11-26 01:39:55

cloverskull
#! Junkie
Registered: 2013-10-26
Posts: 331

Re: the ultimate pipe menu thread

Hey guys, I made a playonlinux game launcher pipe menu, code follows:

#!/bin/bash
#       polmenu.sh - a playonlinux game launcher for openbox
#
#
# path to your PlayOnLinux shortcuts folder, assumes $HOME/
pol_shortcuts_folder=.PlayOnLinux/shortcuts/

# command to launch playonlinux software
pol_launcher_command='playonlinux --run'

function generate_pol_menu {

ls ~/$pol_shortcuts_folder | while read; do

        echo '<item label="'"${REPLY}"'">'
        echo -n '<action name="Execute"><execute>'
        echo -n "$pol_launcher_command '${REPLY}'"
        echo '</execute></action>'
        echo '</item>'
   done

}

echo '<openbox_pipe_menu>'

generate_pol_menu

echo '</openbox_pipe_menu>'

Cheers!

Offline

#43 2013-11-29 10:06:48

cloverskull
#! Junkie
Registered: 2013-10-26
Posts: 331

Re: the ultimate pipe menu thread

And as a follow-up, I wrote one that (for me) gets a lot more use.  This one parses your scummvmrc file (~/.scummvmrc) and makes a pipemenu.  Code follows.

#!/bin/bash
#       openbox_scummvm_pipemenu.sh
#       initially created 2013 - Ryan Fantus
#
# assumes your scummvmrc file is ~/.scummvmrc and your scummvm launcher is /usr/local/bin/scummvm
# I noticed a bug with unescaped ampersands (&) cropping up in Sam & Max, so I replaced it with "and".

scumm_launcher=/usr/local/bin/scummvm
scumm_rc=~/.scummvmrc

function generate_scummvm_menu {

  while read line
  do
        if [[ $line == "["* ]]; then                    # test for an open bracket, see ~/.scummvmrc for why
                if [[ $line != "[scummvm]" ]]; then     # but skip the [scummvm] bracket
                        scumm_description=''            # and here make sure we find [game] followed by
                        while [[ $scumm_description != "description"* ]]; do    # description= text
                                read scumm_description
                        done
                        echo -n '<item label="'
                        echo -n $scumm_description | sed s/'description='/\/g | tr -d '\"' | sed s/'&'/'and'\/g
                        echo '">'
                        echo -n '<action name="Execute"><execute>'
                        echo -n "$scumm_launcher '${line}'" | tr -d "[]"
                        echo '</execute></action>'
                        echo '</item>'
                fi
        fi
  done < $scumm_rc

}

echo '<openbox_pipe_menu>'

# First, we'll create a launcher specifically for ScummVM

echo '<item label="ScummVM">'
echo -n '<action name="Execute"><execute>'
echo -n "$scumm_launcher"
echo '</execute></action>'
echo '</item>'
echo '<separator/>'

generate_scummvm_menu

echo '</openbox_pipe_menu>'

Cheers again!

Offline

#44 2014-01-03 19:53:06

gomer
New Member
Registered: 2014-01-03
Posts: 1

Re: the ultimate pipe menu thread

I am trying to come up with a pipemenu but having issues sorting out how to make something like this happen

CustomMainCategory/
├── subCat1
│   ├── subsubCat1
│   │   ├── subsubsubCat1
│   │   │   └── Tool1
│   │   └── Tool1
│   ├── Tool1
│   └── Tool2
└── subCat2
    ├── Tool1
    └── Tool2

Also what would my categorty line look like? Would it be similar to this if I want it in subCat1 only?

Categories=SubCat1;

I have been able to get CustomMainCategory to display, but cant sort out the submenu portions. I have tried messing with schema.pl but dont think I am getting it yet. Thanks for your time and help on this.

Last edited by gomer (2014-01-03 19:56:29)

Offline

#45 2014-11-14 23:38:31

uriel1998
Member
From: Dayton, OH
Registered: 2012-02-10
Posts: 49
Website

Re: the ultimate pipe menu thread

I made an OB pipe menu helper for surfraw - it both lists all elvii and also lets you have a preselected (smaller) variety to choose from when you want it.  I started with cloverskull's PlayOnLinux script as a base, but it got a bit more complex.

I've posted the code below;  there's more explanation (and linkage) at the github repository.

Here's what the pipemenu looks like in action:
elvi_list.jpg
selected_elvi.jpg

#!/bin/bash

########################################################################
# Credits, blame, etc
########################################################################
#	searchraw - a surfraw launcher for openbox

#   Base from openbox_playonlinux_pipemenu by Ryan Fantus
#	https://github.com/ryanfantus/openbox_playonlinux_pipemenu

#	Helpful solutions
#   http://stackoverflow.com/questions/5998066/bash-script-variable-content-as-a-command-to-run
#   http://www.cyberciti.biz/faq/awk-find-and-replace-fields-values/
# 	


########################################################################
# Usage
########################################################################

# Call this script by itself to generate an openbox menu with all elvi
# that are on the system and to search them with a popup text box.
# Call with -d to pop up (optional) few elvi to use, or to use the 
# default, and search with a popup text box.  
# Call with -d and an elvi to pop up a text box to search.

########################################################################
# Requires
########################################################################

# * Surfraw - http://surfraw.alioth.debian.org
# * Openbox (Sort of.  This is way overblown if you're not using OB.)
# * zenity or a replacement like matedialog or wenity.

########################################################################
# Configuration
########################################################################

# Default elvii.  SPECIFY ONE HERE
default_elvii="google"

# Do you want a popup if no elvii are specified?
popup="TRUE"

# What elvii should be presented in the Zenity combobox?  These should
# be in a single line, space separated.
# DO NOT INCLUDE THE DEFAULT ELVII HERE unless you want repeats
custom_elvii="scholar stack github wayback wikipedia"

########################################################################
# Generate list of elvii for OB
########################################################################

function generate_elvi_menu {

sr -elvi | while read; do
		elvi_cmd=$(echo "${REPLY}" | awk '{print $1}')
		# The long description chokes my install of OB
		elvi_dsc=$(echo "${REPLY}" | awk '{print $1}')
		echo -n '<item label="'"$elvi_dsc"'">'
		echo -n '<action name="Execute"><execute>'
		echo -n "$0 -d $elvi_cmd"
		echo '</execute></action>'
		echo '</item>'
	done

}

########################################################################
# Write the Menu				
########################################################################
function write_ob_menu {

echo '<openbox_pipe_menu>'
generate_elvi_menu
echo '</openbox_pipe_menu>'

}

# Are we being launched directly?
if [ "$1" == "-d" ]; then
	# When being launched directly, what elvii should be presented/used?
	if [ "$2" == "" ]; then 
		if [ "$popup" == "TRUE" ]; then
			buildinglist=" $default_elvii $custom_elvii"
			elvii_list=$(echo "$buildinglist" | awk '{ gsub(" "," FALSE "); print }')
			choicecmdline="zenity --timeout 30 --list  --text 'Elvi to use?' --radiolist  --column 'Pick' --column 'Elvi' $elvii_list"
			echo "$choicecmdline"
			read
			elvi=$(eval "$choicecmdline")
#			elvi=$(zenity --timeout 30 --list  --text "Elvi to use?" --radiolist  --column "Pick" --column "Elvi" TRUE google FALSE scholar FALSE stack FALSE github FALSE wayback FALSE wikipedia)
		else
			elvi="$default_elvii"
		fi	
	else
		elvi="$2"
	fi

	szAnswer=$(zenity --entry --title "search" --text "Search what?" --entry-text "") 
	if [ "$szAnswer" != "" ]; then
		sr_command="sr -g $elvi $szAnswer"
		eval "$sr_command"
	fi
else
	write_ob_menu
fi

Offline

#46 2014-11-15 20:48:41

olminator
New Member
Registered: 2014-11-15
Posts: 2

Re: the ultimate pipe menu thread

I made one that lists all thunar bookmarks (listed in ~/.gtk-bookmarks):

#!/usr/bin/env sh

echo '<openbox_pipe_menu>'

cat ~/.gtk-bookmarks | while read line; do
  dir=`echo $line | sed 's/[ ][^ ]*$//' | sed 's/file:\/\///'`
  name=`echo $line | sed 's/^.*\s//'`
  echo '<menu execute="/usr/bin/cb-places-pipemenu '$dir'" label="'$name'" id="'$name'"/>'
done

echo '</openbox_pipe_menu>'

and another one that lists google chrome bookmarks (written in coffeescript... but quite easy to translate):

#!/usr/bin/env coffee
fs = require 'fs'
_ = require 'underscore'

bookmarks = JSON.parse fs.readFileSync "#{process.env.HOME}/.config/google-chrome/Default/Bookmarks", 'utf8'
roots = [
  bookmarks.roots.bookmark_bar
  bookmarks.roots.other
]

bookmarks = [].concat bookmarks.roots.bookmark_bar.children, bookmarks.roots.other.children

print = ->
  console.log.apply console, arguments

htmlentities = (str) ->
  str.replace /&/g, '\&amp;'
    .replace /"/g, '\&quot;'
    .replace /</g, '\&lt;'
    .replace />/g, '\&gt;'

printBookmark = (bookmark) ->
  if bookmark.children
    # print menu
    print '<menu id="chrome-bookmark-' + bookmark.id + '" label="' + bookmark.name + '">'
    _.each bookmark.children, (bookmark) ->
      printBookmark bookmark
    print '</menu>'
  else
    return if bookmark.url.match /^javascript/
    # print item
    print '<item id="chrome-bookmark-' + bookmark.id + '" label="' + (htmlentities bookmark.name) + '">'
    print '<action name="Execute">'
    print '<command>'
    print 'x-www-browser \'' + (htmlentities encodeURI bookmark.url) + '\''
    print '</command>'
    print '</action>'
    print '</item>'

print '<openbox_pipe_menu>'

_.each roots, (root) ->
  print '<separator label="' + root.name + '"/>'

  _.each root.children, (bookmark) ->
    printBookmark bookmark

print '</openbox_pipe_menu>'

Last edited by olminator (2014-11-15 20:51:43)

Offline

Board footer

Powered by FluxBB

Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.

Debian Logo