Audiobook plugin


#1

I want to develop an audio-book extension for mopidy. I started by reading the docs (really good and a lots of docs) about developing extensions. I have already started here. mopidy-audiobook.
Up to now its only the cookiecutter template.

The only real difference for audio books from normal music files is, you want them to always resume from where you last stopped.

The easiest should be to develop a backend plugin that is essentially the mopidy-file plugin + a database file, to store where the audio books was last stopped.

Do you think this is a good way to do it? Should I better use mopidy-local? Its my first plugin so I want to be as simple as possible.
Currently I found myself re implementing mopidy-file extension. Would it be okay, to inherit directly from e.g. mopidy.file.library.FileLibraryProvider instad of from mopidy.backend.LibraryProvider or is that a nogo?

I would welcome some feedback.
Cheers Malte


#2

I can’t offer any practical advice, but would be very interested in this if you can do it. Before my father passed away he went 95% blind and I tried at the time to find a solution to the audiobook problem but was never successful.

As I could use musicbox to stream his favourite radio stations, use festival and a remote control to tell him which station he had selected it would have been the ideal solution for him to listen to audiobooks as well, in the end he used an mp3 player but was forever losing his place.

Good luck with it.


#3

Hey

Nice to hear there is a demand for this :slight_smile: I started looking into it and writing first code. But I’m working on this in my free time, and its my first extension of such a kind, so don’t expect it to be ready soon.


#4

I found and tried this when I was looking https://code.google.com/archive/p/mpdpss/ unfortunately it only saves playlist not song position and it didn’t work through musicbox or mopidy very well. You might find some useful information in it. If you want the download to have a look at let me know, but I think most of it is available from the site above.


#5

I think you are on the right track. I’d probably use mopidy-local’s LocalBackend as a base class and provide some extra functionality for PlaybackProvider methods to save/restore the current position to/from your data structure for each audiobook uri. Providing you stick to Mopidy APIs you should be fine, anything else is subject to change.


#6

I think so as well :slight_smile: I currently reimplemented the mopidy.file extension and it is working. I can browse some test audiobooks and play them(I guess its gonne be mopidy.local later on but for the time beeing the concept of files seems more simple to me).
However I’m struggling with the PlaybackProvider. From the name I deduced I need to implement a custom AudiobookPlaybackProvider.play method. I thought this gets called when I play an audiobook, but this is not the case. I’m currently trying to understand what functions are called when I play a song. Can you point me to it?


#7

Okay, I learned now that mopidy.core.CoreListener.track_playback_started is called when ever you start playing a file. Now its just a matter of some hacking to get a first working version of this. I’m on the track :slight_smile:


#8

The problem now is, that the track_playback_started is always called whenever a track is started. How can I limit this to tracks only within the library of the mopidy-audiobook extension.


#9

It might be easier for people to provide input if the latest code is pushed to the git repository that you are working on.

I’m not sure that I am following exactly what the problem is, but if it is a matter of the standard mopidy.file extension PlaybackProvider still being called instead of the one that you are working on then you either need to use your own unique URI scheme, or look at https://github.com/mopidy/mopidy/issues/696.


#10

Of course you are right, the program was/is a very rough working place, I first needed to understand mopidy. By now I have a version pushed to local branch of the project. You can find it here

As @kingosticks suggested, I switched to use the LocalBackend with this version, but It didnt help much, I still have the same problems as I had with using files as backend. Now its + I don’t really understand how the local and audiobook databases are to be separated.


#11

I’m not sure how you are planning on operating the plugin, but why not make the default that every track, whether book, music or speech, is saved in place when pressing pause or changing playlist.
Pressing play or reloading that playlist have a pop up box asking if you want to resume or start from beginning.
This would also have an advantage if the end user forgot to add the audiobook to the database the default would be to save anyway.


#12

That would be a possibility. Thank you for the suggestion. My questions
are:

Wouldn’t it lead to a problem when people are using the mpd backend as
well? E.g. I’m often using my phone with the mpddroid app to control
mopidy. How would such a popup be implemented there?

Another problem is that this database would be significant larger then
just the audiobook databse, thus I would need to think about performance
a bit more. How far can one get with a simple json database. Do I need
to use SQL, any body got experience there?


#13

I only use Musicbox so didn’t give any thought to other methods - perhaps though the default could be to start at previous stop point, if user wants to restart from beginning they would need to select a track from within the playlist and start from there.
I agree about the database it could end up being huge, could it be set up to clear any stop points and related data if they haven’t been accessed for 7 days. Most people listening to books would be regularly updating them.


#14

I wouldn’t like that so much. I know from myself that I can have long pauses in between listening to an audiobook and such a live time parameter would stress me. I could make it optional though and if one wants to use it, it is available.
Best thing for me would still be if get to understand how to subclass Library correctly.


#15

I am slowly developing a mopidy sql-alchemy backend that will include something like this (or a seperate extension focused solely on audiobooks). The issue I see with a lot of the extensions is that there is no coherent database backend solution for these extensions. I am aiming to make the database reusable by other extensions so they can store data however they need and not have to worry about how to get the database up and going. I would note that u may want to use an audiobook storage schema that complies with some sort of standard that is currently being used elsewhere.


#16

I don’t think you’ll be able to have any specific UI for this, unless you’re creating your own front-end.
You’d probably just want to resume playback and if the user wants to go back to the beginning, they can do that via the usual UI.


#17

Oh. Just realised this thread is from last year.


#18

Hello,

BTW, I just released my first Mopidy backend plugin. Related to audiobooks service.
https://github.com/jedrus2000/mopidy-audioteka

This service originates from Poland, and is very popular here.
On technical background this service has HTTP digest auth so I couldn’t simply pass URI.
I just had to handle it on my own. Book chapters on this service are files to download (chunks are also supported).

I was trying to look at sample backends, but I didn’t found way to play media while downloading. Any idea, suggestions ?


#19

Looks like souphttpsrc supports digest auth (as you would expect). Did you try setting the user and pass properties?

https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-souphttpsrc.html#GstSoupHTTPSrc--user-id


#20

Thanks for a tip ! No, I didn’t tried, but I will. Thanks for the direction.

I am curious if gstreamer will be able to play mp3 while downloading, if it is not streaming service.

Now, I download media file in other thread, but I wait (with threading.Event() ) until about 1 MB of data
is downloaded, then I pass uri. To fool gstreamer about track length, I had to create file with final size before downloading.
All of my audiobooks works great, except one book has such mp3 data that even with 1MB of data gstreamer can’t recognize format. As I look at ffprobe output it has attached big image as 2nd stream.
GStreamer verbose output is about 17 MB with image=(sample) section.