DocMarty84 / koozic

Self-hosted media streaming server
https://koozic.net
Other
90 stars 12 forks source link

[Feature Request]Dynamic Smart Playlists organized by Skip to Play ratio #41

Closed 10bn closed 4 years ago

10bn commented 4 years ago

Hi,

would it be easy to also ad skip counts to the smart playlist features?

It would be wonderful to have smart lists basted on skip to play ratio.

Also if we could custom define, what is a skip and what is a play in seconds, it would be perfect.

DocMarty84 commented 4 years ago

Hello,

I'm not sure I understand a "smart playlist based on skip to play ratio". I would think more about a "I don't like it" button which would skip the track and do not add it again in a smart playlist.

About the duration of a play, I agree, at the moment it's quite basic: if the tracks starts playing, it is considered as played, which might not be what people expect.

10bn commented 4 years ago

Lets say i have 6 root playlists :

Pacing: calm, active, neutral Style: acoustic, electronic, mixed

All my music is sorted into these lists.

Now i do a smart list from calm and acoustic, which is dynamically updating by the skip to play ratio. Means, songs with a ratio of < 1 will be played more often and songs with a ratio of > 1 will be played less depending on the factor. Of course this would need extra rules but as soon as i have the ratio it should't be very difficult.

If we could get this, we had a perfect dynamic playlist, that adjusts to our momentary listening Habits.

sry, the initial post was not very clear. I updated the title.

DocMarty84 commented 4 years ago

Ok, I get it, thanks for the clarification. That would also mean adding the possibility to choose on which field to sort. Indeed, at the moment the order is simply random.

I'll have a look into that.

10bn commented 4 years ago

The general idea it that if one has large playlists that one listens to often, it would be nice to filter out the songs that have already been played or skipped in the recent past. To further refine this, the period for which each song is filtered out can be varied by how much one likes the song. This would mean that one's favourites are being played more often while songs that one likes but doesn't want to hear every day are being played more rarely.

To filter out a song, one needs to know when it was last played or skipped to define something such as "not played in the past two days and not skipped in the past four days"

To define how much a song is liked, two approaches are possible: either manually, by giving each song a star rating or by automatically by operationalizing liking as a quotient of play count over skip count. The latter approach means that no active input of the user is required and that liking can organically vary over a period of time. For this, the skip and play count of a song are required. Ideally, these counts are specific to each playlist, as one might like a song better in one playlist as opposed to another depending on how well the song fits the rest of the playlist. A resulting filter might then be: "for songs with a play/skip ratio > 2: not played in the past four days and not skipped in the past eight days; for songs with a play/skip ratio > 4: not played in the past two days and not skipped in the past four days"

DocMarty84 commented 4 years ago

There are several parts in your request.

  1. Including a skip count is quite easy, it just needs to define what is a skip and what is a play. The ratio between both is trivial to compute. Recording the 'last skip' date is also easy.

  2. Introducing conditions on fields is already possible through the custom playlist feature. As soon as these fields are added, filtering is readily available.

  3. Setting the field(s) to order by is also something very easy to implement. At the moment, the order is random, but that can be changed.

The latter approach means that no active input of the user is required and that liking can organically vary over a period of time. For this, the skip and play count of a song are required.

This starts to be quite cumbersome. You want to either define a playlist which depends on another one, or a playlist which somehow regenerates itself based on the conditions you defined. At the moment, the first one could be possible in KooZic. The second one could also be possible; we could probably define a maximum number of tracks in the playlist, and clean it as long as we go. For example, no more than 200 tracks in the playlist: after 200 tracks, when we add a track we remove the first one. So this way, it's going to adapt dynamically.

Ideally, these counts are specific to each playlist, as one might like a song better in one playlist as opposed to another depending on how well the song fits the rest of the playlist.

This won't be the case in KooZic. The preferences are meant to be user-specific, not playlist-specific.

By the way, I saw you created the same request elsewhere:

Therefore, I'd be curious to know if you are using KooZic somehow? Or is this just a general request?

10bn commented 4 years ago

Dear Marty, thank you for the clarification so far. At the moment I’m going through every sever client based music library, trying to find the right one. To me this feature is a game changer when it comes to listening Musik and exploring new stuff, if you don’t want to rely on the big players. Any how they almost don’t offer any kind of cool smart list functions.

At the moment I’m still using Spotify mostly. But in the long therm I would like use a player with the functions as described. So I posted the idea at all promising projects, hooping developers would pick it up.

DocMarty84 commented 4 years ago

Including a skip count is quite easy, it just needs to define what is a skip and what is a play. The ratio between both is trivial to compute. Recording the 'last skip' date is also easy.

Done in https://github.com/DocMarty84/oomusic/commit/39215785b51c31911c9321d97fd5062c7e7bb5f8

Last Play, Last Skipped, Play Count, Skip Count and Play/Skip ratio are introduced. You can search and order by these fields in a smart playlist.

Setting the field(s) to order by is also something very easy to implement. At the moment, the order is random, but that can be changed.

Done in https://github.com/DocMarty84/oomusic/commit/72b69da4601e495f53c184dd8412a5a376ed73c0

The second one could also be possible; we could probably define a maximum number of tracks in the playlist, and clean it as long as we go. For example, no more than 200 tracks in the playlist: after 200 tracks, when we add a track we remove the first one. So this way, it's going to adapt dynamically.

Done in https://github.com/DocMarty84/oomusic/commit/08a09c0948d0cc648f5c6570e799b7050825b0a4

It still needs some testing, and it will be hopefully released with v3.1.0.

10bn commented 4 years ago

Thank you for picking it up!

Has this alredy been included into the docker container?

Br Max

DocMarty84 commented 4 years ago

Not yet

DocMarty84 commented 4 years ago

Hello,

It's included in the latest beta release: https://github.com/DocMarty84/koozic/releases/tag/v3.1.0-beta.1

10bn commented 4 years ago

Hello Marty,

thank you for your effort! I've just been playing with the current beta, dint't you say it should be possible to do playlists referencing other playlists?

DocMarty84 commented 4 years ago

Hello,

I think you are referring to:

You want to either define a playlist which depends on another one, or a playlist which somehow regenerates itself based on the conditions you defined. At the moment, the first one could be possible in KooZic.

I didn't implement a playlist depending on another one. However, I did implement the maximum number of tracks in a playlist. This way, you can generate an 'infinite' playlist. Moreover, you can specify a custom order for track addition. You can sort by any track field, but I think these are the relevant ones for sorting in such a dynamic playlist:

Field Name Field Label
create_date Create Date
duration Duration
last_play Last Played
last_skip Last Skipped
play_count Play Count
play_skip_ratio Play/Skip Ratio
rating Rating
skip_count Skip Count
star Favorite
track_number Track #

You need to use the Field Name in the 'Custom Order' field:

Screenshot_2020-08-17 RND - Odoo

For example: play_skip_ratio (ascending order) or play_skip_ratio desc (descending order). The documentation will be updated when the 3.1.0 is released. It can already be found at: https://github.com/DocMarty84/web/commit/1c63cd8b866ade0441fbf97dda8bd95191950691#diff-65da39582978dc84ad960cad8b779eabR99

10bn commented 4 years ago

Hello Marty,

this I understood and I managed to create a playlist with the parameters you mentioned. The reason I'm asking is that I want to build smart playlists from a certain set of root playlists (calm, active, neutral, vocal, non vocal, electronic, acoustic) which are defining the pacing and style. Whenever I add a song to my library all I need to do is add it to the right root playlist and it will show up in the smart playlist I use for daily listening.

Br. Max

Am Mo., 17. Aug. 2020 um 22:10 Uhr schrieb DocMarty84 < notifications@github.com>:

Hello,

I think you are referring to:

You want to either define a playlist which depends on another one, or a playlist which somehow regenerates itself based on the conditions you defined. At the moment, the first one could be possible in KooZic.

I didn't implement a playlist depending on another one. However, I did implement the maximum number of tracks in a playlist. This way, you can generate an 'infinite' playlist. Moreover, you can specify a custom order for track addition. You can sort by any track field, but I think these are the relevant ones for sorting in such a dynamic playlist: Field Name Field Label create_date Create Date duration Duration last_play Last Played last_skip Last Skipped play_count Play Count play_skip_ratio Play/Skip Ratio rating Rating skip_count Skip Count star Favorite track_number Track #

You need to use the Field Name in the 'Custom Order' field:

[image: Screenshot_2020-08-17 RND - Odoo] https://user-images.githubusercontent.com/386952/90439639-27963500-e0d6-11ea-9dbe-4e2494453644.png

For example: play_skip_ratio (ascending order) or play_skip_ratio desc (descending order)

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/DocMarty84/koozic/issues/41#issuecomment-675087850, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALA6WVAVUGOGL2M5P3LQMLDSBGFDDANCNFSM4KPCFYZQ .

DocMarty84 commented 4 years ago

Hello,

Thanks for the clarification. I think the same result can be achieved by using custom tags. Instead of defining playlists for a given pace / style, you could define a custom tag and assign it to tracks, albums or artists. Then, you can refer to this tag when creating the playlist domain. Here is an example with tracks: https://drive.google.com/file/d/1qGqfQXhaYDMZ6Q2KZsdJbwW6bPxRpG_W/view?usp=sharing

I did it with the tracks, but it also works if you assign a tag to an album or an artist. The domain would then look like "Album > Custom Tags > Name".

Note that I activated the multi_edit feature to be able to edit multiple tracks at once: https://drive.google.com/file/d/1n9zDnZc3tnLtO5uAcuyIySUSLI7LlgTw/view?usp=sharing

10bn commented 4 years ago

thanks for the reply I'll give it a try!

10bn commented 4 years ago

A resulting filter might then be: "for songs with a play/skip ratio > 2: not played in the past four days and not skipped in the > past eight days; for songs with a play/skip ratio > 4: not played in the past two days and not skipped in the past four days"

I managed to set the tags...

Now I was trying to build a dynamic playlist with the filter described above, but it seems I can't set the "with in days" properly. Is there a way to do this in code?

My first attempt below:

Screenshot 2020-08-26 at 19 18 22
DocMarty84 commented 4 years ago

Hello,

  1. Do you mean the custom tags (a) is either 'calm' or 'acoustic' (one of the two tags) or (b) must contain 'calm' and 'acoustic' (both tags)?
  2. The Play/Skip ratio condition is weird: if it is >= 4.0, it also matches >= 2.0. I think one of your condition should be >= 2.0 and < 4.0.
  3. What about the tracks never played? Or only played once? They will never have a Play/Skip ratio >= 2.0, so they won't be taken into account.
  4. The Last Played / Last Skipped is causing the problem here: it must match the exact value given (01/01/2020 00:00:00), which can't be the case for any of your tracks.

You could try this which seems more logical to me. I hardcoded the dates:

[
    "&",
        ["tag_ids.name","in",["calm", "acoustic"]],

    "|", "|",
        ["play_skip_ratio","<",2],
        "&", "&", "&", ["play_skip_ratio",">=",2], ["play_skip_ratio","<",4], ["last_play","<","2020-08-22 00:00:00"], ["last_skip","<","2020-08-18 00:00:00"],
        "&", "&", ["play_skip_ratio",">=",4], ["last_play","<","2020-08-24 00:00:00"], ["last_skip","<","2020-08-22 00:00:00"]
]

Before building domains too complex, add one condition at a time to see which one works and which one doesn't.

I can't set the "with in days" properly

No indeed, you can't do that... But it's not impossible if you modify a few lines of codes. The modification enables the multi-edit, makes the Custom Domain a simple text field (so you loose the fancy domain builder) and brings a few modifications to the code.

Before going further, please note that you need to understand what you are doing, and it's better to do this on a test installation first. Moreover, helping you becomes difficult since the domain is quite complex and I don't have any access to your installation to check if it could match anything. To apply:

  1. Go to <path_to>/koozic/addons/oomusic
  2. curl "https://gist.githubusercontent.com/DocMarty84/93fb357eb9967264b7171fd42bce62c0/raw/87a04ffc365fcb272d9914d43851a2dd5e806103/dynamic.diff" | patch -p1
  3. Restart the service
  4. Go to Menu > Apps > OOMusic > 3 dots on the top right (Dropdown menu) > Upgrade

It will look like this: Screenshot_2020-08-26 test - Odoo

And you can set the Custom Domain to:

[
    "&",
        ["tag_ids.name","in",["calm", "acoustic"]],

    "|", "|",
        ["play_skip_ratio","<",2],
        "&", "&", "&", ["play_skip_ratio",">=",2], ["play_skip_ratio","<",4], ["last_play","<",fields.Datetime.now() - relativedelta(days=4)], ["last_skip","<",fields.Datetime.now() - relativedelta(days=8)],
        "&", "&", ["play_skip_ratio",">=",4], ["last_play","<",fields.Datetime.now() - relativedelta(days=2)], ["last_skip","<",fields.Datetime.now() - relativedelta(days=4)]
]

You notice: ["last_play","<","2020-08-22 00:00:00"] => ["last_play","<",fields.Datetime.now() - relativedelta(days=4)]. I don't know how familiar you are with programming, but I think Datetime.now() - relativedelta(days=4) is obvious.