RadioFreeMonkey 1.2

Download and get help for different MediaMonkey Addons.

Moderators: Peke, Gurus

RadioFreeMonkey 1.2

Postby Risser » Fri Sep 16, 2005 10:15 am

A minor update to Monkey Radio:
- The 'boost' from being in the library for 30+days no longer can push the weighting over the original rating. This means that stuff that was rated 2 stars won't slowly creep up into 5 star range as time goes by and they aren't getting played.
- No longer use the Left function
- Actually implemented the ReduceIfPlayed flag. If this is false, all items will simply be weighted based on their ratings, no messing around with play-counts and dates.

I can see that, if you have listened to an album 50 times over the last year since you first added it to your library, the weighting for those songs will be zero or less (negative). This means they will never come up. This isn't usually a problem for me, because I have a very large library, and the work computer I usually use it on has a lot of churn, with songs being added and removed almost every day.

If this is causing a problem for you, you will have to either (a) turn off ReduceIfPlayed (set it to false) or (b) remove and re-add your tunes to reset the playcount to 0. Simply moving them to another directory out of MM's view, then back should do it.

I've looked into two-for and three-for artist blocks, but that involves extra spinning through the list of tunes, which is okay, but also a lot of checking to make sure that it's not picking the same song it just picked, and that you actually have a second song by that artist.

If you didn't mind whether the second or third song were weighted, it might be easier... I'll think about it.

Meanwhile, enjoy!
Peter



===

' RadioFreeMonkey
' Version 1.2
' A script to create a "radio station" for you based on your song ratings.

' This script creates a root node in the tree, beneath the library node, called "RadioFreeMonkey".
' Under this node, you have a Radio List node, a Done node and a Weightings node.
' - The Radio List node lists 20 songs, in random order. These are weighted, so songs
' with a higher weighting have a higher chance of getting selected.
' - If you have selected a sorting column, even though the songs are selected randomly, the
' radio list will be sorted based on that column. To return the list to "random" sorting, click
' on any playlist (Now Playing works nicely). When you visit the Radio List node, the songs will
' be unsorted, in true random order.
' - The Done list shows you which songs aren't going to be played. This includes songs that have
' passed their maximum playcount, or anything within MinDaysRepeat.
' - The Weighting node shows all tunes, sorted by their calculated weights. This can help you
' determine what the optimal weighting choices are for you. Plus, it's just nice to see what's
' more likely to be played.

' Songs are weighted as follows:
' Rating * 2 (5 stars = 10, 3.5 stars = 7, 0 stars = 0)
' - Number of Plays (if Reduce if Played is TRUE)
' + Days since added to library / DayFactor (always rounded down)
' However, the weighting can't be more than the original rating (* 2).

' TO DO: At some point, I'd like to make the main 'list' node a PlayList instead of a regular
' list of tracks, but I'm not sure how to do this.
'
' This script can be freely used and modified.
' This is an early release and there may be bugs. If it's causing you problems, simply delete
' it or move it out of the scripts\auto folder.
'
' The script does not modify the database, registry or INI file.

'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Global Variables and Declarations
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Option Explicit

' %%% The caption for the root node.
Const RootNodeCaption = "RadioFreeMonkey"

' %%% Add 1 to weighting for each X days since added to library
Const DayFactor = 30

' %%% Anything rated this or below will not receive the 'date boost'
Const DateBoostCutoff = 1.5

' %%% The minimum number of days that must pass before a song is repeated. Zero means, go ahead
' and repeat it right away.
Const MinDaysRepeat = 1

' %%% Reduce the weighting by the number of times played. This means, as songs are played more often,
' they are less likely to be played again
Const ReduceIfPlayed = True

' %%% Number of Songs in list
Const NumberOfSongs = 20




'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' The Meat. Don't change anything under here.
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

' the text of the formulas to be used throughout
Dim weightedRatingFormula, dateBoostFormula, ratingFormula, weightedPlayCountFormula
dateBoostFormula = "IIF(Songs.rating <= "&(DateBoostCutoff*20)&", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / "&DayFactor&"))"
ratingFormula = "(IIF(Songs.rating < 0, 0, Songs.rating) / 10)"

If ReduceIfPlayed Then
weightedPlayCountFormula = "(Songs.PlayCounter - " & dateBoostFormula & ")"
Else
weightedPlayCountFormula = "0"
End If

weightedRatingFormula = ratingFormula & " - IIF(" & weightedPlayCountFormula & "<0,0," & weightedPlayCountFormula & ")"


Sub FillStandardProperties(parentNode, childNode)
With childNode
.CustomNodeId = parentNode.CustomNodeId
.CustomDataId = parentNode.CustomDataId + 1
.UseScript = Script.ScriptPath
End With
End Sub


Sub FillGoodLeaf(Node)
Randomize

Dim SplitCustomData, Tracks
Dim SQLCondition, SQLStatement
Dim SELECT_Clause, FROM_Clause, WHERE_Clause, ORDER_Clause
Dim Iter, res, i, total, sum, index, weight
Dim hold, weights
Set hold = CreateObject("Scripting.Dictionary")
Set weights = CreateObject("Scripting.Dictionary")

SELECT_Clause = " SELECT Songs.Id, "&weightedRatingFormula&" "
FROM_Clause = " FROM Songs "
' WHERE_Clause = " WHERE Songs.PlayCounter < "&weightedRatingFormula&" "
WHERE_Clause = " WHERE " & weightedPlayCountFormula &" < " & ratingFormula & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat
SQLStatement = SELECT_Clause & FROM_Clause & WHERE_Clause
Set Iter = SDB.Database.OpenSQL(SQLStatement)

total=0
sum = 0
While Not Iter.EOF
hold.add total,Iter.StringByIndex(0)
weights.add total,Iter.StringByIndex(1)
total = total + 1
sum = sum + Iter.StringByIndex(1)
Iter.Next
Wend

Dim R, max : max = NumberOfSongs
If (total < max) Then
max = total
End If

Dim inStr : inStr = ""
Set Tracks = SDB.MainTracksWindow
While i < max
' R = Round((rnd() * (total+1))-0.5, 0)
R = rnd() * sum
For index = 0 to total
If R < cdbl(weights.item(index)) Then
Exit For
Else
R = R - cdbl(weights.item(index))
End If
Next 'index
If i = 0 Then
inStr = index
Else
inStr = inStr & ", " & hold.item(index)
End If
i = i + 1
Wend
'res = SDB.MessageBox(inStr, mtError, Array(mbOk))

Tracks.AddTracksFromQuery("AND Songs.ID IN (" & inStr & ") ORDER BY Rnd((1000*Songs.ID)*Now())")
Tracks.FinishAdding
' function WeightedRandom(const Weights : array of Double) : Integer ;
' var R : Double ;
' begin
' R := Random * Sum(Weights) ;
' for Result := 0 to High(Weights) do
' if (R < Weights[Result]) then BREAK
' else R := R - Weights[Result] ;
' end ;

End Sub

Sub FillWeightNode(Node)
Dim SplitCustomData ' Auxiliary Array used to collect the pieces of Node.CustomData
Dim SQLLinking ' Piece of SQL Code (WHERE statement) defining the relations between tables
Dim SQLTables ' Part of FROM clause indicating which tables to query
Dim SQLCondition ' String containing the part of the WHERE statement coming from the ancestor nodes
Dim fullMask, curLevelMask
Dim Tree, newNode, nextIsLeaf
Dim FldTxt ' Text identifying the field by which the created nodes will be filtered
Dim Field, IdField, OrderField ' Fields to be queried
' Variables that store qualifier values and related expressions
Dim TopQualifier, TopClause, SortCondition, minTracks, maxTracks, trimValue, doFormatting
Dim ContentIndex ' An index to the field to be displayed
Dim SELECT_Clause, FROM_Clause, WHERE_Clause, GROUP_BY_Clause, ORDER_BY_Clause, HAVING_Clause
Dim SQLStatement ' SQL query to the database
Dim CaptionPrefix ' Used to modify the caption when a sorting has been specified
Dim EscapedId ' Used to escape a text value in the database to be used as a test
Dim idArgument ' The first argument submitted to the Format function
Dim Iter ' SDBD Iterator obtained by running the SQL query to get the nodes


Set Tree = SDB.MainTree
Node.HasChildren = false ' To delete all old children

SQLStatement = "SELECT DISTINCT " & weightedRatingFormula & " from Songs "

Set Iter = SDB.Database.OpenSQL(SQLStatement)

While Not Iter.EOF

Set newNode = Tree.CreateNode

NewNode.Caption = Iter.StringByIndex(0)
NewNode.iconIndex = 32
newNode.CustomData = Iter.StringByIndex(0)

FillStandardProperties node,newNode
newNode.onFillTracksFunct = "FillWeightLeaf"
newNode.hasChildren = False
Tree.AddNode Node, NewNode, 3

Iter.Next
Wend

End Sub


Sub FillWeightLeaf(Node)
Dim Weight
Dim Tracks
Dim SELECT_Clause, FROM_Clause, WHERE_Clause

Weight = Node.CustomData

SELECT_Clause = " SELECT Songs.Id "
FROM_Clause = " FROM Songs "
WHERE_Clause = " WHERE " & weightedRatingFormula & " = " & Weight & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat

Set Tracks = SDB.MainTracksWindow

Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
Tracks.FinishAdding

End Sub


Sub FillDoneLeaf(Node)
Dim Tracks
Dim SELECT_Clause, FROM_Clause, WHERE_Clause


SELECT_Clause = " SELECT Songs.Id "
FROM_Clause = " FROM Songs "
WHERE_Clause = " WHERE "& weightedPlayCountFormula &" >= " & ratingFormula & " OR DateDiff('d',Songs.LastTimePlayed, Now) <= " & MinDaysRepeat

Set Tracks = SDB.MainTracksWindow

Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
Tracks.FinishAdding

End Sub



'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Startup Function
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Sub onStartUp
Dim Tree, RadioFreeMonkeyRoot
Dim RadioMonkeyGood, RadioMonkeyBad, RadioMonkeyWeight

Set Tree = Sdb.MainTree
Set RadioFreeMonkeyRoot = Tree.createNode

RadioFreeMonkeyRoot.Caption = RootNodeCaption
RadioFreeMonkeyRoot.IconIndex = 14
RadioFreeMonkeyRoot.UseScript = Script.ScriptPath
RadioFreeMonkeyRoot.hasChildren = True
Tree.AddNode Tree.Node_Library, RadioFreeMonkeyRoot, 1
SDB.Objects("RadioFreeMonkeyRoot") = RadioFreeMonkeyRoot

Set RadioMonkeyGood = Tree.createNode
RadioMonkeyGood.Caption = "Radio List"
RadioMonkeyGood.IconIndex = 14
RadioMonkeyGood.UseScript = Script.ScriptPath
RadioMonkeyGood.hasChildren = False
RadioMonkeyGood.onFillTracksFunct = "FillGoodLeaf"
Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyGood, 2
SDB.Objects("RadioMonkeyGood") = RadioMonkeyGood

Set RadioMonkeyWeight = Tree.createNode
RadioMonkeyWeight.Caption = "Weightings"
RadioMonkeyWeight.IconIndex = 32
RadioMonkeyWeight.UseScript = Script.ScriptPath
RadioMonkeyWeight.hasChildren = True
RadioMonkeyWeight.onFillTracksFunct = "FillWeightNode"
Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyWeight, 3
SDB.Objects("RadioMonkeyWeight") = RadioMonkeyWeight

Set RadioMonkeyBad = Tree.createNode
RadioMonkeyBad.Caption = "Done"
RadioMonkeyBad.IconIndex = 15
RadioMonkeyBad.UseScript = Script.ScriptPath
RadioMonkeyBad.hasChildren = False
RadioMonkeyBad.onFillTracksFunct = "FillDoneLeaf"
Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyBad, 3
SDB.Objects("RadioMonkeyBad") = RadioMonkeyBad
End Sub
Risser
 
Posts: 183
Joined: Thu Mar 03, 2005 11:28 am

Postby rovingcowboy » Tue Sep 27, 2005 4:15 pm

wow this is a lot to take in?

how do you put this in monkey?

right now i am using the windows scheduler script from peke and the auto play count to keep the jingles out of the top 50 list.

but i have notice that the rateing for songs was preventing some from being played at all.

so i made them all 5 stars for the whole librairy

would this script change them back to ratings on how many times they were played?

it does seem like a good idea but i also have a huge librairy but i don't remove songs i keep adding :D i have not heard some in weeks.
but i then also only use the shuffle button on the monkeys player.
it is better then winamp's shuffle. and using the widows scheduler script it only works when using the monkey player not winamp.

so is this script for radio monkey going to do me any good or will it just be causing me to do the same thing i already am doing?

:-?
roving cowboy / keith hall. My skins viewtopic.php?f=9&t=16724 for some help check on Monkey's helpful messages at viewtopic.php?p=44008#44008 MY SYSTEMS.1.Xp pro sp3, vers 3.2 jukebox, pcchips mb. amd sem... built by me) 2.WinXP pro sp3, vers 2.5.5 and vers 3.2 backup storage, shuttle 32a mb,734 MHz amd athlon put together by me.) 3.WinXp pro sp 3 version 2.5 and version 3.2 work gigabyte mb. 281 GHz amd athlon x2 240 built by me.) 4.Dell demension, winxp pro sp3, mm3.5 spare jukebox. 5.WinXp pro sp3, vers 2.5.5, moms computer. Sony vaio.)6. Motorola Photon. Android 4.1.2
rovingcowboy
 
Posts: 13740
Joined: Sat Oct 25, 2003 7:57 am
Location: (Texas)

Postby psyXonova » Wed Sep 28, 2005 4:09 am

Why don't you give it a try and see if it does your job. After all this script doesnt modify database or files in any way so you are safe.
Don't forget you are the only one that knows what exactly wants to do, and so you are the only one that can answer your question...
psyXonova
 
Posts: 785
Joined: Fri May 20, 2005 3:57 am
Location: Nicosia, Cyprus

Postby rovingcowboy » Wed Sep 28, 2005 3:01 pm

psyxonova wrote:Why don't you give it a try and see if it does your job. After all this script doesnt modify database or files in any way so you are safe.
Don't forget you are the only one that knows what exactly wants to do, and so you are the only one that can answer your question...



:lol: :o

so in other words you don't know either :P
roving cowboy / keith hall. My skins viewtopic.php?f=9&t=16724 for some help check on Monkey's helpful messages at viewtopic.php?p=44008#44008 MY SYSTEMS.1.Xp pro sp3, vers 3.2 jukebox, pcchips mb. amd sem... built by me) 2.WinXP pro sp3, vers 2.5.5 and vers 3.2 backup storage, shuttle 32a mb,734 MHz amd athlon put together by me.) 3.WinXp pro sp 3 version 2.5 and version 3.2 work gigabyte mb. 281 GHz amd athlon x2 240 built by me.) 4.Dell demension, winxp pro sp3, mm3.5 spare jukebox. 5.WinXp pro sp3, vers 2.5.5, moms computer. Sony vaio.)6. Motorola Photon. Android 4.1.2
rovingcowboy
 
Posts: 13740
Joined: Sat Oct 25, 2003 7:57 am
Location: (Texas)

Postby psyXonova » Thu Sep 29, 2005 2:15 am

I am a user of RadioFreeMOnkey for quite a long time. I know what it does but i'm not sure what you want, that's why i say give it a try
:lol: :P
psyXonova
 
Posts: 785
Joined: Fri May 20, 2005 3:57 am
Location: Nicosia, Cyprus

Postby charlieMOGUL » Thu Sep 29, 2005 6:04 pm

Risser,

Thanks for the update on the RadioFreeMonkey script. I use it all the time and enjoy your programming.
A feature request for version 1.3: could you implement a 'factor' that adds random songs to the playlist as well ?
eg: unrateFactor = 5, then 5% of the songs of the RadioFreeMonkey playlist are truly random (regardless to their rating or number of times played).
The reason I ask for this is that usually not all tracks are rated. You rate songs when you hear them. But when you don't hear the tracks, you won't rate them. Hence...

Once again thanks for your script: let the monkey play FREE!

charlieMOGUL
charlieMOGUL
 
Posts: 168
Joined: Fri Mar 11, 2005 5:26 am

RadioFreeMonkey v1.5

Postby popper » Mon Apr 03, 2006 4:19 pm

I've been using this script for quite some time now. When Auto-DJ became available, I switched over to that, only to find that that it could not do the same for me as RadioFreeMonkey did! So thank you for that great script, Risser.

Still, there were some things I was missing here. Over the time, I've made some modifications and added some features to it. These are:

- added possibility to boost songs that have been added to the DB recently (like a radio station would play new songs more often)
- added possibility to define the genres that should be played (so that classic and pop won't be mixed)
- redesign of the mechanism that selects the actual songs to be played (because I did not really understand what was going on in the existing algorithm :lol:)
- now it is possible to influence more easily what songs you will hear (e.g. 30% of songs with a weighting of 8-10 and 70% with a weighting of 5-7).

You will probably have to do some tweaking of the parameters, the ones below are giving me sensible results.

My programming skills are not very good and I don't really know VBScript, but by looking closely at the code and a lot of debugging I found out what was going on and was able to make the modifications I wanted. I learned a lot from this already, but would be glad if one of you Real Programmers(tm) out there could do some kind of code review for me to point out what could be done better.

For installation, just copy the code below into a text file, name it RadioFreeMonkey.vbs and put it in your [...]\MediaMonkey\Scripts\Auto directory. Make your modifications to the parameters at the top of the script. They all have comments so it should be easy to work out what their intention is.
Then save the script and restart MediaMonkey.

I hope you like it.
Thanks again to Risser for the original version.

popper.


Code: Select all

' RadioFreeMonkey
' Version 1.5
' A script to create a "radio station" for you based on your song ratings.

' #####################
' Version 1.2 by Risser

' This script creates a root node in the tree, beneath the library node, called "RadioFreeMonkey".
' Under this node, you have a Radio List node, a Done node and a Weightings node.
' - The Radio List node lists 20 songs, in random order. These are weighted, so songs
' with a higher weighting have a higher chance of getting selected.
' - If you have selected a sorting column, even though the songs are selected randomly, the
' radio list will be sorted based on that column. To return the list to "random" sorting, click
' on any playlist (Now Playing works nicely). When you visit the Radio List node, the songs will
' be unsorted, in true random order.
' - The Done list shows you which songs aren't going to be played. This includes songs that have
' passed their maximum playcount, or anything within MinDaysRepeat.
' - The Weighting node shows all tunes, sorted by their calculated weights. This can help you
' determine what the optimal weighting choices are for you. Plus, it's just nice to see what's
' more likely to be played.

' Songs are weighted as follows:
' Rating * 2 (5 stars = 10, 3.5 stars = 7, 0 stars = 0)
' - Number of Plays (if Reduce if Played is TRUE)
' + Days since added to library / DayFactor (always rounded down)
' However, the weighting can't be more than the original rating (* 2).

' TO DO: At some point, I'd like to make the main 'list' node a PlayList instead of a regular
' list of tracks, but I'm not sure how to do this.
'
' This script can be freely used and modified.
' This is an early release and there may be bugs. If it's causing you problems, simply delete
' it or move it out of the scripts\auto folder.
'
' The script does not modify the database, registry or INI file.

' #####################
' Version 1.5 by popper

' - added possibility to boost songs that have been added to the DB recently
' - added possibility to define the genres that should be played
' - redesign of the mechanism that selects the actual songs to be played (because I did not
'   really understand what was going on in the existing algorithm ;-), with the goal of making
'   it easier to influence what will be played (e.g. 30% of songs with a weighting of 8-10 and
'   70% with a weighting of 5-7))
'
' Disclaimer:
' Use at your own risk. Back up your data before using.
' Changing some of the values might lead to endless loops that can only be solved by
' killing the MediaMonkey process, so take care when modifying anything!

'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Global Variables and Declarations
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Option Explicit

' %%% The caption for the root node.
Const RootNodeCaption = "RadioFreeMonkey 1.5"

' %%% Add 1 to weighting for each X days since added to library
Const DayFactor = 150

' %%% Anything rated this or below will not receive the 'date boost'
Const DateBoostCutoff = 1.5

' %%% The minimum number of days that must pass before a song is repeated. Zero means, go ahead
' and repeat it right away.
Const MinDaysRepeat = 5

' %%% Reduce the weighting by the number of times played. This means, as songs are played more often,
' they are less likely to be played again
Const ReduceIfPlayed = True

' %%% Boost Songs that have been added during the last n days (MinDaysRepeat does still apply for these)
Const BoostNewSongsDays = 75

' %%% The boost modifier for new songs (Zero means, don't boost):
' Add x to the weighting of these songs
Const BoostNewSongsModifier = 3

' %%% Anything rated this or below will not receive the 'new song boost'
Const BoostNewSongsCutoff = 2.0

' %%% Genres that should be played. Leave empty (Const PlayGenres = "") to ignore.
' "-1, 13, 17, 20, 24" means "empty genre field, Pop, Rock, Alternative, Soundtrack"
' Look up the other genre Ids in the database by using MS Access
Const PlayGenres = "-1, 13, 17, 20, 24"

' %%% Number of Songs in list
Const NumberOfSongs = 20


' %%% Influence which songs will be played. You have three sets that you can use
' Example:
' Const Set1Weight = 8.5    ' Basic weight for this set is 8.5
' Const Set1Boundary = 1.5  ' with a variation of 1.5, which means that songs between 7 and 10 will be chosen
' Const Set1Percentage = 60 ' this is how big the part of this set should be in the overall contents

Const Set1Weight = 8.5
Const Set1Boundary = 1.5
Const Set1Percentage = 60    ' make sure all 3 percentages sum up to 100!

Const Set2Weight = 6.0
Const Set2Boundary = 1
Const Set2Percentage = 40    ' make sure all 3 percentages sum up to 100!

Const Set3Weight = 2.0      ' Right now, it is not possible to choose songs with a weight < 1, so unfortunately you cannot add unrated songs
Const Set3Boundary = 1
'Const Set3Percentage = 20  ' This is not needed because it just takes what is missing to 100%


'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' The Meat. Don't change anything under here.
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

' the text of the formulas to be used throughout
Dim weightedRatingFormula, dateBoostFormula, ratingFormula, weightedPlayCountFormula, boostNewSongsFormula
If BoostNewSongsModifier <> 0 Then
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & " OR FIX(DateDiff('d',Songs.DateAdded,Now) <= " & BoostNewSongsDays & "), 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
Else
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & ", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
End If

ratingFormula = "(IIF(Songs.rating < 0, 0, Songs.rating) / 10)"

If ReduceIfPlayed Then
   weightedPlayCountFormula = "(Songs.PlayCounter - " & dateBoostFormula & ")"
Else
   weightedPlayCountFormula = "0"
End If

If BoostNewSongsModifier <> 0 Then
   boostNewSongsFormula = "IIF(Songs.rating <= " & (BoostNewSongsCutoff*20) & ", 0, (IIF(FIX(DateDiff('d',Songs.DateAdded,Now) > " & BoostNewSongsDays & "), 0, " & BoostNewSongsModifier & ")))"
End If

weightedRatingFormula = ratingFormula & " - IIF(" & weightedPlayCountFormula & " < 0, 0, " & weightedPlayCountFormula & ") + " & boostNewSongsFormula


Sub FillStandardProperties(parentNode, childNode)
   With childNode
      .CustomNodeId = parentNode.CustomNodeId
      .CustomDataId = parentNode.CustomDataId + 1
      .UseScript = Script.ScriptPath
   End With
End Sub


Sub FillGoodLeaf(Node)
   Randomize

   Dim Tracks
   Dim SQLStatement
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause, ORDER_Clause
   Dim Iter, res, i, total, sum, index
   Dim weight, minweight, maxweight
   Dim hold, weights, average, start, baseweight, boundary
   Dim R, max : max = NumberOfSongs
   Dim inStr : inStr = ""

   Set hold = CreateObject("Scripting.Dictionary") ' define an associative array or "hash array" to hold the songs
   Set weights = CreateObject("Scripting.Dictionary") ' define an associative array or "hash array" to hold the weightings

   
   SELECT_Clause = " SELECT Songs.Id, " & weightedRatingFormula & " "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE " & weightedPlayCountFormula &" < " & ratingFormula & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " AND Songs.Genre IN (" & PlayGenres & ")"
   End If
   ORDER_Clause = " ORDER BY Rnd((1000*Songs.ID)*Now())" ' This is important because otherwise they will all come as they are stored in the DB
   
   SQLStatement = SELECT_Clause & FROM_Clause & WHERE_Clause & ORDER_Clause
   'res = InputBox("SQL Statement: ", "debugging", SQLStatement) ' For debugging
   
   Set Iter = SDB.Database.OpenSQL(SQLStatement) ' holds all songs that are collected by the SQL formula

   total=0 ' initialise total amount of songs that can be used for the playlist (=all songs with weights from 1 to 10 minus "done" songs)
   sum = 0 ' initialise sum of all weightings
   maxweight = 0 ' initialise maximum weight in this iteration
   minweight = 9 ' initialise minimum weight in this iteration
   
   While (Not Iter.EOF)
      hold.add total,Iter.StringByIndex(0)
      weight = Iter.StringByIndex(1)
      weights.add total,weight
      total = total + 1
      sum = sum + weight
      If minweight > cdbl(weight) then
         minweight = cdbl(weight)
      End if
      if maxweight < cdbl(weight) then
         maxweight = cdbl(weight)
      End if

        Iter.Next
   Wend

   ' some overflow checks
   if total <= 0 or sum <= 0 then
      SDB.MessageBox "Something is wrong with your ratings. Do you have any rated songs at all?", mtInformation, Array(mbOk)
      Exit Sub
   end if
   If Set1Weight < minweight or Set2Weight < minweight or Set3Weight < minweight or Set1Weight > maxweight or Set2Weight > maxweight or Set3Weight > maxweight then
      SDB.MessageBox "Something is wrong with your SetXWeight constants. They are either too high or too low.", mtInformation, Array(mbOk)
      Exit Sub
   end if
   
   If (total < max) Then
        max = total
   End If
     
   Set Tracks = SDB.MainTracksWindow
   start = 0
   
   While i < max ' do this until the max number of songs for the playlist is reached
   
      If i < max * Set1Percentage / 100 then ' put in Set1Percentage percent of higher-rated songs
         baseweight = Set1Weight
         boundary = Set1Boundary
      elseif i < max * (Set1Percentage + Set2Percentage) / 100 then ' put in Set2Percentage percent of lower-rated songs
         baseweight = Set2Weight
         boundary = Set2Boundary
      elseif i <= max then ' and also put in some really lowly-rated songs
         baseweight = Set3Weight
         boundary = Set3Boundary
      end if
            
      For index = start to total ' go through all of the songs that could potentially become part of the radio node, starting where we left off last time
         weight = cdbl(weights.item(index)) ' weight of the song that is being looked at right now
            
         if weight >= (baseweight - boundary) and weight <= (baseweight + boundary) then
            ' This song is inside the weighting borders that are defined above
            ' so let's see if it is also lucky
            R = rnd(1) ' this song's lucky number
            if R > 0.8 then
               ' so let's leave this for-next loop and add it to the list!
               Exit For
            end if
         end if
      Next   
      
      start = index + 1 ' We don't want to go through the same songs again, so next time we start from here
      if start > total then
         if inStr = "" then
            SDB.MessageBox "There does not seem to be enough stuff to work on. Try to use criteria that are easier to meet.", mtInformation, Array(mbOk)
            Exit Sub
         else
            start = 0 ' start over again
         end if
      else
         ' We've got a winner! The song with the hash index "index" will now be added to the radio node
         ' This is done by collecting all songs in inStr, separating them by commas, and afterwards collecting their song.ids via SQL        
           If i = 0 Then
             inStr = index
           Else
             inStr = inStr & ", " & hold.item(index)
           End If
           i = i + 1
      end if   

   Wend

   If inStr <> "" then
      Tracks.AddTracksFromQuery("AND Songs.ID IN (" & inStr & ") ORDER BY Rnd((1000*Songs.ID)*Now())")
      Tracks.FinishAdding
   End If
      
End Sub





Sub FillWeightNode(Node)

   Dim Tree, newNode
   Dim SQLStatement ' SQL query to the database
   Dim Iter ' SDBD Iterator obtained by running the SQL query to get the nodes

   Set Tree = SDB.MainTree
   Node.HasChildren = false ' To delete all old children

   SQLStatement = "SELECT DISTINCT " & weightedRatingFormula & " from Songs "
   'res = InputBox("SQL Statement: ", SQLStatement, SQLStatement) ' For debugging
   Set Iter = SDB.Database.OpenSQL(SQLStatement)

   While Not Iter.EOF

      Set newNode = Tree.CreateNode

      NewNode.Caption = Iter.StringByIndex(0)
      NewNode.iconIndex = 32
      newNode.CustomData = Iter.StringByIndex(0)

      FillStandardProperties node,newNode
      newNode.onFillTracksFunct = "FillWeightLeaf"
      newNode.hasChildren = False
      Tree.AddNode Node, NewNode, 3

      Iter.Next
   Wend

End Sub


Sub FillWeightLeaf(Node)
   Dim Weight
   Dim Tracks
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause

   Weight = Node.CustomData

   SELECT_Clause = " SELECT Songs.Id "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE " & weightedRatingFormula & " = " & Weight & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " AND Songs.Genre IN (" & PlayGenres & ")"
   End If
   'res = InputBox("SQL Statement: ", "Debugging", SELECT_Clause & FROM_Clause & WHERE_Clause) ' For debugging
   
   Set Tracks = SDB.MainTracksWindow

   Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
   Tracks.FinishAdding

End Sub


Sub FillDoneLeaf(Node)
   Dim Tracks
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause


   SELECT_Clause = " SELECT Songs.Id "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE "& weightedPlayCountFormula &" >= " & ratingFormula & " OR DateDiff('d',Songs.LastTimePlayed, Now) <= " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " OR Songs.Genre NOT IN (" & PlayGenres & ")"
   End If

   Set Tracks = SDB.MainTracksWindow

   Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
   Tracks.FinishAdding

End Sub



'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Startup Function
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Sub onStartUp
   Dim Tree, RadioFreeMonkeyRoot
   Dim RadioMonkeyGood, RadioMonkeyBad, RadioMonkeyWeight

   Set Tree = Sdb.MainTree
   Set RadioFreeMonkeyRoot = Tree.createNode

   RadioFreeMonkeyRoot.Caption = RootNodeCaption
   RadioFreeMonkeyRoot.IconIndex = 14
   RadioFreeMonkeyRoot.UseScript = Script.ScriptPath
   RadioFreeMonkeyRoot.hasChildren = True
   Tree.AddNode Tree.Node_Library, RadioFreeMonkeyRoot, 1
   SDB.Objects("RadioFreeMonkeyRoot") = RadioFreeMonkeyRoot

   Set RadioMonkeyGood = Tree.createNode
   RadioMonkeyGood.Caption = "Radio List"
   RadioMonkeyGood.IconIndex = 14
   RadioMonkeyGood.UseScript = Script.ScriptPath
   RadioMonkeyGood.hasChildren = False
   RadioMonkeyGood.onFillTracksFunct = "FillGoodLeaf"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyGood, 2
   SDB.Objects("RadioMonkeyGood") = RadioMonkeyGood

   Set RadioMonkeyWeight = Tree.createNode
   RadioMonkeyWeight.Caption = "Weightings"
   RadioMonkeyWeight.IconIndex = 32
   RadioMonkeyWeight.UseScript = Script.ScriptPath
   RadioMonkeyWeight.hasChildren = True
   RadioMonkeyWeight.onFillTracksFunct = "FillWeightNode"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyWeight, 3
   SDB.Objects("RadioMonkeyWeight") = RadioMonkeyWeight

   Set RadioMonkeyBad = Tree.createNode
   RadioMonkeyBad.Caption = "Done"
   RadioMonkeyBad.IconIndex = 15
   RadioMonkeyBad.UseScript = Script.ScriptPath
   RadioMonkeyBad.hasChildren = False
   RadioMonkeyBad.onFillTracksFunct = "FillDoneLeaf"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyBad, 3
   SDB.Objects("RadioMonkeyBad") = RadioMonkeyBad
End Sub
popper
 
Posts: 34
Joined: Mon Feb 21, 2005 5:10 pm
Location: Germany

Postby DuQ3r » Thu May 04, 2006 4:01 pm

When I press Radio Playlist It says "Something is wrong! Do you have any rated songs?"

But I do have reted songs? What does it mean then?
Am I doing something wrong?
DuQ3r
 

Postby popper » Sun May 07, 2006 3:06 am

Hmm. Several possibilities come to mind:

- Perhaps you have to play around with the settings at the beginning of the script ("Global Variables and Declarations"), especially the part where the Set1Weight etc. are set. This has to match the ratings that you have given your songs.
- How many songs do you have in your library?
- What happens when you open the node "Weightings" oder "done"?
- Perhaps you use different genres than I did? Then you should in a first step disable the genres by setting the following: Const PlayGenres = ""

Good luck & Let me know how it goes!
popper
popper
 
Posts: 34
Joined: Mon Feb 21, 2005 5:10 pm
Location: Germany

Postby fastspinecho » Sun Aug 20, 2006 1:22 pm

Thanks for the excellent script, risser & popper!

I'm using popper's version, but I think I've come across a small bug: BoostNewSongsCutoff is defined but never actually used. I'm no programmer, but I'll bet that

Code: Select all
If BoostNewSongsModifier <> 0 Then
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & " OR FIX(DateDiff('d',Songs.DateAdded,Now) <= " & BoostNewSongsDays & "), 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
Else
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & ", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
End If


should actually read

Code: Select all
If BoostNewSongsModifier <> 0 Then
   dateBoostFormula = "IIF(Songs.rating <= " & (BoostNewSongsCutoff *20) & " OR FIX(DateDiff('d',Songs.DateAdded,Now) <= " & BoostNewSongsDays & "), 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
Else
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & ", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
End If
fastspinecho
 

Postby fastspinecho » Sun Aug 20, 2006 1:26 pm

Oh, snap. NVM.
fastspinecho
 

Postby Tylast » Sat Oct 07, 2006 10:43 am

Feature Request:

How about creates nodes in the browser tree based on the genres & other options popper introduced that we pick? I imagine only needing to make 3 of these nodes.

Also, how about an easier way to pick the genres to be used?
Image
Tylast
 
Posts: 129
Joined: Sun Jan 29, 2006 12:54 pm
Location: US

Some Fixes

Postby ElGringo » Thu Oct 26, 2006 9:11 pm

Hi !

This script is exactly what i was looking for... Thank you very much.

I picked the last script from popper, and saw a couple of errors that i corrected.

1. There was always a song that had nothing to do in my playlists, investigated and saw the error in FillGoodLeaf :

Code: Select all
' We've got a winner! The song with the hash index "index" will now be added to the radio node
         ' This is done by collecting all songs in inStr, separating them by commas, and afterwards collecting their song.ids via SQL         
           If i = 0 Then
             inStr = index
           Else
             inStr = inStr & ", " & hold.item(index)
           End If
           i = i + 1


If i=0, then It should be hold.item(index), instead of index, so the first song that was added was not good, we were taking the index, instead of the real song.id

2. There is an error in the calculation of the dateboost formula, the dateboostcutoff*20 should be dateboostcutoff*10. There were a couple of places wrong

Code: Select all
If BoostNewSongsModifier <> 0 Then
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & " OR FIX(DateDiff('d',Songs.DateAdded,Now) <= " & BoostNewSongsDays & "), 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
Else
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*20) & ", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
End If


3. By adding, the BoostNewSongsModifier, the actual weight calculated, could go higher than 10, but the algorithm was never picking songs with a weight higher than 10. So, i fixed a couple of places in the script, so that calculated weight higher than 10, are now fixed at 10.

4. There was a bug, when the BoostNewSongsModifier is set to 0... fixed it.


I paste here the complete fixed script :

Code: Select all
' RadioFreeMonkey
' Version 1.6
' A script to create a "radio station" for you based on your song ratings.

' #####################
' Version 1.2 by Risser

' This script creates a root node in the tree, beneath the library node, called "RadioFreeMonkey".
' Under this node, you have a Radio List node, a Done node and a Weightings node.
' - The Radio List node lists 20 songs, in random order. These are weighted, so songs
' with a higher weighting have a higher chance of getting selected.
' - If you have selected a sorting column, even though the songs are selected randomly, the
' radio list will be sorted based on that column. To return the list to "random" sorting, click
' on any playlist (Now Playing works nicely). When you visit the Radio List node, the songs will
' be unsorted, in true random order.
' - The Done list shows you which songs aren't going to be played. This includes songs that have
' passed their maximum playcount, or anything within MinDaysRepeat.
' - The Weighting node shows all tunes, sorted by their calculated weights. This can help you
' determine what the optimal weighting choices are for you. Plus, it's just nice to see what's
' more likely to be played.

' Songs are weighted as follows:
' Rating * 2 (5 stars = 10, 3.5 stars = 7, 0 stars = 0)
' - Number of Plays (if Reduce if Played is TRUE)
' + Days since added to library / DayFactor (always rounded down)
' However, the weighting can't be more than the original rating (* 2).

' TO DO: At some point, I'd like to make the main 'list' node a PlayList instead of a regular
' list of tracks, but I'm not sure how to do this.
'
' This script can be freely used and modified.
' This is an early release and there may be bugs. If it's causing you problems, simply delete
' it or move it out of the scripts\auto folder.
'
' The script does not modify the database, registry or INI file.

' #####################
' Version 1.5 by popper

' - added possibility to boost songs that have been added to the DB recently
' - added possibility to define the genres that should be played
' - redesign of the mechanism that selects the actual songs to be played (because I did not
'   really understand what was going on in the existing algorithm ;-), with the goal of making
'   it easier to influence what will be played (e.g. 30% of songs with a weighting of 8-10 and
'   70% with a weighting of 5-7))
' #####################
' Version 1.6 by ElGringo

' - Fixes to the algorithm
'   - 1. There was always a song that had nothing to do in my playlists, investigated
'        and saw the error in FillGoodLeaf
'   - 2. There is an error in the calculation of the dateboost formula, the
'        dateboostcutoff*20 should be dateboostcutoff*10. There were a couple of places wrong
'   - 3. By adding, the BoostNewSongsModifier, the actual weight calculated, could go higher
'        than 10, but the algorithm was never picking songs with a weight higher than 10. So,
'        i fixed a couple of places in the script, so that calculated weight higher than 10,
'        are now fixed at 10.
'   - 4.There was a bug, when the BoostNewSongsModifier is set to 0... fixed it.
'
'
' Disclaimer:
' Use at your own risk. Back up your data before using.
' Changing some of the values might lead to endless loops that can only be solved by
' killing the MediaMonkey process, so take care when modifying anything!

'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Global Variables and Declarations
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Option Explicit

' %%% The caption for the root node.
Const RootNodeCaption = "Radio Rock2"

' %%% Add 1 to weighting for each X days since added to library
Const DayFactor = 150

' %%% Anything rated this or below will not receive the 'date boost'
Const DateBoostCutoff = 1.5

' %%% The minimum number of days that must pass before a song is repeated. Zero means, go ahead
' and repeat it right away.
Const MinDaysRepeat = 5

' %%% Reduce the weighting by the number of times played. This means, as songs are played more often,
' they are less likely to be played again
Const ReduceIfPlayed = True

' %%% Boost Songs that have been added during the last n days (MinDaysRepeat does still apply for these)
Const BoostNewSongsDays = 5

' %%% The boost modifier for new songs (Zero means, don't boost):
' Add x to the weighting of these songs
Const BoostNewSongsModifier = 3

' %%% Anything rated this or below will not receive the 'new song boost'
Const BoostNewSongsCutoff = 2.0

' %%% Genres that should not be played. Leave empty (Const PlayGenres = "") to ignore.
' Look up the other genre Ids in the database by using MS Access
Const PlayGenres = "-1, 13, 17, 20, 24"

' %%% Number of Songs in list
Const NumberOfSongs = 20


' %%% Influence which songs will be played. You have three sets that you can use
' Example:
' Const Set1Weight = 8.5    ' Basic weight for this set is 8.5
' Const Set1Boundary = 1.5  ' with a variation of 1.5, which means that songs between 7 and 10 will be chosen
' Const Set1Percentage = 60 ' this is how big the part of this set should be in the overall contents

Const Set1Weight = 8.5
Const Set1Boundary = 1.5
Const Set1Percentage = 60    ' make sure all 3 percentages sum up to 100!

Const Set2Weight = 6.0
Const Set2Boundary = 1
Const Set2Percentage = 40    ' make sure all 3 percentages sum up to 100!

Const Set3Weight = 2.0      ' Right now, it is not possible to choose songs with a weight < 1, so unfortunately you cannot add unrated songs
Const Set3Boundary = 1
'Const Set3Percentage = 20  ' This is not needed because it just takes what is missing to 100%


'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' The Meat. Don't change anything under here.
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

' the text of the formulas to be used throughout
Dim weightedRatingFormula, dateBoostFormula, ratingFormula, weightedPlayCountFormula, boostNewSongsFormula

If BoostNewSongsModifier <> 0 Then
   dateBoostFormula = "IIF(Songs.rating <= " & (BoostNewSongsCutoff *10) & " OR FIX(DateDiff('d',Songs.DateAdded,Now) <= " & BoostNewSongsDays & "), 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
Else
   dateBoostFormula = "IIF(Songs.rating <= " & (DateBoostCutoff*10) & ", 0, FIX(DateDiff('d',Songs.DateAdded,Now) / " & DayFactor & "))"
End If

ratingFormula = "(IIF(Songs.rating < 0, 0, Songs.rating) / 10)"

If ReduceIfPlayed Then
   weightedPlayCountFormula = "(Songs.PlayCounter - " & dateBoostFormula & ")"
Else
   weightedPlayCountFormula = "0"
End If

If BoostNewSongsModifier <> 0 Then
   boostNewSongsFormula = "IIF(Songs.rating <= " & (BoostNewSongsCutoff*10) & ", 0, (IIF(FIX(DateDiff('d',Songs.DateAdded,Now) > " & BoostNewSongsDays & "), 0, " & BoostNewSongsModifier & ")))"
End If

weightedRatingFormula = ratingFormula & " - IIF(" & weightedPlayCountFormula & " < 0, 0, " & weightedPlayCountFormula & ") "
if boostNewSongsFormula <> "" then weightedRatingFormula = weightedRatingFormula & "+ " & boostNewSongsFormula


Sub FillStandardProperties(parentNode, childNode)
   With childNode
      .CustomNodeId = parentNode.CustomNodeId
      .CustomDataId = parentNode.CustomDataId + 1
      .UseScript = Script.ScriptPath
   End With
End Sub


Sub FillGoodLeaf(Node)
   Randomize

   Dim Tracks
   Dim SQLStatement
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause, ORDER_Clause
   Dim Iter, res, i, total, sum, index
   Dim weight, minweight, maxweight
   Dim hold, weights, average, start, baseweight, boundary
   Dim R, max : max = NumberOfSongs
   Dim inStr : inStr = ""

   Set hold = CreateObject("Scripting.Dictionary") ' define an associative array or "hash array" to hold the songs
   Set weights = CreateObject("Scripting.Dictionary") ' define an associative array or "hash array" to hold the weightings

   
   SELECT_Clause = " SELECT Songs.Id, IIF(" & weightedRatingFormula & ">10,10," & weightedRatingFormula & ") "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE " & weightedPlayCountFormula &" < " & ratingFormula & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " AND Songs.Genre IN (" & PlayGenres & ")"
   End If
   ORDER_Clause = " ORDER BY Rnd((1000*Songs.ID)*Now())" ' This is important because otherwise they will all come as they are stored in the DB
   
   SQLStatement = SELECT_Clause & FROM_Clause & WHERE_Clause & ORDER_Clause
   'res = InputBox("SQL Statement: ", "debugging", SQLStatement) ' For debugging
   
   Set Iter = SDB.Database.OpenSQL(SQLStatement) ' holds all songs that are collected by the SQL formula

   total=0 ' initialise total amount of songs that can be used for the playlist (=all songs with weights from 1 to 10 minus "done" songs)
   sum = 0 ' initialise sum of all weightings
   maxweight = 0 ' initialise maximum weight in this iteration
   minweight = 9 ' initialise minimum weight in this iteration
   
   While (Not Iter.EOF)
      hold.add total,Iter.StringByIndex(0)
      weight = Iter.StringByIndex(1)
      weights.add total,weight
      total = total + 1
      sum = sum + weight
      If minweight > cdbl(weight) then
         minweight = cdbl(weight)
      End if
      if maxweight < cdbl(weight) then
         maxweight = cdbl(weight)
      End if

        Iter.Next
   Wend

   ' some overflow checks
   if total <= 0 or sum <= 0 then
      SDB.MessageBox "Something is wrong with your ratings. Do you have any rated songs at all?", mtInformation, Array(mbOk)
      Exit Sub
   end if

   If Set1Weight < minweight or Set2Weight < minweight or Set3Weight < minweight or Set1Weight > maxweight or Set2Weight > maxweight or Set3Weight > maxweight then
      SDB.MessageBox "Something is wrong with your SetXWeight constants. They are either too high or too low.", mtInformation, Array(mbOk)
      Exit Sub
   end if
   
   If (total < max) Then
        max = total
   End If
     
   Set Tracks = SDB.MainTracksWindow
   start = 0
   
   While i < max ' do this until the max number of songs for the playlist is reached
      If i < max * Set1Percentage / 100 then ' put in Set1Percentage percent of higher-rated songs
         baseweight = Set1Weight
         boundary = Set1Boundary
      elseif i < max * (Set1Percentage + Set2Percentage) / 100 then ' put in Set2Percentage percent of lower-rated songs
         baseweight = Set2Weight
         boundary = Set2Boundary
      elseif i <= max then ' and also put in some really lowly-rated songs
         baseweight = Set3Weight
         boundary = Set3Boundary
      end if
             
      For index = start to total ' go through all of the songs that could potentially become part of the radio node, starting where we left off last time
         weight = cdbl(weights.item(index)) ' weight of the song that is being looked at right now
             
         if weight >= (baseweight - boundary) and weight <= (baseweight + boundary) then
            ' This song is inside the weighting borders that are defined above
            ' so let's see if it is also lucky
            R = rnd(1) ' this song's lucky number
            if R > 0.8 then
               ' so let's leave this for-next loop and add it to the list!
               Exit For
            end if
         end if
      Next   
       
      start = index + 1 ' We don't want to go through the same songs again, so next time we start from here
      if start > total then
         if inStr = "" then
            SDB.MessageBox "There does not seem to be enough stuff to work on. Try to use criteria that are easier to meet.", mtInformation, Array(mbOk)
            Exit Sub
         else
            start = 0 ' start over again
         end if
      else
         ' We've got a winner! The song with the hash index "index" will now be added to the radio node
         ' This is done by collecting all songs in inStr, separating them by commas, and afterwards collecting their song.ids via SQL         
           If i = 0 Then
             inStr = hold.item(index)
           Else
             inStr = inStr & ", " & hold.item(index)
           End If
           i = i + 1
      end if   

   Wend

   If inStr <> "" then
      Tracks.AddTracksFromQuery("AND Songs.ID IN (" & inStr & ") ORDER BY Rnd((1000*Songs.ID)*Now())")
      Tracks.FinishAdding
   End If
       
End Sub





Sub FillWeightNode(Node)

   Dim Tree, newNode
   Dim SQLStatement ' SQL query to the database
   Dim Iter ' SDBD Iterator obtained by running the SQL query to get the nodes

   Set Tree = SDB.MainTree
   Node.HasChildren = false ' To delete all old children

   SQLStatement = "SELECT DISTINCT IIF(" & weightedRatingFormula & ">10,10," & weightedRatingFormula & ") from Songs "
   'res = InputBox("SQL Statement: ", SQLStatement, SQLStatement) ' For debugging
   Set Iter = SDB.Database.OpenSQL(SQLStatement)

   While Not Iter.EOF

      Set newNode = Tree.CreateNode

      NewNode.Caption = Iter.StringByIndex(0)
      NewNode.iconIndex = 32
      newNode.CustomData = Iter.StringByIndex(0)

      FillStandardProperties node,newNode
      newNode.onFillTracksFunct = "FillWeightLeaf"
      newNode.hasChildren = False
      Tree.AddNode Node, NewNode, 3

      Iter.Next
   Wend

End Sub


Sub FillWeightLeaf(Node)
   Dim Weight
   Dim Tracks
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause

   Weight = Node.CustomData

   SELECT_Clause = " SELECT Songs.Id "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE IIF(" & weightedRatingFormula & ">10,10," & weightedRatingFormula & ") = " & Weight & " AND DateDiff('d',Songs.LastTimePlayed, Now) > " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " AND Songs.Genre IN (" & PlayGenres & ")"
   End If
   'res = InputBox("SQL Statement: ", "Debugging", SELECT_Clause & FROM_Clause & WHERE_Clause) ' For debugging
   
   Set Tracks = SDB.MainTracksWindow

   Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
   Tracks.FinishAdding

End Sub


Sub FillDoneLeaf(Node)
   Dim Tracks
   Dim SELECT_Clause, FROM_Clause, WHERE_Clause


   SELECT_Clause = " SELECT Songs.Id "
   FROM_Clause = " FROM Songs "
   WHERE_Clause = " WHERE "& weightedPlayCountFormula &" >= " & ratingFormula & " OR DateDiff('d',Songs.LastTimePlayed, Now) <= " & MinDaysRepeat
   If PlayGenres <> "" then
      WHERE_Clause = WHERE_Clause & " OR Songs.Genre NOT IN (" & PlayGenres & ")"
   End If

   Set Tracks = SDB.MainTracksWindow

   Tracks.AddTracksFromQuery("AND Songs.ID IN (" & SELECT_Clause & FROM_Clause & WHERE_Clause & ")")
   Tracks.FinishAdding

End Sub



'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
' Startup Function
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Sub onStartUp
   Dim Tree, RadioFreeMonkeyRoot
   Dim RadioMonkeyGood, RadioMonkeyBad, RadioMonkeyWeight

   Set Tree = Sdb.MainTree
   Set RadioFreeMonkeyRoot = Tree.createNode

   RadioFreeMonkeyRoot.Caption = RootNodeCaption
   RadioFreeMonkeyRoot.IconIndex = 14
   RadioFreeMonkeyRoot.UseScript = Script.ScriptPath
   RadioFreeMonkeyRoot.hasChildren = True
   Tree.AddNode Tree.Node_Library, RadioFreeMonkeyRoot, 1
   SDB.Objects("RadioFreeMonkeyRoot") = RadioFreeMonkeyRoot

   Set RadioMonkeyGood = Tree.createNode
   RadioMonkeyGood.Caption = "Radio List"
   RadioMonkeyGood.IconIndex = 14
   RadioMonkeyGood.UseScript = Script.ScriptPath
   RadioMonkeyGood.hasChildren = False
   RadioMonkeyGood.onFillTracksFunct = "FillGoodLeaf"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyGood, 2
   SDB.Objects("RadioMonkeyGood") = RadioMonkeyGood

   Set RadioMonkeyWeight = Tree.createNode
   RadioMonkeyWeight.Caption = "Weightings"
   RadioMonkeyWeight.IconIndex = 32
   RadioMonkeyWeight.UseScript = Script.ScriptPath
   RadioMonkeyWeight.hasChildren = True
   RadioMonkeyWeight.onFillTracksFunct = "FillWeightNode"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyWeight, 3
   SDB.Objects("RadioMonkeyWeight") = RadioMonkeyWeight

   Set RadioMonkeyBad = Tree.createNode
   RadioMonkeyBad.Caption = "Done"
   RadioMonkeyBad.IconIndex = 15
   RadioMonkeyBad.UseScript = Script.ScriptPath
   RadioMonkeyBad.hasChildren = False
   RadioMonkeyBad.onFillTracksFunct = "FillDoneLeaf"
   Tree.AddNode RadioFreeMonkeyRoot, RadioMonkeyBad, 3
   SDB.Objects("RadioMonkeyBad") = RadioMonkeyBad
End Sub
[/code]
ElGringo
 
Posts: 6
Joined: Sat Oct 21, 2006 2:04 pm
Location: Val-David, Qc, Canada

Re: Some Fixes

Postby popper » Sun Oct 29, 2006 2:55 pm

Hi ElGringo,

thank you for pointing out my mistakes and correcting them. I was waiting all the time for someone to take a closer look at the code, because I knew that it was probably not perfect.

I have got some comments to your improvements.

ElGringo wrote:Hi !

This script is exactly what i was looking for... Thank you very much.

I picked the last script from popper, and saw a couple of errors that i corrected.

1. There was always a song that had nothing to do in my playlists, investigated and saw the error in FillGoodLeaf :

(...)

If i=0, then It should be hold.item(index), instead of index, so the first song that was added was not good, we were taking the index, instead of the real song.id



Yes, of course you are right. Silly mistake!


ElGringo wrote:2. There is an error in the calculation of the dateboost formula, the dateboostcutoff*20 should be dateboostcutoff*10. There were a couple of places wrong


I am not so sure about this one. Please correct me if I am wrong, but the ratings are stored in the database using numbers from 0 (or -1) to 100. So to calculate the number of stars from a rating in the database, you have to divide by 20, and not by ten.


ElGringo wrote:3. By adding, the BoostNewSongsModifier, the actual weight calculated, could go higher than 10, but the algorithm was never picking songs with a weight higher than 10. So, i fixed a couple of places in the script, so that calculated weight higher than 10, are now fixed at 10.

4. There was a bug, when the BoostNewSongsModifier is set to 0... fixed it.


Yes, these are very valid points. Thanks for correcting them.

I am already looking forward to using the new version of this script...

cheers,
popper.
popper
 
Posts: 34
Joined: Mon Feb 21, 2005 5:10 pm
Location: Germany

Postby tinny » Wed Nov 01, 2006 3:30 pm

thanks for this excellent script!
tinny
 
Posts: 39
Joined: Tue Oct 03, 2006 5:30 am

Next

Return to Need Help with Addons?

Who is online

Users browsing this forum: No registered users and 16 guests