' ========================================================================= ' WebSearch Panels ' ' This script adds as many panels as defined to the MediaMonkey interface. ' Each panel performs a specific web search on Artist, Title or Album. ' ' The script needs a XML file as a configuration file. ' ' The script is discussed in in the Forum at the MediaMonkey homepage at ' http://www.mediamonkey.com/forum/viewtopic.php?t=11254 ' ' Script by jn ' Last modified by gege in 2007-02-24 ' ' Changelog: ' ---------- ' ' Version 2007-02-24: ' ' - Fixed: a bug in PanelToComment procedure. NewLyrics variable was referenced ' instead of NewComment. ' ' - Fixed: UpdateDB and WriteTags methods are invoked after assining new text ' to Lyrics or Comment fields, in PanelToLyrics and PanelToComment procedures. ' This is necessary, so the information is permanently written to the Db and the Tag. ' ' - Modified: all the text strings declared as constants in the begginig of the ' script, for easier localization. ' ' - Modified: WebSearch.XML file moved to %MMhome%\Scripts\Auto folder, as I prefer ' it staying close to its dad. Also added an option to easily change this. ' ' - Added: option to choose buttons placement. I prefer then at bottom. ' ' - Added: TextCleanUp function, to make some very basic text clean-up, before it is ' saved to lyrics or comments. Needs improvement. There's also an option to disable this. ' ' - Added: GetTextFromClipboard function. When there's nothing selected in current panel, ' it gets the text from the clipboard. Useful when the text you want to paste in lyrics ' or comments field is outside the panel, like a TXT file, for instance. All you need is ' select and copy (CTRL+C) that text and then press Lyrics or Comment button. ' ' - ToDo: Add tooltip Hints to the buttons (that "?" isn't very explanatory, at all), but ' I suspect that buttons don't support hints... ' ' ========================================================================= ' ------------------------------------------------------------------------- ' Make sure all variables are declared Option Explicit Const ObjectName = "WebSearch_Panels" Const optionXmlPath = "\Scripts\Auto\WebSearch.xml" Const optionToolbarAlign = 2 ' 1=top 2=bottom 3=left 4=right Const optionDoTextCleanUp = 1 ' 1=yes 0=no ' Localizable strings Const stringsMenuCaption = "Search the web" Const stringsMenuHint = "Search the Web for information about current song or artist!" Const stringsMsgOverwriteLyrics = "Overwrite existing Lyrics?" Const stringsMsgOverwriteComment = "Overwrite existing Comment?" Const stringsLyricsBtn = "Lyrics" Const stringsLyricsHint = "Saves current selection or clipboard content to Lyrics field in ID3 tag." 'Not used yet Const stringsCommentBtn = "Comment" Const stringsCommentHint = "Saves current selection or clipboard content to Comment field in ID3 tag." 'Not used yet ' ------------------------------------------------------------------------- ' This is the main start function that is executed when MM starts Sub OnStartup Dim Items ' Create a menu anchor in the search toolbar Dim Menu Set Menu = SDB.UI.AddMenuItemSub(SDB.UI.Menu_TbSearch, 0, 0) With menu .Caption = stringsMenuCaption .Hint = stringsMenuHint End With ' Create the Panels Set Items = GetWebSearchItems With Items .ReadFile SDB.ApplicationPath & optionXmlPath .CreatePanels .CreateMenus(Menu) End With ' Save them for later use Set SDB.Objects(ObjectName) = Items ' Listen for changes Script.RegisterEvent SDB, "OnPlay", "PanelInfom" End Sub ' ------------------------------------------------------------------------- ' Just for convenience: Returns the instance of WebSearchItems we need. Function GetWebSearchItems If SDB.Objects(ObjectName) Is Nothing Then Set GetWebSearchItems = New WebSearchItems Else Set GetWebSearchItems = SDB.Objects(ObjectName) End If End Function ' ------------------------------------------------------------------------- ' Handler Routines ' ' These Handlers only call the Methods on the current Panel Object. ' They are fired by events like menu clicks, panel closure etc. ' ------------------------------------------------------------------------- ' ------------------------------------------------------------------------- ' PanelToggle is called whenever a panel is closed or opened (by menu or by X) Sub PanelToggle(ByVal Item) GetWebSearchItems.PanelSearch(Item).Toggle End Sub ' ------------------------------------------------------------------------- ' PanelClose is called whenever a Panel is closed ' (we can't use PanelToggle for this, because it is already closed when the ' function is called) Sub PanelClose(ByVal Item) GetWebSearchItems.PanelSearch(Item).Close End Sub ' ------------------------------------------------------------------------- ' PanelGoForward is called whenever a forward button is klicked Sub PanelGoForward(ByVal Item) GetWebSearchItems.PanelSearch(Item).GoForward End Sub ' ------------------------------------------------------------------------- ' PanelGoBack is called whenever a back button is klicked Sub PanelGoBack(ByVal Item) GetWebSearchItems.PanelSearch(Item).GoBack End Sub ' ------------------------------------------------------------------------- ' PanelGoSearch is called whenever a home button is klicked Sub PanelGoSearch(ByVal Item) GetWebSearchItems.PanelSearch(Item).GoSearch End Sub ' ------------------------------------------------------------------------- ' OnPlayChange is called whenever a new title is played ' It and informs all panels about the new title Sub PanelInfom GetWebSearchItems.Inform End Sub ' ------------------------------------------------------------------------- ' TextCleanUp is used... (guess what) to clean-up the text before it is ' saved to lyrics or comments field. ' For now it is very primitive and does only basic replacements. ' I'd like to be able to do more complex operations like capitalising ' sentences (useful for those lyrics all in lowercase or, even worse, all ' in uppercase). Maybe this can be achieved using regular expressions... ' (function added by gege) Function TextCleanUp (Text) If optionDoTextCleanUp = 1 Then ' Let's get rid of those double/triple empty lines... Text=Replace(Text,vbnewline&vbnewline&vbnewline, vbnewline&vbnewline) Text=Replace(Text,vbnewline&vbnewline&vbnewline, vbnewline&vbnewline) ' And now we correct some common punctuation problems Text=Replace(Text," ?","?") Text=Replace(Text," !","!") Text=Replace(Text," ,",",") Text=Replace(Text," :",":") Text=Replace(Text,"…","...") Text=Replace(Text," ...","...") Text=Replace(Text,"‘","'") Text=Replace(Text,"’","'") Text=Replace(Text,"´","'") ' Capitalised it's much better... Text=Replace(Text," i "," I ") Text=Replace(Text," i'm "," I'm ") Text=Replace(Text," i'd "," I'd ") Text=Replace(Text," i'll "," I'll ") Text=Replace(Text," i've "," I've ") Text=Replace(Text," ok "," OK ") Text=Replace(Text," tv "," TV ") Text=Replace(Text," dj "," DJ ") ' Let's get things appart... Text=Replace(Text," youre "," you're") Text=Replace(Text," youve "," you've") Text=Replace(Text," dont "," don't ") Text=Replace(Text," cant "," can't ") Text=Replace(Text," aint "," ain't ") Text=Replace(Text," didnt "," didn't ") Text=Replace(Text," wasnt "," wasn't ") Text=Replace(Text," isnt "," isn't ") Text=Replace(Text," wont "," won't ") Text=Replace(Text," wouldnt "," wouldn't ") Text=Replace(Text," shouldnt "," shouldn't ") Text=Replace(Text," havent "," haven't ") End If TextCleanUp = Text End Function ' ------------------------------------------------------------------------- ' Returns the current text content of clipboard. I looked at the forums and ' it looks like there isn't a more elegant way to do this (I mean without ' instantiating IE). ' This is useful when the text you want to paste in lyrics or comments field ' is outside the panel, like a TXT file, for instance. All you need is ' select and CTRL+C in that text... ' (function added by gege) Function GetTextFromClipboard Dim IE Set IE = CreateObject("InternetExplorer.Application") IE.Navigate("about:blank") GetTextFromClipboard = IE.Document.ParentWindow.ClipBoardData.GetData("text") IE.Quit Set IE=Nothing End Function ' ------------------------------------------------------------------------- ' PanelToLyrics is called whenever the lyrics button is clicked Sub PanelToLyrics(ByVal Item) Dim NewLyrics NewLyrics = GetWebSearchItems.PanelSearch(Item).Selection If Len(NewLyrics) = 0 Then ' If there's nothing selected in current panel, let's try the clipboard... NewLyrics = GetTextFromClipboard End If If Len(NewLyrics) > 10 Then With SDB.Player.CurrentSong If Len(.Lyrics) = 0 Then .Lyrics = TextCleanUp(NewLyrics) .UpdateDB .WriteTags Elseif MsgBox(stringsMsgOverwriteLyrics, vbYesNo) = vbYes Then .Lyrics = TextCleanUp(NewLyrics) .UpdateDB .WriteTags End If End With End If End Sub ' ------------------------------------------------------------------------- ' PanelToComment is called whenever the comments button is klicked Sub PanelToComment(ByVal Item) Dim NewComment NewComment = GetWebSearchItems.PanelSearch(Item).Selection If Len(NewComment) = 0 Then ' If there's nothing selected in current panel, let's try the clipboard... NewComment = GetTextFromClipboard End If If Len(NewComment) > 10 Then With SDB.Player.CurrentSong If Len(.Comment) = 0 Then .Comment = TextCleanUp(NewComment) .UpdateDB .WriteTags Elseif MsgBox(stringsMsgOverwriteComment, vbYesNo) = vbYes Then .Comment = TextCleanUp(NewComment) .UpdateDB .WriteTags End If End With End If End Sub ' ------------------------------------------------------------------------- ' The WebSearchItem class ' ------------------------------------------------------------------------- Class WebSearchItem Public Name Public Caption Public Description Public Start Public SearchURL Private Panel Private Menuitem Private Browser ' Buttons Private btnGoBack Private btnGoForward Private btnGoSearch Private btnLyrics Private btnComment ' ------------------------------------------------------------------------- ' Add a Panel for the WebSearchItem Sub CreatePanel Dim UI Set UI = SDB.UI Set Panel = UI.NewDockablePersistentPanel(Name) With Panel If Panel.IsNew then .DockedTo = 2 .Common.Width = 250 .Common.Visible = true End If .Caption = Caption End With Script.RegisterEvent Panel, "OnClose", "PanelClose" ' Create a web browser component Set Browser = UI.NewActiveX(Panel, "Shell.Explorer") With Browser .Common.Align = 5 ' Fill all client rectangle .Interf.Navigate Start End With ' Navigation Bar Dim Nav Set Nav = UI.NewPanel(Panel) With Nav.Common .Align = optionToolbarAlign .Height = 35 End With ' Back button Set btnGoBack = UI.NewButton(Nav) With btnGoBack .Common.SetRect 5, 5, 25, 25 .Caption = "<" .UseScript = Script.ScriptPath .OnClickFunc = "PanelGoBack" End With ' Forward button Set btnGoForward = UI.NewButton(Nav) With btnGoForward .Common.SetRect 35, 5, 25, 25 .Caption = ">" .UseScript = Script.ScriptPath .OnClickFunc = "PanelGoForward" End With ' Search button Set btnGoSearch = UI.NewButton(Nav) With btnGoSearch .Common.SetRect 65, 5, 25, 25 .Caption = "?" .UseScript = Script.ScriptPath .OnClickFunc = "PanelGoSearch" End With ' Search button Set btnLyrics = UI.NewButton(Nav) With btnLyrics .Common.SetRect 95, 5, 75, 25 .Caption = stringsLyricsBtn .UseScript = Script.ScriptPath .OnClickFunc = "PanelToLyrics" End With ' Search button Set btnComment = UI.NewButton(Nav) With btnComment .Common.SetRect 175, 5, 75, 25 .Caption = stringsCommentBtn .UseScript = Script.ScriptPath .OnClickFunc = "PanelToComment" End With End Sub ' ------------------------------------------------------------------------- ' Add a menu item for the WebSearchItem Sub CreateMenu(ByVal Parent) Set Menuitem = SDB.UI.AddMenuItem(Parent, 0, 0) With Menuitem .Caption = Caption .Checked = Panel.Common.Visible .IconIndex = 55 .Hint = Description End With Script.RegisterEvent Menuitem, "OnClick", "PanelToggle" End Sub ' ------------------------------------------------------------------------- ' Go to the respective page Sub GoSearch Browser.Interf.Navigate(ReplaceTokens(SearchURL, SDB.Player.CurrentSong)) End Sub ' ------------------------------------------------------------------------- ' Go forward one page Sub GoForward 'I've found no better way to find out if navigation is possible... On Error Resume Next Browser.Interf.GoForward End Sub ' ------------------------------------------------------------------------- ' Go back one page Sub GoBack On Error Resume Next Browser.Interf.GoBack End Sub ' ------------------------------------------------------------------------- ' Switch from visible to invisible or the other way Sub Toggle Panel.Common.Visible = not Panel.Common.Visible Menuitem.Checked = Panel.Common.Visible End Sub ' ------------------------------------------------------------------------- ' Close a panel Sub Close Menuitem.Checked = false End Sub ' ------------------------------------------------------------------------- ' Returns the selected text in a browser Public Property Get Selection Selection = Browser.Interf.document.selection.createRange.text End Property ' ------------------------------------------------------------------------- ' Returns the Panel's visibility Public Property Get Visible Visible = Panel.Common.Visible End Property ' ------------------------------------------------------------------------- ' Replace tokens in the URL. Function ReplaceTokens(ByVal URL, ByVal Song) With Song URL = Replace(URL, "%artist%", .ArtistName) URL = Replace(URL, "%title%", .Title) URL = Replace(URL, "%album%", .AlbumName) URL = Replace(URL, "%albumartist%", .AlbumArtistName) End With ReplaceTokens = URL End Function End Class ' ------------------------------------------------------------------------- ' The WebSearchItems class ' ------------------------------------------------------------------------- Class WebSearchItems Public Panels ' ------------------------------------------------------------------------- ' Clears the current collection and creates Panels as defined in a ' configuration file Sub ReadFile(ByVal XMLFile) ' The configuration file Dim XMLDoc ' For the config file's root object Dim Root ' One config file's entry Dim Site ' One config file's details Dim config ' One panel Dim Panel ' Read the Configuration File set XMLDoc = CreateObject("Microsoft.XMLDOM") With XMLDoc .async = "false" .load XMLFile Set Root = .selectNodes("configuration") End With Set XMLDoc = Nothing Set Panels = CreateObject("Scripting.Dictionary") ' We now create the Panels, adding them to the Dictionary object for later ' retrieval For Each Site In Root(0).childNodes Set Panel = New WebSearchItem With Panel For Each config In Site.childNodes if config.baseName = "name" then .Name = config.Text if config.baseName = "caption" then .Caption = config.Text if config.baseName = "description" then .Description = config.Text if config.baseName = "start" then .Start = config.Text if config.baseName = "url" then .SearchURL = config.Text Next Panels.Add .Name, Panel End With Next Set Root = Nothing End Sub ' ------------------------------------------------------------------------- ' Saves the configuration to a file Sub SaveFile(ByVal XMLFile) ' The configuration file Dim XMLDoc ' For the config file's root object Dim Root ' For one site Dim Site ' For a config entry Dim config Set XMLDoc = CreateObject("Microsoft.XMLDOM") Set Root = XMLDoc.CreateNode(1, "configuration", "") Dim Key For Each Key in Panels Set Site = XMLDoc.CreateNode(1, "site", "") Set config = XMLDoc.CreateNode(1, "name", "") config.text =Panels(Key).Name Site.AppendChild config Set config = XMLDoc.CreateNode(1, "caption", "") config.text =Panels(Key).Caption Site.AppendChild config Set config = XMLDoc.CreateNode(1, "description", "") config.text =Panels(Key).Description Site.AppendChild config Set config = XMLDoc.CreateNode(1, "start", "") config.text =Panels(Key).Start Site.AppendChild config Set config = XMLDoc.CreateNode(1, "url", "") config.text =Panels(Key).SearchURL Site.AppendChild config Root.AppendChild Site Next Dim PI Set PI = XMLDoc.createProcessingInstruction("xml", " version = ""1.0""") XMLDoc.AppendChild PI XMLDoc.AppendChild Root XMLDoc.Save(XMLFile) End Sub ' ------------------------------------------------------------------------- ' Show the panels Sub CreatePanels Dim Key For Each Key in Panels Panels(Key).CreatePanel Next End Sub ' ------------------------------------------------------------------------- ' Add the menu items. The parameter mus be a SDBUI.Submenu object. ' By calling this method multiple times, it *might* be possible to create ' more than one menu structure? Sub CreateMenus(RootMenu) Dim Key For Each Key in Panels Panels(Key).CreateMenu(RootMenu) Next End Sub ' ------------------------------------------------------------------------- ' Inform all panels about the new title Sub Inform Dim Key For Each Key in Panels Panels(Key).GoSearch Next End Sub ' ------------------------------------------------------------------------- ' This helper function returns one WebSearchItem by the "Item". ' The "Item" can be a panel object, a menu object etc. Function PanelSearch(ByVal Item) Dim Key Select Case TypeName(Item) Case "SDBUIDockablePanel" ' The Panel object has a naming property that is the same as the ' index in our Dictionary, so it's easy in this case Set PanelSearch = Panels(Item.Common.ControlName) Exit Function Case "SDBMenuItem" ' Unfortunately, Menuitem objects don't have such a naming property. ' Therefore, we have to search for the caption. This is the reason ' that the captions have to be unique. For Each Key in Panels If Panels(Key).Caption = Item.Caption Then Set PanelSearch = Panels(Key) Exit Function End If Next Case "SDBUIButton" ' A bit complicated: The Panel is the Button's grand-parent Key = Item.Common.Parent.Common.Parent.Common.ControlName Set PanelSearch = Panels(Key) Exit Function End Select End Function End Class