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:
parent
37c2260ebc
commit
d2c71f83a8
29
emmental.ui
29
emmental.ui
|
@ -438,7 +438,7 @@ audio-volume-medium-symbolic</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkPaned">
|
<object class="GtkPaned" id="sidebar_pane">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="position">180</property>
|
<property name="position">180</property>
|
||||||
|
@ -477,6 +477,31 @@ audio-volume-medium-symbolic</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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>
|
<child>
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkScrolledWindow">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -524,7 +549,7 @@ audio-volume-medium-symbolic</property>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">2</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -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()
|
|
@ -1,4 +1,5 @@
|
||||||
# Copyright 2019 (c) Anna Schumaker.
|
# Copyright 2019 (c) Anna Schumaker.
|
||||||
|
from . import artwork
|
||||||
from gi.repository import GLib, Gst
|
from gi.repository import GLib, Gst
|
||||||
|
|
||||||
Playbin = Gst.ElementFactory.make("playbin")
|
Playbin = Gst.ElementFactory.make("playbin")
|
||||||
|
@ -27,6 +28,7 @@ def set_uri(uri, state=None):
|
||||||
uri = GLib.filename_to_uri(uri)
|
uri = GLib.filename_to_uri(uri)
|
||||||
if state != None:
|
if state != None:
|
||||||
Playbin.set_state(Gst.State.NULL)
|
Playbin.set_state(Gst.State.NULL)
|
||||||
|
artwork.reset()
|
||||||
set_property("uri", uri)
|
set_property("uri", uri)
|
||||||
if state != None:
|
if state != None:
|
||||||
Playbin.set_state(state)
|
Playbin.set_state(state)
|
||||||
|
|
|
@ -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())
|
|
@ -1,4 +1,5 @@
|
||||||
# Copyright 2019 (c) Anna Schumaker.
|
# Copyright 2019 (c) Anna Schumaker.
|
||||||
|
from . import artwork
|
||||||
from . import autopause
|
from . import autopause
|
||||||
from . import playbin
|
from . import playbin
|
||||||
from .. import gtk
|
from .. import gtk
|
||||||
|
@ -96,7 +97,13 @@ def set_tag_markup(label, text):
|
||||||
label.set_markup(f"<big>{markup}</big>")
|
label.set_markup(f"<big>{markup}</big>")
|
||||||
|
|
||||||
def on_each_tag(taglist, name):
|
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)
|
(valid, value) = taglist.get_string(name)
|
||||||
if valid and name == "artist":
|
if valid and name == "artist":
|
||||||
set_tag_markup(Artist, f"by {value}")
|
set_tag_markup(Artist, f"by {value}")
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
# Copyright 2019 (c) Anna Schumaker.
|
# Copyright 2019 (c) Anna Schumaker.
|
||||||
|
import base64
|
||||||
import mutagen
|
import mutagen
|
||||||
|
import mutagen.flac
|
||||||
|
import mutagen.id3
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
trier = os.path.abspath("trier")
|
trier = os.path.abspath("trier")
|
||||||
ffmpeg = "ffmpeg -hide_banner -nostdin -f s16le -i /dev/zero -codec libvorbis -loglevel warning".split()
|
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={}):
|
def generate_track(length, filename, tags={}):
|
||||||
path = os.path.join(trier, filename)
|
path = os.path.join(trier, filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
@ -16,6 +30,7 @@ def generate_track(length, filename, tags={}):
|
||||||
fileinfo = mutagen.File(path)
|
fileinfo = mutagen.File(path)
|
||||||
for (key, value) in tags.items():
|
for (key, value) in tags.items():
|
||||||
fileinfo[key] = value
|
fileinfo[key] = value
|
||||||
|
fileinfo["metadata_block_picture"] = [ image_data ]
|
||||||
fileinfo.save()
|
fileinfo.save()
|
||||||
|
|
||||||
# Create a bunch of tracks in the Test Album directory
|
# Create a bunch of tracks in the Test Album directory
|
||||||
|
|
Loading…
Reference in New Issue