unity-scope-gmusicbrowser-0.1+13.10.20130723/0000755000015700001700000000000012173421327021055 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/po/0000755000015700001700000000000012173421327021473 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/po/unity-scope-gmusicbrowser.pot0000644000015700001700000000232112173420373027365 0ustar pbuserpbgroup00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #: ../src/unity_gmusicbrowser_daemon.py:35 #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-03 19:18+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../src/unity_gmusicbrowser_daemon.py:33 ../data/gmusicbrowser.scope.in.h:4 msgid "Search Gmusicbrowser" msgstr "" #: ../src/unity_gmusicbrowser_daemon.py:34 msgid "Sorry, there are no Gmusicbrowser results that match your search." msgstr "" #: ../src/unity_gmusicbrowser_daemon.py:44 msgid "Songs" msgstr "" #: ../src/unity_gmusicbrowser_daemon.py:48 msgid "Albums" msgstr "" #: ../data/gmusicbrowser.scope.in.h:1 msgid "gmusicbrowser;" msgstr "" #: ../data/gmusicbrowser.scope.in.h:2 msgid "Gmusicbrowser" msgstr "" #: ../data/gmusicbrowser.scope.in.h:3 msgid "Find Gmusicbrowser items" msgstr "" unity-scope-gmusicbrowser-0.1+13.10.20130723/po/POTFILES.in0000644000015700001700000000014312173420373023246 0ustar pbuserpbgroup00000000000000[encoding: UTF-8] src/unity_gmusicbrowser_daemon.py [type: gettext/ini]data/gmusicbrowser.scope.in unity-scope-gmusicbrowser-0.1+13.10.20130723/MANIFEST.in0000644000015700001700000000007612173420373022616 0ustar pbuserpbgroup00000000000000include MANIFEST.in include src/* include data/* include po/* unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/0000755000015700001700000000000012173421327022217 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/test_gmusicbrowser.py0000644000015700001700000000377512173420373026537 0ustar pbuserpbgroup00000000000000#! /usr/bin/python3 # -*- coding: utf-8 -*- from gi.repository import Unity from unittest import TestCase import imp class ResultSet(Unity.ResultSet): def __init__(self): Unity.ResultSet.__init__(self) self.results = [] def do_add_result(self, result): self.results.append({'uri': result.uri, 'title': result.title, 'comment': result.comment, 'icon': result.icon_hint}) class ScopeTestCase(TestCase): def init_scope(self, scope_path): self.scope_module = imp.load_source('scope', scope_path) self.scope = self.scope_module.load_scope() def perform_query(self, query, filter_set=Unity.FilterSet.new()): result_set = ResultSet() ctx = Unity.SearchContext.create(query, 0, filter_set, None, result_set, None) s = self.scope.create_search_for_query(ctx) s.run() return result_set class TestGmusicbrowser(ScopeTestCase): def setUp(self): self.init_scope('src/unity_gmusicbrowser_daemon.py') def tearDown(self): self.scope = None self.scope_module = None def test_qsearch(self): self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_pass' expected_results = ["/home/mark/Music/Jacques Dutronc/En Vogue/02. Mini, Mini, Mini.mp3", "Mini, Mini, Mini"] results = [] for s in ['Mini']: result_set = self.perform_query(s) results.append(result_set.results[0]['uri']) results.append(result_set.results[0]['title']) self.assertEqual(results, expected_results) def test_failing_search(self): self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_fail' for s in ['upnriitnyt']: result_set = self.perform_query(s) self.assertEqual(len(result_set.results), 0) if __name__ == '__main__': unittest.main() unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/__init__.py0000644000015700001700000000000012173420373024316 0ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/data/0000755000015700001700000000000012173421327023130 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/data/mock_gmusicbrowser_pass0000644000015700001700000000130212173420373030001 0ustar pbuserpbgroup00000000000000 [Songs] added album album_artist_raw artist bitrate channel comment compilation disc file filetype genre grouping label lastplay lastskip length length_estimated missing modif path playcount rating replaygain_album_gain replaygain_album_peak replaygain_track_gain replaygain_track_peak samprate size skipcount title track version year 1 1320584364 En Vogue Jacques Dutronc Jacques Dutronc 256 2 0 0 02. Mini, Mini, Mini.mp3 mp3 l3v1 Rock 0 1332807323 112 0 0 1320580335 /home/mark/Music/Jacques Dutronc/En Vogue 0 0 0 0 0 44100 3637688 2 Mini, Mini, Mini 2 0 [album] album_picture En Vogue\x00album_artist=Jacques Dutronc /home/mark/Music/Jacques Dutronc/En Vogue/02. Mini, Mini, Mini.mp3 [artist] unity-scope-gmusicbrowser-0.1+13.10.20130723/tests/data/mock_gmusicbrowser_fail0000644000015700001700000000000612173420373027746 0ustar pbuserpbgroup00000000000000 unity-scope-gmusicbrowser-0.1+13.10.20130723/src/0000755000015700001700000000000012173421327021644 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/src/unity_gmusicbrowser_daemon.py0000644000015700001700000003246712173420373027700 0ustar pbuserpbgroup00000000000000#! /usr/bin/python3 # -*- coding: utf-8 -*- # Copyright(C) 2013 Mark Tully # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License version 3, as published # by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . from gi.repository import GLib, Gio from gi.repository import Unity import gettext import os import dbus import urllib APP_NAME = 'unity-scope-gmusicbrowser' LOCAL_PATH = '/usr/share/locale/' gettext.bindtextdomain(APP_NAME, LOCAL_PATH) gettext.textdomain(APP_NAME) _ = gettext.gettext GROUP_NAME = 'com.canonical.Unity.Scope.Music.Gmusicbrowser' UNIQUE_PATH = '/com/canonical/unity/scope/music/gmusicbrowser' SEARCH_HINT = _('Search Gmusicbrowser') NO_RESULTS_HINT = _('Sorry, there are no Gmusicbrowser results that match your search.') PROVIDER_CREDITS = _('') SVG_DIR = '/usr/share/icons/unity-icon-theme/places/svg/' PROVIDER_ICON = SVG_DIR + 'service-gmusicbrowser.svg' DEFAULT_RESULT_ICON = SVG_DIR + 'result-gmusicbrowser.svg' DEFAULT_RESULT_MIMETYPE = 'taglib/mp3' DEFAULT_RESULT_TYPE = Unity.ResultType.PERSONAL GMUSICBROWSER_DBFILE = os.getenv("HOME") + "/.config/gmusicbrowser/gmbrc" c1 = {'id': 'songs', 'name': _('Songs'), 'icon': SVG_DIR + 'group-installed.svg', 'renderer': Unity.CategoryRenderer.VERTICAL_TILE} c2 = {'id': 'albums', 'name': _('Albums'), 'icon': SVG_DIR + 'group-installed.svg', 'renderer': Unity.CategoryRenderer.VERTICAL_TILE} CATEGORIES = [c1, c2] FILTERS = [] m1 = {'id' :'album', 'type' :'s', 'field':Unity.SchemaFieldType.OPTIONAL} m2 = {'id' :'artist', 'type' :'s', 'field':Unity.SchemaFieldType.OPTIONAL} m3 = {'id' :'genre', 'type' :'s', 'field':Unity.SchemaFieldType.OPTIONAL} m4 = {'id' :'year', 'type' :'i', 'field':Unity.SchemaFieldType.OPTIONAL} m5 = {'id': 'track_length', 'type': 'i', 'field': Unity.SchemaFieldType.OPTIONAL} m6 = {'id': 'track_number', 'type': 'i', 'field': Unity.SchemaFieldType.OPTIONAL} EXTRA_METADATA = [m1, m2, m3, m4, m5, m6] tracks = [] albumart = [] def get_music_from_gmusicbrowser(): """Parses GMusicBrowser's collection into a form we can use""" global tracks global albumart tracks = [] albumart = [] songlist = [] albumartlist = [] if not os.path.exists(GMUSICBROWSER_DBFILE): return tracks try: filename = open(GMUSICBROWSER_DBFILE) database = filename.readlines() for index, item in enumerate(database): if item == '[Songs]\n': songstart = index if item == '[album]\n': albumstart = index if item == '[artist]\n': artiststart = index except: return tracks songlist = database[songstart + 2:albumstart - 1] for song in songlist: if song.startswith("added\talbum"): continue fields = song.split("\t") track = {} track[0] = fields[31] # title track[1] = fields[21] + "/" + fields[10] # Location track[2] = fields[4] # Artist track[3] = fields[2] # Album Name track[4] = "audio/mp3" # mimetype track[5] = fields[3] # Album Artist track[6] = fields[12] # Genre if len(fields) < 35: track[7] = "0" else: track[7] = str(fields[34])[0:4] # Year if track[7] == "0Non": track[7] = "0" if track[7] == "": track[7] = "0" track[8] = 0 if fields[32] is None else fields[32] track[9] = int(fields[32]) track[10] = fields[17] tracks.append(track) albumartlist = database[albumstart + 2:artiststart - 1] for art in albumartlist: albumarta = {} fields = art.split("\t") fields2 = fields[0].split('=') albumarta[0] = fields2[0][:fields[0].find('\\')] albumarta[1] = fields2[1] albumarta[2] = fields[1] albumart.append(albumarta) print("Updated tracks from GMusicBrowser database") tracks.sort(key=lambda track: track[9]) return albumart, tracks def get_album_art(track, albums): for album in albums: if album[0] == track[3]: return album[2] def search(search, filters): ''' Search for help documents matching the search string ''' global tracks global albumart results = [] albums, tracks = get_music_from_gmusicbrowser() trackresults = [] albumresults = [] for track in tracks: title = "" if track[0] is None else track[0] uri = "" if track[1] is None else track[1] artist = "" if track[2] is None else track[2] album = "" if track[3] is None else track[3] mimetype = "" if track[4] is None else track[4] albumartist = "" if track[5] is None else track[5] year = 0 if track[7] is None else int(track[7]) genre = "" if track[6] is None else track[6] track_length = 0 if track[10] is None else int(track[10]) track_number = 0 if track[9] is None else int(track[9]) trackname = title + " - " + album + " - " + artist if search.lower() in trackname.lower(): albumart = 'file://' + get_album_art(track, albums).replace('\n', '') albumuri = "album://" + albumartist + "/" + album if track not in trackresults: results.append({'uri': uri, 'icon': albumart, 'category': 0, 'title': title, 'album':GLib.Variant('s', album), 'artist':GLib.Variant('s', artist), 'genre':GLib.Variant('s', genre), 'year':GLib.Variant('i', year), 'track_length': GLib.Variant('i', track_length), 'track_number': GLib.Variant('i', track_number)}) trackresults.append(track) if album not in albumresults: results.append({'uri': albumuri, 'icon': albumart, 'category': 1, 'title': album, 'album':GLib.Variant('s', album), 'artist':GLib.Variant('s', artist), 'genre':GLib.Variant('s', genre), 'year':GLib.Variant('i', year), 'track_length': GLib.Variant('i', track_length), 'track_number': GLib.Variant('i', track_number)}) albumresults.append(album) return results class Preview(Unity.ResultPreviewer): def do_run(self): global tracks album = self.result.metadata['album'].get_string() artist = self.result.metadata['artist'].get_string() preview = Unity.MusicPreview.new(self.result.title, '', None) preview.props.image_source_uri = self.result.icon_hint preview.props.subtitle = self.result.metadata['artist'].get_string() if self.result.uri.startswith("album://"): for track in tracks: if album in track[3] and artist in track[2]: track = Unity.TrackMetadata.full(track[1], int(track[9]), track[0], track[2], track[3], int(track[10])) preview.add_track(track) else: print(self.result.uri) track = Unity.TrackMetadata.full('file://%s' % self.result.uri.replace(' ', '%20'), self.result.metadata['track_number'].get_int32(), self.result.title, self.result.metadata['artist'].get_string(), self.result.metadata['album'].get_string(), self.result.metadata['track_length'].get_int32()) preview.add_track(track) view_action = Unity.PreviewAction.new("play", _("Play"), None) preview.add_action(view_action) show_action = Unity.PreviewAction.new("show", _("Show in Folder"), None) preview.add_action(show_action) return preview # Classes below this point establish communication # with Unity, you probably shouldn't modify them. class MySearch(Unity.ScopeSearchBase): def __init__(self, search_context): super(MySearch, self).__init__() self.set_search_context(search_context) def do_run(self): ''' Adds results to the model ''' try: result_set = self.search_context.result_set for i in search(self.search_context.search_query, self.search_context.filter_state): if not 'uri' in i or not i['uri'] or i['uri'] == '': continue if not 'icon' in i or not i['icon'] or i['icon'] == '': i['icon'] = DEFAULT_RESULT_ICON if not 'mimetype' in i or not i['mimetype'] or i['mimetype'] == '': i['mimetype'] = DEFAULT_RESULT_MIMETYPE if not 'result_type' in i or not i['result_type'] or i['result_type'] == '': i['result_type'] = DEFAULT_RESULT_TYPE if not 'category' in i or not i['category'] or i['category'] == '': i['category'] = 0 if not 'title' in i or not i['title']: i['title'] = '' if not 'comment' in i or not i['comment']: i['comment'] = '' if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '': i['dnd_uri'] = i['uri'] i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS) result_set.add_result(**i) except Exception as error: print(error) class Scope(Unity.AbstractScope): def __init__(self): Unity.AbstractScope.__init__(self) def do_get_search_hint(self): return SEARCH_HINT def do_get_schema(self): ''' Adds specific metadata fields ''' schema = Unity.Schema.new() if EXTRA_METADATA: for m in EXTRA_METADATA: schema.add_field(m['id'], m['type'], m['field']) #FIXME should be REQUIRED for credits schema.add_field('provider_credits', 's', Unity.SchemaFieldType.OPTIONAL) return schema def do_get_categories(self): ''' Adds categories ''' cs = Unity.CategorySet.new() if CATEGORIES: for c in CATEGORIES: cat = Unity.Category.new(c['id'], c['name'], Gio.ThemedIcon.new(c['icon']), c['renderer']) cs.add(cat) return cs def do_get_filters(self): ''' Adds filters ''' fs = Unity.FilterSet.new() #if FILTERS: # return fs def do_get_group_name(self): return GROUP_NAME def do_get_unique_name(self): return UNIQUE_PATH def do_create_search_for_query(self, search_context): se = MySearch(search_context) return se def do_activate(self, result, metadata, id): album = result.metadata['album'].get_string() artist = result.metadata['artist'].get_string() global tracks if id == 'show': if result.uri.startswith("album://"): for track in tracks: if album in track[3] and artist in track[2]: filename = tracks[1] continue else: filename = result.uri dirname = os.path.dirname(filename) os.system("xdg-open '%s'" % str(dirname)) else: albumtracks = '' if result.uri.startswith('album://'): for track in tracks: if album in track[3] and artist in track[2]: albumtracks = albumtracks + ' \'%s\'' % (track[1]) else: albumtracks = '\'%s\'' % result.uri os.system('gmusicbrowser -play -playlist %s' % albumtracks) return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri=None) def do_create_previewer(self, result, metadata): rp = Preview() rp.set_scope_result(result) rp.set_search_metadata(metadata) return rp def load_scope(): return Scope() unity-scope-gmusicbrowser-0.1+13.10.20130723/src/__init__.py0000644000015700001700000000000012173420373023743 0ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/setup.py0000644000015700001700000000164212173420373022572 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- ''' Setup file for gmusicbrowser dash plugin ''' from distutils.core import setup from DistUtilsExtra.command import build_extra from DistUtilsExtra.command import build_i18n setup(name='unity-scope-gmusicbrowser', version='0.1', author='Mark Tully', author_email='markjtully@gmail.com', url='http://launchpad.net/ubuntu-scopes', license='GNU General Public License (GPL)', data_files=[('share/dbus-1/services', ['data/unity-scope-gmusicbrowser.service']), # ('share/icons/unity-icon-theme/places/svg', ['data/icons/service-gmusicbrowser.svg']), ('share/unity-scopes/gmusicbrowser', ['src/unity_gmusicbrowser_daemon.py']), ('share/unity-scopes/gmusicbrowser', ['src/__init__.py']), ], cmdclass={'build': build_extra.build_extra, 'build_i18n': build_i18n.build_i18n, }) unity-scope-gmusicbrowser-0.1+13.10.20130723/setup.cfg0000644000015700001700000000022012173420373022670 0ustar pbuserpbgroup00000000000000[build] i18n=True [build_i18n] domain=unity-scope-gmusicbrowser desktop_files=[('share/unity/scopes/music', ('data/gmusicbrowser.scope.in',))] unity-scope-gmusicbrowser-0.1+13.10.20130723/data/0000755000015700001700000000000012173421327021766 5ustar pbuserpbgroup00000000000000unity-scope-gmusicbrowser-0.1+13.10.20130723/data/gmusicbrowser.scope.in0000644000015700001700000000153212173420373026322 0ustar pbuserpbgroup00000000000000[Scope] DBusName=com.canonical.Unity.Scope.Music.Gmusicbrowser DBusPath=/com/canonical/unity/scope/music/gmusicbrowser Icon=/usr/share/unity/icons/lens-nav-music.svg QueryBinary=gmusicbrowser _Keywords=gmusicbrowser; RequiredMetadata= OptionalMetadata=album[s];artist[s];genre[s];year[i];track_length[i];track_number[i] Loader=/usr/share/unity-scopes/gmusicbrowser/unity_gmusicbrowser_daemon.py Module=gmusicbrowser.unity_gmusicbrowser_daemon ModuleType=python3 RemoteContent=false Type=music _Name=gMusicBrowser _Description=This is an Ubuntu search plugin that enables information from gMusicBrowser to be searched and displayed in the Dash underneath the Music header. If you do not wish to search this content source, you can disable this search plugin. _SearchHint=Search Gmusicbrowser [Desktop Entry] X-Ubuntu-Gettext-Domain=unity-scope-gmusicbrowser unity-scope-gmusicbrowser-0.1+13.10.20130723/data/unity-scope-gmusicbrowser.service0000644000015700001700000000024312173420373030517 0ustar pbuserpbgroup00000000000000[D-BUS Service] Name=com.canonical.Unity.Scope.Music.Gmusicbrowser Exec=/usr/bin/python3 /usr/share/unity-scopes/scope-runner-dbus.py -s music/gmusicbrowser.scope unity-scope-gmusicbrowser-0.1+13.10.20130723/data/icons/0000755000015700001700000000000012173421327023101 5ustar pbuserpbgroup00000000000000