pyfoobeef

Allows control of the Foobar2000 and DeaDBeeF media players through the beefweb plugin API.

  • Both asynchronous and synchronous clients
  • An asynchronous event listener with callbacks
  • For Python 3.6 and up
  • MIT License

Installation

  1. Install and configure the beefweb plugin for your media player.

  2. Run:

    pip install pyfoobeef
    

Examples

Synchronous client:

import pyfoobeef
from time import sleep


player = pyfoobeef.Client("localhost", 8880)

# Add a new playlist.
new_playlist = player.add_playlist(title="My New Playlist")
player.set_current_playlist(new_playlist)

# Add items to the playlist.  Note that paths including drive letters
# are case sensitive even on Windows due to limitations of the beefweb
# plugin (so r"c:\Music" would not work here).
player.add_playlist_items(new_playlist, items=[r"C:\Music"])

player.play_specific(new_playlist, 1)
# Give the media player a bit of time to actually start playing.
sleep(0.5)

# Column maps represent the media data fields to retrieve and the names
# to assign the returned data to.
column_map = {
    "%artist%": "artist",
    "%title%": "title",
    "%album% - %track number% - %title%": "my_custom_column",
}
status = player.get_player_state(column_map)

if status.active_item.has_columns():
    # Returned columns may be addressed by subscripting or as attributes.
    print(status.active_item.columns["artist"])
    print(status.active_item.columns.title)
    print(status.active_item.columns.my_custom_column)

# Display the playback state (ex. "playing")
print(status.playback_state)

# Display information about the volume level (current, min, max, etc.)
print(status.volume)

The asynchronous client follows a very similar format:

import pyfoobeef
import asyncio


async def example():
    player = pyfoobeef.AsyncClient("localhost", 8880)

    # Add a new playlist.
    new_playlist = await player.add_playlist(title="My New Playlist")
    await player.set_current_playlist(new_playlist)

    # Add items to the playlist.  Note that paths including drive letters
    # are case sensitive even on Windows due to limitations of the beefweb
    # plugin (so r"c:\Music" would not work here).
    await player.add_playlist_items(new_playlist, items=[r"C:\Music"])

    # sort items by length
    await player.sort_playlist_items(new_playlist, by="%length_seconds%")

    # Get information about the first 10 items in a playlist.
    items = await player.get_playlist_items(
        new_playlist,
        column_map=["%artist%", "%title%", "%length%"],
        offset=0,
        count=10,
    )
    for item in items:
        print(item)

    # Play a specific item.
    await player.play_specific(new_playlist, 4)


asyncio.run(example())

The asynchronous event listener can automatically execute callbacks when certain events are received or the media players state can be determined from the EventListener object’s attributes:

import pyfoobeef
import asyncio


def print_active_item(state):
    print("From player state callback.  Active item is:")
    print(state.active_item)


def print_playlists(playlists):
    print("From playlists callback.  Current playlists:")
    for playlist in playlists:
        print(playlist)


async def example():
    listener = pyfoobeef.EventListener(
        base_url="localhost",
        port=8880,
        active_item_column_map={
            "%artist%": "artist",
            "%title%": "title",
            "%length%": "length",
        },
    )

    # Add callbacks for player events.
    listener.add_callback("player_state", print_active_item)
    listener.add_callback("playlists", print_playlists)

    # Start listening for events from the player.
    await listener.connect(reconnect_time=1)

    await asyncio.sleep(10)

    # The last received information about the player state and playlists
    # can be accessed from the listener object itself.
    print("From the last player state object saved to listener."
          "  Active item is:")
    print(listener.player_state.active_item)
    print("Estimated playback position: ",
          listener.player_state.estimated_position_mmss())
    for playlist in listener.playlists:
        print(playlist)

    await asyncio.sleep(10)

    # The listener should always be disconnected when done.
    await listener.disconnect()


asyncio.run(example())