0

I'm trying to get the thumbnail of the currently playing media on windows, and thanks to this answer (https://stackoverflow.com/a/66037406/15491505) i got quite far, however I'm facing a strange issue where in get_thumbnail() the variable byte_buffer always ends up being 0 in length after the first run... as in the first time I call it I get back the thumbnail perfectly, but all further calls end up failing...

This is what I have so far:

from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
from winrt.windows.storage.streams import DataReader, Buffer, InputStreamOptions
from io import BytesIO
from PIL import Image
import asyncio


async def get_thumbnail():
    sessions = await MediaManager.request_async()
    current_session = sessions.get_current_session()

    if current_session:
        properties = await current_session.try_get_media_properties_async()
        media_info = {song_attr: properties.__getattribute__(song_attr) for song_attr in dir(properties) if song_attr[0] != '_'}

        if media_info.get('thumbnail'):
            thumb_stream_ref = media_info['thumbnail']
            thumb_read_buffer = Buffer(5000000)

            readable_stream = await thumb_stream_ref.open_read_async()
            readable_stream.read_async(thumb_read_buffer, thumb_read_buffer.capacity, InputStreamOptions.READ_AHEAD)

            buffer_reader = DataReader.from_buffer(thumb_read_buffer)
            byte_buffer = buffer_reader.read_bytes(thumb_read_buffer.length)

            binary = BytesIO()
            binary.write(bytearray(byte_buffer))
            binary.seek(0)
            print(len(bytearray(byte_buffer)))

            img = Image.open(binary)
            return img


thumbnail = asyncio.run(get_thumbnail())
thumbnail.show()
# This will work

thumbnail2 = asyncio.run(get_thumbnail())
thumbnail2.show()
# This will not

Example output:

C:\Users\willy\Desktop>test.py
117672
0
Traceback (most recent call last):
  File "C:\Users\willy\Desktop\test.py", line 39, in <module>
    thumbnail2 = asyncio.run(get_thumbnail())
  File "C:\Python38\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\willy\Desktop\test.py", line 31, in get_thumbnail
    img = Image.open(binary)
  File "C:\Python38\lib\site-packages\PIL\Image.py", line 2930, in open
    raise UnidentifiedImageError(
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x00000278D2FB3B30>
WillyJL
  • 3
  • 3

1 Answers1

0

Solution

Simply await the result of the readable_stream.read_async(...) call:

...
readable_stream = await thumb_stream_ref.open_read_async()
await readable_stream.read_async(thumb_read_buffer, thumb_read_buffer.capacity, InputStreamOptions.READ_AHEAD)

buffer_reader = DataReader.from_buffer(thumb_read_buffer)
...

The thumbnail should now be successfully displayed each time.

Debugging process

(for anyone interested and for similar bugs in the future)

After break-pointing your code, it appeared that, on the second call of get_thumbnail(), byte_buffer was left empty. This indicated that the thumb_read_buffer was not being populated correctly from the stream.

Interestingly, when single-stepping the code instead, the image displayed both times. This suggested to me that maybe an asynchronous function call wasn't being awaited.

Turns out .read_async() (as the function name suggests) is an asynchronous operation in winrt (see IInputStream.ReadAsync on learn.microsoft.com). Hence, awaiting its execution fixed the problem of the empty thumb_read_buffer.

tameTNT
  • 376
  • 3
  • 6
  • **Attempt at an explanation** _I am not guaranteeing that this explanation is correct, it is merely my best guess..._ When `.read_async()` was called without `await`, no time was being given for data to actually be read into `thumb_read_buffer`; the program just moved straight on to executing the `read_bytes()` call which didn't have anything to read from. As to why this didn't happen on the first call of `get_thumbnail()`, I really have no idea. (I'll try to edit this if I ever find out). – tameTNT Mar 28 '21 at 00:21