rind: Add an artwork widget

And look for the "image" tag from the gstreamer pipeline when setting.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2019-12-30 21:57:51 -05:00
parent 37c2260ebc
commit d2c71f83a8
6 changed files with 122 additions and 3 deletions

View File

@ -438,7 +438,7 @@ audio-volume-medium-symbolic</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkPaned">
<object class="GtkPaned" id="sidebar_pane">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">180</property>
@ -477,6 +477,31 @@ audio-volume-medium-symbolic</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkImage" id="album_artwork">
<property name="can_focus">False</property>
<property name="icon_name">image-missing</property>
<property name="icon_size">5</property>
<style>
<class name="view"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="artwork_separator">
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
@ -524,7 +549,7 @@ audio-volume-medium-symbolic</property>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">4</property>
</packing>
</child>
</object>

28
rind/audio/artwork.py Normal file
View File

@ -0,0 +1,28 @@
# Copyright 2019 (c) Anna Schumaker.
from .. import gtk
from gi.repository import GdkPixbuf
Image = gtk.Builder.get_object("album_artwork")
Paned = gtk.Builder.get_object("sidebar_pane")
Pixbuf = None
Separator = gtk.Builder.get_object("artwork_separator")
def reset():
Image.hide()
Separator.hide()
def scale_image(new_w):
new_h = (Pixbuf.get_height() * new_w) / Pixbuf.get_width()
return Pixbuf.scale_simple(new_w, new_h, GdkPixbuf.InterpType.HYPER)
def set_image(data):
global Pixbuf
loader = GdkPixbuf.PixbufLoader()
loader.write(data)
Pixbuf = loader.get_pixbuf()
loader.close()
Image.set_from_pixbuf(scale_image(Paned.get_position() - 1))
Image.show()
Separator.show()

View File

@ -1,4 +1,5 @@
# Copyright 2019 (c) Anna Schumaker.
from . import artwork
from gi.repository import GLib, Gst
Playbin = Gst.ElementFactory.make("playbin")
@ -27,6 +28,7 @@ def set_uri(uri, state=None):
uri = GLib.filename_to_uri(uri)
if state != None:
Playbin.set_state(Gst.State.NULL)
artwork.reset()
set_property("uri", uri)
if state != None:
Playbin.set_state(state)

View File

@ -0,0 +1,42 @@
# Copyright 2019 (c) Anna Schumaker.
from . import artwork
from . import playbin
from . import widgets
from .. import gtk
import os
import unittest
from gi.repository import Gtk, Gst
test_track = os.path.abspath("./trier/Test Album/01 - Test Track.ogg")
class TestAudioArtwork(unittest.TestCase):
def setUp(self):
playbin.reset()
widgets.reset()
def test_artwork_init(self):
self.assertIsInstance(artwork.Image, Gtk.Image)
self.assertIsInstance(artwork.Paned, Gtk.Paned)
self.assertIsInstance(artwork.Separator, Gtk.Separator)
self.assertIsNone(artwork.Pixbuf)
self.assertFalse(artwork.Image.is_visible())
self.assertFalse(artwork.Separator.is_visible())
def test_artwork_load(self):
artwork.Paned.set_position(150)
playbin.set_uri(test_track, Gst.State.PAUSED)
gtk.main_loop(delay=0.1)
self.assertTrue(artwork.Image.is_visible())
self.assertTrue(artwork.Separator.is_visible())
self.assertEqual(artwork.Image.get_storage_type(), Gtk.ImageType.PIXBUF)
self.assertEqual(artwork.Pixbuf.get_height(), 512)
self.assertEqual(artwork.Pixbuf.get_width(), 512)
pbuf = artwork.Image.get_pixbuf()
self.assertEqual(pbuf.get_height(), 149)
self.assertEqual(pbuf.get_width(), 149)
playbin.set_uri(test_track)
self.assertFalse(artwork.Image.is_visible())
self.assertFalse(artwork.Separator.is_visible())

View File

@ -1,4 +1,5 @@
# Copyright 2019 (c) Anna Schumaker.
from . import artwork
from . import autopause
from . import playbin
from .. import gtk
@ -96,7 +97,13 @@ def set_tag_markup(label, text):
label.set_markup(f"<big>{markup}</big>")
def on_each_tag(taglist, name):
if name in [ "artist", "title" ]:
if name == "image":
(res, sample) = taglist.get_sample(name)
buffer = sample.get_buffer()
(res, map) = buffer.map(Gst.MapFlags.READ)
artwork.set_image(map.data)
buffer.unmap(map)
elif name in [ "artist", "title" ]:
(valid, value) = taglist.get_string(name)
if valid and name == "artist":
set_tag_markup(Artist, f"by {value}")

View File

@ -1,11 +1,25 @@
# Copyright 2019 (c) Anna Schumaker.
import base64
import mutagen
import mutagen.flac
import mutagen.id3
import os
import subprocess
trier = os.path.abspath("trier")
ffmpeg = "ffmpeg -hide_banner -nostdin -f s16le -i /dev/zero -codec libvorbis -loglevel warning".split()
image = mutagen.flac.Picture()
image.data = open("emmental.png", "rb").read()
image.type = mutagen.id3.PictureType.COVER_FRONT
image.mime = u"image/png"
image.width = 512
image.height = 512
image.depth = 16
encoded_data = base64.b64encode(image.write())
image_data = encoded_data.decode("ascii")
def generate_track(length, filename, tags={}):
path = os.path.join(trier, filename)
if os.path.exists(path):
@ -16,6 +30,7 @@ def generate_track(length, filename, tags={}):
fileinfo = mutagen.File(path)
for (key, value) in tags.items():
fileinfo[key] = value
fileinfo["metadata_block_picture"] = [ image_data ]
fileinfo.save()
# Create a bunch of tracks in the Test Album directory