From 48be37cd57ef80b43aef1c2e694ece79064a37e1 Mon Sep 17 00:00:00 2001 From: Ivan Frade Date: Fri, 1 Jul 2011 17:59:36 +0300 Subject: [PATCH] Big changes all around. Basic download works. --- src/qml/aa_search.py | 92 ++++++++---------------------------------- src/qml/albumItem.py | 20 ++++++++-- src/qml/albumModel.py | 3 ++ src/qml/controller.py | 97 ++++++++++++++++++++++++++------------------- src/qml/coverItem.py | 30 +++++--------- src/qml/coverModel.py | 20 ++++++---- src/qml/mussorgsky-qml.py | 20 ++++------ ui/AlbumsPage.qml | 23 ++++++----- ui/Alternatives.qml | 64 +++++++++++++++++++++++++++--- ui/Mussorgsky.qml | 7 +++- ui/main.qml | 2 - 11 files changed, 199 insertions(+), 179 deletions(-) diff --git a/src/qml/aa_search.py b/src/qml/aa_search.py index edf39a3..6eaab7a 100644 --- a/src/qml/aa_search.py +++ b/src/qml/aa_search.py @@ -1,25 +1,10 @@ #!/usr/bin/env python2.5 import os -from aa_spec import getCoverArtFileName, getCoverArtThumbFileName, get_thumb_filename_for_path from utils import UrllibWrapper import dbus, time import string import urllib -try: - import libxml2 - libxml_available = True -except ImportError: - libxml_available = False - -try: - import PIL - import Image -except ImportError: - import sys - print "Please install python-imaging package" - sys.exit (-1) - LASTFM_APIKEY = "1e1d53528c86406757a6887addef0ace" BASE_LASTFM = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo" @@ -42,12 +27,10 @@ class AADownloadThread (threading.Thread): def __init__ (self, url, artist, album, counter): threading.Thread.__init__ (self, target=self.grab_image, args=(url,)) - self.thumbnailer = LocalThumbnailer () self.counter = counter self.artistName = artist.replace (" ", "_") self.albumName = album.replace (" ", "_") self.image_path = None - self.thumb_path = None self.urllib_wrapper = UrllibWrapper () def grab_image (self, image_url): @@ -55,12 +38,10 @@ class AADownloadThread (threading.Thread): image = self.urllib_wrapper.get_url (image_url) if (image): self.image_path = os.path.join (CACHE_LOCATION, self.artistName + self.albumName + str(self.counter)) - self.thumb_path = os.path.join (CACHE_LOCATION, self.artistName + self.albumName + str(self.counter) + "thumb") self.urllib_wrapper.save_content_into_file (image, self.image_path) - self.thumbnailer.create (self.image_path, self.thumb_path) def get_result (self): - return self.image_path, self.thumb_path + return self.image_path @@ -72,7 +53,6 @@ class MussorgskyAlbumArt: if (not os.path.exists (CACHE_LOCATION)): os.makedirs (CACHE_LOCATION) - self.thumbnailer = LocalThumbnailer () self.urllib_wrapper = UrllibWrapper () def get_possible_url (self, artist, album, amount=4): @@ -80,45 +60,28 @@ class MussorgskyAlbumArt: return self.__get_url_from_msn_results_page (results_page) - def get_album_art (self, artist, album, force=False): + def get_album_art (self, albumItem, force=False): """ - Return a tuple (album_art, thumbnail_album_art) + Save the first available result as the albumart for that item """ - filename = getCoverArtFileName (album) - thumbnail = getCoverArtThumbFileName (album) - - album_art_available = False + filename = albumItem.get_aa().get_media_art_path () if (os.path.exists (filename) and not force): print "Album art already there " + filename - album_art_available = True - else: - results_page = self.__msn_images (artist, album) - for online_resource in self.__get_url_from_msn_results_page (results_page): - print "Choosed:", online_resource - content = self.urllib_wrapper.get_url (online_resource) - if (content): - print "Albumart: %s " % (filename) - self.urllib_wrapper.save_content_into_file (content, filename) - album_art_available = True - break - - if (not album_art_available): - return (None, None) - - if (not os.path.exists (thumbnail) or force or album_art_available): - if (not self.__request_thumbnail (filename)): - print "Failed doing thumbnail. Probably album art is not an image!" - os.remove (filename) - return (None, None) - else: - print "Thumbnail exists (and probably valid) " + thumbnail - - return (filename, thumbnail) + return + results_page = self.__msn_images (albumItem.artist, albumItem.title) + for online_resource in self.__get_url_from_msn_results_page (results_page): + print "Trying:", online_resource + content = self.urllib_wrapper.get_url (online_resource) + if (content): + print "Saved on: %s " % (filename) + self.urllib_wrapper.save_content_into_file (content, filename) + albumItem.album_art = filename + break def get_alternatives (self, artist, album, max_alternatives=4): """ - return a list of paths of possible album arts + return a list of pairs (image/ """ results_page = self.__msn_images (artist, album) return self.__process_results_page (results_page, artist, album, max_alternatives) @@ -146,7 +109,7 @@ class MussorgskyAlbumArt: for t in threads: t.join (5) if (t.isAlive ()): - yield (None, None) + yield None else: yield t.get_result () @@ -246,29 +209,6 @@ class MussorgskyAlbumArt: clean = clean.replace (" CD1", "").replace(" CD2", "") return urllib.quote(clean) - def __request_thumbnail (self, filename): - thumbFile = get_thumb_filename_for_path (filename) - return self.thumbnailer.create (filename, thumbFile) - - - -class LocalThumbnailer: - def __init__ (self): - self.THUMBNAIL_SIZE = (124,124) - - def create (self, fullCoverFileName, thumbFile): - if (os.path.exists (fullCoverFileName)): - try: - image = Image.open (fullCoverFileName) - image = image.resize (self.THUMBNAIL_SIZE, Image.ANTIALIAS ) - image.save (thumbFile, "JPEG") - print "Thumbnail: " + thumbFile - except IOError, e: - print e - return False - return True - - if __name__ == "__main__": import sys diff --git a/src/qml/albumItem.py b/src/qml/albumItem.py index 6d13ff6..7689db4 100644 --- a/src/qml/albumItem.py +++ b/src/qml/albumItem.py @@ -5,14 +5,24 @@ from PySide import QtCore from PySide import QtGui from PySide import QtDeclarative +from albumArt import AlbumArt class AlbumItem (QtCore.QObject): - def __init__ (self, title, artist, album_art): + def __init__ (self, title, artist): QtCore.QObject.__init__(self) self._title = title self._artist = artist - self._album_art = album_art + self.aa = AlbumArt (self._title, self._artist) + self.require_download = False + if os.path.exists (self.aa.get_media_art_path ()): + self._album_art = self.aa.get_media_art_path () + elif os.path.exists (self.aa.get_generated ()): + self._album_art = self.aa.get_generated () + self.require_download = True + else: + self.require_download = True + self._album_art = None def _title (self): return self._title @@ -25,9 +35,13 @@ class AlbumItem (QtCore.QObject): def _setAlbumArt (self, path): print "Setting the new album art to", path + self.require_download = False self._album_art = path self.album_art_changed.emit () - + + def get_aa (self): + return self.aa + prop_changed = QtCore.Signal () album_art_changed = QtCore.Signal () diff --git a/src/qml/albumModel.py b/src/qml/albumModel.py index b93f5de..a8190c9 100644 --- a/src/qml/albumModel.py +++ b/src/qml/albumModel.py @@ -31,3 +31,6 @@ class AlbumModel (QtCore.QAbstractListModel): print "Changing album_art from",self._albums[row].album_art, "to:", url assert row >= 0 and row < len (self._albums) self._albums[row].album_art = url + + def get_albums (self): + return self._albums diff --git a/src/qml/controller.py b/src/qml/controller.py index ecbdc89..53b99ce 100644 --- a/src/qml/controller.py +++ b/src/qml/controller.py @@ -13,8 +13,7 @@ except ImportError: from tracker_backend_dbus import TrackerBackendDBus as TrackerBackend from albumItem import AlbumItem -from aa_spec import getCoverArtThumbFileName, getCoverArtFileName - +from coverModel import CoversModel class DownloadThread (QtCore.QThread): @@ -28,55 +27,77 @@ class DownloadThread (QtCore.QThread): print "Running the thread" MAX_OPTIONS = 4 counter = 0 - for img, thumb in self.downloader.get_alternatives (self.album.artist, - self.album.title, MAX_OPTIONS): + for img in self.downloader.get_alternatives (self.album.artist, + self.album.title, MAX_OPTIONS): if counter >= MAX_OPTIONS: break - self.model.updateData (counter, img, thumb) + self.model.updateData (counter, img) counter += 1 class MussorgskyController (QtCore.QObject): - def __init__ (self): + def __init__ (self, rootContext): QtCore.QObject.__init__ (self) self.download = None + self.ctx = rootContext self.tracker = TrackerBackend () - @QtCore.Slot (QtCore.QObject, QtCore.QObject) - def albumSelected (self, coversModel, album): - """ - Starts a thread to look for possible images online. - The thread will update the model (and the changes are visible in the UI) - """ - print "clicked on", album.title - self.download = DownloadThread (coversModel, album) - self.download.start () - - @QtCore.Slot (QtCore.QObject, QtCore.QObject, int) - def coverSelected (self, coverObject, albumModel, index): - """ - The user has clicked in one cover! - """ - albumObject = albumModel.getAlbumInRow (index) - - print "Selected cover", albumObject.title - filename = getCoverArtFileName (albumObject.title) - thumbnail = getCoverArtThumbFileName (albumObject.title) - - coverObject.save (filename, thumbnail) +# @QtCore.Slot (QtCore.QObject, QtCore.QObject, int) +# def coverSelected (self, coverObject, albumModel, index): +# """ +# The user has clicked in one cover! +# """ +# albumObject = albumModel.getAlbumInRow (index) +# +# print "Selected cover", albumObject.title +# filename = getCoverArtFileName (albumObject.title) +# thumbnail = getCoverArtThumbFileName (albumObject.title) +# +# coverObject.save (filename, thumbnail) +# +# albumModel.updateThumb (index, filename) +# #albumObject.album_art = thumbnail +# albumObject.album_art_changed.emit () + + #@QtCore.Slot (QtCore.QObject) + #def resetAlternatives (self, coversModel): + # print "Reseting alternatives", coversModel + # QtGui.QPixmapCache.clear () + # coversModel.resetAlternatives () - albumModel.updateThumb (index, filename) - #albumObject.album_art = thumbnail - albumObject.album_art_changed.emit () + @QtCore.Slot (QtCore.QObject) + def download_all (self, albumModel): + print "well, we will do as soon as possible" + downloader = MussorgskyAlbumArt () + for albumItem in albumModel.get_albums (): + if albumItem.require_download: + downloader.get_album_art (albumItem) @QtCore.Slot (QtCore.QObject) - def resetAlternatives (self, coversModel): - print "Reseting alternatives", coversModel - QtGui.QPixmapCache.clear () - coversModel.resetAlternatives () + def get_options_for (self, albumItem): + print "Getting options for", albumItem.title + m = CoversModel (albumItem) + print m.rowCount () + self.ctx.setContextProperty ("coversModel", m) + self.download = DownloadThread (m, albumItem) + self.download.start () + @QtCore.Slot (QtCore.QObject, int) + def save_option_for (self, coversModel, index): + print "Saving option", index + coverItem = coversModel.getData (index) + print "Moving image:", coverItem.url, "to", coversModel.albumItem.get_aa ().get_media_art_path () + os.rename (coverItem.url, coversModel.albumItem.get_aa().get_media_art_path ()) + # Update the main model. Is this enough? + coversModel.albumItem.album_art = None + coversModel.albumItem.album_art = coversModel.albumItem.get_aa().get_media_art_path () + + @QtCore.Slot () + def stop_pending_jobs (self): + if self.download : + self.download.quit () def get_all_albums (self): """ @@ -85,9 +106,5 @@ class MussorgskyController (QtCore.QObject): """ results = [] for album_title, album_artist in self.tracker.get_all_albums (): - album_art = getCoverArtThumbFileName (album_title) - if (not os.path.exists (album_art)): - album_art = None - - results.append (AlbumItem (album_title, album_artist, album_art)) + results.append (AlbumItem (album_title, album_artist)) return results diff --git a/src/qml/coverItem.py b/src/qml/coverItem.py index 41b21fa..5f429a4 100644 --- a/src/qml/coverItem.py +++ b/src/qml/coverItem.py @@ -12,7 +12,6 @@ class CoverItem (QtCore.QObject): QtCore.QObject.__init__(self) self._initial_image = initial_image self._url = initial_image - self._thumb = None def _url (self): return self._url @@ -21,32 +20,23 @@ class CoverItem (QtCore.QObject): self._url = url self.url_changed.emit () - def _thumb (self): - return self._thumb - def _setThumb (self, thumb): - self._thumb = thumb - - def reset (self): - cached_image = self._url - if cached_image and os.path.exists (cached_image): - os.remove (cached_image) - - cached_thumb = self._thumb - if cached_thumb and os.path.exists (cached_thumb): - os.remove (cached_thumb) - - self.url = self._initial_image - self.url_changed.emit () +# def reset (self): +# cached_image = self._url +# if cached_image and os.path.exists (cached_image): +# os.remove (cached_image) +# +# if cached_thumb and os.path.exists (cached_thumb): +# os.remove (cached_thumb) +# +# self.url = self._initial_image +# self.url_changed.emit () def save (self, cover, thumbnail): assert not self.url == self._initial_image os.rename (self.url, cover) - os.rename (self.thumb, thumbnail) - url_changed = QtCore.Signal () url = QtCore.Property (unicode, _url, _setUrl, notify=url_changed) - thumb = QtCore.Property (unicode, _thumb, _setThumb) diff --git a/src/qml/coverModel.py b/src/qml/coverModel.py index 25b9af3..19442bb 100644 --- a/src/qml/coverModel.py +++ b/src/qml/coverModel.py @@ -6,13 +6,14 @@ from PySide import QtGui from PySide import QtDeclarative from coverItem import CoverItem - +from albumItem import AlbumItem class CoversModel (QtCore.QAbstractListModel): COLUMNS = ('cover', ) - def __init__ (self): + def __init__ (self, albumItem): QtCore.QAbstractListModel.__init__ (self) + self.albumItem = albumItem self._alternatives = [ CoverItem ("images/button-red.png"), CoverItem ("images/button-blue.png"), @@ -29,12 +30,15 @@ class CoversModel (QtCore.QAbstractListModel): return self._alternatives[index.row ()] return None - def updateData (self, row, url, thumb): + def updateData (self, row, url): assert row >= 0 and row < len (self._alternatives) self._alternatives[row].url = url - self._alternatives[row].thumb = thumb - def resetAlternatives (self): - print "Resseting alternatives" - for cover in self._alternatives: - cover.reset () + def getData (self, row): + assert row >= 0 and row < len (self._alternatives) + return self._alternatives[row] + +# def resetAlternatives (self): +# print "Resseting alternatives" +# for cover in self._alternatives: +# cover.reset () diff --git a/src/qml/mussorgsky-qml.py b/src/qml/mussorgsky-qml.py index b88ef74..bc97a75 100644 --- a/src/qml/mussorgsky-qml.py +++ b/src/qml/mussorgsky-qml.py @@ -8,32 +8,28 @@ from PySide.QtDeclarative import QDeclarativeView from albumModel import AlbumModel from controller import MussorgskyController -from coverModel import CoversModel # Create Qt application and the QDeclarative view app = QApplication(sys.argv) view = QDeclarativeView() +controller = MussorgskyController (view.rootContext ()) -#MOCK_DATA = [ -# AlbumItem ("Are you experienced?", "Jimy Hendrix", None), -# AlbumItem ("Bring them all back home", "Bob dylan", None), -# AlbumItem ("OK computer", "Radiohead", None), -# AlbumItem ("Absolution", "Muse", None), -# AlbumItem ("Come with us", "Chemical brothers", None) -# ] +#from albumItem import AlbumItem +#MOCK_DATA = [AlbumItem (u"x", u"y") for i in xrange (0, 100)] +#albumModel = AlbumModel (MOCK_DATA) - -controller = MussorgskyController () albumModel = AlbumModel (controller.get_all_albums()) print "Model with", albumModel.rowCount(), "rows" -coverModel = CoversModel () +#from coverModel import CoversModel +#coverModel = CoversModel () rc = view.rootContext () rc.setContextProperty ('albumModel', albumModel) rc.setContextProperty ('missionControl', controller) -rc.setContextProperty ('coversModel', coverModel) +#rc.setContextProperty ('coversModel', coverModel) + # Create an URL to the QML file #url = QUrl('view.qml') url = QUrl ("../../ui/main.qml") diff --git a/ui/AlbumsPage.qml b/ui/AlbumsPage.qml index 2c6fd6e..bb297a4 100644 --- a/ui/AlbumsPage.qml +++ b/ui/AlbumsPage.qml @@ -1,14 +1,12 @@ import QtQuick 1.1 import com.meego 1.0 -Page { + +PageStack { id: albumsPage - tools: commonTools anchors.fill: parent - signal rowSelected (int index, variant selectedAlbum) - GridView { id: albumsView model: albumModel @@ -25,21 +23,26 @@ Page { Image { id: cover - source: model.album.album_art // || "images/button-blue.png" - //anchors.fill: parent + source: model.album.album_art + width: parent.width + height: parent.height + cache: false anchors.centerIn: parent } Text { id: t - text: model.album.title - visible: (model.album.album_art != null) + text: "xxx" + visible: (model.album.album_art == null) } - MouseArea { anchors.fill: albumPaintArea - onClicked: { albumsPage.rowSelected (index, model.album) } + onClicked: { + console.log (model.album.title) + missionControl.get_options_for (model.album) + pageStack.push(Qt.createComponent("Alternatives.qml")) + } } } diff --git a/ui/Alternatives.qml b/ui/Alternatives.qml index 41bab39..1fab2bb 100644 --- a/ui/Alternatives.qml +++ b/ui/Alternatives.qml @@ -1,12 +1,63 @@ -import Qt 4.7 +import QtQuick 1.1 +import com.meego 1.0 + +Page { + id: coversAlternativesPage + + tools: ToolBarLayout { + ToolIcon { + id: backButton + iconId: "toolbar-back" + onClicked: { missionControl.stop_pending_jobs(); pageStack.pop () } + } + } + + GridView { + id: coversView + model: coversModel + anchors.fill : coversAlternativesPage + cellWidth: 160 + cellHeight: 160 + + delegate: Component { + Rectangle { + id: coverPaintArea + width: coversView.cellWidth + height: coversView.cellHeight + border.color: "red" + + Image { + id: cover + source: model.cover.url + width: parent.width + height: parent.height + cache: false + anchors.centerIn: parent + } + + Text { + id: t + text: "xxx" + visible: (model.cover.url == null) + } + + MouseArea { + anchors.fill: coverPaintArea + onClicked: { + console.log ("wohooo") + missionControl.save_option_for (coversModel, index) + backButton.clicked () + } + } + + } + } + } -/* -Item { - anchors.fill: parent - Text { text: "hola oh"; color: "white" } } -*/ + +/* Row { id: coversAlternatives @@ -42,3 +93,4 @@ Row { } } +*/ diff --git a/ui/Mussorgsky.qml b/ui/Mussorgsky.qml index 7722426..d77839b 100644 --- a/ui/Mussorgsky.qml +++ b/ui/Mussorgsky.qml @@ -6,7 +6,7 @@ Page { TabGroup { id: tabGroup currentTab: albumsTab - AlbumsPage {id: albumsTab} + AlbumsPage {id: albumsTab } SongsPage {id: othersTab} } @@ -33,8 +33,11 @@ Page { Menu { id: myMenu MenuLayout { - MenuItem { text: "Download all" } + MenuItem { text: "Download all"; + onClicked: { missionControl.download_all (albumModel) } + } } } + } diff --git a/ui/main.qml b/ui/main.qml index f7b65bf..4976ca4 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -7,6 +7,4 @@ PageStackWindow { platformStyle: PageStackWindowStyle { id: defaultStyle } initialPage: Mussorgsky {} - - } -- 1.7.9.5