Commit 86fa98a1 authored by Frank Scholz's avatar Frank Scholz
Browse files

separation between the images and the audio presentation

parent 7f3a8c75
This diff is collapsed.
data/stop.png

881 Bytes

__version_info__ = (0,0,3)
__version__ = '%d.%d.%d' % (__version_info__[0],__version_info__[1],__version_info__[2],)
\ No newline at end of file
# -*- coding: utf-8 -*-
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php
# Copyright 2007, Frank Scholz <coherence@beebits.net>
import os, random
import time
# Twisted
from twisted.internet import reactor
from twisted.internet import task
from twisted.web import client
# Pygame
import pygame
from pygame.locals import *
# Coherence
from coherence.base import Coherence
from coherence.upnp.core import DIDLLite
import louie
from mediarenderer.menus import Menu
class TrackView(object):
def __init__(self, client, id):
print "TrackView init", client, id
self.client = client
self.id = id
d = self.client.content_directory.browse(id, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_album_browse, client)
def process_album_browse( self, results, client):
for k,v in results.iteritems():
#print k, v
if k == 'items':
for id, values in v.iteritems():
#print values
if values['upnp_class'].startswith('object.item.audioItem'):
id = values['id']
title = values.get('title', 'untitled')
artist = values.get('artist', 'unknown')
cover = values.get('album_art_uri', None)
print "track", id, title, artist, cover
class Album(object):
width = 100
height = 100
def __init__(self, client, id, title, artist, cover):
self.id = id
self.client = client
self.title = title
self.artist = artist
self.cover = cover
self.image = pygame.Surface((self.width,self.height))
self.image.fill((0, 0, 0)) # black
self.rect = self.image.get_rect()
self.get_cover()
self.finished = False
self.touched = 0
print "album created", id, title, artist, cover
def get_cover(self):
def got_error(f):
self.finished = True
louie.send('MediaRenderer.Album.cover', None, None)
d = client.getPage(self.cover)
d.addCallback(self.got_cover)
d.addErrback(got_error)
def got_cover(self, result):
try:
import Image
import StringIO
im = Image.open(StringIO.StringIO(result))
self.image = pygame.image.frombuffer( im.tostring("raw","RGB"), im.size, "RGB")
except ImportError:
import tempfile
tmp_fp, tmp_path = tempfile.mkstemp()
os.write(tmp_fp,result)
os.close(tmp_fp)
self.image = pygame.image.load(tmp_path).convert()
os.unlink(tmp_path)
self.image = pygame.transform.scale(self.image, (self.width,self.height))
self.rect = self.image.get_rect()
self.finished = True
louie.send('MediaRenderer.Album.cover', None, None)
print "cover stored"
class Audio(object):
album_x_offset = 100
album_y_offset = 70
def __init__(self, controller, main_rect):
self.controller = controller
self.screen = pygame.Surface((main_rect.width,main_rect.height))
self.container_watch = []
self.client = {}
self.local_store = None
self.content = []
self.view = 0 # 0 = albums
# 1 = track list
buttons = (('save',(44,50),None,None),
('backward',(31,140),self.proceed_to_previous_song,None),
('pause',(31,216),self.pause,None),
('play',(31,300),self.play,'stop.png'),
('forward',(44,380),self.proceed_to_next_song,None))
self.right_menu = Menu(controller, 'right', buttons)
louie.connect(self.media_server_found, 'Coherence.UPnP.ControlPoint.MediaServer.detected', louie.Any)
louie.connect(self.media_server_removed, 'Coherence.UPnP.ControlPoint.MediaServer.removed', louie.Any)
louie.connect(self.ready,'MediaRenderer.Album.cover',louie.Any)
def check(self, button, pos):
if self.view == 0:
for album in self.content[:18]:
if album.rect.collidepoint(pos[0],pos[1]):
print "touched album", album.id, album.title
t = time.time()
if album.touched > 0 and t - album.touched < 0.5:
print "double click"
album.touched = 0
TrackView(album.client,album.id)
else:
album.touched = time.time()
def toggle_fullscreen(self):
return
def clear_screen(self):
self.screen.fill((0,0,0))
def ready(self,r):
for album in self.content[:18]:
if album.finished == False:
return
self.draw_screen()
def draw_screen(self):
self.clear_screen()
column = 0
row = 0
for album in self.content[:18]:
album.rect[0] = self.album_x_offset + (column * album.rect[2])
album.rect[1] = self.album_y_offset + (row * album.rect[3])
self.screen.blit(album.image,album.rect)
column += 1
if column == 6:
row += 1
column = 0
louie.send('MediaRenderer.Screen.redraw', None, self.screen)
def media_server_found(self, client, usn):
print "audio - media_server_found", client.device.get_friendly_name()
if 'Coherence Test Content' == client.device.get_friendly_name():
self.client[usn] = client
#d = client.content_directory.browse(0, browse_flag='BrowseMetadata')
d = self.client[usn].content_directory.browse(0, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, client)
client.content_directory.subscribe_for_variable('ContainerUpdateIDs', self.state_variable_change)
client.content_directory.subscribe_for_variable('SystemUpdateID', self.state_variable_change)
def media_server_removed(self, usn):
print "media_server_removed", usn
if(isinstance(self.local_store, tuple) is True and
len(self.local_store) == 2 and
usn == self.local_store[0].device.get_usn()):
self.local_store = None
self.right_menu.set_button_action('save',None)
if self.client.has_key(usn) == True:
if self.display_loop.running:
self.display_loop.stop()
del self.client[usn]
self.content = []
def process_media_server_browse( self, results, client, albums=False):
for k,v in results.iteritems():
#print k, v
if k == 'items':
for id, values in v.iteritems():
print values
if(values['upnp_class'].startswith('object.container') and
values['title'] == 'audio'):
d = client.content_directory.browse(id, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, client, albums=True)
if albums == True and values['upnp_class'].startswith('object.container'):
id = values['id']
title = values.get('title', 'untitled')
artist = values.get('artist', 'unknown')
cover = values.get('album_art_uri', None)
self.content.append(Album( client, id, title, artist, cover))
if values['parent_id'] not in self.container_watch:
self.container_watch.append(values['parent_id'])
def process_local_media_server_browse( self, results, client):
for k,v in results.iteritems():
#print k, v
if k == 'items':
for id, values in v.iteritems():
#print values
if(values['upnp_class'].startswith('object.container') and
values['title'] == 'content'):
d = client.content_directory.browse(id, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_local_media_server_browse, client)
if(values['upnp_class'].startswith('object.container') and
values['title'] == 'audio'):
print "found object id", values['id'], "as storage point"
if hasattr(self,'right_menu'):
self.right_menu.set_button_action('save',self.store_locally)
self.local_store = (self.local_store,values['id'])
def state_variable_change( self, variable, usn):
print variable.name, 'changed from', variable.old_value, 'to', variable.value
if variable.old_value == '':
return
if variable.name == 'SystemUpdateID':
if self.client.has_key(usn) == True:
if len(self.content) == 0:
d = self.client[usn].content_directory.browse(0, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, self.client[usn])
if variable.name == 'ContainerUpdateIDs':
changes = variable.value.split(',')
while len(changes) > 1:
container = changes.pop(0).strip()
update_id = changes.pop(0).strip()
if container in self.container_watch:
print "heureka, we have a change in ", container, ", container needs a reload"
self.content = []
d = self.client[usn].content_directory.browse(container, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, self.client[usn], albums=True)
def pause(self):
""" pause audio play """
def play(self):
""" start or stop audio play """
def proceed_to_next_song(self, skip_junk=False):
""" skip one song forward """
def proceed_to_previous_song(self, skip_junk=False):
""" skip one song backward """
# -*- coding: utf-8 -*-
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php
# Copyright 2007, Frank Scholz <coherence@beebits.net>
import os, random
# Twisted
from twisted.internet import reactor
from twisted.internet import task
from twisted.web import client
# Pygame
import pygame
from pygame.locals import *
# Coherence
from coherence.base import Coherence
from coherence.upnp.core import DIDLLite
import louie
from mediarenderer.menus import Menu
class Images(object):
def __init__(self, controller, main_rect):
self.controller = controller
self.screen = pygame.Surface((main_rect.width,main_rect.height))
self.images = []
self.container_watch = []
self.image_index = -1
self.displaying = None
self.current_image = None
self.client = {}
self.local_store = None
buttons = (('save',(44,50),None,None),
('backward',(31,140),self.proceed_to_previous_image,None),
('pause',(31,216),self.pause,'play.png'),
('forward',(31,300),self.proceed_to_next_image,None),
('mark-junk',(44,380),self.mark_junk,None))
self.right_menu = Menu(controller, 'right', buttons)
self.display_loop = task.LoopingCall(self.proceed_to_next_image,skip_junk=True)
louie.connect(self.media_server_found, 'Coherence.UPnP.ControlPoint.MediaServer.detected', louie.Any)
louie.connect(self.media_server_removed, 'Coherence.UPnP.ControlPoint.MediaServer.removed', louie.Any)
def check(self, button, pos):
pass
def toggle_fullscreen(self):
return
if self.fullscreen == 1:
self.fullscreen = FULLSCREEN
else:
self.fullscreen = 1
self.screen = pygame.display.set_mode(SCREENRECT.size, self.fullscreen, self.bestdepth)
self.background.clear_screen()
pygame.display.update(self.displaying)
self.displaying = self.current_image.get_rect(center=((self.screen.get_width()/2)-1,(self.screen.get_height()/2)-1))
self.screen.blit(self.current_image,self.displaying, (0,0,self.displaying.width,self.displayin.height))
pygame.display.update(self.displaying)
def media_server_found(self, client, usn):
print "images - media_server_found", client.device.get_friendly_name()
if 'Flickr Images' == client.device.get_friendly_name():
self.client[usn] = client
#d = client.content_directory.browse(0, browse_flag='BrowseMetadata')
d = self.client[usn].content_directory.browse(0, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, client)
client.content_directory.subscribe_for_variable('ContainerUpdateIDs', self.state_variable_change)
client.content_directory.subscribe_for_variable('SystemUpdateID', self.state_variable_change)
if 'Coherence Test Content' == client.device.get_friendly_name():
print "found a local MediaServer for storage"
self.local_store = client
d = client.content_directory.browse(0, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_local_media_server_browse,client)
def media_server_removed(self, usn):
print "media_server_removed", usn
if(isinstance(self.local_store, tuple) is True and
len(self.local_store) == 2 and
usn == self.local_store[0].device.get_usn()):
self.local_store = None
self.right_menu.set_button_action('save',None)
if self.client.has_key(usn) == True:
if self.display_loop.running:
self.display_loop.stop()
del self.client[usn]
self.images = []
def process_media_server_browse( self, results, client):
for k,v in results.iteritems():
#print k, v
if k == 'items':
for id, values in v.iteritems():
if values['upnp_class'].startswith('object.container'):
d = client.content_directory.browse(id, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, client)
if values['upnp_class'].startswith('object.item.imageItem'):
#print values
if values.has_key('resources'):
if(values.has_key('parent_id') and
values['parent_id'] not in self.container_watch):
self.container_watch.append(values['parent_id'])
if len(values['resources']):
title = values.get('title', 'untitled').encode('ascii', 'ignore')
self.images.append({'url': values['resources'].keys()[0], 'title': title})
random.shuffle(self.images)
if len(self.images):
if not self.display_loop.running:
self.display_loop.start(20, now=True)
def process_local_media_server_browse( self, results, client):
for k,v in results.iteritems():
#print k, v
if k == 'items':
for id, values in v.iteritems():
#print values
if(values['upnp_class'].startswith('object.container') and
values['title'] == 'content'):
d = client.content_directory.browse(id, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_local_media_server_browse, client)
if(values['upnp_class'].startswith('object.container') and
values['title'] == 'images'):
print "found object id", values['id'], "as storage point"
if hasattr(self,'right_menu'):
self.right_menu.set_button_action('save',self.store_locally)
self.local_store = (self.local_store,values['id'])
def state_variable_change( self, variable, usn):
print variable.name, 'changed from', variable.old_value, 'to', variable.value
if variable.old_value == '':
return
if variable.name == 'SystemUpdateID':
if self.client.has_key(usn) == True:
if len(self.images) == 0:
d = self.client[usn].content_directory.browse(0, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, usn)
if variable.name == 'ContainerUpdateIDs':
changes = variable.value.split(',')
while len(changes) > 1:
container = changes.pop(0).strip()
update_id = changes.pop(0).strip()
if container in self.container_watch:
print "heureka, we have a change in ", container, ", container needs a reload"
if self.display_loop.running:
self.display_loop.stop()
self.images = []
d = self.client[usn].content_directory.browse(container, browse_flag='BrowseDirectChildren',
backward_compatibility=False)
d.addCallback( self.process_media_server_browse, usn)
def loop_start(self, x=None, now=False):
if len(self.images) and not self.display_loop.running:
self.display_loop.start(20, now)
def loop_stop(self):
if self.display_loop.running:
self.display_loop.stop()
def pause(self):
if self.display_loop.running:
self.display_loop.stop()
elif len(self.images) and not self.display_loop.running:
self.display_loop.start(20, now=True)
def store_locally(self):
print "store current image", self.image_index, self.images[self.image_index].get('url')
if(isinstance(self.local_store, tuple) is True and
len(self.local_store) == 2):
print "at", self.local_store[0].device.get_friendly_name(), "in container id", self.local_store[1]
d = self.local_store[0].content_directory.create_object(self.local_store[1],
{'title':self.images[self.image_index].get('title'),
'upnp_class':'object.item.imageItem.photo',
'parentID':self.local_store[1]})
def got_import_result(r,s,d):
print "import from", s, "to", d, "was successful"
def got_result(r, source_uri):
print "store_locally got_result", r
elt = DIDLLite.DIDLElement.fromString(r.get('Result',''))
for item in elt:
for res in item.findall('res'):
destination_uri = res.get('importUri', None)
if destination_uri is not None:
d = self.local_store[0].content_directory.import_resource(source_uri, destination_uri)
d.addCallback(got_import_result, self.images[self.image_index].get('url'), destination_uri)
d.addErrback(got_error)
def got_error(failure):
print "store_locally got_error", failure
d.addCallback(got_result, self.images[self.image_index].get('url'))
d.addErrback(got_error)
def mark_junk(self):
print "mark junk image", self.image_index, self.images[self.image_index].get('url')
self.images[self.image_index]['junk'] = True
self.proceed_to_next_image()
def proceed_to_next_image(self, skip_junk=False):
def got_error(failure, url):
print "got_error", failure, url
self.loop_start(None,now=True)
if len(self.images)>0:
self.loop_stop()
while True:
try:
self.image_index += 1
image = self.images[self.image_index]
except IndexError:
self.image_index = 0
image = self.images[self.image_index]
print image
if skip_junk==True and image.has_key('junk'):
continue
image_url = image.get('url')
image_title = image.get('title')
d = client.getPage(image_url)
d.addCallback(self.got_image, image_title)
d.addCallback(self.loop_start)
d.addErrback(got_error, image_url)
break
def proceed_to_previous_image(self, skip_junk=False):
def got_error(failure, url):
print "got_error", failure, url
self.loop_start(None,now=True)
if len(self.images)>0:
self.loop_stop()
while True:
try:
self.image_index -= 1
image = self.images[self.image_index]
except IndexError:
self.image_index = len(self.images)-1
image = self.images[self.image_index]
print image
if skip_junk==True and image.has_key('junk'):
continue
image_url = image.get('url')
image_title = image.get('title')
d = client.getPage(image_url)
d.addCallback(self.got_image, image_title)
d.addCallback(self.loop_start)
d.addErrback(got_error, image_url)
break
def got_image(self, result, title = ''):
try:
import Image
import StringIO
im = Image.open(StringIO.StringIO(result))
size = im.size
self.current_image = pygame.image.frombuffer( im.tostring("raw","RGB"), im.size, "RGB")
except ImportError:
import tempfile
tmp_fp, tmp_path = tempfile.mkstemp()
os.write(tmp_fp,result)
os.close(tmp_fp)
self.current_image = pygame.image.load(tmp_path).convert()
size = self.current_image.get_size()
os.unlink(tmp_path)
transform = None
if size[0] > self.screen.get_width():
new_width = self.screen.get_width()
relation = float(self.screen.get_width())/float(size[0])
new_heigth = float(size[1]) * relation
new_height = int(new_height)
if new_height > self.screen.get_height():
relation = float(self.screen.get_height())/float(new_height)
new_width = float(new_width) * relation
new_height = self.screen.get_height()
transform =(new_width,new_height)
elif size[1] > self.screen.get_height():
relation = float(self.screen.get_height())/float(size[1])
new_height = self.screen.get_height()
new_width = int(float(size[0]) * relation)
transform =(new_width,new_height)
if transform is not None:
self.current_image = pygame.transform.scale(self.current_image, transform)
if self.displaying is not None:
#print "clear old image", self.displaying
self.controller.clear_part(self.displaying)
self.displaying = self.current_image.get_rect(center=((self.screen.get_width()/2),(self.screen.get_height()/2)))
self.controller.redraw_part(self.current_image,self.displaying, screen=self.screen)
pygame.display.set_caption('Coherence MediaRenderer - %s' % title)
# -*- coding: utf-8 -*-
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php
# Copyright 2007, Frank Scholz <coherence@beebits.net>
import os
# Twisted
from twisted.internet import reactor
from twisted.internet import task
from twisted.web import client
# Pygame