Author Topic: New plugin: Ghost files! Can API provide? Suggestions needed!  (Read 14763 times)

e-motiv

  • Full Member
  • ***
  • Posts: 182
I am (slowly) writing a new plugin that will let one keeps ghost files / tracks.  These are are not longer on your file system (deleted), but all info of it is still saved (like filename, size, tags, how many times you listened, rating, ..).
My main reason is a better organization for "music collecting", e.g. you listen to some new music from friend or site or whatever, and you keep/download the tracks you like, but delete the others, but some other time you happen to listen to some new tracks, you might be listening to the same ones you discarded before.  With ghost files, you will know you have listened to it before and you save yourself time and headaches.

Now, I have some questions (for everyone, but I need some answers from Steven):
  • Can the database engine be accessed via the API? If not, is there any dll that can be double used from MB?
  • Shall I keep these ghost files in a seperate DB, or same DB, but different table or the actual MB database tables themselves in conjuction with an extra table, or should I work together with Steven for some extra fields so it will all be in the exact same DB table from MB???
  • I guess .NET 4 (MB2+) is the safest way to be future proof? Is the .NET4 API the one of the first post of the API topic  or the last post with API update?
  • Would it be possible to use the current Music Library (including filtering) and default (what's it called?) organizing panels?
  • Any suggestions, things I forgot from anyone?

Thanks and appreciation in advance!!  ;)
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

Steven

  • Administrator
  • Hero Member
  • *****
  • Posts: 31045
  • Can the database engine be accessed via the API? If not, is there any dll that can be double used from MB?
the API supports accessing the library and fields
            public Library_GetFilePropertyDelegate Library_GetFileProperty;
            public Library_GetFileTagDelegate Library_GetFileTag;
            public Library_GetLyricsDelegate Library_GetLyrics;
            public Library_GetArtworkDelegate Library_GetArtwork;
            public Library_QueryFilesDelegate Library_QueryFiles;

  • Shall I keep these ghost files in a seperate DB, or same DB, but different table or the actual MB database tables themselves in conjuction with an extra table, or should I work together with Steven for some extra fields so it will all be in the exact same DB table from MB???
keep the files in your own storage
            public Setting_GetPersistentStoragePathDelegate Setting_GetPersistentStoragePath;
this api returns the writteable storage area. Suggest you create your own sub-folder and files there. Whether you use SQL Lite or your own flat file scheme is up to you
  • I guess .NET 4 (MB2+) is the safest way to be future proof? Is the .NET4 API the one of the first post of the API topic  or the last post with API update?
the api is compatible with .NET2 up to API revision 10 - see the MusicBeeApiInterface structure
            public short ApiRevision;
but i expect you will need new features so best just work with the new API and .NET4
  • Would it be possible to use the current Music Library (including filtering) and default (what's it called?) organizing panels?
i would need to add support and can do. For the panels, i will need a good idea of how you think it should be implemented

e-motiv

  • Full Member
  • ***
  • Posts: 182
Thanks, Steven! Still have some questions though:
  • Can the database engine be accessed via the API? If not, is there any dll that can be double used from MB?
the API supports accessing the library and fields
            public Library_GetFilePropertyDelegate Library_GetFileProperty;
            public Library_GetFileTagDelegate Library_GetFileTag;
            public Library_GetLyricsDelegate Library_GetLyrics;
            public Library_GetArtworkDelegate Library_GetArtwork;
            public Library_QueryFilesDelegate Library_QueryFiles;
These are only for tracks from MB's own database and table, right? And only possible with their own fields, or? (And no write access, but I guess the other functions can do that.)
If so, I am more interested in general SQL Lite access functions since I will have my own DB and table (after your suggestion). Since you already use SQL Lite, I was thinking to double use the function-library MB already uses itself, via calling the same dll (or via the API).  To evade having to add another dll myself, just for the same DB access (not same DB, just same engine=SQL Lite)
[/quote]
  • Would it be possible to use the current Music Library (including filtering) and default (what's it called?) organizing panels?
i would need to add support and can do. For the panels, i will need a good idea of how you think it should be implemented
Great!
In the music library I would just have to be able to feed my table into it (with similar, but also extra track fields e.g. "ghost file yes/no") or have a distinct menu item under it in the library dropdown, or what were you thinking? Maybe there are other options.
-About the panels: First, that's only needed if the above is not possible.  I just need a tab to display my ghost music tracks the exact same way as MB displays any track list today.  (Except for some extra fields maybe (like "ghost file" yes/no.)
So, just a list of tracks with fields (and if possible all the other things that come with it, such as the different views, the different filters, the mouse context menus, ordering, etc..).  I could actually also use this latter solution for my Radio Dig plugin (which has a limited amount of fields.)
Concerning good ideas, I am afraid I am not much of use, especially since I don't  (have time nor will to ;D) know your code, but maybe the function that you use to display a track list panel can have an extra parameter and that parameter tells it what source it should take (MB itself or a plugin-propagated source; this source being a handle, pointer, class-object whatever you use today, or maybe even a database connection).

Thanks in advance, whatever and however you would get this done.
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

e-motiv

  • Full Member
  • ***
  • Posts: 182
Hi Steven,
Regarding double use sql dll, after much searching I found this solution:
In build file,reference MB dll:
Code
			<references>
        <include name='C:\Program Files (x86)\MusicBee\System.Data.SQLite.dll'/>
</references>
In source, just SQlite away:
Code
using System.Data.SQLite; //http://system.data.sqlite.org
pluginDBFileName = mbApi.Setting_GetPersistentStoragePath()+sep+about.Name+".db";
DB = new SQLiteConnection(@"Data Source="+pluginDBFileName);
DB.Open();
That simple!

But now, my main block is that I can't ghost-delete the current selected file (in library or player or wherever).
I think the current API doesn't cover the following things or does it?:
  • a "delete" method (so that MB deletes the file and all derivative actions are taken (library, ..))
  • Get current selected file (to know which file to delete if working via shortcut key) OR..
  • a way to add a context menu item "Delete (keep ghost file)" (in a tab panel(=library, I guess?) or anywhere a track can be deleted)
  • OR replacing all of the above points, would be to allow a certain delete notification on which my plugin would popup a question dialog "Keep as ghost file?"

OR just an extra option in  MB's own delete confirmation which (if checked) triggers a plugin method / notification.
[/list]
Think you can implement any of those, Steven? I do allow a lot of options, don't I?  ;D ;D
(I think the last one is the best for as well you as users, don't you think?)

Later on, I would need even more I am afraid, like:
  • a way to search in my db (preferably via the MB search field)

What would be even cooler is that one can search into library and ghost files at same time (so checkbox option "also search ghost file")
  • previous discussed way of visualising ghost files (into library itself OR in a seperate panel)

Anything much appreciated!  :-*
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

Steven

  • Administrator
  • Hero Member
  • *****
  • Posts: 31045
i'm still looking at the theater mode plugin so probably wont be able to start looking at this until next weekend.
But i can advise you a couple of things now
- i will only make access available to musicbee data via the existing API. As a principle i dont want to build dependencies on plugins that have any sort direct access - this is so i can make internal changes if i need to without worrying about any plugins
- for the same reason you will need to have your own data store that is completely independent to musicbee's data storage. If you choose to use SQL Lite that is fine
- their is a way to get the selected file - its a bit crappy, but on Library_QueryFiles(string query), the query string supports the following:
"domain=SelectedFiles"
"domain=DisplayedFiles"
- you can add toolbar menu items using MB_AddMenuItem(...) where the path parameter can be:
mnuView/xxxx
mnuTools/xxxx
mnuTools/mnuTagTools/xxxx
mnuTools/mnuTagTools/mnuAdvanced/xxxx
- for context menus, i will need to add an api call for that



e-motiv

  • Full Member
  • ***
  • Posts: 182
  • Thanks for 'QueryFiles "domain=SelectedFiles"', Steven!  It's a good workaround for now and it works!
  • No worries about my own DB.   ;D  I just re-use your MB SQLite dll to access my own DB.
.

Now, let me give you a better request overview for when you find some more time.

Summary list:                                     (in order of priority)

  • An extra custom (plugin) option in  MB's delete confirmation dialog which (if checked) triggers my plugin method (or notification) (most prefered option over my other proposals above)
  • Possibility to use/create a (track list) panel for my own DB (including filtering)  and searching in it (preferably via the same MB search field)
  • What would be supercool is that one could search into the library and my ghost files at same time (e.g. search checkbox option "also search ghost file")

Thanks again, Steven.  I'll hold my horses for now!  ;)
Last Edit: April 04, 2012, 11:32:20 AM by R U Bn ?
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

Steven

  • Administrator
  • Hero Member
  • *****
  • Posts: 31045
actually it occured to me yesterday that you can probably acheive what you want using an existing but not documented API i created for the SubSonic plugin.
So the idea would be that you would advertise your plugin to MusicBee as a storage server. MusicBee would add a node to the Computer section, and clicking on it will show files

in the plugin initialisation
        about.Type = PluginType.PluginStorage
        about.ReceiveNotifications = ReceiveNotificationFlags.StartupOnly
        about.TargetApplication = "GhostFiles"   ' this is used as an Id in musicbee for a folder or file path eg. GhostFiles\\xxxxx\x.mp3

    Public Sub ReceiveNotification(ByVal sourceFileUrl As String, ByVal type As NotificationType)
        If type = NotificationType.PluginStartup Then
            ' do your initialisation
            mbApiInterface.MB_SendNotification(CallBackType.StorageReady)  ' or CallBackType.StorageFailed
        End If
    End Sub

by doing that MusicBee will look for the following methods that you would expose (this is in VB but can be C#):
    Public Function IsReady() As Boolean
        ' is the database available for file retrieval
    End Function

    Public Function GetIcon() As Bitmap
        ' return an 16x16 icon for the main navigation node
    End Function

    Public Sub Refresh()
        ' refresh any cached files - called when the user presses F5 or does some operation that requires a refresh of data. In your case this probably wouldnt need to do anything
    End Sub

    Public Function GetFolders(ByVal path As String) As String()
        ' i guess in your case you wouldnt have folders so you would just return one dummy master folder
        ' if there is a structure, depending on whether the user has clicked the main navigation node or a specific folder, MusicBee will call GetFiles(path) with the appropriate path
    End Function

    Public Function FolderExists(ByVal path As String) As Boolean
    End Function

    Public Function GetFiles(ByVal path As String) As KeyValuePair(Of Byte, String)()()
        ' return an array for file tag data
        ' each row on the array represents a file
        ' and a file consists of an array of tags (FilePropertyType and MetaDataType) and values
    End Function

    Public Function FileExists(ByVal url As String) As Boolean
    End Function

    Public Function GetFile(ByVal url As String) As KeyValuePair(Of Byte, String)()
    End Function

    Public Function GetFileArtwork(ByVal url As String) As Byte()
        ' return base64 representation of bitmap data
    End Function

    Public Function GetPlaylists() As KeyValuePair(Of String, String)()
    End Function

    Public Function GetPlaylistFiles(ByVal id As String) As KeyValuePair(Of Byte, String)()()
    End Function

    Public Function GetStream(ByVal url As String) As IO.Stream
    End Function

    Public Function GetError() As Exception
    End Function
Last Edit: April 04, 2012, 12:32:27 PM by Steven

e-motiv

  • Full Member
  • ***
  • Posts: 182
Another woraround! Grea! Keeps me going!  :D
And now I know what all those functions were for in the "TestCSharpDll.cs"!  :D

Unfortunatly, I am stuck.  I managed to get the computer menu show my ghost tracks, but it stops there. As if MB is never asking for folders nor files. I tried Message.Show boxes on all these get functions, but none EVER show up. Maybe the only way to make MB do it anymore, is via notification?

Here is my relevant code:
Code
        public void ReceiveNotification(string sourceFileUrl, NotificationType type)	// receive event notifications from MusicBee
       { //MessageBox.Show(about.Name+" notification:"+type);//debug
         switch (type)
         {    //perform startup initialisation
            case NotificationType.PluginStartup:
          mbAPI.MB_SendNotification(CallbackType.StorageReady); //Must be done here
        //MessageBox.Show("storage ready");
            break;
         }
      }

        public string[] GetFolders(string path) // return the full path of folders in a folder
        { //MessageBox.Show("GetFolders:"+path);
            return new string[]{"test","Test2"};
        }

        public Bitmap GetIcon() // return a 16x16 bitmap for the storage icon
        { //MessageBox.Show("GetIcon:"+Application.StartupPath+sep+"Plugins"+sep+about.Name+sep+about.Name+".png");
            return new Bitmap(Application.StartupPath+sep+"Plugins"+sep+about.Name+sep+about.Name+".png");//
        }

        public byte[] GetFileArtwork(string url ) // return an array of bytes for the raw picture data
        {
            return null;
        }

        public bool FileExists(string url)
        {
            return true;
        }

        //  each file is represented as a array of tags - each tag being a KeyValuePair(Of Byte, String), where Byte is a FilePropertyType or MetaDataType enum value and String is the value
        // a tag for FilePropertyType.Url must be included
        public KeyValuePair<byte, string>[] GetFile(string url)
        { //MessageBox.Show("GetFile:"+url);
            return null;
        }
       

        // return an array of playlist identifiers
        // where each playlist identifier is a KeyValuePair(id, name)
        public KeyValuePair<string, string>[] GetPlaylists()
        { //MessageBox.Show("GetPlaylists");
            return null;
        }

        // return an array of files in a playlist - a playlist being identified by the id parameter returned by GetPlaylists()
        // each file is represented as a array of tags - each tag being a KeyValuePair(Of Byte, String), where Byte is a FilePropertyType or MetaDataType enum value and String is the value
        // a tag for FilePropertyType.Url must be included
        public KeyValuePair<byte, string>[][] GetPlaylistFiles(string id)
        { //MessageBox.Show("GetPlaylistFiles");
            return null;
        }

        // return a stream that can read through the raw (undecoded) bytes of a music file
        public System.IO.Stream GetStream(string url)
        {
            return null;
        }

        public bool FolderExists(string path)
        { //MessageBox.Show("FolderExists");
            return true;
        }


        public  Exception GetError()        // return the last error that occurred
        { //MessageBox.Show("GetError");
            return null;
        }


        // you can initially return false and then use MB_SendNotification when the storage is ready (or failed)
        public bool IsReady()        // is the server ready
        {
            return false;
        }
        // user initiated refresh (eg. pressing F5) - reconnect/ clear cache as appropriate
        public void Refresh()
        { //MessageBox.Show("Refresh");
        }

        #endregion
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

Steven

  • Administrator
  • Hero Member
  • *****
  • Posts: 31045
try returning true for IsReady()
in a fully implemented solution, it should be returning false until your initialisation has completed sucessfully and then true
Last Edit: April 05, 2012, 12:40:28 PM by Steven

e-motiv

  • Full Member
  • ***
  • Posts: 182
NEVER MIND! Got it! IsReady never returns true!
For the record:
Code
..in Initialise...
storageReady=true;
....
            case NotificationType.PluginStartup:
          mbAPI.MB_SendNotification(storageReady?CallbackType.StorageReady:CallbackType.StorageFailed); //Must be done here        //MessageBox.Show("storage ready");
....
        public bool IsReady()        // is the server ready
        { MessageBox.Show("IsReady");
            return storageReady?true:false;
        }
I don't know which notification can substitute that, so I used a variable
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

e-motiv

  • Full Member
  • ***
  • Posts: 182
try returning true for IsReady()
LoL!  Just realized!  Sorry to have bothered you!  :)
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig


e-motiv

  • Full Member
  • ***
  • Posts: 182
Here is an alpha release for whomever.
I still want to finish integrating it in MB Music search, Delete action and hopefull out of Computer Node before beta.
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

e-motiv

  • Full Member
  • ***
  • Posts: 182
@Steven,
I'd like to start with the delete action and I presume I need your help. Can you make the following possible (via the API)?

  • A delete event so I can catch the file tags and save them in my database (which is what a ghost file is all about)?
    I presume this has to be triggered before the actual delete because else the track tags and file information are lost? But if not, if MB would still have that info,  I would actually prefer it to be after the actual delete (so there is really only a ghost file if the file is really deleted without any potential OS delete problems).

  • Allow for an extra parameter/option in the delete confirmation dialog? In my plugin this would be  "[checkbox] keep a ghost file"one level deeper under the existing bullet (remove from computer).
  Developing @ e-motiv.net       --       Musicbee plugins: Speak Back - Ghost Tracks - Radio Dig

boroda

  • Hero Member
  • *****
  • Posts: 3520
    • Allow for an extra parameter/option in the delete confirmation dialog? In my plugin this would be  "[checkbox] keep a ghost file"one level deeper under the existing bullet (remove from computer).
    Probably you could display your own confirmation dialog after user confirmed deletion from computer?