jaseg / python-mpv

Python interface to the awesome mpv media player
https://git.jaseg.de/python-mpv.git
Other
543 stars 68 forks source link

Appending to playlist while started in new thread #141

Closed Stax124 closed 3 years ago

Stax124 commented 3 years ago

Hi, I'm developing a command line program and I need to start mpv.MPV in a new thread. I was trying to use playlist_append but its starting new instance instead of actually appending to playlist. Is there a way to use this function with threading or is there any other workaround ?

Python: 3.9.0 Python-MPV: 0.5.2 Platform: Linux and Windows

Himan10 commented 3 years ago

Hey, @Stax124 If you don't mind then can you please tell me how to run a playlist using this library? Actually I just started using it and got confused when it comes to run N number of songs and each time give the control to the user to do another task, you get what I am saying ? I want to run a playlist (contains N number of song), do you know how to ? I am sorry for asking this but I looked over some things and none of them helped me.

Stax124 commented 3 years ago

Hi @Himan10, so using playlists is quite easy, just like in Readme:

import mpv

urls = ["URL1","URL2"]
player = mpv.MPV(ytdl=True, osc=True, input_default_bindings=True, input_vo_keyboard=True,player_operation_mode='pseudo-gui')
for url in urls:
    player.playlist_append(url)
player.playlist_pos = 0
player.wait_for_shutdown()
player.terminate()

The problem I had was I wanted to run it in the background and then append to playlist based on a given input. I guess that's what you are after too. I´m using threading for this task:

from threading import Thread
import mpv
import os

# Mpv debug will output to console
def _logger(loglevel, component, message):
        print('[{}] {}: {}'.format(
            loglevel, component, message), flush=True)

# Initialize player
player = mpv.MPV(log_handler=_logger, ytdl=True, osc=True, input_default_bindings=True, input_vo_keyboard=True, ytdl_format="bestaudio", player_operation_mode='pseudo-gui')

# Define function for threading
def _play():
    print("Initialization")
    player.playlist_append("https://www.youtube.com/watch?v=aam9VvzFuI0")
    player.playlist_pos = 0
    player.wait_for_shutdown()
    player.terminate()

# Start mpv in thread so it´s not blocking our terminal
thread = Thread(target=_play)
thread.start()

# Wait for any input just for demonstration
os.system("pause")

# Finally append another song to currently playing playlist
print("Appending")
player.playlist_append("https://www.youtube.com/watch?v=FkklG9MA0vM")

# Get input while playing
while True:
    input("Input is not blocked > ")

Hope this will help. If you have any other question, feel free to contact me :)

Himan10 commented 3 years ago

Hey man, thanks for the code snippet, Really helped. And sorry for such a late reply, I didn't know about Threading and was away too.

Yeah, so the first code snippet was completely understood but would you like to tell what's the working of player.wait_for_shutdown()? is it kind of a loop that is waiting for signals to exit() and terminate()? Also, I've seen this mpv.MPV creates an N number of threads, means it is already running in a seperate thread. for instance if you would create a class for your player (or whatever you're doing) and inherit the class mpv.MPV then things might be lot easier.

The problem I had was I wanted to run it in the background and then append to playlist based on a given input. I guess that's what you are after too. I´m using threading for this task:

Yes exactly, I wanted the same, and your example explained this well. mine project using mpv is kind of limited like, I only have to create a music terminal for fun and keep adding random things haha. I was planning to create logs (both, to save in a file and pictorial representation. For example : which genre music I listen to most and time spent on this music terminal).

Yeah so, your problem i.e., appending new songs to the same thread but explicitly right? I guess you need to make a use of QUEUE and use the same memory (as we know, all the threads shared same memory) then try creating a list/dictionary that can be used by both (your main thread and your play thread) or might be the class idea would work here. I am still working on this project haha.

Thank you.

Stax124 commented 3 years ago

player.wait_for_shutdown() is blocking current thread until the player receives a close signal - SIGBREAK is the right one I guess. The problem is that sometimes it doesn't want to kill itself, so this will get rid of that problem

For example: which genre music I listen to most and time spent on this music terminal).

I think the part with time spent can be done like this:

Regards, Stax124

Himan10 commented 3 years ago

this value can be later pulled and processed The part of processing the genre will be a lot harder and I don't have any knowledge in this space.

For this part, I've planned something like a graph structure : For instance : suppose if I somehow could retrieve song genre (which is basically when fetching the youtube link of the video) then I can distribute them in their respective genres and each vertex (the main genre) would connect to other vertices (sub-genres) via edge (here, If i use weighter edge then I can put some % of how much I listen to this particular genre) right now, I haven't started working on this feature yet but this is a basic structure and it only follow the songs link given by the user :

              GENRE
            /
         ROCK (40%) -> HARD rock (30%) -> HEAVY METAL 
        / (60%)
    soft rock/acoustic rock
       | (70%)
      Grunge

and for the time stamps, I guess there are two ways to do this :

  1. Save it in a file
  2. Create a graph via matplotlib of those time stamps, and how much I listen to local dir music and external links.

BTW which docs you followed for this mpv library ? Because I want to make a use of such method that will tell me if the song is currently playing via mpv.MPV player or not. if it's then show the prompt related with that song otherwise show the normal prompt. Any guess?