afrancoto / WebMenu

Rhythmbox 3 third party plugin WebMenu
6 stars 2 forks source link

Let the user decide #11

Closed afrancoto closed 12 years ago

afrancoto commented 12 years ago

Next step (difficult but challenging): the user, via the configuration window, should be able to add it's own search options using some keywords. For example, with just three textbox:

_______________________________________________________________________________________
|                                                                                     |
| Service Name:      |_Allmusic_______________________________________________|       |
|                                                                                     |
| Album search URL:  |_http://www.allmusic.com/search/artists/[ARTIST]________|       |
|                                                                                     |
| Artist search URL: |_http://www.allmusic.com/search/albums/[ALBUM]+[ARTIST]_|       |
|                                                                                     |                                                                            
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Those three variables could be saved in dconf in a single array; The extension read them in do_activate; PROBLEM: How to adds the entries to the web_menu_item and context_menu_part; PROBLEM/DRASTIC CHANGE: A single function can now read the search URL whatever it is (even those already in the extension) and is connected to every action

Ok maybe it's too much :P

asermax commented 12 years ago

Neh, I don't think it's too much, it's a little difficult, but feasible. (I was thinking that adding your own services would be good too, like search engines on google chrome, lol)

For the first problem, you can still use the ui_manager to dinamically add items (you would have to generate a unique item name, so there should be some checks to make sure the service name is indeed unique).

And I think using a single function will work wonders, will be a lot more clean and dynamic. I might help you implement it during the week if you let me (and if you haven't finished with it already, lol), I gotta study right now -_-

afrancoto commented 12 years ago

Great! I don't know how much time i will find in the next weeks, i'm changing home :D But I'll try! I'll start by writing the unique function in a separate file.py

afrancoto commented 12 years ago

Uploaded unique.py with the unique function, it's really simple, now I just have to figure out how to build the array and insert the function in WebMenu

asermax commented 12 years ago

Some thoughs: What if we use a dict instead of a list to store the services and it's data? I was thinking of something like this (using as base what you wrote on unique.py):

import webbrowser
import urllib2

#Services data are stored in a dict like this:
# 'service_name' : ('song_engine_url','album_engine_url','artist_engine_url', enabled)

services = {}

class Test:
  def __init__(self):
    global services
    services['AllMusic']=("","http://www.allmusic.com/search/albums/[ALBUM]+[ARTIST]", "http://www.allmusic.com/search/artists/[ARTIST]", True)
    services['Wikipedia']=("","http://en.wikipedia.org/w/index.php?search=[ALBUM]", "http://en.wikipedia.org/w/index.php?search=[ARTIST]", False)
    services['Fail']=("","Fail","Fail", False)

    self.the_unique_function('activate', None, 1, 'AllMusic', False) #Simulates click, shell=none because we don't need it in this example, 1=album/2=artist, allmusic/wikipedia=the service in lowercase, False=command sent from Menubar 

##########
#The "the_unique_function" is the one which is called by the menu/context menu actions
##########
  def the_unique_function(self, event, shell, what, service, context=False):
    metadata=self.get_metadata(shell, context) #Calls "get_metadata"
    print "We are looking for",metadata[what],"on",service

    base_url = services[service][what]
    print "Base URL is:", base_url

    final_url=self.replace_keywords(base_url, metadata) #Replace keywords
    print "Final URL is:", final_url

    webbrowser.open( final_url )

(Also added the library webbrowser instead of using a raw os command)

We could store the dict on dconf using this definition on the schema:

<key type="a{s(sssb)}" name="services">
    <default>{'Wikipedia':('', 'http://en.wikipedia.org/w/index.php?search=[ARTIST]', 'http://en.wikipedia.org/w/index.php?search=[ALBUM]', true), 'AllMusic':('', 'http://www.allmusic.com/search/artist/[ARTIST]', 'http://www.allmusic.com/search/album/[ALBUM]', false)}</default>
    <summary>Music Services</summary>
    <description>Services with their respectives urls for song, album and artist search</description>
</key>

And an example of how we could load the menu items once we got the settings (I only included the album menu for the example):

#Draw menu test
ui_album ='''
<menubar name="MenuBar">
    <menu name="AlbumMenu" action="album_menu_action">
        %s
    </menu>
</menubar>
'''
def draw_menu( self, shell, settings ):
    services = settings['services']
    uim = shell.props.ui_manager
    action_group = Gtk.ActionGroup()
    ui = ''

    for service, data in services.items():
        action_name = '%s_action' % service

        #add ui string
        ui += '<menuitem name=AL_%s action=%s/>' % (service, action_name)

        #create action
        action = Gtk.Action( action_name, service, _('Look for the current album on %s' % service), '' )
        action.connect( 'activate', self.the_unique_function, shell, 1, service )
        action_group.add_action( action )

    ui = ui_album % ui
    uim.insert_action_group( action_group )
    self.ui_menu_album_id = uim.add_ui_from_string( ui )
    ui_manager.ensure_update()

Woot, sorry for the long post. Anyway, let me know what you think!

PS: good luck with the moving :3

afrancoto commented 12 years ago

The dict is perfect, I didn't know it exists :P Now I try to implement the new draw menu and, then, the unique function in the extension... :)

afrancoto commented 12 years ago
#Services data are stored in a dict like this:
# 'service_name' : ('song_engine_url','album_engine_url','artist_engine_url', enabled_album, enabled_artist)
afrancoto commented 12 years ago

It works perfectly, i'm still adapting the various functions... Tonight it will be ready :) Here is how it is now: http://www.2shared.com/file/1OfMExi3/WebMenu_Xtar.html

asermax commented 12 years ago

Nice, you sure work fast xD After modifying the plugin module, there should be some refactoring on the config module to use the new settings structure... Well, I'll keep an eye on your progess, but can't really focus on writing code right now. If you need help with something else, let me know.

Oh, btw if you are up to it, you can try creating a 'testing' branch on your repo to commit this changes, without breaking the stable version. Here is some info on that, if you don't know much about it http://learn.github.com/p/branching.html

afrancoto commented 12 years ago

Thanks, testing branch created!

afrancoto commented 12 years ago

Mumble mumble, I don't know how to import the global variable 'services' from WebMenu.py to WebMenu_config.py...

asermax commented 12 years ago

Why don't you retrieve the dict again from the settings?

afrancoto commented 12 years ago

Mmm... ok, but usually I don't like to repeat the code :P

afrancoto commented 12 years ago

Ok, i'm blocked:

   global services
   services = self.settings['services']
[...]
        for service, data in services.items():
            check = Gtk.CheckButton(service)
            check.set_active(services[service][3])
            check.connect("toggled", self.website_toggled, service, 1)#The last argument, 1, stands for "Album"   
[...]
def website_toggled(self, checkbutton, service, what):
    services[service][what+2]=checkbutton.get_active()

website_toggled is the function called when a website is checked/unchecked in the settings menu; services is the dict with all the data;

I get this error:

Traceback (most recent call last):
  File "/home/andrea/.local/share/rhythmbox/plugins/WebMenu/WebMenu_config.py", line 88, in website_toggled
    services[service][what+2]=checkbutton.get_active()
TypeError: 'tuple' object does not support item assignment

when i click on the checkbox, probably because a tuple is a read-only variable...

Do you know a workaround? A google search didn't work! Sorry for all these questions, but I know really a little about python :P

asermax commented 12 years ago

Oh, totally forgot about that. Tuples are immutables on python :F There are two things you can do:

data = list(services[service])
data[what+2] = checkbutton.get_active()
services[service]= tuple(data)

#after asigning the new data, you should persist the services
settings['services'] = services

This a little troublesome, but it's a little more organized I believe.

afrancoto commented 12 years ago

Thank you! Now it works! I pushed the last changes in the testing branch if you want to take a look :D

There is only one problem left (I hope XD): The menu items and the checkbox in the config window are shown in a different order than the one in the gschema, I can't figure out why! In dconf the order is right after the install, but when a WebMenu option is changed the order is lost.

Gotta go now, thanks again for all your help! :D

asermax commented 12 years ago

Wow, that's weird. I don't know either :/ Does the order really matter? If it really does, the only thing I can think of (given that the reordering thing is the default Gio behavior with dictinaries), is keep an extra schema key to persist the ordering; the dict would keep the data, and the extra key would contain all the defined services' keys, in the preferred order. Anyway, gonna look into it when I have some time, I'll let you know if I find something about it.

afrancoto commented 12 years ago

I added the "source-order" key in dconf and make everything work :) Now we only need to write the function to add a new service but that's not too difficoult, I think :P

fossfreedom commented 12 years ago

speedy work guys ... :)

how close are we to making this into the official release branch (v1.1 or v2.0)?

afrancoto commented 12 years ago

You can see the To Do in the testing branch! Right now, I have some problems in implementing the new_service_add function in WebMwnu_config.py and in opening the options window from a menu item. :P

afrancoto commented 12 years ago

https://github.com/afrancoto/WebMenu/blob/testing/README.md

afrancoto commented 12 years ago

The Add/Delete new services functions and the new unique function to parse and open the URLs now work perfectly, so i can close this issue :D Unfortunately, other two must be opened :P Maybe I'm adding too much features XD

Thanks again!