#!/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"
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):
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
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):
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)
for t in threads:
t.join (5)
if (t.isAlive ()):
- yield (None, None)
+ yield None
else:
yield t.get_result ()
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
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
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 ()
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
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):
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):
"""
"""
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
QtCore.QObject.__init__(self)
self._initial_image = initial_image
self._url = initial_image
- self._thumb = None
def _url (self):
return self._url
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)
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"),
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 ()
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")
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
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"))
+ }
}
}
-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
}
}
+*/
TabGroup {
id: tabGroup
currentTab: albumsTab
- AlbumsPage {id: albumsTab}
+ AlbumsPage {id: albumsTab }
SongsPage {id: othersTab}
}
Menu {
id: myMenu
MenuLayout {
- MenuItem { text: "Download all" }
+ MenuItem { text: "Download all";
+ onClicked: { missionControl.download_all (albumModel) }
+ }
}
}
+
}
platformStyle: PageStackWindowStyle { id: defaultStyle }
initialPage: Mussorgsky {}
-
-
}