├── MBGmusicSync.suo ├── Screenshot.png ├── Plugin ├── mb_GoogleMusicSync_v1.zip ├── mb_GoogleMusicSync_v1.5.zip ├── mb_GoogleMusicSync_v1.7.zip └── mb_GoogleMusicSync_v1.6wLogging.zip ├── MBGmusic ├── app.config ├── Models │ ├── MbPlaylist.cs │ └── MbSong.cs ├── packages.config ├── MBGmusic.csproj.user ├── Properties │ └── AssemblyInfo.cs ├── Plugin │ ├── Logger.cs │ ├── PlaylistSync.cs │ ├── Settings.cs │ ├── GMusicSyncData.cs │ ├── MBGmusicPlugin.cs │ ├── MbSyncData.cs │ └── MusicBeeInterface.cs ├── Configure.resx ├── MBGmusic.csproj ├── Configure.cs └── Configure.Designer.cs ├── TestGMusicAPI ├── app.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Program.cs ├── TestGMusicAPI.csproj ├── Form1.cs ├── Form1.resx └── Form1.Designer.cs ├── TestPlaylistCreation ├── TestWindow.cs ├── Properties │ └── AssemblyInfo.cs ├── TestMBApi.csproj ├── TestWindow.Designer.cs ├── TestWindow.resx └── MBTestAPIPlugin.cs ├── .gitignore ├── readme.md └── MBGmusicSync.sln /MBGmusicSync.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/MBGmusicSync.suo -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/Screenshot.png -------------------------------------------------------------------------------- /Plugin/mb_GoogleMusicSync_v1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/Plugin/mb_GoogleMusicSync_v1.zip -------------------------------------------------------------------------------- /Plugin/mb_GoogleMusicSync_v1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/Plugin/mb_GoogleMusicSync_v1.5.zip -------------------------------------------------------------------------------- /Plugin/mb_GoogleMusicSync_v1.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/Plugin/mb_GoogleMusicSync_v1.7.zip -------------------------------------------------------------------------------- /Plugin/mb_GoogleMusicSync_v1.6wLogging.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoedin/MBGmusicSync/HEAD/Plugin/mb_GoogleMusicSync_v1.6wLogging.zip -------------------------------------------------------------------------------- /MBGmusic/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /TestGMusicAPI/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /TestGMusicAPI/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MBGmusic/Models/MbPlaylist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MusicBeePlugin.Models 7 | { 8 | public class MbPlaylist 9 | { 10 | public String mbName; 11 | public String Name; 12 | public override string ToString() 13 | { 14 | return Name; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MBGmusic/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /MBGmusic/Models/MbSong.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MusicBeePlugin.Models 7 | { 8 | public class MbSong 9 | { 10 | public String Filename; 11 | public String Artist; 12 | public String Title; 13 | 14 | public override string ToString() 15 | { 16 | return Artist + " - " + Title; 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /TestGMusicAPI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace TestGMusicAPI 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | Application.Run(new Form1()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MBGmusic/MBGmusic.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Program 5 | C:\Program Files (x86)\MusicBee\MusicBee.exe 6 | 7 | 8 | Program 9 | C:\Program Files (x86)\MusicBee\MusicBee.exe 10 | 11 | 12 | Program 13 | C:\Program Files (x86)\MusicBee\MusicBee.exe 14 | 15 | -------------------------------------------------------------------------------- /TestGMusicAPI/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TestGMusicAPI.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TestPlaylistCreation/TestWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace TestPlaylistCreation 11 | { 12 | public partial class TestWindow : Form 13 | { 14 | private MusicBeePlugin.Plugin.MusicBeeApiInterface _mbApiInterface; 15 | public TestWindow(MusicBeePlugin.Plugin.MusicBeeApiInterface api) 16 | { 17 | InitializeComponent(); 18 | _mbApiInterface = api; 19 | } 20 | 21 | private void CreatePlaylist_button_Click(object sender, EventArgs e) 22 | { 23 | string dir = CreatePlaylistDirectory_tb.Text; 24 | string name = CreatePlaylistName_tb.Text; 25 | 26 | string[] files = null; 27 | if (_mbApiInterface.Library_QueryFiles("domain=library")) 28 | { 29 | // Old (deprecated) 30 | //public char[] filesSeparators = { '\0' }; 31 | //files = _mbApiInterface.Library_QueryGetAllFiles().Split(filesSeparators, StringSplitOptions.RemoveEmptyEntries); 32 | _mbApiInterface.Library_QueryFilesEx("domain=library", ref files); 33 | } 34 | 35 | if (dir == null) 36 | dir = ""; 37 | 38 | _mbApiInterface.Playlist_CreatePlaylist(dir, name, files); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TestGMusicAPI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestGMusicAPI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestGMusicAPI")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d5a99921-cbe0-4a64-b0ef-d382bd3a5515")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MBGmusic/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MusicBeeGoogleMusicPlaylistSync")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Leo Rampen")] 12 | [assembly: AssemblyProduct("MbGMusicSync")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c1acdbd8-6b22-4807-bba3-d0237ccd74c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.5.0.0")] 36 | [assembly: AssemblyFileVersion("1.5.0.0")] 37 | -------------------------------------------------------------------------------- /TestPlaylistCreation/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestPlaylistCreation")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestPlaylistCreation")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a1dd2d31-feb5-4cb8-a2e5-596517baf1e8")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MBGmusic/Plugin/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | 7 | namespace MusicBeePlugin 8 | { 9 | class Logger 10 | { 11 | private List> _log; 12 | 13 | public EventHandler OnLogUpdated; 14 | 15 | public static Logger Instance 16 | { 17 | get 18 | { 19 | if (_instance == null) 20 | _instance = new Logger(); 21 | return _instance; 22 | } 23 | } 24 | 25 | private static Logger _instance; 26 | 27 | private Logger() 28 | { 29 | _log = new List>(); 30 | logToFile = false; 31 | } 32 | 33 | private String _logFile; 34 | private bool logToFile; 35 | public String LogFile 36 | { 37 | get 38 | { 39 | return _logFile; 40 | } 41 | set 42 | { 43 | _logFile = value; 44 | logToFile = true; 45 | } 46 | } 47 | 48 | 49 | 50 | public void Log(string text) 51 | { 52 | _log.Add(new Tuple(DateTime.Now, text)); 53 | 54 | if (OnLogUpdated != null) 55 | OnLogUpdated(this, new EventArgs()); 56 | 57 | } 58 | 59 | public void DebugLog(string text) 60 | { 61 | if (logToFile) 62 | { 63 | using (StreamWriter w = File.AppendText(LogFile)) 64 | { 65 | w.WriteLine(text + "\r\n"); 66 | } 67 | } 68 | } 69 | 70 | public List> LogData { get { return _log; } } 71 | 72 | public string LastLog 73 | { 74 | get 75 | { 76 | if (_log.Count > 0) 77 | { 78 | return _log[_log.Count - 1].Item2; 79 | } 80 | else 81 | { 82 | return ""; 83 | } 84 | } 85 | } 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /MBGmusic/Plugin/PlaylistSync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using MusicBeePlugin.Models; 6 | using System.Threading; 7 | using GooglePlayMusicAPI; 8 | 9 | namespace MusicBeePlugin 10 | { 11 | class PlaylistSync 12 | { 13 | private Logger log; 14 | 15 | private Settings _settings; 16 | 17 | private Plugin.MusicBeeApiInterface _mbApiInterface; 18 | 19 | public PlaylistSync(Settings settings, Plugin.MusicBeeApiInterface mbApiInterface) 20 | { 21 | _settings = settings; 22 | 23 | _mbApiInterface = mbApiInterface; 24 | 25 | log = Logger.Instance; 26 | 27 | _gMusic = new GMusicSyncData(settings, mbApiInterface); 28 | _mbSync = new MbSyncData(settings, mbApiInterface); 29 | } 30 | 31 | private GMusicSyncData _gMusic; 32 | public GMusicSyncData GMusic { get { return _gMusic; } } 33 | 34 | private MbSyncData _mbSync; 35 | public MbSyncData MBSync { get { return _mbSync; } } 36 | 37 | /// 38 | /// This is blocking, so run it on a thread 39 | /// 40 | public async void SyncPlaylists() 41 | { 42 | if (!_gMusic.LoggedIn || _gMusic.SyncRunning) 43 | return; 44 | 45 | if (_settings.SyncLocalToRemote) 46 | { 47 | List playlists = new List(); 48 | List allPlaylists = _mbSync.GetMbPlaylists(); 49 | // Only sync the playlists that the settings say we should 50 | // Surely there's a nicer LINQ query for this? 51 | foreach (MbPlaylist pls in allPlaylists) 52 | { 53 | if (_settings.MBPlaylistsToSync.Contains(pls.mbName)) 54 | { 55 | playlists.Add(pls); 56 | } 57 | } 58 | _gMusic.SyncPlaylistsToGMusic(playlists); 59 | } 60 | else 61 | { 62 | if (_gMusic.DataFetched) 63 | { 64 | List playlists = new List(); 65 | foreach (string id in _settings.GMusicPlaylistsToSync) 66 | { 67 | Playlist pls = _gMusic.AllPlaylists.FirstOrDefault(p => p.ID == id); 68 | if (pls != null) 69 | playlists.Add(pls); 70 | } 71 | _mbSync.SyncPlaylistsToMusicBee(playlists, _gMusic.AllSongs); 72 | return; 73 | } else { 74 | return; 75 | } 76 | } 77 | 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /TestGMusicAPI/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TestGMusicAPI.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TestGMusicAPI.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /TestPlaylistCreation/TestMBApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {4D303419-70E9-4989-933D-9BDF8CBA87CA} 9 | Library 10 | Properties 11 | TestPlaylistCreation 12 | mb_TestPlaylistCreation 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Form 50 | 51 | 52 | TestWindow.cs 53 | 54 | 55 | 56 | 57 | TestWindow.cs 58 | 59 | 60 | 61 | 62 | copy /Y "$(TargetDir)\*.*" "C:\Program Files (x86)\MusicBee\Plugins\" 63 | 64 | 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Secret.cs 2 | packages/ 3 | 4 | ################# 5 | ## Eclipse 6 | ################# 7 | 8 | *.pydevproject 9 | .project 10 | .metadata 11 | bin/ 12 | tmp/ 13 | *.tmp 14 | *.bak 15 | *.swp 16 | *~.nib 17 | local.properties 18 | .classpath 19 | .settings/ 20 | .loadpath 21 | 22 | # External tool builders 23 | .externalToolBuilders/ 24 | 25 | # Locally stored "Eclipse launch configurations" 26 | *.launch 27 | 28 | # CDT-specific 29 | .cproject 30 | 31 | # PDT-specific 32 | .buildpath 33 | 34 | 35 | ################# 36 | ## Visual Studio 37 | ################# 38 | 39 | ## Ignore Visual Studio temporary files, build results, and 40 | ## files generated by popular Visual Studio add-ons. 41 | 42 | # User-specific files 43 | *.suo 44 | *.user 45 | *.sln.docstates 46 | 47 | # Build results 48 | 49 | [Dd]ebug/ 50 | [Rr]elease/ 51 | x64/ 52 | build/ 53 | [Bb]in/ 54 | [Oo]bj/ 55 | Secret.cs 56 | 57 | # MSTest test Results 58 | [Tt]est[Rr]esult*/ 59 | [Bb]uild[Ll]og.* 60 | 61 | *_i.c 62 | *_p.c 63 | *.ilk 64 | *.meta 65 | *.obj 66 | *.pch 67 | *.pdb 68 | *.pgc 69 | *.pgd 70 | *.rsp 71 | *.sbr 72 | *.tlb 73 | *.tli 74 | *.tlh 75 | *.tmp 76 | *.tmp_proj 77 | *.log 78 | *.vspscc 79 | *.vssscc 80 | .builds 81 | *.pidb 82 | *.log 83 | *.scc 84 | 85 | # Visual C++ cache files 86 | ipch/ 87 | *.aps 88 | *.ncb 89 | *.opensdf 90 | *.sdf 91 | *.cachefile 92 | 93 | # Visual Studio profiler 94 | *.psess 95 | *.vsp 96 | *.vspx 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | *.ncrunch* 113 | .*crunch*.local.xml 114 | 115 | # Installshield output folder 116 | [Ee]xpress/ 117 | 118 | # DocProject is a documentation generator add-in 119 | DocProject/buildhelp/ 120 | DocProject/Help/*.HxT 121 | DocProject/Help/*.HxC 122 | DocProject/Help/*.hhc 123 | DocProject/Help/*.hhk 124 | DocProject/Help/*.hhp 125 | DocProject/Help/Html2 126 | DocProject/Help/html 127 | 128 | # Click-Once directory 129 | publish/ 130 | 131 | # Publish Web Output 132 | *.Publish.xml 133 | *.pubxml 134 | *.publishproj 135 | 136 | # NuGet Packages Directory 137 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 138 | #packages/ 139 | 140 | # Windows Azure Build Output 141 | csx 142 | *.build.csdef 143 | 144 | # Windows Store app package directory 145 | AppPackages/ 146 | 147 | # Others 148 | sql/ 149 | *.Cache 150 | ClientBin/ 151 | [Ss]tyle[Cc]op.* 152 | ~$* 153 | *~ 154 | *.dbmdl 155 | *.[Pp]ublish.xml 156 | *.pfx 157 | *.publishsettings 158 | 159 | # RIA/Silverlight projects 160 | Generated_Code/ 161 | 162 | # Backup & report files from converting an old project file to a newer 163 | # Visual Studio version. Backup files are not needed, because we have git ;-) 164 | _UpgradeReport_Files/ 165 | Backup*/ 166 | UpgradeLog*.XML 167 | UpgradeLog*.htm 168 | 169 | # SQL Server files 170 | App_Data/*.mdf 171 | App_Data/*.ldf 172 | 173 | ############# 174 | ## Windows detritus 175 | ############# 176 | 177 | # Windows image file caches 178 | Thumbs.db 179 | ehthumbs.db 180 | 181 | # Folder config file 182 | Desktop.ini 183 | 184 | # Recycle Bin used on file shares 185 | $RECYCLE.BIN/ 186 | 187 | # Mac crap 188 | .DS_Store 189 | 190 | 191 | ############# 192 | ## Python 193 | ############# 194 | 195 | *.py[cod] 196 | 197 | # Packages 198 | *.egg 199 | *.egg-info 200 | dist/ 201 | build/ 202 | eggs/ 203 | parts/ 204 | var/ 205 | sdist/ 206 | develop-eggs/ 207 | .installed.cfg 208 | 209 | # Installer logs 210 | pip-log.txt 211 | 212 | # Unit test / coverage reports 213 | .coverage 214 | .tox 215 | 216 | #Translations 217 | *.mo 218 | 219 | #Mr Developer 220 | .mr.developer.cfg 221 | /packages/Mono.HttpUtility.1.0.0.1 222 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | MusicBee to Google Music Playlist Sync 2 | ====================================== 3 | 4 | This is a [MusicBee](http://getmusicbee.com) plugin designed to allow users to synchronise their local playlists to Google Play and a .NET API for the Google Play Music website. 5 | 6 | Warning 7 | ------- 8 | 9 | This plugin is in *ALPHA*. It has not been fully tested, and could do any number of things to your Google Music account. While I have used it to some extent on my own account without issues, there are many, many edge cases that I may have missed. Proceed with caution! *Don't use this if you value your Google Music playlists.* It may delete all of them. 10 | 11 | Plugin 12 | ------ 13 | 14 | ### Installation 15 | 16 | To just use the plugin, download the built DLLs from the "Plugin" directory. Place both included DLLs into the MusicBee\\Plugins directory 17 | 18 | ### Usage 19 | 20 | In MusicBee, Preferences -> Plugins, enable and click "Configure". 21 | 22 | Enter your login details in the box, select to Remember Login and click "Login". The text below the email box will indicate if you've been successful. 23 | 24 | The plugin attempts to fetch your Google Music library and playlists after logging in. If you have a big library, this might take a while. Once fetched, Google Music playlists will be shown in the right hand box. 25 | 26 | To synchronise your MusicBee playlists to Google Music, select the playlists you'd like to synchronise from the left hand list, ensure the "To Google Music" radio button is selected and click "Synchronise Selected". To synchronise from Google Music to your computer, select the remote playlists you'd like to copy to MusicBee. Ensure that the "From Google Music" radio button is selected and click "Synchronise Selected" Check the "Sync on Startup" box to synchronise every time you start MusicBee. This will synchronise with whatever settings you set before you close the window, and is only one way (based on the radio button selection). 27 | 28 | ### How it Works 29 | 30 | On logging in the plugin fetches a full list of songs and playlists tied to your Google Music account. It goes through each local playlist you wish to synchronise and looks for a playlist with the same name on Google Music. If it finds one, it deletes it and then creates a new playlist with the local playlist's name. For each song in the local playlist, the plugin attempts to match it with a remote song. Songs it can find remote matches for are placed into the new playlist in order. It silently skips those it can't match. 31 | 32 | When synchronising Remote to local, it checks for a local playlist with the same name as the remote one. If it exists, then it deletes the .m3u file that playlist is contained in, and recreates it as a blank text file. If it doesn't exist, it creates a new playlist with that name. It then attempts to match each song in the remote playlist with a song in the local library. If it finds a match, it adds it to the new playlist, otherwise it skips that song silently. 33 | 34 | ### Limitations 35 | 36 | 1. Error handling is awful. If something goes wrong in communicating with Google, it probably won't tell you in a meaningful way. 37 | 38 | 2. It deletes the contents of existing playlists with the same name. Without another level of complexity it's not clear what the best solution to this is. The remote playlist appears to have a "lastModified" tag attached to it, so it may be possible to use that and local playlist monitoring to determine which is the newer playlist, but it would probably be quite a lot of work. 39 | 40 | 3. It's fairly buggy. My MusicBee plugin abilities are limited! 41 | 42 | C#/.NET API For Google Play Music 43 | ---------------------------------- 44 | 45 | The plugin uses an incomplete implementation of an API for Google Play Music, [GooglePlayMusicApi](https://github.com/mitchhymel/GooglePlayMusicAPI), which is a port of the Python library, [gmusicapi](https://github.com/simon-weber/Unofficial-Google-Music-API) 46 | 47 | -------------------------------------------------------------------------------- /MBGmusicSync.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBGMusic", "MBGmusic\MBGMusic.csproj", "{F5D46BA1-6F21-40EF-9695-46105CCACD08}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestMBApi", "TestPlaylistCreation\TestMBApi.csproj", "{4D303419-70E9-4989-933D-9BDF8CBA87CA}" 9 | EndProject 10 | Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "MusicBee", "..\..\..\Program Files (x86)\MusicBee\MusicBee.exe", "{DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}" 11 | ProjectSection(DebuggerProjectSystem) = preProject 12 | PortSupplier = 00000000-0000-0000-0000-000000000000 13 | Executable = C:\Program Files (x86)\MusicBee\MusicBee.exe 14 | RemoteMachine = MH-BOXBOX 15 | StartingDirectory = C:\Program Files (x86)\MusicBee 16 | Environment = Default 17 | LaunchingEngine = 00000000-0000-0000-0000-000000000000 18 | UseLegacyDebugEngines = No 19 | LaunchSQLEngine = No 20 | AttachLaunchAction = No 21 | EndProjectSection 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Debug|Mixed Platforms = Debug|Mixed Platforms 27 | Debug|x86 = Debug|x86 28 | Release|Any CPU = Release|Any CPU 29 | Release|Mixed Platforms = Release|Mixed Platforms 30 | Release|x86 = Release|x86 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 36 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|Mixed Platforms.Build.0 = Debug|x86 37 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|x86.ActiveCfg = Debug|x86 38 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Debug|x86.Build.0 = Debug|x86 39 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|Mixed Platforms.ActiveCfg = Release|x86 42 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|Mixed Platforms.Build.0 = Release|x86 43 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|x86.ActiveCfg = Release|x86 44 | {F5D46BA1-6F21-40EF-9695-46105CCACD08}.Release|x86.Build.0 = Release|x86 45 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 48 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 49 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Debug|x86.ActiveCfg = Debug|Any CPU 50 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 53 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU 54 | {4D303419-70E9-4989-933D-9BDF8CBA87CA}.Release|x86.ActiveCfg = Release|Any CPU 55 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Debug|Any CPU.ActiveCfg = Release|x86 56 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Debug|Mixed Platforms.ActiveCfg = Release|x86 57 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Debug|x86.ActiveCfg = Release|x86 58 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Release|Any CPU.ActiveCfg = Release|x86 59 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Release|Mixed Platforms.ActiveCfg = Release|x86 60 | {DD3C2606-CAD7-4FD2-A53D-DD54F2200E1B}.Release|x86.ActiveCfg = Release|x86 61 | EndGlobalSection 62 | GlobalSection(SolutionProperties) = preSolution 63 | HideSolutionNode = FALSE 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /MBGmusic/Plugin/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | using System.Xml.Serialization; 7 | 8 | namespace MusicBeePlugin 9 | { 10 | [Serializable] 11 | public class Settings 12 | { 13 | public Settings(string filename) 14 | { 15 | 16 | MBPlaylistsToSync = new List(); 17 | GMusicPlaylistsToSync = new List(); 18 | 19 | // defaults 20 | SyncOnStartup = false; 21 | SyncLocalToRemote = true; 22 | 23 | PlaylistDirectory = "GMusic"; 24 | 25 | SettingsFile = filename; 26 | 27 | } 28 | 29 | public Settings() 30 | { 31 | MBPlaylistsToSync = new List(); 32 | GMusicPlaylistsToSync = new List(); 33 | } 34 | 35 | public String SettingsFile { get; set; } 36 | 37 | public Boolean SyncOnStartup { get; set; } 38 | public String AuthorizationToken { get; set; } 39 | public String Password { get; set; } 40 | public String Email { get; set; } 41 | public Boolean SaveCredentials { get; set; } 42 | public Boolean SyncLocalToRemote { get; set; } 43 | public List MBPlaylistsToSync { get; private set; } 44 | public List GMusicPlaylistsToSync { get; private set; } 45 | public String PlaylistDirectory { get; set; } 46 | 47 | public bool Save() 48 | { 49 | Settings.SaveSettings(this); 50 | return true; 51 | } 52 | 53 | public void Delete() 54 | { 55 | File.Delete(SettingsFile); 56 | /* 57 | try 58 | { 59 | // delete the config file 60 | 61 | return true; 62 | } 63 | catch 64 | { 65 | return false; 66 | }*/ 67 | } 68 | 69 | public static Settings ReadSettings(string filename) 70 | { 71 | if (File.Exists(filename)) 72 | { 73 | XmlSerializer controlsDefaultsSerializer = controlsDefaultsSerializer = new XmlSerializer(typeof(Settings)); 74 | 75 | FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None); 76 | StreamReader file = new StreamReader(stream, Encoding.UTF8); 77 | Settings settings = null; 78 | try 79 | { 80 | settings = (Settings)controlsDefaultsSerializer.Deserialize(file); 81 | } 82 | catch (Exception e) 83 | { 84 | Logger.Instance.Log("ERROR: Couldn't read saved settings"); 85 | Logger.Instance.DebugLog("ERROR: Couldn't read saved settings"); 86 | Logger.Instance.DebugLog(e.Message); 87 | return new Settings(filename); 88 | } 89 | finally 90 | { 91 | file.Close(); 92 | } 93 | settings.SettingsFile = filename; 94 | return settings; 95 | } 96 | else 97 | { 98 | return new Settings(filename); 99 | } 100 | } 101 | 102 | public static void SaveSettings(Settings settings) 103 | { 104 | try 105 | { 106 | using (FileStream cfgFile = File.Open(settings.SettingsFile, FileMode.Create, FileAccess.Write, FileShare.None)) 107 | { 108 | StreamWriter file = new StreamWriter(cfgFile, Encoding.UTF8); 109 | XmlSerializer controlsDefaultsSerializer = new XmlSerializer(typeof(Settings)); 110 | controlsDefaultsSerializer.Serialize(file, settings); 111 | file.Close(); 112 | } 113 | } 114 | catch 115 | { 116 | Logger.Instance.Log("ERROR: Couldn't save settings"); 117 | Logger.Instance.DebugLog("ERROR: Couldn't save settings"); 118 | } 119 | 120 | } 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /TestGMusicAPI/TestGMusicAPI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {D61BD1FC-DE73-40B5-91DF-D8E756FC752C} 9 | WinExe 10 | Properties 11 | TestGMusicAPI 12 | TestGMusicAPI 13 | v4.5 14 | 15 | 16 | 512 17 | 18 | 19 | x86 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | x86 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | false 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Form 54 | 55 | 56 | Form1.cs 57 | 58 | 59 | 60 | 61 | 62 | Form1.cs 63 | 64 | 65 | ResXFileCodeGenerator 66 | Resources.Designer.cs 67 | Designer 68 | 69 | 70 | True 71 | Resources.resx 72 | True 73 | 74 | 75 | 76 | SettingsSingleFileGenerator 77 | Settings.Designer.cs 78 | 79 | 80 | True 81 | Settings.settings 82 | True 83 | 84 | 85 | 86 | 87 | {F5D46BA1-6F21-40EF-9695-46105CCACD08} 88 | MBGMusic 89 | 90 | 91 | 92 | 99 | -------------------------------------------------------------------------------- /TestPlaylistCreation/TestWindow.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace TestPlaylistCreation 2 | { 3 | partial class TestWindow 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.CreatePlaylist_button = new System.Windows.Forms.Button(); 32 | this.CreatePlaylistDirectory_tb = new System.Windows.Forms.TextBox(); 33 | this.label1 = new System.Windows.Forms.Label(); 34 | this.label2 = new System.Windows.Forms.Label(); 35 | this.CreatePlaylistName_tb = new System.Windows.Forms.TextBox(); 36 | this.SuspendLayout(); 37 | // 38 | // CreatePlaylist_button 39 | // 40 | this.CreatePlaylist_button.Location = new System.Drawing.Point(255, 64); 41 | this.CreatePlaylist_button.Name = "CreatePlaylist_button"; 42 | this.CreatePlaylist_button.Size = new System.Drawing.Size(139, 23); 43 | this.CreatePlaylist_button.TabIndex = 0; 44 | this.CreatePlaylist_button.Text = "Create Playlist"; 45 | this.CreatePlaylist_button.UseVisualStyleBackColor = true; 46 | this.CreatePlaylist_button.Click += new System.EventHandler(this.CreatePlaylist_button_Click); 47 | // 48 | // CreatePlaylistDirectory_tb 49 | // 50 | this.CreatePlaylistDirectory_tb.Location = new System.Drawing.Point(108, 12); 51 | this.CreatePlaylistDirectory_tb.Name = "CreatePlaylistDirectory_tb"; 52 | this.CreatePlaylistDirectory_tb.Size = new System.Drawing.Size(286, 20); 53 | this.CreatePlaylistDirectory_tb.TabIndex = 1; 54 | // 55 | // label1 56 | // 57 | this.label1.AutoSize = true; 58 | this.label1.Location = new System.Drawing.Point(53, 15); 59 | this.label1.Name = "label1"; 60 | this.label1.Size = new System.Drawing.Size(49, 13); 61 | this.label1.TabIndex = 2; 62 | this.label1.Text = "Directory"; 63 | // 64 | // label2 65 | // 66 | this.label2.AutoSize = true; 67 | this.label2.Location = new System.Drawing.Point(67, 41); 68 | this.label2.Name = "label2"; 69 | this.label2.Size = new System.Drawing.Size(35, 13); 70 | this.label2.TabIndex = 4; 71 | this.label2.Text = "Name"; 72 | // 73 | // CreatePlaylistName_tb 74 | // 75 | this.CreatePlaylistName_tb.Location = new System.Drawing.Point(108, 38); 76 | this.CreatePlaylistName_tb.Name = "CreatePlaylistName_tb"; 77 | this.CreatePlaylistName_tb.Size = new System.Drawing.Size(286, 20); 78 | this.CreatePlaylistName_tb.TabIndex = 3; 79 | // 80 | // TestWindow 81 | // 82 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 83 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 84 | this.ClientSize = new System.Drawing.Size(406, 315); 85 | this.Controls.Add(this.label2); 86 | this.Controls.Add(this.CreatePlaylistName_tb); 87 | this.Controls.Add(this.label1); 88 | this.Controls.Add(this.CreatePlaylistDirectory_tb); 89 | this.Controls.Add(this.CreatePlaylist_button); 90 | this.Name = "TestWindow"; 91 | this.Text = "TestWindow"; 92 | this.ResumeLayout(false); 93 | this.PerformLayout(); 94 | 95 | } 96 | 97 | #endregion 98 | 99 | private System.Windows.Forms.Button CreatePlaylist_button; 100 | private System.Windows.Forms.TextBox CreatePlaylistDirectory_tb; 101 | private System.Windows.Forms.Label label1; 102 | private System.Windows.Forms.Label label2; 103 | private System.Windows.Forms.TextBox CreatePlaylistName_tb; 104 | } 105 | } -------------------------------------------------------------------------------- /TestGMusicAPI/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using MusicBeePlugin; 10 | using MusicBeePlugin.GMusicAPI; 11 | using MusicBeePlugin.Models; 12 | 13 | namespace TestGMusicAPI 14 | { 15 | public partial class Form1 : Form 16 | { 17 | private List AllPlaylists = new List(); 18 | private List AllSongs = new List(); 19 | private List AllEntries = new List(); 20 | 21 | API api = new API(); 22 | APIOAuth apiOauth = new APIOAuth(); 23 | 24 | public Form1() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | private async void loginButton_Click(object sender, EventArgs e) 30 | { 31 | bool loggedIn = await apiOauth.LoginAsync(Secret.USERNAME, Secret.PASSWORD); 32 | this.statusLabel.Text = String.Format("Login Status: {0}", loggedIn); 33 | } 34 | 35 | private async void getTracksButton_Click(object sender, EventArgs e) 36 | { 37 | List library = await apiOauth.GetLibraryAsync(); 38 | AllSongs = library; 39 | foreach(GMusicSong song in library) 40 | { 41 | songListBox.Items.Add(song); 42 | } 43 | 44 | songTotalLabel.Text = String.Format("Total songs: {0}", library.Count); 45 | } 46 | 47 | #region Get playlists 48 | // Get all the playlists tied to this account and display them 49 | 50 | private async void getPlaylistsButton_Click(object sender, EventArgs e) 51 | { 52 | List playlists = await apiOauth.GetPlaylistsWithEntriesAsync(); 53 | AllPlaylists = playlists; 54 | playlistListBox.Items.Clear(); 55 | foreach (GMusicPlaylist playlist in playlists) 56 | { 57 | playlistListBox.Items.Add(playlist); 58 | } 59 | } 60 | 61 | #endregion 62 | 63 | #region Create playlists 64 | private async void createPlaylistButton_Click(object sender, EventArgs e) 65 | { 66 | await apiOauth.CreatePlaylistAsync(createPlaylistName.Text); 67 | getPlaylistsButton.PerformClick(); 68 | } 69 | 70 | #endregion 71 | 72 | #region Delete playlist 73 | // Deletes the playlist currently selected by the user 74 | private async void deletePlaylistButton_Click(object sender, EventArgs e) 75 | { 76 | GMusicPlaylist selectedPlaylist = (GMusicPlaylist)playlistListBox.SelectedItem; 77 | await apiOauth.DeletePlaylistAsync(selectedPlaylist.ID); 78 | getPlaylistsButton.PerformClick(); 79 | } 80 | 81 | #endregion 82 | 83 | #region Modify playlists 84 | private async void addSongsButton_Click(object sender, EventArgs e) 85 | { 86 | ListBox.SelectedObjectCollection songsSelected = songListBox.SelectedItems; 87 | List songsList = new List(); 88 | foreach (GMusicSong song in songsSelected) 89 | songsList.Add(song); 90 | 91 | GMusicPlaylist selectedPlaylist = (GMusicPlaylist)playlistListBox.SelectedItem; 92 | 93 | await apiOauth.AddToPlaylistAsync(selectedPlaylist.ID, songsList); 94 | getPlaylistsButton.PerformClick(); 95 | 96 | } 97 | 98 | // This could delete multiple selections at once, but it doesn't 99 | private async void deleteSong_Click(object sender, EventArgs e) 100 | { 101 | GMusicSong selectedSong = (GMusicSong)playlistSongsBox.SelectedItem; 102 | GMusicPlaylist selectedPlaylist = (GMusicPlaylist)playlistListBox.SelectedItem; 103 | GMusicPlaylistEntry songEntry = selectedPlaylist.Songs.First(s => s.TrackID == selectedSong.ID); 104 | await apiOauth.RemoveFromPlaylistAsync(new List { songEntry }); 105 | } 106 | 107 | #endregion 108 | 109 | #region Update playlist songs 110 | private void playlistListBox_SelectedIndexChanged(object sender, EventArgs e) 111 | { 112 | playlistSongsBox.Items.Clear(); 113 | GMusicPlaylist selectedPlaylist = (GMusicPlaylist)playlistListBox.SelectedItem; 114 | foreach (GMusicPlaylistEntry song in selectedPlaylist.Songs) 115 | { 116 | if (!song.Deleted) 117 | { 118 | GMusicSong thisSong = AllSongs.FirstOrDefault(s => s.ID == song.TrackID); 119 | if (thisSong != null) 120 | { 121 | playlistSongsBox.Items.Add(thisSong); 122 | } 123 | } 124 | } 125 | } 126 | 127 | #endregion 128 | 129 | private async void renameButton_Click(object sender, EventArgs e) 130 | { 131 | GMusicPlaylist selectedPlaylist = (GMusicPlaylist)playlistListBox.SelectedItem; 132 | await apiOauth.UpdatePlaylistAsync(selectedPlaylist.ID, renamePlaylistTextBox.Text, description:"test test new description test"); 133 | getPlaylistsButton.PerformClick(); 134 | } 135 | 136 | 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /TestGMusicAPI/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /MBGmusic/Configure.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /TestPlaylistCreation/TestWindow.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /TestPlaylistCreation/MBTestAPIPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.IO; 9 | using System.Text; 10 | using TestPlaylistCreation; 11 | 12 | namespace MusicBeePlugin 13 | { 14 | public partial class Plugin 15 | { 16 | 17 | public MusicBeeApiInterface mbApiInterface; 18 | 19 | private PluginInfo about = new PluginInfo(); 20 | 21 | #region Plugin Exported Methods 22 | 23 | public PluginInfo Initialise(IntPtr apiInterfacePtr) 24 | { 25 | mbApiInterface = new MusicBeeApiInterface(); 26 | mbApiInterface.Initialise(apiInterfacePtr); 27 | about.PluginInfoVersion = PluginInfoVersion; 28 | about.Name = "MB Test API Plugin"; 29 | about.Description = "Quickly test API functionality"; 30 | about.Author = "Leo Rampen"; 31 | about.TargetApplication = "None"; // current only applies to artwork, lyrics or instant messenger name that appears in the provider drop down selector or target Instant Messenger 32 | about.Type = PluginType.General; 33 | about.VersionMajor = 1; // your plugin version 34 | about.VersionMinor = 1; 35 | about.Revision = 1; 36 | about.MinInterfaceVersion = MinInterfaceVersion; 37 | about.MinApiRevision = MinApiRevision; 38 | about.ReceiveNotifications = (ReceiveNotificationFlags.PlayerEvents | ReceiveNotificationFlags.TagEvents); 39 | about.ConfigurationPanelHeight = 0; // not implemented yet: height in pixels that musicbee should reserve in a panel for config settings. When set, a handle to an empty panel will be passed to the Configure function 40 | 41 | 42 | // Comment this out to disable logging 43 | // Logger.Instance.LogFile = System.IO.Path.Combine(mbApiInterface.Setting_GetPersistentStoragePath(), "gMusicPlaylistSync.log.txt"); 44 | 45 | createMenu(); 46 | 47 | return about; 48 | } 49 | 50 | private TestWindow _testWindow; 51 | 52 | public bool Configure(IntPtr panelHandle) 53 | { 54 | 55 | int backColor = mbApiInterface.Setting_GetSkinElementColour(SkinElement.SkinInputControl, ElementState.ElementStateDefault, 56 | ElementComponent.ComponentBackground); 57 | int foreColor = mbApiInterface.Setting_GetSkinElementColour(SkinElement.SkinInputControl, ElementState.ElementStateDefault, 58 | ElementComponent.ComponentForeground); 59 | 60 | return false; 61 | } 62 | 63 | private void createMenu() 64 | { 65 | mbApiInterface.MB_AddMenuItem("mnuTools/Test MB API Plugin", "", onMenuItemClick); 66 | } 67 | 68 | private void onMenuItemClick(object sender, EventArgs e) 69 | { 70 | if (_testWindow != null) 71 | { 72 | _testWindow.Dispose(); 73 | _testWindow = null; 74 | } 75 | 76 | _testWindow = new TestWindow(mbApiInterface); 77 | 78 | _testWindow.Show(); 79 | } 80 | 81 | // called by MusicBee when the user clicks Apply or Save in the MusicBee Preferences screen. 82 | // its up to you to figure out whether anything has changed and needs updating 83 | public void SaveSettings() 84 | { 85 | } 86 | 87 | // MusicBee is closing the plugin (plugin is being disabled by user or MusicBee is shutting down) 88 | public void Close(PluginCloseReason reason) 89 | { 90 | } 91 | 92 | 93 | 94 | // uninstall this plugin - clean up any persisted files 95 | public void Uninstall() 96 | { 97 | } 98 | 99 | 100 | // receive event notifications from MusicBee 101 | // you need to set about.ReceiveNotificationFlags = PlayerEvents to receive all notifications, and not just the startup event 102 | public void ReceiveNotification(string sourceFileUrl, NotificationType type) 103 | { 104 | // perform some action depending on the notification type 105 | switch (type) 106 | { 107 | case NotificationType.PluginStartup: 108 | // Do a sync straight after we get the playlists 109 | /* 110 | if (SavedSettings.syncOnStartup) 111 | { 112 | OnFetchDataComplete = SyncPlaylists; 113 | LoginToGMusic(); 114 | }*/ 115 | 116 | break; 117 | } 118 | } 119 | 120 | // return an array of lyric or artwork provider names this plugin supports 121 | // the providers will be iterated through one by one and passed to the RetrieveLyrics/ RetrieveArtwork function in order set by the user in the MusicBee Tags(2) preferences screen until a match is found 122 | public string[] GetProviders() 123 | { 124 | return null; 125 | } 126 | 127 | // return lyrics for the requested artist/title from the requested provider 128 | // only required if PluginType = LyricsRetrieval 129 | // return null if no lyrics are found 130 | public string RetrieveLyrics(string sourceFileUrl, string artist, string trackTitle, string album, bool synchronisedPreferred, string provider) 131 | { 132 | return null; 133 | } 134 | 135 | // return Base64 string representation of the artwork binary data from the requested provider 136 | // only required if PluginType = ArtworkRetrieval 137 | // return null if no artwork is found 138 | public string RetrieveArtwork(string sourceFileUrl, string albumArtist, string album, string provider) 139 | { 140 | //Return Convert.ToBase64String(artworkBinaryData) 141 | return null; 142 | } 143 | 144 | #endregion 145 | 146 | } 147 | } -------------------------------------------------------------------------------- /MBGmusic/Plugin/GMusicSyncData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using MusicBeePlugin.Models; 7 | using System.Threading.Tasks; 8 | using GooglePlayMusicAPI; 9 | 10 | namespace MusicBeePlugin 11 | { 12 | class GMusicSyncData 13 | { 14 | private Settings _settings; 15 | 16 | private Logger log; 17 | 18 | private Plugin.MusicBeeApiInterface _mbApiInterface; 19 | 20 | public GMusicSyncData(Settings settings, Plugin.MusicBeeApiInterface mbApiInterface) 21 | { 22 | _allPlaylists = new List(); 23 | _allSongs = new List(); 24 | 25 | _settings = settings; 26 | 27 | _syncRunning = false; 28 | 29 | log = Logger.Instance; 30 | 31 | _mbApiInterface = mbApiInterface; 32 | } 33 | 34 | private List _allPlaylists; 35 | public List AllPlaylists { get { return _allPlaylists; } } 36 | 37 | private List _allSongs; 38 | public List AllSongs { get { return _allSongs; } } 39 | 40 | 41 | 42 | private Boolean _syncRunning; 43 | public Boolean SyncRunning { get { return _syncRunning; } } 44 | 45 | private Boolean _dataFetched; 46 | public Boolean DataFetched { get { return _dataFetched; } } 47 | 48 | public Boolean LoggedIn { get { return api.LoggedIn(); } } 49 | 50 | #region Logging in 51 | 52 | public async Task LoginToGMusic(string email, string password) 53 | { 54 | bool result = await api.LoginAsync(email, password); 55 | FetchLibraryAndPlaylists(); 56 | return result; 57 | } 58 | 59 | #endregion 60 | 61 | #region Fetch GMusic Information 62 | 63 | // The global-ish stuff we need to sync with Google Music 64 | private GooglePlayMusicClient api = new GooglePlayMusicClient(); 65 | 66 | public async void FetchLibraryAndPlaylists() 67 | { 68 | _allSongs = await api.GetLibraryAsync(); 69 | _allPlaylists = await api.GetPlaylistsWithEntriesAsync(); 70 | _dataFetched = true; 71 | } 72 | 73 | public async Task> FetchLibrary() 74 | { 75 | _allSongs = await api.GetLibraryAsync(); 76 | return _allSongs; 77 | } 78 | 79 | public async Task> FetchPlaylists() 80 | { 81 | _allPlaylists = await api.GetPlaylistsWithEntriesAsync(); 82 | return _allPlaylists; 83 | } 84 | 85 | #endregion 86 | 87 | #region Sync to GMusic 88 | 89 | // Synchronise the playlists defined in the settings file to Google Music 90 | public async void SyncPlaylistsToGMusic(List mbPlaylistsToSync) 91 | { 92 | _syncRunning = true; 93 | AutoResetEvent waitForEvent = new AutoResetEvent(false); 94 | 95 | if (_dataFetched) 96 | { 97 | // Get the MusicBee playlists 98 | foreach (MbPlaylist playlist in mbPlaylistsToSync) 99 | { 100 | // Use LINQ to check for a playlist with the same name 101 | // If there is one, clear it's contents, otherwise create one 102 | // Unless it's been deleted, in which case pretend it doesn't exist. 103 | // I'm not sure how to undelete a playlist, or even if you can 104 | Playlist thisPlaylist = _allPlaylists.FirstOrDefault(p => p.Name == playlist.Name && p.Deleted == false); 105 | String thisPlaylistID = ""; 106 | if (thisPlaylist != null) 107 | { 108 | List allPlsSongs = thisPlaylist.Songs; 109 | 110 | if (allPlsSongs.Count > 0) 111 | { 112 | MutatePlaylistResponse response = await api.RemoveFromPlaylistAsync(allPlsSongs); 113 | } 114 | thisPlaylistID = thisPlaylist.ID; 115 | } 116 | else 117 | { 118 | MutatePlaylistResponse response = await api.CreatePlaylistAsync(playlist.Name); 119 | thisPlaylistID = response.MutateResponses.First().ID; 120 | } 121 | 122 | // Create a list of files based on the MB Playlist 123 | string[] playlistFiles = null; 124 | if (_mbApiInterface.Playlist_QueryFiles(playlist.mbName)) 125 | { 126 | bool success = _mbApiInterface.Playlist_QueryFilesEx(playlist.mbName, ref playlistFiles); 127 | if (!success) 128 | throw new Exception("Couldn't get playlist files"); 129 | } 130 | else 131 | { 132 | playlistFiles = new string[0]; 133 | } 134 | 135 | List songsToAdd = new List(); 136 | // And get the title and artist of each file, and add it to the GMusic playlist 137 | foreach (string file in playlistFiles) 138 | { 139 | string title = _mbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.TrackTitle); 140 | string artist = _mbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.Artist); 141 | Track gSong = _allSongs.FirstOrDefault(item => (item.Artist == artist && item.Title == title)); 142 | if (gSong != null) 143 | songsToAdd.Add(gSong); 144 | } 145 | 146 | await api.AddToPlaylistAsync(thisPlaylistID, songsToAdd); 147 | } 148 | 149 | _syncRunning = false; 150 | 151 | } 152 | else 153 | { 154 | throw new Exception("Not fetched data yet"); 155 | } 156 | 157 | 158 | } 159 | 160 | #endregion 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /TestGMusicAPI/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 133, 17 125 | 126 | -------------------------------------------------------------------------------- /MBGmusic/Plugin/MBGmusicPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.IO; 9 | using System.Text; 10 | 11 | namespace MusicBeePlugin 12 | { 13 | public partial class Plugin 14 | { 15 | 16 | public MusicBeeApiInterface mbApiInterface; 17 | 18 | private PluginInfo about = new PluginInfo(); 19 | 20 | #region Plugin Exported Methods 21 | 22 | public PluginInfo Initialise(IntPtr apiInterfacePtr) 23 | { 24 | mbApiInterface = new MusicBeeApiInterface(); 25 | mbApiInterface.Initialise(apiInterfacePtr); 26 | about.PluginInfoVersion = PluginInfoVersion; 27 | about.Name = "Google Music Sync"; 28 | about.Description = "Sync your playlists to Google Play Music."; 29 | about.Author = "Leo Rampen"; 30 | about.TargetApplication = "None"; // current only applies to artwork, lyrics or instant messenger name that appears in the provider drop down selector or target Instant Messenger 31 | about.Type = PluginType.General; 32 | about.VersionMajor = 1; // your plugin version 33 | about.VersionMinor = 7; 34 | about.Revision = 1; 35 | about.MinInterfaceVersion = MinInterfaceVersion; 36 | about.MinApiRevision = MinApiRevision; 37 | about.ReceiveNotifications = (ReceiveNotificationFlags.PlayerEvents | ReceiveNotificationFlags.TagEvents); 38 | about.ConfigurationPanelHeight = 0; // not implemented yet: height in pixels that musicbee should reserve in a panel for config settings. When set, a handle to an empty panel will be passed to the Configure function 39 | 40 | 41 | // Comment this out to disable logging 42 | // Logger.Instance.LogFile = System.IO.Path.Combine(mbApiInterface.Setting_GetPersistentStoragePath(), "gMusicPlaylistSync.log.txt"); 43 | 44 | createMenu(); 45 | 46 | Logger.Instance.DebugLog("Getting settings"); 47 | // Process taken from tag tools 48 | //Lets try to read defaults for controls from settings file 49 | string configFilePath = System.IO.Path.Combine(mbApiInterface.Setting_GetPersistentStoragePath(), "gMusicPlaylistSync.Settings.xml"); 50 | _settings = Settings.ReadSettings(configFilePath); 51 | 52 | Logger.Instance.DebugLog("Creating PlaylistSync object"); 53 | 54 | _playlistSync = new PlaylistSync(_settings, mbApiInterface); 55 | 56 | return about; 57 | } 58 | 59 | private Settings _settings; 60 | private PlaylistSync _playlistSync; 61 | Configure _configureForm; 62 | 63 | public bool Configure(IntPtr panelHandle) 64 | { 65 | 66 | int backColor = mbApiInterface.Setting_GetSkinElementColour(SkinElement.SkinInputControl, ElementState.ElementStateDefault, 67 | ElementComponent.ComponentBackground); 68 | int foreColor = mbApiInterface.Setting_GetSkinElementColour(SkinElement.SkinInputControl, ElementState.ElementStateDefault, 69 | ElementComponent.ComponentForeground); 70 | 71 | return false; 72 | } 73 | 74 | private void createMenu() 75 | { 76 | Logger.Instance.DebugLog("Adding menu"); 77 | mbApiInterface.MB_AddMenuItem("mnuTools/Google Music Playlist Sync", "", onMenuItemClick); 78 | } 79 | 80 | private void onMenuItemClick(object sender, EventArgs e) 81 | { 82 | Logger.Instance.DebugLog("Opening config window"); 83 | if (_configureForm != null) 84 | { 85 | _configureForm.Dispose(); 86 | _configureForm = null; 87 | } 88 | 89 | _configureForm = new Configure(_playlistSync, _settings, mbApiInterface); 90 | 91 | _configureForm.Show(); 92 | } 93 | 94 | // called by MusicBee when the user clicks Apply or Save in the MusicBee Preferences screen. 95 | // its up to you to figure out whether anything has changed and needs updating 96 | public void SaveSettings() 97 | { 98 | _settings.Save(); 99 | } 100 | 101 | // MusicBee is closing the plugin (plugin is being disabled by user or MusicBee is shutting down) 102 | public void Close(PluginCloseReason reason) 103 | { 104 | } 105 | 106 | 107 | // uninstall this plugin - clean up any persisted files 108 | public void Uninstall() 109 | { 110 | _settings.Delete(); 111 | } 112 | 113 | 114 | // receive event notifications from MusicBee 115 | // you need to set about.ReceiveNotificationFlags = PlayerEvents to receive all notifications, and not just the startup event 116 | public void ReceiveNotification(string sourceFileUrl, NotificationType type) 117 | { 118 | // perform some action depending on the notification type 119 | switch (type) 120 | { 121 | case NotificationType.PluginStartup: 122 | // Do a sync straight after we get the playlists 123 | /* 124 | if (SavedSettings.syncOnStartup) 125 | { 126 | OnFetchDataComplete = SyncPlaylists; 127 | LoginToGMusic(); 128 | }*/ 129 | 130 | break; 131 | } 132 | } 133 | 134 | // return an array of lyric or artwork provider names this plugin supports 135 | // the providers will be iterated through one by one and passed to the RetrieveLyrics/ RetrieveArtwork function in order set by the user in the MusicBee Tags(2) preferences screen until a match is found 136 | public string[] GetProviders() 137 | { 138 | return null; 139 | } 140 | 141 | // return lyrics for the requested artist/title from the requested provider 142 | // only required if PluginType = LyricsRetrieval 143 | // return null if no lyrics are found 144 | public string RetrieveLyrics(string sourceFileUrl, string artist, string trackTitle, string album, bool synchronisedPreferred, string provider) 145 | { 146 | return null; 147 | } 148 | 149 | // return Base64 string representation of the artwork binary data from the requested provider 150 | // only required if PluginType = ArtworkRetrieval 151 | // return null if no artwork is found 152 | public string RetrieveArtwork(string sourceFileUrl, string albumArtist, string album, string provider) 153 | { 154 | //Return Convert.ToBase64String(artworkBinaryData) 155 | return null; 156 | } 157 | 158 | #endregion 159 | 160 | } 161 | } -------------------------------------------------------------------------------- /MBGmusic/Plugin/MbSyncData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using MusicBeePlugin.Models; 6 | using System.IO; 7 | using GooglePlayMusicAPI; 8 | 9 | namespace MusicBeePlugin 10 | { 11 | class MbSyncData 12 | { 13 | private Settings _settings; 14 | 15 | private Logger log; 16 | 17 | private Plugin.MusicBeeApiInterface _mbApiInterface; 18 | 19 | public EventHandler OnSyncComplete; 20 | 21 | public MbSyncData(Settings settings, Plugin.MusicBeeApiInterface mbApiInterface) 22 | { 23 | _settings = settings; 24 | 25 | log = Logger.Instance; 26 | 27 | _mbApiInterface = mbApiInterface; 28 | } 29 | 30 | //Taken from TagTools AdvanceSearchandReplace.cs #720 31 | // In MB you run a query and then fetch the results 32 | // First, we query the library for all the playlists. 33 | // For each playlist, we fetch all its files. 34 | public List GetMbPlaylists() 35 | { 36 | List MbPlaylists = new List(); 37 | _mbApiInterface.Playlist_QueryPlaylists(); 38 | string playlist = _mbApiInterface.Playlist_QueryGetNextPlaylist(); 39 | while (playlist != null) 40 | { 41 | string playlistName = _mbApiInterface.Playlist_GetName(playlist); 42 | MbPlaylist MbPlaylist = new MbPlaylist(); 43 | MbPlaylist.mbName = playlist; 44 | MbPlaylist.Name = playlistName; 45 | 46 | MbPlaylists.Add(MbPlaylist); 47 | 48 | // Query the next mbPlaylist to start again 49 | playlist = _mbApiInterface.Playlist_QueryGetNextPlaylist(); 50 | } 51 | 52 | return MbPlaylists; 53 | } 54 | 55 | public List GetMbSongs() 56 | { 57 | string[] files = null; 58 | List allMbSongs = new List(); 59 | 60 | if (_mbApiInterface.Library_QueryFiles("domain=library")) 61 | { 62 | // Old (deprecated) 63 | //public char[] filesSeparators = { '\0' }; 64 | //files = _mbApiInterface.Library_QueryGetAllFiles().Split(filesSeparators, StringSplitOptions.RemoveEmptyEntries); 65 | _mbApiInterface.Library_QueryFilesEx("domain=library", ref files); 66 | } 67 | else 68 | { 69 | files = new string[0]; 70 | } 71 | 72 | foreach (string path in files) 73 | { 74 | MbSong thisSong = new MbSong(); 75 | thisSong.Filename = path; 76 | thisSong.Artist = _mbApiInterface.Library_GetFileTag(path, Plugin.MetaDataType.Artist); 77 | thisSong.Title = _mbApiInterface.Library_GetFileTag(path, Plugin.MetaDataType.TrackTitle); 78 | allMbSongs.Add(thisSong); 79 | } 80 | return allMbSongs; 81 | } 82 | 83 | 84 | // Go through the selected playlists from GMusic, 85 | // delete the correspondingly named MusicBee playlist 86 | // Create a new playlist with the GMusic playlist contents 87 | public void SyncPlaylistsToMusicBee(List playlists, List allGMusicSongs) 88 | { 89 | 90 | // The API doesn't give us a directory for playlists, 91 | // We need to guess by finding the root directory of the first playlist 92 | /* Apparently playlistDir = "" is "root" playlist dir, so this is unneeded. 93 | MbPlaylist useForDir = localPlaylists.First(); 94 | String playlistDir = new FileInfo(useForDir.mbName).DirectoryName; 95 | if (useForDir.Name.Contains('\\')) 96 | { 97 | String folder = useForDir.Name.Split('\\')[0]; 98 | playlistDir = playlistDir.Replace(folder, ""); 99 | }*/ 100 | 101 | List localPlaylists = GetMbPlaylists(); 102 | List allMbSongs = GetMbSongs(); 103 | 104 | // Go through each playlist we want to sync in turn 105 | foreach (Playlist playlist in playlists) 106 | { 107 | // Create an empty list for this playlist's local songs 108 | List mbPlaylistSongs = new List(); 109 | 110 | // For each entry in the playlist we're syncing, get the song from the GMusic library we've downloaded, 111 | // Get the song Title and Artist and then look it up in the list of local songs. 112 | // If we find it, add it to the list of local songs 113 | foreach (PlaylistEntry entry in playlist.Songs) 114 | { 115 | Track thisSong = allGMusicSongs.FirstOrDefault(s => s.ID == entry.TrackID); 116 | if (thisSong != null) 117 | { 118 | MbSong thisMbSong = allMbSongs.FirstOrDefault(s => s.Artist == thisSong.Artist && s.Title == thisSong.Title); 119 | if (thisMbSong != null) 120 | mbPlaylistSongs.Add(thisMbSong); 121 | } 122 | } 123 | 124 | //mbAPI expects a string array of song filenames to create a playlist 125 | string[] mbPlaylistSongFiles = new string[mbPlaylistSongs.Count]; 126 | int i = 0; 127 | foreach (MbSong song in mbPlaylistSongs) 128 | { 129 | mbPlaylistSongFiles[i] = song.Filename; 130 | i++; 131 | } 132 | // Now we need to either clear (by deleting and recreating the file) or create the playlist 133 | MbPlaylist localPlaylist = localPlaylists.FirstOrDefault(p => p.Name == playlist.Name); 134 | if (localPlaylist != null) 135 | { 136 | string playlistPath = localPlaylist.mbName; 137 | // delete the local playlist 138 | File.Delete(playlistPath); 139 | // And create a new empty file in its place 140 | File.Create(playlistPath).Dispose(); 141 | 142 | // Set all our new files into the playlist 143 | _mbApiInterface.Playlist_SetFiles(localPlaylist.mbName, mbPlaylistSongFiles); 144 | } 145 | else 146 | { 147 | // Create the playlist 148 | _mbApiInterface.Playlist_CreatePlaylist("", playlist.Name, mbPlaylistSongFiles); 149 | // I haven't been able to get a playlist to be created in a directory yet 150 | // For now, don't give that option 151 | // _mbApiInterface.Playlist_CreatePlaylist(_settings.PlaylistDirectory, playlist.Name, mbPlaylistSongFiles); 152 | } 153 | } 154 | 155 | // Get the local playlists again 156 | 157 | // Call the delegate 158 | if (OnSyncComplete != null) 159 | OnSyncComplete(this, new EventArgs()); 160 | } 161 | 162 | 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /MBGmusic/MBGmusic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {F5D46BA1-6F21-40EF-9695-46105CCACD08} 9 | Library 10 | Properties 11 | MusicBeePlugin 12 | mb_GoogleMusicSync 13 | v4.5.2 14 | 512 15 | 16 | 17 | 3.5 18 | 19 | publish\ 20 | true 21 | Disk 22 | false 23 | Foreground 24 | 7 25 | Days 26 | false 27 | false 28 | true 29 | 0 30 | 1.0.0.%2a 31 | false 32 | false 33 | true 34 | 35 | 36 | 37 | true 38 | full 39 | false 40 | bin\Debug\ 41 | DEBUG;TRACE 42 | prompt 43 | 4 44 | false 45 | 46 | 47 | pdbonly 48 | true 49 | bin\Release\ 50 | TRACE 51 | prompt 52 | 4 53 | false 54 | 55 | 56 | true 57 | bin\x86\Debug\ 58 | DEBUG;TRACE 59 | full 60 | x86 61 | prompt 62 | true 63 | true 64 | false 65 | 66 | 67 | bin\x86\Release\ 68 | TRACE 69 | true 70 | pdbonly 71 | x86 72 | prompt 73 | false 74 | false 75 | false 76 | 77 | 78 | 79 | ..\packages\GooglePlayMusicAPI.1.1.0\lib\net452\GooglePlayMusicAPI.dll 80 | True 81 | 82 | 83 | ..\packages\Mono.HttpUtility.1.0.0.1\lib\net40\Mono.HttpUtility.dll 84 | True 85 | 86 | 87 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 88 | True 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Form 110 | 111 | 112 | Configure.cs 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | Designer 121 | 122 | 123 | Designer 124 | 125 | 126 | 127 | 128 | False 129 | Microsoft .NET Framework 4 %28x86 and x64%29 130 | true 131 | 132 | 133 | False 134 | .NET Framework 3.5 SP1 Client Profile 135 | false 136 | 137 | 138 | False 139 | .NET Framework 3.5 SP1 140 | false 141 | 142 | 143 | False 144 | Windows Installer 3.1 145 | true 146 | 147 | 148 | 149 | 150 | Configure.cs 151 | 152 | 153 | 154 | 155 | 156 | copy /Y "$(TargetDir)\*.*" "C:\Program Files (x86)\MusicBee\Plugins\" 157 | 158 | 165 | -------------------------------------------------------------------------------- /TestGMusicAPI/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace TestGMusicAPI 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.loginButton = new System.Windows.Forms.Button(); 33 | this.getTracksButton = new System.Windows.Forms.Button(); 34 | this.getPlaylistsButton = new System.Windows.Forms.Button(); 35 | this.createPlaylistName = new System.Windows.Forms.TextBox(); 36 | this.createPlaylistButton = new System.Windows.Forms.Button(); 37 | this.deletePlaylistButton = new System.Windows.Forms.Button(); 38 | this.statusLabel = new System.Windows.Forms.Label(); 39 | this.addSongsButton = new System.Windows.Forms.Button(); 40 | this.songListBox = new System.Windows.Forms.ListBox(); 41 | this.playlistListBox = new System.Windows.Forms.ListBox(); 42 | this.playlistSongsBox = new System.Windows.Forms.ListBox(); 43 | this.songTotalLabel = new System.Windows.Forms.Label(); 44 | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 45 | this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); 46 | this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); 47 | this.renamePlaylistTextBox = new System.Windows.Forms.TextBox(); 48 | this.renameButton = new System.Windows.Forms.Button(); 49 | this.deleteSong = new System.Windows.Forms.Button(); 50 | this.contextMenuStrip1.SuspendLayout(); 51 | this.SuspendLayout(); 52 | // 53 | // loginButton 54 | // 55 | this.loginButton.Location = new System.Drawing.Point(35, 12); 56 | this.loginButton.Name = "loginButton"; 57 | this.loginButton.Size = new System.Drawing.Size(75, 23); 58 | this.loginButton.TabIndex = 0; 59 | this.loginButton.Text = "Login"; 60 | this.loginButton.UseVisualStyleBackColor = true; 61 | this.loginButton.Click += new System.EventHandler(this.loginButton_Click); 62 | // 63 | // getTracksButton 64 | // 65 | this.getTracksButton.Location = new System.Drawing.Point(116, 12); 66 | this.getTracksButton.Name = "getTracksButton"; 67 | this.getTracksButton.Size = new System.Drawing.Size(75, 23); 68 | this.getTracksButton.TabIndex = 1; 69 | this.getTracksButton.Text = "Get Tracks"; 70 | this.getTracksButton.UseVisualStyleBackColor = true; 71 | this.getTracksButton.Click += new System.EventHandler(this.getTracksButton_Click); 72 | // 73 | // getPlaylistsButton 74 | // 75 | this.getPlaylistsButton.Location = new System.Drawing.Point(35, 41); 76 | this.getPlaylistsButton.Name = "getPlaylistsButton"; 77 | this.getPlaylistsButton.Size = new System.Drawing.Size(75, 23); 78 | this.getPlaylistsButton.TabIndex = 2; 79 | this.getPlaylistsButton.Text = "Get Playlists"; 80 | this.getPlaylistsButton.UseVisualStyleBackColor = true; 81 | this.getPlaylistsButton.Click += new System.EventHandler(this.getPlaylistsButton_Click); 82 | // 83 | // createPlaylistName 84 | // 85 | this.createPlaylistName.Location = new System.Drawing.Point(15, 70); 86 | this.createPlaylistName.Name = "createPlaylistName"; 87 | this.createPlaylistName.Size = new System.Drawing.Size(169, 20); 88 | this.createPlaylistName.TabIndex = 3; 89 | // 90 | // createPlaylistButton 91 | // 92 | this.createPlaylistButton.Location = new System.Drawing.Point(199, 68); 93 | this.createPlaylistButton.Name = "createPlaylistButton"; 94 | this.createPlaylistButton.Size = new System.Drawing.Size(64, 23); 95 | this.createPlaylistButton.TabIndex = 4; 96 | this.createPlaylistButton.Text = "Create Playlist"; 97 | this.createPlaylistButton.UseVisualStyleBackColor = true; 98 | this.createPlaylistButton.Click += new System.EventHandler(this.createPlaylistButton_Click); 99 | // 100 | // deletePlaylistButton 101 | // 102 | this.deletePlaylistButton.Location = new System.Drawing.Point(12, 539); 103 | this.deletePlaylistButton.Name = "deletePlaylistButton"; 104 | this.deletePlaylistButton.Size = new System.Drawing.Size(51, 23); 105 | this.deletePlaylistButton.TabIndex = 6; 106 | this.deletePlaylistButton.Text = "Delete"; 107 | this.deletePlaylistButton.UseVisualStyleBackColor = true; 108 | this.deletePlaylistButton.Click += new System.EventHandler(this.deletePlaylistButton_Click); 109 | // 110 | // statusLabel 111 | // 112 | this.statusLabel.AutoSize = true; 113 | this.statusLabel.Location = new System.Drawing.Point(9, 581); 114 | this.statusLabel.Name = "statusLabel"; 115 | this.statusLabel.Size = new System.Drawing.Size(40, 13); 116 | this.statusLabel.TabIndex = 7; 117 | this.statusLabel.Text = "Status:"; 118 | // 119 | // addSongsButton 120 | // 121 | this.addSongsButton.Location = new System.Drawing.Point(598, 160); 122 | this.addSongsButton.Name = "addSongsButton"; 123 | this.addSongsButton.Size = new System.Drawing.Size(46, 127); 124 | this.addSongsButton.TabIndex = 8; 125 | this.addSongsButton.Text = "<--\r\nAdd Songs\r\n<--"; 126 | this.addSongsButton.UseVisualStyleBackColor = true; 127 | this.addSongsButton.Click += new System.EventHandler(this.addSongsButton_Click); 128 | // 129 | // songListBox 130 | // 131 | this.songListBox.FormattingEnabled = true; 132 | this.songListBox.Location = new System.Drawing.Point(650, 12); 133 | this.songListBox.Name = "songListBox"; 134 | this.songListBox.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; 135 | this.songListBox.Size = new System.Drawing.Size(319, 524); 136 | this.songListBox.TabIndex = 10; 137 | // 138 | // playlistListBox 139 | // 140 | this.playlistListBox.FormattingEnabled = true; 141 | this.playlistListBox.Location = new System.Drawing.Point(12, 100); 142 | this.playlistListBox.Name = "playlistListBox"; 143 | this.playlistListBox.Size = new System.Drawing.Size(239, 433); 144 | this.playlistListBox.TabIndex = 11; 145 | this.playlistListBox.SelectedIndexChanged += new System.EventHandler(this.playlistListBox_SelectedIndexChanged); 146 | // 147 | // playlistSongsBox 148 | // 149 | this.playlistSongsBox.FormattingEnabled = true; 150 | this.playlistSongsBox.Location = new System.Drawing.Point(269, 12); 151 | this.playlistSongsBox.Name = "playlistSongsBox"; 152 | this.playlistSongsBox.Size = new System.Drawing.Size(323, 524); 153 | this.playlistSongsBox.TabIndex = 12; 154 | // 155 | // songTotalLabel 156 | // 157 | this.songTotalLabel.AutoSize = true; 158 | this.songTotalLabel.Location = new System.Drawing.Point(647, 581); 159 | this.songTotalLabel.Name = "songTotalLabel"; 160 | this.songTotalLabel.Size = new System.Drawing.Size(65, 13); 161 | this.songTotalLabel.TabIndex = 13; 162 | this.songTotalLabel.Text = "Total songs:"; 163 | // 164 | // statusStrip1 165 | // 166 | this.statusStrip1.Location = new System.Drawing.Point(0, 572); 167 | this.statusStrip1.Name = "statusStrip1"; 168 | this.statusStrip1.Size = new System.Drawing.Size(973, 22); 169 | this.statusStrip1.TabIndex = 14; 170 | this.statusStrip1.Text = "statusStrip1"; 171 | // 172 | // contextMenuStrip1 173 | // 174 | this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 175 | this.toolStripMenuItem1}); 176 | this.contextMenuStrip1.Name = "contextMenuStrip1"; 177 | this.contextMenuStrip1.Size = new System.Drawing.Size(181, 26); 178 | // 179 | // toolStripMenuItem1 180 | // 181 | this.toolStripMenuItem1.Name = "toolStripMenuItem1"; 182 | this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 22); 183 | this.toolStripMenuItem1.Text = "toolStripMenuItem1"; 184 | // 185 | // renamePlaylistTextBox 186 | // 187 | this.renamePlaylistTextBox.Location = new System.Drawing.Point(70, 539); 188 | this.renamePlaylistTextBox.Name = "renamePlaylistTextBox"; 189 | this.renamePlaylistTextBox.Size = new System.Drawing.Size(100, 20); 190 | this.renamePlaylistTextBox.TabIndex = 16; 191 | // 192 | // renameButton 193 | // 194 | this.renameButton.Location = new System.Drawing.Point(176, 539); 195 | this.renameButton.Name = "renameButton"; 196 | this.renameButton.Size = new System.Drawing.Size(75, 23); 197 | this.renameButton.TabIndex = 17; 198 | this.renameButton.Text = "Rename"; 199 | this.renameButton.UseVisualStyleBackColor = true; 200 | this.renameButton.Click += new System.EventHandler(this.renameButton_Click); 201 | // 202 | // deleteSong 203 | // 204 | this.deleteSong.Location = new System.Drawing.Point(598, 293); 205 | this.deleteSong.Name = "deleteSong"; 206 | this.deleteSong.Size = new System.Drawing.Size(46, 107); 207 | this.deleteSong.TabIndex = 18; 208 | this.deleteSong.Text = "-->\r\nRmv\r\nSongs\r\n-->"; 209 | this.deleteSong.UseVisualStyleBackColor = true; 210 | this.deleteSong.Click += new System.EventHandler(this.deleteSong_Click); 211 | // 212 | // Form1 213 | // 214 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 215 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 216 | this.ClientSize = new System.Drawing.Size(973, 594); 217 | this.Controls.Add(this.renamePlaylistTextBox); 218 | this.Controls.Add(this.deleteSong); 219 | this.Controls.Add(this.renameButton); 220 | this.Controls.Add(this.songTotalLabel); 221 | this.Controls.Add(this.statusLabel); 222 | this.Controls.Add(this.statusStrip1); 223 | this.Controls.Add(this.playlistSongsBox); 224 | this.Controls.Add(this.playlistListBox); 225 | this.Controls.Add(this.songListBox); 226 | this.Controls.Add(this.deletePlaylistButton); 227 | this.Controls.Add(this.createPlaylistButton); 228 | this.Controls.Add(this.createPlaylistName); 229 | this.Controls.Add(this.getPlaylistsButton); 230 | this.Controls.Add(this.getTracksButton); 231 | this.Controls.Add(this.addSongsButton); 232 | this.Controls.Add(this.loginButton); 233 | this.Name = "Form1"; 234 | this.Text = "Form1"; 235 | this.contextMenuStrip1.ResumeLayout(false); 236 | this.ResumeLayout(false); 237 | this.PerformLayout(); 238 | 239 | } 240 | 241 | #endregion 242 | 243 | private System.Windows.Forms.Button loginButton; 244 | private System.Windows.Forms.Button getTracksButton; 245 | private System.Windows.Forms.Button getPlaylistsButton; 246 | private System.Windows.Forms.TextBox createPlaylistName; 247 | private System.Windows.Forms.Button createPlaylistButton; 248 | private System.Windows.Forms.Button deletePlaylistButton; 249 | private System.Windows.Forms.Label statusLabel; 250 | private System.Windows.Forms.Button addSongsButton; 251 | private System.Windows.Forms.ListBox songListBox; 252 | private System.Windows.Forms.ListBox playlistListBox; 253 | private System.Windows.Forms.ListBox playlistSongsBox; 254 | private System.Windows.Forms.Label songTotalLabel; 255 | private System.Windows.Forms.StatusStrip statusStrip1; 256 | private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; 257 | private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; 258 | private System.Windows.Forms.TextBox renamePlaylistTextBox; 259 | private System.Windows.Forms.Button renameButton; 260 | private System.Windows.Forms.Button deleteSong; 261 | } 262 | } 263 | 264 | -------------------------------------------------------------------------------- /MBGmusic/Configure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.IO; 10 | using System.Configuration; 11 | using MusicBeePlugin.Models; 12 | using System.Threading.Tasks; 13 | using GooglePlayMusicAPI; 14 | using System.Security; 15 | 16 | namespace MusicBeePlugin 17 | { 18 | partial class Configure : Form, IDisposable 19 | { 20 | 21 | private PlaylistSync _playlistSync; 22 | 23 | private Settings _settings; 24 | 25 | private Logger log; 26 | 27 | private void updateSyncStatus(string text) 28 | { 29 | syncStatusLabel.Text = text; 30 | } 31 | 32 | private void updateLoginStatus(string text) 33 | { 34 | loginStatusLabel.Text = text; 35 | } 36 | 37 | public Configure(PlaylistSync playlistSync, Settings settings, Plugin.MusicBeeApiInterface mbApiInterface) 38 | { 39 | InitializeComponent(); 40 | 41 | foreach (Control control in this.Controls) 42 | { 43 | control.ForeColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 44 | MusicBeePlugin.Plugin.SkinElement.SkinInputPanel, 45 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 46 | MusicBeePlugin.Plugin.ElementComponent.ComponentForeground)); 47 | control.BackColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 48 | MusicBeePlugin.Plugin.SkinElement.SkinInputControl, 49 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 50 | MusicBeePlugin.Plugin.ElementComponent.ComponentBackground)); 51 | 52 | if (control.Controls.Count > 0) 53 | { 54 | foreach (Control child in control.Controls) 55 | { 56 | child.ForeColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 57 | MusicBeePlugin.Plugin.SkinElement.SkinInputPanel, 58 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 59 | MusicBeePlugin.Plugin.ElementComponent.ComponentForeground)); 60 | child.BackColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 61 | MusicBeePlugin.Plugin.SkinElement.SkinInputControl, 62 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 63 | MusicBeePlugin.Plugin.ElementComponent.ComponentBackground)); 64 | } 65 | } 66 | } 67 | 68 | this.ForeColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 69 | MusicBeePlugin.Plugin.SkinElement.SkinInputPanel, 70 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 71 | MusicBeePlugin.Plugin.ElementComponent.ComponentForeground)); 72 | this.BackColor = Color.FromArgb(mbApiInterface.Setting_GetSkinElementColour( 73 | MusicBeePlugin.Plugin.SkinElement.SkinInputControl, 74 | MusicBeePlugin.Plugin.ElementState.ElementStateDefault, 75 | MusicBeePlugin.Plugin.ElementComponent.ComponentBackground)); 76 | 77 | 78 | 79 | log = Logger.Instance; 80 | log.OnLogUpdated = new EventHandler(log_OnLogUpdated); 81 | 82 | _settings = settings; 83 | _playlistSync = playlistSync; 84 | 85 | // Register event handlers 86 | _playlistSync.MBSync.OnSyncComplete = new EventHandler(MBSync_OnSyncComplete); 87 | 88 | if (_playlistSync.GMusic.SyncRunning) 89 | { 90 | updateSyncStatus("Background sync running"); 91 | } 92 | 93 | if (_settings.Email != null) 94 | { 95 | // decode it from base64 96 | byte[] email = Convert.FromBase64String(_settings.Email); 97 | emailTextBox.Text = Encoding.UTF8.GetString(email); 98 | } 99 | 100 | if (_settings.Password != null) 101 | { 102 | byte[] passwd = Convert.FromBase64String(_settings.Password); 103 | passwordTextBox.Text = Encoding.UTF8.GetString(passwd); 104 | } 105 | 106 | rememberCheckbox.Checked = _settings.SaveCredentials; 107 | 108 | // autoSyncCheckbox.Checked = _settings.SyncOnStartup; 109 | 110 | populateLocalPlaylists(); 111 | 112 | // tagToolsPlugin.mbForm.AddOwnedForm(this); 113 | } 114 | 115 | void MBSync_OnSyncComplete(object sender, EventArgs e) 116 | { 117 | this.Invoke(new MethodInvoker(delegate 118 | { 119 | syncStatusLabel.Text = "Synchronisation done!"; 120 | closeButton.Enabled = false; 121 | populateLocalPlaylists(); 122 | })); 123 | } 124 | 125 | void GMusic_OnSyncComplete(object sender, EventArgs e) 126 | { 127 | this.Invoke(new MethodInvoker(delegate 128 | { 129 | syncStatusLabel.Text = "Synchronisation done!"; 130 | closeButton.Enabled = false; 131 | // Just refresh the playlists (don't bother fetching all the songs again) 132 | _playlistSync.GMusic.FetchPlaylists(); 133 | })); 134 | } 135 | 136 | void log_OnLogUpdated(object sender, EventArgs e) 137 | { 138 | this.Invoke(new MethodInvoker(delegate 139 | { 140 | fetchPlaylistStatusLabel.Text = log.LastLog; 141 | })); 142 | } 143 | 144 | private async void loginButton_Click(object sender, EventArgs e) 145 | { 146 | // Save the pwd and email to disc 147 | // NOTE although this encodes them as base64 (so they're not immediately obvious to anyone reading them) this is 148 | // NOT SECURITY. There is no encryption. Don't check that box unless you trust your machine! 149 | if (rememberCheckbox.Checked) 150 | { 151 | _settings.SaveCredentials = true; 152 | Byte[] email = Encoding.UTF8.GetBytes(emailTextBox.Text); 153 | _settings.Email = Convert.ToBase64String(email); 154 | Byte[] pwd = Encoding.UTF8.GetBytes(passwordTextBox.Text); 155 | _settings.Password = Convert.ToBase64String(pwd); 156 | _settings.Save(); 157 | } 158 | else 159 | { 160 | _settings.SaveCredentials = false; 161 | _settings.Email = ""; 162 | _settings.Password = ""; 163 | _settings.Save(); 164 | } 165 | 166 | bool loggedIn = await _playlistSync.GMusic.LoginToGMusic(emailTextBox.Text, passwordTextBox.Text); 167 | 168 | if (loggedIn) 169 | { 170 | updateLoginStatus("Successfully logged in."); 171 | } 172 | else 173 | { 174 | updateLoginStatus("LOGIN FAILED. PLEASE TRY AGAIN"); 175 | } 176 | 177 | this.closeButton.Enabled = true; 178 | this.syncNowButton.Enabled = true; 179 | //this.autoSyncCheckbox.Enabled = true; 180 | List allPlaylists = await _playlistSync.GMusic.FetchPlaylists(); 181 | googleMusicPlaylistBox.Items.Clear(); 182 | foreach (Playlist playlist in allPlaylists) 183 | { 184 | if (!playlist.Deleted) 185 | { 186 | if (_settings.GMusicPlaylistsToSync.Contains(playlist.ID)) 187 | googleMusicPlaylistBox.Items.Add(playlist, true); 188 | else 189 | googleMusicPlaylistBox.Items.Add(playlist, false); 190 | } 191 | } 192 | 193 | 194 | } 195 | 196 | // Get local Mb playlists and place them in the checkedlistbox 197 | // Check the settings to see if they're currently syncable 198 | private void populateLocalPlaylists() 199 | { 200 | List mbPlaylists = _playlistSync.MBSync.GetMbPlaylists(); 201 | localPlaylistBox.Items.Clear(); 202 | foreach (MbPlaylist mbPlaylist in mbPlaylists) 203 | { 204 | if (_settings.MBPlaylistsToSync.Contains(mbPlaylist.mbName)) 205 | localPlaylistBox.Items.Add(mbPlaylist, true); 206 | else 207 | localPlaylistBox.Items.Add(mbPlaylist, false); 208 | } 209 | 210 | } 211 | 212 | /* 213 | private void autoSyncCheckbox_CheckedChanged(object sender, EventArgs e) 214 | { 215 | _settings.SyncOnStartup = autoSyncCheckbox.Checked; 216 | _settings.Save(); 217 | }*/ 218 | 219 | // Depending on user settings, either start a local sync to remote, or start a remote sync to local 220 | private async void syncNowButton_Click(object sender, EventArgs e) 221 | { 222 | // Make sure we're logged in and have playlists, otherwise stop 223 | if (!_playlistSync.GMusic.LoggedIn) 224 | { 225 | updateSyncStatus("Error: NOT LOGGED IN"); 226 | return; 227 | } 228 | 229 | if (!_playlistSync.GMusic.DataFetched) 230 | { 231 | updateSyncStatus("Please fetch data before attempting to sync."); 232 | return; 233 | } 234 | 235 | closeButton.Enabled = false; 236 | updateSyncStatus("Now synchronising. Please wait."); 237 | 238 | 239 | _playlistSync.SyncPlaylists(); 240 | 241 | updateSyncStatus("Done Synching."); 242 | 243 | // List selected = new List(); 244 | //foreach (GMusicPlaylist selectedPlaylist in googleMusicPlaylistBox.CheckedItems) 245 | // selected.Add(selectedPlaylist); 246 | 247 | } 248 | 249 | private void toGMusicRadiobutton_CheckedChanged(object sender, EventArgs e) 250 | { 251 | if (toGMusicRadiobutton.Checked) 252 | fromGMusicRadioButton.Checked = false; 253 | 254 | _settings.SyncLocalToRemote = toGMusicRadiobutton.Checked; 255 | _settings.Save(); 256 | } 257 | 258 | private void fromGMusicRadioButton_CheckedChanged(object sender, EventArgs e) 259 | { 260 | if (fromGMusicRadioButton.Checked) 261 | toGMusicRadiobutton.Checked = false; 262 | } 263 | 264 | 265 | private void allLocalPlayCheckbox_CheckedChanged(object sender, EventArgs e) 266 | { 267 | if (allLocalPlayCheckbox.Checked) 268 | { 269 | for (int i = 0; i < localPlaylistBox.Items.Count; i++) 270 | { 271 | localPlaylistBox.SetItemChecked(i, true); 272 | } 273 | } 274 | else 275 | { 276 | for (int i = 0; i < localPlaylistBox.Items.Count; i++) 277 | { 278 | localPlaylistBox.SetItemChecked(i, false); 279 | } 280 | } 281 | 282 | saveLocalPlaylistSettings(); 283 | } 284 | 285 | 286 | private void allRemotePlayCheckbox_CheckedChanged(object sender, EventArgs e) 287 | { 288 | 289 | if (allRemotePlayCheckbox.Checked) 290 | for (int i = 0; i < googleMusicPlaylistBox.Items.Count; i++) 291 | googleMusicPlaylistBox.SetItemChecked(i, true); 292 | else 293 | for (int i = 0; i < googleMusicPlaylistBox.Items.Count; i++) 294 | googleMusicPlaylistBox.SetItemChecked(i, false); 295 | 296 | saveRemotePlaylistSettings(); 297 | } 298 | 299 | private void closeButton_Click(object sender, EventArgs e) 300 | { 301 | this.Close(); 302 | } 303 | 304 | //SelectedIndexChanged NOT CheckedItemsChanged because the latter is called before the CheckedItems collection has actually updated, 305 | // making our eventual list miss the most recently selected item... 306 | private void localPlaylistBox_SelectedIndexChanged(object sender, EventArgs e) 307 | { 308 | saveLocalPlaylistSettings(); 309 | } 310 | 311 | private void googleMusicPlaylistBox_SelectedIndexChanged(object sender, EventArgs e) 312 | { 313 | saveRemotePlaylistSettings(); 314 | } 315 | 316 | 317 | 318 | private void saveLocalPlaylistSettings() 319 | { 320 | _settings.MBPlaylistsToSync.Clear(); 321 | foreach (MbPlaylist playlist in localPlaylistBox.CheckedItems) 322 | { 323 | _settings.MBPlaylistsToSync.Add(playlist.mbName); 324 | } 325 | _settings.Save(); 326 | } 327 | 328 | private void saveRemotePlaylistSettings() 329 | { 330 | _settings.GMusicPlaylistsToSync.Clear(); 331 | foreach (Playlist playlist in googleMusicPlaylistBox.CheckedItems) 332 | { 333 | _settings.GMusicPlaylistsToSync.Add(playlist.ID); 334 | } 335 | _settings.Save(); 336 | } 337 | 338 | private void unsubscribeEvents() 339 | { 340 | log.OnLogUpdated = null; 341 | 342 | } 343 | 344 | public new void Dispose() 345 | { 346 | this.unsubscribeEvents(); 347 | base.Dispose(); 348 | } 349 | 350 | private void Configure_FormClosing(object sender, FormClosingEventArgs e) 351 | { 352 | this.unsubscribeEvents(); 353 | } 354 | 355 | 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /MBGmusic/Configure.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MusicBeePlugin 2 | { 3 | partial class Configure 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.loginButton = new System.Windows.Forms.Button(); 32 | this.emailTextBox = new System.Windows.Forms.TextBox(); 33 | this.emailLabel = new System.Windows.Forms.Label(); 34 | this.passwordTextBox = new System.Windows.Forms.TextBox(); 35 | this.passwordLabel = new System.Windows.Forms.Label(); 36 | this.rememberCheckbox = new System.Windows.Forms.CheckBox(); 37 | this.warnSaveLabel = new System.Windows.Forms.Label(); 38 | this.syncNowButton = new System.Windows.Forms.Button(); 39 | this.loginStatusLabel = new System.Windows.Forms.Label(); 40 | this.syncStatusLabel = new System.Windows.Forms.Label(); 41 | this.localPlaylistBox = new System.Windows.Forms.CheckedListBox(); 42 | this.googleMusicPlaylistBox = new System.Windows.Forms.CheckedListBox(); 43 | this.label1 = new System.Windows.Forms.Label(); 44 | this.label2 = new System.Windows.Forms.Label(); 45 | this.allLocalPlayCheckbox = new System.Windows.Forms.CheckBox(); 46 | this.allRemotePlayCheckbox = new System.Windows.Forms.CheckBox(); 47 | this.closeButton = new System.Windows.Forms.Button(); 48 | this.toGMusicRadiobutton = new System.Windows.Forms.RadioButton(); 49 | this.fromGMusicRadioButton = new System.Windows.Forms.RadioButton(); 50 | this.fetchPlaylistStatusLabel = new System.Windows.Forms.Label(); 51 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 52 | this.groupBox1.SuspendLayout(); 53 | this.SuspendLayout(); 54 | // 55 | // loginButton 56 | // 57 | this.loginButton.Location = new System.Drawing.Point(754, 50); 58 | this.loginButton.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 59 | this.loginButton.Name = "loginButton"; 60 | this.loginButton.Size = new System.Drawing.Size(150, 44); 61 | this.loginButton.TabIndex = 0; 62 | this.loginButton.Text = "Login"; 63 | this.loginButton.UseVisualStyleBackColor = true; 64 | this.loginButton.Click += new System.EventHandler(this.loginButton_Click); 65 | // 66 | // emailTextBox 67 | // 68 | this.emailTextBox.Location = new System.Drawing.Point(24, 50); 69 | this.emailTextBox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 70 | this.emailTextBox.Name = "emailTextBox"; 71 | this.emailTextBox.Size = new System.Drawing.Size(316, 31); 72 | this.emailTextBox.TabIndex = 1; 73 | // 74 | // emailLabel 75 | // 76 | this.emailLabel.AutoSize = true; 77 | this.emailLabel.Location = new System.Drawing.Point(18, 17); 78 | this.emailLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 79 | this.emailLabel.Name = "emailLabel"; 80 | this.emailLabel.Size = new System.Drawing.Size(65, 25); 81 | this.emailLabel.TabIndex = 2; 82 | this.emailLabel.Text = "Email"; 83 | // 84 | // passwordTextBox 85 | // 86 | this.passwordTextBox.Location = new System.Drawing.Point(384, 50); 87 | this.passwordTextBox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 88 | this.passwordTextBox.Name = "passwordTextBox"; 89 | this.passwordTextBox.PasswordChar = '*'; 90 | this.passwordTextBox.Size = new System.Drawing.Size(316, 31); 91 | this.passwordTextBox.TabIndex = 3; 92 | // 93 | // passwordLabel 94 | // 95 | this.passwordLabel.AutoSize = true; 96 | this.passwordLabel.Location = new System.Drawing.Point(378, 17); 97 | this.passwordLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 98 | this.passwordLabel.Name = "passwordLabel"; 99 | this.passwordLabel.Size = new System.Drawing.Size(106, 25); 100 | this.passwordLabel.TabIndex = 4; 101 | this.passwordLabel.Text = "Password"; 102 | // 103 | // rememberCheckbox 104 | // 105 | this.rememberCheckbox.AutoSize = true; 106 | this.rememberCheckbox.Location = new System.Drawing.Point(754, 15); 107 | this.rememberCheckbox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 108 | this.rememberCheckbox.Name = "rememberCheckbox"; 109 | this.rememberCheckbox.Size = new System.Drawing.Size(207, 29); 110 | this.rememberCheckbox.TabIndex = 5; 111 | this.rememberCheckbox.Text = "Remember Login"; 112 | this.rememberCheckbox.UseVisualStyleBackColor = true; 113 | // 114 | // warnSaveLabel 115 | // 116 | this.warnSaveLabel.AutoSize = true; 117 | this.warnSaveLabel.Location = new System.Drawing.Point(1000, 17); 118 | this.warnSaveLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 119 | this.warnSaveLabel.Name = "warnSaveLabel"; 120 | this.warnSaveLabel.Size = new System.Drawing.Size(132, 75); 121 | this.warnSaveLabel.TabIndex = 6; 122 | this.warnSaveLabel.Text = "Stores login \r\ndetails in \r\nplain text!"; 123 | // 124 | // syncNowButton 125 | // 126 | this.syncNowButton.Location = new System.Drawing.Point(312, 1008); 127 | this.syncNowButton.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 128 | this.syncNowButton.Name = "syncNowButton"; 129 | this.syncNowButton.Size = new System.Drawing.Size(250, 44); 130 | this.syncNowButton.TabIndex = 8; 131 | this.syncNowButton.Text = "Synchronise Selected"; 132 | this.syncNowButton.UseVisualStyleBackColor = true; 133 | this.syncNowButton.Click += new System.EventHandler(this.syncNowButton_Click); 134 | // 135 | // loginStatusLabel 136 | // 137 | this.loginStatusLabel.AutoSize = true; 138 | this.loginStatusLabel.Location = new System.Drawing.Point(30, 115); 139 | this.loginStatusLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 140 | this.loginStatusLabel.Name = "loginStatusLabel"; 141 | this.loginStatusLabel.Size = new System.Drawing.Size(139, 25); 142 | this.loginStatusLabel.TabIndex = 9; 143 | this.loginStatusLabel.Text = "Not logged in"; 144 | // 145 | // syncStatusLabel 146 | // 147 | this.syncStatusLabel.AutoSize = true; 148 | this.syncStatusLabel.Location = new System.Drawing.Point(608, 1017); 149 | this.syncStatusLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 150 | this.syncStatusLabel.Name = "syncStatusLabel"; 151 | this.syncStatusLabel.Size = new System.Drawing.Size(137, 25); 152 | this.syncStatusLabel.TabIndex = 10; 153 | this.syncStatusLabel.Text = "Click to Sync"; 154 | // 155 | // localPlaylistBox 156 | // 157 | this.localPlaylistBox.CheckOnClick = true; 158 | this.localPlaylistBox.FormattingEnabled = true; 159 | this.localPlaylistBox.Location = new System.Drawing.Point(12, 88); 160 | this.localPlaylistBox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 161 | this.localPlaylistBox.Name = "localPlaylistBox"; 162 | this.localPlaylistBox.Size = new System.Drawing.Size(526, 680); 163 | this.localPlaylistBox.TabIndex = 11; 164 | this.localPlaylistBox.SelectedIndexChanged += new System.EventHandler(this.localPlaylistBox_SelectedIndexChanged); 165 | // 166 | // googleMusicPlaylistBox 167 | // 168 | this.googleMusicPlaylistBox.CheckOnClick = true; 169 | this.googleMusicPlaylistBox.FormattingEnabled = true; 170 | this.googleMusicPlaylistBox.Location = new System.Drawing.Point(564, 88); 171 | this.googleMusicPlaylistBox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 172 | this.googleMusicPlaylistBox.Name = "googleMusicPlaylistBox"; 173 | this.googleMusicPlaylistBox.Size = new System.Drawing.Size(526, 680); 174 | this.googleMusicPlaylistBox.TabIndex = 12; 175 | this.googleMusicPlaylistBox.SelectedIndexChanged += new System.EventHandler(this.googleMusicPlaylistBox_SelectedIndexChanged); 176 | // 177 | // label1 178 | // 179 | this.label1.AutoSize = true; 180 | this.label1.Location = new System.Drawing.Point(12, 46); 181 | this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 182 | this.label1.Name = "label1"; 183 | this.label1.Size = new System.Drawing.Size(148, 25); 184 | this.label1.TabIndex = 13; 185 | this.label1.Text = "Local playlists"; 186 | // 187 | // label2 188 | // 189 | this.label2.AutoSize = true; 190 | this.label2.Location = new System.Drawing.Point(558, 46); 191 | this.label2.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 192 | this.label2.Name = "label2"; 193 | this.label2.Size = new System.Drawing.Size(228, 25); 194 | this.label2.TabIndex = 14; 195 | this.label2.Text = "Google Music playlists"; 196 | // 197 | // allLocalPlayCheckbox 198 | // 199 | this.allLocalPlayCheckbox.AutoSize = true; 200 | this.allLocalPlayCheckbox.Location = new System.Drawing.Point(398, 44); 201 | this.allLocalPlayCheckbox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 202 | this.allLocalPlayCheckbox.Name = "allLocalPlayCheckbox"; 203 | this.allLocalPlayCheckbox.Size = new System.Drawing.Size(134, 29); 204 | this.allLocalPlayCheckbox.TabIndex = 15; 205 | this.allLocalPlayCheckbox.Text = "Select All"; 206 | this.allLocalPlayCheckbox.UseVisualStyleBackColor = true; 207 | this.allLocalPlayCheckbox.CheckedChanged += new System.EventHandler(this.allLocalPlayCheckbox_CheckedChanged); 208 | // 209 | // allRemotePlayCheckbox 210 | // 211 | this.allRemotePlayCheckbox.AutoSize = true; 212 | this.allRemotePlayCheckbox.Location = new System.Drawing.Point(954, 44); 213 | this.allRemotePlayCheckbox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 214 | this.allRemotePlayCheckbox.Name = "allRemotePlayCheckbox"; 215 | this.allRemotePlayCheckbox.Size = new System.Drawing.Size(134, 29); 216 | this.allRemotePlayCheckbox.TabIndex = 16; 217 | this.allRemotePlayCheckbox.Text = "Select All"; 218 | this.allRemotePlayCheckbox.UseVisualStyleBackColor = true; 219 | this.allRemotePlayCheckbox.CheckedChanged += new System.EventHandler(this.allRemotePlayCheckbox_CheckedChanged); 220 | // 221 | // closeButton 222 | // 223 | this.closeButton.ForeColor = System.Drawing.SystemColors.ControlText; 224 | this.closeButton.Location = new System.Drawing.Point(980, 1058); 225 | this.closeButton.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 226 | this.closeButton.Name = "closeButton"; 227 | this.closeButton.Size = new System.Drawing.Size(150, 44); 228 | this.closeButton.TabIndex = 17; 229 | this.closeButton.Text = "Close"; 230 | this.closeButton.UseVisualStyleBackColor = true; 231 | this.closeButton.Click += new System.EventHandler(this.closeButton_Click); 232 | // 233 | // toGMusicRadiobutton 234 | // 235 | this.toGMusicRadiobutton.AutoSize = true; 236 | this.toGMusicRadiobutton.Checked = true; 237 | this.toGMusicRadiobutton.Location = new System.Drawing.Point(24, 1013); 238 | this.toGMusicRadiobutton.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 239 | this.toGMusicRadiobutton.Name = "toGMusicRadiobutton"; 240 | this.toGMusicRadiobutton.Size = new System.Drawing.Size(231, 29); 241 | this.toGMusicRadiobutton.TabIndex = 18; 242 | this.toGMusicRadiobutton.TabStop = true; 243 | this.toGMusicRadiobutton.Text = "-> To Google Music"; 244 | this.toGMusicRadiobutton.UseVisualStyleBackColor = true; 245 | this.toGMusicRadiobutton.CheckedChanged += new System.EventHandler(this.toGMusicRadiobutton_CheckedChanged); 246 | // 247 | // fromGMusicRadioButton 248 | // 249 | this.fromGMusicRadioButton.AutoSize = true; 250 | this.fromGMusicRadioButton.Location = new System.Drawing.Point(24, 1058); 251 | this.fromGMusicRadioButton.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 252 | this.fromGMusicRadioButton.Name = "fromGMusicRadioButton"; 253 | this.fromGMusicRadioButton.Size = new System.Drawing.Size(255, 29); 254 | this.fromGMusicRadioButton.TabIndex = 19; 255 | this.fromGMusicRadioButton.Text = "<- From Google Music"; 256 | this.fromGMusicRadioButton.UseVisualStyleBackColor = true; 257 | this.fromGMusicRadioButton.CheckedChanged += new System.EventHandler(this.fromGMusicRadioButton_CheckedChanged); 258 | // 259 | // fetchPlaylistStatusLabel 260 | // 261 | this.fetchPlaylistStatusLabel.AutoSize = true; 262 | this.fetchPlaylistStatusLabel.Location = new System.Drawing.Point(840, 115); 263 | this.fetchPlaylistStatusLabel.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); 264 | this.fetchPlaylistStatusLabel.Name = "fetchPlaylistStatusLabel"; 265 | this.fetchPlaylistStatusLabel.Size = new System.Drawing.Size(286, 25); 266 | this.fetchPlaylistStatusLabel.TabIndex = 20; 267 | this.fetchPlaylistStatusLabel.Text = "Login to see remote playlists"; 268 | this.fetchPlaylistStatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 269 | // 270 | // groupBox1 271 | // 272 | this.groupBox1.Controls.Add(this.label1); 273 | this.groupBox1.Controls.Add(this.allLocalPlayCheckbox); 274 | this.groupBox1.Controls.Add(this.localPlaylistBox); 275 | this.groupBox1.Controls.Add(this.label2); 276 | this.groupBox1.Controls.Add(this.allRemotePlayCheckbox); 277 | this.groupBox1.Controls.Add(this.googleMusicPlaylistBox); 278 | this.groupBox1.Location = new System.Drawing.Point(24, 163); 279 | this.groupBox1.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 280 | this.groupBox1.Name = "groupBox1"; 281 | this.groupBox1.Padding = new System.Windows.Forms.Padding(6, 6, 6, 6); 282 | this.groupBox1.Size = new System.Drawing.Size(1106, 812); 283 | this.groupBox1.TabIndex = 21; 284 | this.groupBox1.TabStop = false; 285 | this.groupBox1.Text = "Set Up Sync"; 286 | // 287 | // Configure 288 | // 289 | this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); 290 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 291 | this.ClientSize = new System.Drawing.Size(1154, 1125); 292 | this.Controls.Add(this.fetchPlaylistStatusLabel); 293 | this.Controls.Add(this.syncStatusLabel); 294 | this.Controls.Add(this.fromGMusicRadioButton); 295 | this.Controls.Add(this.toGMusicRadiobutton); 296 | this.Controls.Add(this.closeButton); 297 | this.Controls.Add(this.loginStatusLabel); 298 | this.Controls.Add(this.syncNowButton); 299 | this.Controls.Add(this.warnSaveLabel); 300 | this.Controls.Add(this.rememberCheckbox); 301 | this.Controls.Add(this.passwordLabel); 302 | this.Controls.Add(this.passwordTextBox); 303 | this.Controls.Add(this.emailLabel); 304 | this.Controls.Add(this.emailTextBox); 305 | this.Controls.Add(this.loginButton); 306 | this.Controls.Add(this.groupBox1); 307 | this.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); 308 | this.Name = "Configure"; 309 | this.Text = "Google Music Sync"; 310 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Configure_FormClosing); 311 | this.groupBox1.ResumeLayout(false); 312 | this.groupBox1.PerformLayout(); 313 | this.ResumeLayout(false); 314 | this.PerformLayout(); 315 | 316 | } 317 | 318 | #endregion 319 | 320 | private System.Windows.Forms.Button loginButton; 321 | private System.Windows.Forms.TextBox emailTextBox; 322 | private System.Windows.Forms.Label emailLabel; 323 | private System.Windows.Forms.TextBox passwordTextBox; 324 | private System.Windows.Forms.Label passwordLabel; 325 | private System.Windows.Forms.CheckBox rememberCheckbox; 326 | private System.Windows.Forms.Label warnSaveLabel; 327 | private System.Windows.Forms.Button syncNowButton; 328 | private System.Windows.Forms.Label loginStatusLabel; 329 | private System.Windows.Forms.Label syncStatusLabel; 330 | private System.Windows.Forms.CheckedListBox localPlaylistBox; 331 | private System.Windows.Forms.CheckedListBox googleMusicPlaylistBox; 332 | private System.Windows.Forms.Label label1; 333 | private System.Windows.Forms.Label label2; 334 | private System.Windows.Forms.CheckBox allLocalPlayCheckbox; 335 | private System.Windows.Forms.CheckBox allRemotePlayCheckbox; 336 | private System.Windows.Forms.Button closeButton; 337 | private System.Windows.Forms.RadioButton toGMusicRadiobutton; 338 | private System.Windows.Forms.RadioButton fromGMusicRadioButton; 339 | private System.Windows.Forms.Label fetchPlaylistStatusLabel; 340 | private System.Windows.Forms.GroupBox groupBox1; 341 | } 342 | } -------------------------------------------------------------------------------- /MBGmusic/Plugin/MusicBeeInterface.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace MusicBeePlugin 5 | { 6 | public partial class Plugin 7 | { 8 | public const short PluginInfoVersion = 1; 9 | public const short MinInterfaceVersion = 35; 10 | public const short MinApiRevision = 47; 11 | 12 | [StructLayout(LayoutKind.Sequential)] 13 | public struct MusicBeeApiInterface 14 | { 15 | public void Initialise(IntPtr apiInterfacePtr) 16 | { 17 | CopyMemory(ref this, apiInterfacePtr, 4); 18 | if (MusicBeeVersion == MusicBeeVersion.v2_0) 19 | // MusicBee version 2.0 - Api methods > revision 25 are not available 20 | CopyMemory(ref this, apiInterfacePtr, 456); 21 | else if (MusicBeeVersion == MusicBeeVersion.v2_1) 22 | CopyMemory(ref this, apiInterfacePtr, 516); 23 | else if (MusicBeeVersion == MusicBeeVersion.v2_2) 24 | CopyMemory(ref this, apiInterfacePtr, 584); 25 | else if (MusicBeeVersion == MusicBeeVersion.v2_3) 26 | CopyMemory(ref this, apiInterfacePtr, 596); 27 | else if (MusicBeeVersion == MusicBeeVersion.v2_4) 28 | CopyMemory(ref this, apiInterfacePtr, 604); 29 | else 30 | CopyMemory(ref this, apiInterfacePtr, Marshal.SizeOf(this)); 31 | } 32 | public MusicBeeVersion MusicBeeVersion 33 | { 34 | get { 35 | if (ApiRevision <= 25) 36 | return MusicBeeVersion.v2_0; 37 | else if (ApiRevision <= 31) 38 | return MusicBeeVersion.v2_1; 39 | else if (ApiRevision <= 33) 40 | return MusicBeeVersion.v2_2; 41 | else if (ApiRevision <= 38) 42 | return MusicBeeVersion.v2_3; 43 | else if (ApiRevision <= 43) 44 | return MusicBeeVersion.v2_4; 45 | else 46 | return MusicBeeVersion.v2_5; 47 | } 48 | } 49 | public short InterfaceVersion; 50 | public short ApiRevision; 51 | public MB_ReleaseStringDelegate MB_ReleaseString; 52 | public MB_TraceDelegate MB_Trace; 53 | public Setting_GetPersistentStoragePathDelegate Setting_GetPersistentStoragePath; 54 | public Setting_GetSkinDelegate Setting_GetSkin; 55 | public Setting_GetSkinElementColourDelegate Setting_GetSkinElementColour; 56 | public Setting_IsWindowBordersSkinnedDelegate Setting_IsWindowBordersSkinned; 57 | public Library_GetFilePropertyDelegate Library_GetFileProperty; 58 | public Library_GetFileTagDelegate Library_GetFileTag; 59 | public Library_SetFileTagDelegate Library_SetFileTag; 60 | public Library_CommitTagsToFileDelegate Library_CommitTagsToFile; 61 | public Library_GetLyricsDelegate Library_GetLyrics; 62 | [Obsolete("Use Library_GetArtworkEx")] 63 | public Library_GetArtworkDelegate Library_GetArtwork; 64 | public Library_QueryFilesDelegate Library_QueryFiles; 65 | public Library_QueryGetNextFileDelegate Library_QueryGetNextFile; 66 | public Player_GetPositionDelegate Player_GetPosition; 67 | public Player_SetPositionDelegate Player_SetPosition; 68 | public Player_GetPlayStateDelegate Player_GetPlayState; 69 | public Player_ActionDelegate Player_PlayPause; 70 | public Player_ActionDelegate Player_Stop; 71 | public Player_ActionDelegate Player_StopAfterCurrent; 72 | public Player_ActionDelegate Player_PlayPreviousTrack; 73 | public Player_ActionDelegate Player_PlayNextTrack; 74 | public Player_ActionDelegate Player_StartAutoDj; 75 | public Player_ActionDelegate Player_EndAutoDj; 76 | public Player_GetVolumeDelegate Player_GetVolume; 77 | public Player_SetVolumeDelegate Player_SetVolume; 78 | public Player_GetMuteDelegate Player_GetMute; 79 | public Player_SetMuteDelegate Player_SetMute; 80 | public Player_GetShuffleDelegate Player_GetShuffle; 81 | public Player_SetShuffleDelegate Player_SetShuffle; 82 | public Player_GetRepeatDelegate Player_GetRepeat; 83 | public Player_SetRepeatDelegate Player_SetRepeat; 84 | public Player_GetEqualiserEnabledDelegate Player_GetEqualiserEnabled; 85 | public Player_SetEqualiserEnabledDelegate Player_SetEqualiserEnabled; 86 | public Player_GetDspEnabledDelegate Player_GetDspEnabled; 87 | public Player_SetDspEnabledDelegate Player_SetDspEnabled; 88 | public Player_GetScrobbleEnabledDelegate Player_GetScrobbleEnabled; 89 | public Player_SetScrobbleEnabledDelegate Player_SetScrobbleEnabled; 90 | public NowPlaying_GetFileUrlDelegate NowPlaying_GetFileUrl; 91 | public NowPlaying_GetDurationDelegate NowPlaying_GetDuration; 92 | public NowPlaying_GetFilePropertyDelegate NowPlaying_GetFileProperty; 93 | public NowPlaying_GetFileTagDelegate NowPlaying_GetFileTag; 94 | public NowPlaying_GetLyricsDelegate NowPlaying_GetLyrics; 95 | public NowPlaying_GetArtworkDelegate NowPlaying_GetArtwork; 96 | public NowPlayingList_ActionDelegate NowPlayingList_Clear; 97 | public Library_QueryFilesDelegate NowPlayingList_QueryFiles; 98 | public Library_QueryGetNextFileDelegate NowPlayingList_QueryGetNextFile; 99 | public NowPlayingList_FileActionDelegate NowPlayingList_PlayNow; 100 | public NowPlayingList_FileActionDelegate NowPlayingList_QueueNext; 101 | public NowPlayingList_FileActionDelegate NowPlayingList_QueueLast; 102 | public NowPlayingList_ActionDelegate NowPlayingList_PlayLibraryShuffled; 103 | public Playlist_QueryPlaylistsDelegate Playlist_QueryPlaylists; 104 | public Playlist_QueryGetNextPlaylistDelegate Playlist_QueryGetNextPlaylist; 105 | public Playlist_GetTypeDelegate Playlist_GetType; 106 | public Playlist_QueryFilesDelegate Playlist_QueryFiles; 107 | public Library_QueryGetNextFileDelegate Playlist_QueryGetNextFile; 108 | public MB_WindowHandleDelegate MB_GetWindowHandle; 109 | public MB_RefreshPanelsDelegate MB_RefreshPanels; 110 | public MB_SendNotificationDelegate MB_SendNotification; 111 | public MB_AddMenuItemDelegate MB_AddMenuItem; 112 | public Setting_GetFieldNameDelegate Setting_GetFieldName; 113 | [Obsolete("Use Library_QueryFilesEx", true)] 114 | public Library_QueryGetAllFilesDelegate Library_QueryGetAllFiles; 115 | [Obsolete("Use NowPlayingList_QueryFilesEx", true)] 116 | public Library_QueryGetAllFilesDelegate NowPlayingList_QueryGetAllFiles; 117 | [Obsolete("Use Playlist_QueryFilesEx", true)] 118 | public Library_QueryGetAllFilesDelegate Playlist_QueryGetAllFiles; 119 | public MB_CreateBackgroundTaskDelegate MB_CreateBackgroundTask; 120 | public MB_SetBackgroundTaskMessageDelegate MB_SetBackgroundTaskMessage; 121 | public MB_RegisterCommandDelegate MB_RegisterCommand; 122 | public Setting_GetDefaultFontDelegate Setting_GetDefaultFont; 123 | public Player_GetShowTimeRemainingDelegate Player_GetShowTimeRemaining; 124 | public NowPlayingList_GetCurrentIndexDelegate NowPlayingList_GetCurrentIndex; 125 | public NowPlayingList_GetFileUrlDelegate NowPlayingList_GetListFileUrl; 126 | public NowPlayingList_GetFilePropertyDelegate NowPlayingList_GetFileProperty; 127 | public NowPlayingList_GetFileTagDelegate NowPlayingList_GetFileTag; 128 | public NowPlaying_GetSpectrumDataDelegate NowPlaying_GetSpectrumData; 129 | public NowPlaying_GetSoundGraphDelegate NowPlaying_GetSoundGraph; 130 | public MB_GetPanelBoundsDelegate MB_GetPanelBounds; 131 | public MB_AddPanelDelegate MB_AddPanel; 132 | public MB_RemovePanelDelegate MB_RemovePanel; 133 | public MB_GetLocalisationDelegate MB_GetLocalisation; 134 | public NowPlayingList_IsAnyPriorTracksDelegate NowPlayingList_IsAnyPriorTracks; 135 | public NowPlayingList_IsAnyFollowingTracksDelegate NowPlayingList_IsAnyFollowingTracks; 136 | public Player_ShowEqualiserDelegate Player_ShowEqualiser; 137 | public Player_GetAutoDjEnabledDelegate Player_GetAutoDjEnabled; 138 | public Player_GetStopAfterCurrentEnabledDelegate Player_GetStopAfterCurrentEnabled; 139 | public Player_GetCrossfadeDelegate Player_GetCrossfade; 140 | public Player_SetCrossfadeDelegate Player_SetCrossfade; 141 | public Player_GetReplayGainModeDelegate Player_GetReplayGainMode; 142 | public Player_SetReplayGainModeDelegate Player_SetReplayGainMode; 143 | public Player_QueueRandomTracksDelegate Player_QueueRandomTracks; 144 | public Setting_GetDataTypeDelegate Setting_GetDataType; 145 | public NowPlayingList_GetNextIndexDelegate NowPlayingList_GetNextIndex; 146 | public NowPlaying_GetArtistPictureDelegate NowPlaying_GetArtistPicture; 147 | public NowPlaying_GetArtworkDelegate NowPlaying_GetDownloadedArtwork; 148 | // api version 16 149 | public MB_ShowNowPlayingAssistantDelegate MB_ShowNowPlayingAssistant; 150 | // api version 17 151 | public NowPlaying_GetLyricsDelegate NowPlaying_GetDownloadedLyrics; 152 | // api version 18 153 | public Player_GetShowRatingTrackDelegate Player_GetShowRatingTrack; 154 | public Player_GetShowRatingLoveDelegate Player_GetShowRatingLove; 155 | // api version 19 156 | public MB_CreateParameterisedBackgroundTaskDelegate MB_CreateParameterisedBackgroundTask; 157 | public Setting_GetLastFmUserIdDelegate Setting_GetLastFmUserId; 158 | public Playlist_GetNameDelegate Playlist_GetName; 159 | public Playlist_CreatePlaylistDelegate Playlist_CreatePlaylist; 160 | public Playlist_SetFilesDelegate Playlist_SetFiles; 161 | public Library_QuerySimilarArtistsDelegate Library_QuerySimilarArtists; 162 | public Library_QueryLookupTableDelegate Library_QueryLookupTable; 163 | public Library_QueryGetLookupTableValueDelegate Library_QueryGetLookupTableValue; 164 | public NowPlayingList_FilesActionDelegate NowPlayingList_QueueFilesNext; 165 | public NowPlayingList_FilesActionDelegate NowPlayingList_QueueFilesLast; 166 | // api version 20 167 | public Setting_GetWebProxyDelegate Setting_GetWebProxy; 168 | // api version 21 169 | public NowPlayingList_RemoveAtDelegate NowPlayingList_RemoveAt; 170 | // api version 22 171 | public Playlist_RemoveAtDelegate Playlist_RemoveAt; 172 | // api version 23 173 | public MB_SetPanelScrollableAreaDelegate MB_SetPanelScrollableArea; 174 | // api version 24 175 | public MB_InvokeCommandDelegate MB_InvokeCommand; 176 | public MB_OpenFilterInTabDelegate MB_OpenFilterInTab; 177 | // api version 25 178 | public MB_SetWindowSizeDelegate MB_SetWindowSize; 179 | public Library_GetArtistPictureDelegate Library_GetArtistPicture; 180 | public Pending_GetFileUrlDelegate Pending_GetFileUrl; 181 | public Pending_GetFilePropertyDelegate Pending_GetFileProperty; 182 | public Pending_GetFileTagDelegate Pending_GetFileTag; 183 | // api version 26 184 | public Player_GetButtonEnabledDelegate Player_GetButtonEnabled; 185 | // api version 27 186 | public NowPlayingList_MoveFilesDelegate NowPlayingList_MoveFiles; 187 | // api version 28 188 | public Library_GetArtworkDelegate Library_GetArtworkUrl; 189 | public Library_GetArtistPictureThumbDelegate Library_GetArtistPictureThumb; 190 | public NowPlaying_GetArtworkDelegate NowPlaying_GetArtworkUrl; 191 | public NowPlaying_GetArtworkDelegate NowPlaying_GetDownloadedArtworkUrl; 192 | public NowPlaying_GetArtistPictureThumbDelegate NowPlaying_GetArtistPictureThumb; 193 | // api version 29 194 | public Playlist_IsInListDelegate Playlist_IsInList; 195 | // api version 30 196 | public Library_GetArtistPictureUrlsDelegate Library_GetArtistPictureUrls; 197 | public NowPlaying_GetArtistPictureUrlsDelegate NowPlaying_GetArtistPictureUrls; 198 | // api version 31 199 | public Playlist_AddFilesDelegate Playlist_AppendFiles; 200 | // api version 32 201 | public Sync_FileStartDelegate Sync_FileStart; 202 | public Sync_FileEndDelegate Sync_FileEnd; 203 | // api version 33 204 | public Library_QueryFilesExDelegate Library_QueryFilesEx; 205 | public Library_QueryFilesExDelegate NowPlayingList_QueryFilesEx; 206 | public Playlist_QueryFilesExDelegate Playlist_QueryFilesEx; 207 | public Playlist_MoveFilesDelegate Playlist_MoveFiles; 208 | public Playlist_PlayNowDelegate Playlist_PlayNow; 209 | public NowPlaying_IsSoundtrackDelegate NowPlaying_IsSoundtrack; 210 | public NowPlaying_GetArtistPictureUrlsDelegate NowPlaying_GetSoundtrackPictureUrls; 211 | public Library_GetDevicePersistentIdDelegate Library_GetDevicePersistentId; 212 | public Library_SetDevicePersistentIdDelegate Library_SetDevicePersistentId; 213 | public Library_FindDevicePersistentIdDelegate Library_FindDevicePersistentId; 214 | public Setting_GetValueDelegate Setting_GetValue; 215 | public Library_AddFileToLibraryDelegate Library_AddFileToLibrary; 216 | public Playlist_DeletePlaylistDelegate Playlist_DeletePlaylist; 217 | public Library_GetSyncDeltaDelegate Library_GetSyncDelta; 218 | // api version 35 219 | public Library_GetFileTagsDelegate Library_GetFileTags; 220 | public NowPlaying_GetFileTagsDelegate NowPlaying_GetFileTags; 221 | public NowPlayingList_GetFileTagsDelegate NowPlayingList_GetFileTags; 222 | // api version 43 223 | public MB_AddTreeNodeDelegate MB_AddTreeNode; 224 | public MB_DownloadFileDelegate MB_DownloadFile; 225 | // api version 47 226 | public Setting_GetFileConvertCommandLineDelegate Setting_GetFileConvertCommandLine; 227 | public Player_OpenStreamHandleDelegate Player_OpenStreamHandle; 228 | public Player_UpdatePlayStatisticsDelegate Player_UpdatePlayStatistics; 229 | public Library_GetArtworkExDelegate Library_GetArtworkEx; 230 | public Library_SetArtworkExDelegate Library_SetArtworkEx; 231 | public MB_GetVisualiserInformationDelegate MB_GetVisualiserInformation; 232 | public MB_ShowVisualiserDelegate MB_ShowVisualiser; 233 | public MB_GetPluginViewInformationDelegate MB_GetPluginViewInformation; 234 | public MB_ShowPluginViewDelegate MB_ShowPluginView; 235 | public Player_GetOutputDevicesDelegate Player_GetOutputDevices; 236 | public Player_SetOutputDeviceDelegate Player_SetOutputDevice; 237 | } 238 | 239 | public enum MusicBeeVersion 240 | { 241 | v2_0 = 0, 242 | v2_1 = 1, 243 | v2_2 = 2, 244 | v2_3 = 3, 245 | v2_4 = 4, 246 | v2_5 = 5 247 | } 248 | 249 | public enum PluginType 250 | { 251 | Unknown = 0, 252 | General = 1, 253 | LyricsRetrieval = 2, 254 | ArtworkRetrieval = 3, 255 | PanelView = 4, 256 | DataStream = 5, 257 | InstantMessenger = 6, 258 | Storage = 7, 259 | VideoPlayer = 8, 260 | DSP = 9, 261 | TagRetrieval = 10, 262 | TagOrArtworkRetrieval = 11, 263 | Upnp = 12 264 | } 265 | 266 | [StructLayout(LayoutKind.Sequential)] 267 | public class PluginInfo 268 | { 269 | public short PluginInfoVersion; 270 | public PluginType Type; 271 | public string Name; 272 | public string Description; 273 | public string Author; 274 | public string TargetApplication; 275 | public short VersionMajor; 276 | public short VersionMinor; 277 | public short Revision; 278 | public short MinInterfaceVersion; 279 | public short MinApiRevision; 280 | public ReceiveNotificationFlags ReceiveNotifications; 281 | public int ConfigurationPanelHeight; 282 | } 283 | 284 | [Flags()] 285 | public enum ReceiveNotificationFlags 286 | { 287 | StartupOnly = 0x0, 288 | PlayerEvents = 0x1, 289 | DataStreamEvents = 0x2, 290 | TagEvents = 0x04, 291 | DownloadEvents = 0x08 292 | } 293 | 294 | public enum NotificationType 295 | { 296 | PluginStartup = 0, // notification sent after successful initialisation for an enabled plugin 297 | TrackChanging = 16, 298 | TrackChanged = 1, 299 | PlayStateChanged = 2, 300 | AutoDjStarted = 3, 301 | AutoDjStopped = 4, 302 | VolumeMuteChanged = 5, 303 | VolumeLevelChanged = 6, 304 | NowPlayingListChanged = 7, 305 | NowPlayingListEnded = 18, 306 | NowPlayingArtworkReady = 8, 307 | NowPlayingLyricsReady = 9, 308 | TagsChanging = 10, 309 | TagsChanged = 11, 310 | RatingChanging = 15, 311 | RatingChanged = 12, 312 | PlayCountersChanged = 13, 313 | ScreenSaverActivating = 14, 314 | ShutdownStarted = 17, 315 | EmbedInPanel = 19, 316 | PlayerRepeatChanged = 20, 317 | PlayerShuffleChanged = 21, 318 | PlayerEqualiserOnOffChanged = 22, 319 | PlayerScrobbleChanged = 23, 320 | ReplayGainChanged = 24, 321 | FileDeleting = 25, 322 | FileDeleted = 26, 323 | ApplicationWindowChanged = 27, 324 | StopAfterCurrentChanged = 28, 325 | LibrarySwitched = 29, 326 | FileAddedToLibrary = 30, 327 | FileAddedToInbox = 31, 328 | SynchCompleted = 32, 329 | DownloadCompleted = 33, 330 | MusicBeeStarted = 34 331 | } 332 | 333 | public enum PluginCloseReason 334 | { 335 | MusicBeeClosing = 1, 336 | UserDisabled = 2, 337 | StopNoUnload = 3 338 | } 339 | 340 | public enum CallbackType 341 | { 342 | SettingsUpdated = 1, 343 | StorageReady = 2, 344 | StorageFailed = 3, 345 | FilesRetrievedChanged = 4, 346 | FilesRetrievedNoChange = 5, 347 | FilesRetrievedFail = 6, 348 | LyricsDownloaded = 7, 349 | StorageEject = 8, 350 | SuspendPlayCounters = 9, 351 | ResumePlayCounters = 10, 352 | EnablePlugin = 11, 353 | DisablePlugin = 12, 354 | RenderingDevicesChanged = 13, 355 | FullscreenOn = 14, 356 | FullscreenOff = 15 357 | } 358 | 359 | public enum FilePropertyType 360 | { 361 | Url = 2, 362 | Kind = 4, 363 | Format = 5, 364 | Size = 7, 365 | Channels = 8, 366 | SampleRate = 9, 367 | Bitrate = 10, 368 | DateModified = 11, 369 | DateAdded = 12, 370 | LastPlayed = 13, 371 | PlayCount = 14, 372 | SkipCount = 15, 373 | Duration = 16, 374 | Status = 21, 375 | NowPlayingListIndex = 78, // only has meaning when called from NowPlayingList_* commands 376 | ReplayGainTrack = 94, 377 | ReplayGainAlbum = 95 378 | } 379 | 380 | public enum MetaDataType 381 | { 382 | TrackTitle = 65, 383 | Album = 30, 384 | AlbumArtist = 31, // displayed album artist 385 | AlbumArtistRaw = 34, // stored album artist 386 | Artist = 32, // displayed artist 387 | MultiArtist = 33, // individual artists, separated by a null char 388 | PrimaryArtist = 19, // first artist from multi-artist tagged file, otherwise displayed artist 389 | Artists = 144, 390 | ArtistsWithArtistRole = 145, 391 | ArtistsWithPerformerRole = 146, 392 | ArtistsWithGuestRole = 147, 393 | ArtistsWithRemixerRole = 148, 394 | Artwork = 40, 395 | BeatsPerMin = 41, 396 | Composer = 43, // displayed composer 397 | MultiComposer = 89, // individual composers, separated by a null char 398 | Comment = 44, 399 | Conductor = 45, 400 | Custom1 = 46, 401 | Custom2 = 47, 402 | Custom3 = 48, 403 | Custom4 = 49, 404 | Custom5 = 50, 405 | Custom6 = 96, 406 | Custom7 = 97, 407 | Custom8 = 98, 408 | Custom9 = 99, 409 | Custom10 = 128, 410 | Custom11 = 129, 411 | Custom12 = 130, 412 | Custom13 = 131, 413 | Custom14 = 132, 414 | Custom15 = 133, 415 | Custom16 = 134, 416 | DiscNo = 52, 417 | DiscCount = 54, 418 | Encoder = 55, 419 | Genre = 59, 420 | Genres = 143, 421 | GenreCategory = 60, 422 | Grouping = 61, 423 | Keywords = 84, 424 | HasLyrics = 63, 425 | Lyricist = 62, 426 | Lyrics = 114, 427 | Mood = 64, 428 | Occasion = 66, 429 | Origin = 67, 430 | Publisher = 73, 431 | Quality = 74, 432 | Rating = 75, 433 | RatingLove = 76, 434 | RatingAlbum = 104, 435 | Tempo = 85, 436 | TrackNo = 86, 437 | TrackCount = 87, 438 | Virtual1 = 109, 439 | Virtual2 = 110, 440 | Virtual3 = 111, 441 | Virtual4 = 112, 442 | Virtual5 = 113, 443 | Virtual6 = 122, 444 | Virtual7 = 123, 445 | Virtual8 = 124, 446 | Virtual9 = 125, 447 | Virtual10 = 135, 448 | Virtual11 = 136, 449 | Virtual12 = 137, 450 | Virtual13 = 138, 451 | Virtual14 = 139, 452 | Virtual15 = 140, 453 | Virtual16 = 141, 454 | Year = 88 455 | } 456 | 457 | public enum FileCodec 458 | { 459 | Unknown = -1, 460 | Mp3 = 1, 461 | Aac = 2, 462 | Flac = 3, 463 | Ogg = 4, 464 | WavPack = 5, 465 | Wma = 6, 466 | Tak = 7, 467 | Mpc = 8, 468 | Wave = 9, 469 | Asx = 10, 470 | Alac = 11, 471 | Aiff = 12, 472 | Pcm = 13, 473 | Opus = 15, 474 | Spx = 16, 475 | Dsd = 17, 476 | AacNoContainer = 18 477 | } 478 | 479 | public enum EncodeQuality 480 | { 481 | SmallSize = 1, 482 | Portable = 2, 483 | HighQuality = 3, 484 | Archiving = 4 485 | } 486 | 487 | [Flags()] 488 | public enum LibraryCategory 489 | { 490 | Music = 0, 491 | Audiobook = 1, 492 | Video = 2, 493 | Inbox = 4 494 | } 495 | 496 | public enum DeviceIdType 497 | { 498 | GooglePlay = 1, 499 | AppleDevice = 2, 500 | GooglePlay2 = 3, 501 | AppleDevice2 = 4 502 | } 503 | 504 | public enum DataType 505 | { 506 | String = 0, 507 | Number = 1, 508 | DateTime = 2, 509 | Rating = 3 510 | } 511 | 512 | public enum SettingId 513 | { 514 | CompactPlayerFlickrEnabled = 1, 515 | FileTaggingPreserveModificationTime = 2, 516 | LastDownloadFolder = 3, 517 | ArtistGenresOnly = 4, 518 | IgnoreNamePrefixes = 5, 519 | IgnoreNameChars = 6, 520 | PlayCountTriggerPercent = 7, 521 | PlayCountTriggerSeconds = 8, 522 | SkipCountTriggerPercent = 9, 523 | SkipCountTriggerSeconds = 10 524 | } 525 | 526 | public enum ComparisonType 527 | { 528 | Is = 0, 529 | IsSimilar = 20 530 | } 531 | 532 | public enum LyricsType 533 | { 534 | NotSpecified = 0, 535 | Synchronised = 1, 536 | UnSynchronised = 2 537 | } 538 | 539 | public enum PlayState 540 | { 541 | Undefined = 0, 542 | Loading = 1, 543 | Playing = 3, 544 | Paused = 6, 545 | Stopped = 7 546 | } 547 | 548 | public enum RepeatMode 549 | { 550 | None = 0, 551 | All = 1, 552 | One = 2 553 | } 554 | 555 | public enum PlayButtonType 556 | { 557 | PreviousTrack = 0, 558 | PlayPause = 1, 559 | NextTrack = 2, 560 | Stop = 3 561 | } 562 | 563 | public enum PlaylistFormat 564 | { 565 | Unknown = 0, 566 | M3u = 1, 567 | Xspf = 2, 568 | Asx = 3, 569 | Wpl = 4, 570 | Pls = 5, 571 | Auto = 7, 572 | M3uAscii = 8, 573 | AsxFile = 9, 574 | Radio = 10, 575 | M3uExtended = 11, 576 | Mbp = 12 577 | } 578 | 579 | public enum SkinElement 580 | { 581 | SkinInputControl = 7, 582 | SkinInputPanel = 10, 583 | SkinInputPanelLabel = 14, 584 | SkinTrackAndArtistPanel = -1 585 | } 586 | 587 | public enum ElementState 588 | { 589 | ElementStateDefault = 0, 590 | ElementStateModified = 6 591 | } 592 | 593 | public enum ElementComponent 594 | { 595 | ComponentBorder = 0, 596 | ComponentBackground = 1, 597 | ComponentForeground = 3 598 | } 599 | 600 | public enum PluginPanelDock 601 | { 602 | ApplicationWindow = 0, 603 | TrackAndArtistPanel = 1, 604 | TextBox = 3, 605 | ComboBox = 4, 606 | MainPanel = 5 607 | } 608 | 609 | 610 | public enum ReplayGainMode 611 | { 612 | Off = 0, 613 | Track = 1, 614 | Album = 2, 615 | Smart = 3 616 | } 617 | 618 | public enum PlayStatisticType 619 | { 620 | NoChange = 0, 621 | IncreasePlayCount = 1, 622 | IncreaseSkipCount = 2 623 | } 624 | 625 | public enum Command 626 | { 627 | NavigateTo = 1 628 | } 629 | 630 | public enum DownloadTarget 631 | { 632 | Inbox = 0, 633 | MusicLibrary = 1, 634 | SpecificFolder = 3 635 | } 636 | 637 | [Flags()] 638 | public enum PictureLocations: byte 639 | { 640 | None = 0, 641 | EmbedInFile = 1, 642 | LinkToOrganisedCopy = 2, 643 | LinkToSource = 4, 644 | FolderThumb = 8 645 | } 646 | 647 | public enum WindowState 648 | { 649 | Off = -1, 650 | Normal = 0, 651 | Fullscreen = 1, 652 | Desktop = 2 653 | } 654 | 655 | public delegate void MB_ReleaseStringDelegate(string p1); 656 | public delegate void MB_TraceDelegate(string p1); 657 | public delegate IntPtr MB_WindowHandleDelegate(); 658 | public delegate void MB_RefreshPanelsDelegate(); 659 | public delegate void MB_SendNotificationDelegate(CallbackType type); 660 | public delegate System.Windows.Forms.ToolStripItem MB_AddMenuItemDelegate(string menuPath, string hotkeyDescription, EventHandler handler); 661 | public delegate bool MB_AddTreeNodeDelegate(string treePath, string name, System.Drawing.Bitmap icon, EventHandler openHandler, EventHandler closeHandler); 662 | public delegate void MB_RegisterCommandDelegate(string command, EventHandler handler); 663 | public delegate void MB_CreateBackgroundTaskDelegate(System.Threading.ThreadStart taskCallback, System.Windows.Forms.Form owner); 664 | public delegate void MB_CreateParameterisedBackgroundTaskDelegate(System.Threading.ParameterizedThreadStart taskCallback, object parameters, System.Windows.Forms.Form owner); 665 | public delegate void MB_SetBackgroundTaskMessageDelegate(string message); 666 | public delegate System.Drawing.Rectangle MB_GetPanelBoundsDelegate(PluginPanelDock dock); 667 | public delegate bool MB_SetPanelScrollableAreaDelegate(System.Windows.Forms.Control panel, System.Drawing.Size scrollArea, bool alwaysShowScrollBar); 668 | public delegate System.Windows.Forms.Control MB_AddPanelDelegate(System.Windows.Forms.Control panel, PluginPanelDock dock); 669 | public delegate void MB_RemovePanelDelegate(System.Windows.Forms.Control panel); 670 | public delegate string MB_GetLocalisationDelegate(string id, string defaultText); 671 | public delegate bool MB_ShowNowPlayingAssistantDelegate(); 672 | public delegate bool MB_InvokeCommandDelegate(Command command, object parameter); 673 | public delegate bool MB_OpenFilterInTabDelegate(MetaDataType field1, ComparisonType comparison1, string value1, MetaDataType field2, ComparisonType comparison2, string value2); 674 | public delegate bool MB_SetWindowSizeDelegate(int width, int height); 675 | public delegate bool MB_DownloadFileDelegate(string url, DownloadTarget target, string targetFolder, bool cancelDownload); 676 | public delegate bool MB_GetVisualiserInformationDelegate(out string[] visualiserNames, out string defaultVisualiserName, out WindowState defaultState, out WindowState currentState); 677 | public delegate bool MB_ShowVisualiserDelegate(string visualiserName, WindowState state); 678 | public delegate bool MB_GetPluginViewInformationDelegate(string pluginFilename, out string[] viewNames, out string defaultViewName, out WindowState defaultState, out WindowState currentState); 679 | public delegate bool MB_ShowPluginViewDelegate(string pluginFilename, string viewName, WindowState state); 680 | public delegate string Setting_GetFieldNameDelegate(MetaDataType field); 681 | public delegate string Setting_GetPersistentStoragePathDelegate(); 682 | public delegate string Setting_GetSkinDelegate(); 683 | public delegate int Setting_GetSkinElementColourDelegate(SkinElement element, ElementState state, ElementComponent component); 684 | public delegate bool Setting_IsWindowBordersSkinnedDelegate(); 685 | public delegate System.Drawing.Font Setting_GetDefaultFontDelegate(); 686 | public delegate DataType Setting_GetDataTypeDelegate(MetaDataType field); 687 | public delegate string Setting_GetLastFmUserIdDelegate(); 688 | public delegate string Setting_GetWebProxyDelegate(); 689 | public delegate bool Setting_GetValueDelegate(SettingId settingId, ref object value); 690 | public delegate string Setting_GetFileConvertCommandLineDelegate(FileCodec codec, EncodeQuality encodeQuality); 691 | public delegate string Library_GetFilePropertyDelegate(string sourceFileUrl, FilePropertyType type); 692 | public delegate string Library_GetFileTagDelegate(string sourceFileUrl, MetaDataType field); 693 | public delegate bool Library_GetFileTagsDelegate(string sourceFileUrl, MetaDataType[] fields, ref string[] results); 694 | public delegate bool Library_SetFileTagDelegate(string sourceFileUrl, MetaDataType field, string value); 695 | public delegate string Library_GetDevicePersistentIdDelegate(string sourceFileUrl, DeviceIdType idType); 696 | public delegate bool Library_SetDevicePersistentIdDelegate(string sourceFileUrl, DeviceIdType idType, string value); 697 | public delegate bool Library_FindDevicePersistentIdDelegate(DeviceIdType idType, string[] ids, ref string[] values); 698 | public delegate bool Library_CommitTagsToFileDelegate(string sourceFileUrl); 699 | public delegate string Library_AddFileToLibraryDelegate(string sourceFileUrl, LibraryCategory category); 700 | public delegate bool Library_GetSyncDeltaDelegate(string[] cachedFiles, DateTime updatedSince, LibraryCategory categories, ref string[] newFiles, ref string[] updatedFiles, ref string[] deletedFiles); 701 | public delegate string Library_GetLyricsDelegate(string sourceFileUrl, LyricsType type); 702 | public delegate string Library_GetArtworkDelegate(string sourceFileUrl, int index); 703 | public delegate bool Library_GetArtworkExDelegate(string sourceFileUrl, int index, bool retrievePictureData, ref PictureLocations pictureLocations, ref string pictureUrl, ref byte[] imageData); 704 | public delegate bool Library_SetArtworkExDelegate(string sourceFileUrl, int index, byte[] imageData); 705 | public delegate string Library_GetArtistPictureDelegate(string artistName, int fadingPercent, int fadingColor); 706 | public delegate bool Library_GetArtistPictureUrlsDelegate(string artistName, bool localOnly, ref string[] urls); 707 | public delegate string Library_GetArtistPictureThumbDelegate(string artistName); 708 | public delegate bool Library_QueryFilesDelegate(string query); 709 | public delegate string Library_QueryGetNextFileDelegate(); 710 | public delegate string Library_QueryGetAllFilesDelegate(); 711 | public delegate bool Library_QueryFilesExDelegate(string query, ref string[] files); 712 | public delegate string Library_QuerySimilarArtistsDelegate(string artistName, double minimumArtistSimilarityRating); 713 | public delegate bool Library_QueryLookupTableDelegate(string keyTags, string valueTags, string query); 714 | public delegate string Library_QueryGetLookupTableValueDelegate(string key); 715 | public delegate int Player_GetPositionDelegate(); 716 | public delegate bool Player_SetPositionDelegate(int position); 717 | public delegate PlayState Player_GetPlayStateDelegate(); 718 | public delegate bool Player_GetButtonEnabledDelegate(PlayButtonType button); 719 | public delegate bool Player_ActionDelegate(); 720 | public delegate int Player_QueueRandomTracksDelegate(int count); 721 | public delegate float Player_GetVolumeDelegate(); 722 | public delegate bool Player_SetVolumeDelegate(float volume); 723 | public delegate bool Player_GetMuteDelegate(); 724 | public delegate bool Player_SetMuteDelegate(bool mute); 725 | public delegate bool Player_GetShuffleDelegate(); 726 | public delegate bool Player_SetShuffleDelegate(bool shuffle); 727 | public delegate RepeatMode Player_GetRepeatDelegate(); 728 | public delegate bool Player_SetRepeatDelegate(RepeatMode repeat); 729 | public delegate bool Player_GetEqualiserEnabledDelegate(); 730 | public delegate bool Player_SetEqualiserEnabledDelegate(bool enabled); 731 | public delegate bool Player_GetDspEnabledDelegate(); 732 | public delegate bool Player_SetDspEnabledDelegate(bool enabled); 733 | public delegate bool Player_GetScrobbleEnabledDelegate(); 734 | public delegate bool Player_SetScrobbleEnabledDelegate(bool enabled); 735 | public delegate bool Player_GetShowTimeRemainingDelegate(); 736 | public delegate bool Player_GetShowRatingTrackDelegate(); 737 | public delegate bool Player_GetShowRatingLoveDelegate(); 738 | public delegate bool Player_ShowEqualiserDelegate(); 739 | public delegate bool Player_GetAutoDjEnabledDelegate(); 740 | public delegate bool Player_GetStopAfterCurrentEnabledDelegate(); 741 | public delegate bool Player_GetCrossfadeDelegate(); 742 | public delegate bool Player_SetCrossfadeDelegate(bool crossfade); 743 | public delegate ReplayGainMode Player_GetReplayGainModeDelegate(); 744 | public delegate bool Player_SetReplayGainModeDelegate(ReplayGainMode mode); 745 | public delegate int Player_OpenStreamHandleDelegate(string url, bool useMusicBeeSettings, bool enableDsp, ReplayGainMode gainType); 746 | public delegate bool Player_UpdatePlayStatisticsDelegate(string url, PlayStatisticType countType, bool disableScrobble); 747 | public delegate bool Player_GetOutputDevicesDelegate(out string[] deviceNames, out string activeDeviceName); 748 | public delegate bool Player_SetOutputDeviceDelegate(string deviceName); 749 | public delegate string NowPlaying_GetFileUrlDelegate(); 750 | public delegate int NowPlaying_GetDurationDelegate(); 751 | public delegate string NowPlaying_GetFilePropertyDelegate(FilePropertyType type); 752 | public delegate string NowPlaying_GetFileTagDelegate(MetaDataType field); 753 | public delegate bool NowPlaying_GetFileTagsDelegate(MetaDataType[] fields, ref string[] results); 754 | public delegate string NowPlaying_GetLyricsDelegate(); 755 | public delegate string NowPlaying_GetArtworkDelegate(); 756 | public delegate string NowPlaying_GetArtistPictureDelegate(int fadingPercent); 757 | public delegate bool NowPlaying_GetArtistPictureUrlsDelegate(bool localOnly, ref string[] urls); 758 | public delegate string NowPlaying_GetArtistPictureThumbDelegate(); 759 | public delegate bool NowPlaying_IsSoundtrackDelegate(); 760 | public delegate int NowPlaying_GetSpectrumDataDelegate(float[] fftData); 761 | public delegate bool NowPlaying_GetSoundGraphDelegate(float[] graphData); 762 | public delegate int NowPlayingList_GetCurrentIndexDelegate(); 763 | public delegate int NowPlayingList_GetNextIndexDelegate(int offset); 764 | public delegate bool NowPlayingList_IsAnyPriorTracksDelegate(); 765 | public delegate bool NowPlayingList_IsAnyFollowingTracksDelegate(); 766 | public delegate string NowPlayingList_GetFileUrlDelegate(int index); 767 | public delegate string NowPlayingList_GetFilePropertyDelegate(int index, FilePropertyType type); 768 | public delegate string NowPlayingList_GetFileTagDelegate(int index, MetaDataType field); 769 | public delegate bool NowPlayingList_GetFileTagsDelegate(int index, MetaDataType[] fields, ref string[] results); 770 | public delegate bool NowPlayingList_ActionDelegate(); 771 | public delegate bool NowPlayingList_FileActionDelegate(string sourceFileUrl); 772 | public delegate bool NowPlayingList_FilesActionDelegate(string[] sourceFileUrl); 773 | public delegate bool NowPlayingList_RemoveAtDelegate(int index); 774 | public delegate bool NowPlayingList_MoveFilesDelegate(int[] fromIndices, int toIndex); 775 | public delegate string Playlist_GetNameDelegate(string playlistUrl); 776 | public delegate PlaylistFormat Playlist_GetTypeDelegate(string playlistUrl); 777 | public delegate bool Playlist_QueryPlaylistsDelegate(); 778 | public delegate string Playlist_QueryGetNextPlaylistDelegate(); 779 | public delegate bool Playlist_IsInListDelegate(string playlistUrl, string filename); 780 | public delegate bool Playlist_QueryFilesDelegate(string playlistUrl); 781 | public delegate bool Playlist_QueryFilesExDelegate(string playlistUrl, ref string[] filenames); 782 | public delegate string Playlist_CreatePlaylistDelegate(string folderName, string playlistName, string[] filenames); 783 | public delegate bool Playlist_DeletePlaylistDelegate(string playlistUrl); 784 | public delegate bool Playlist_SetFilesDelegate(string playlistUrl, string[] filenames); 785 | public delegate bool Playlist_AddFilesDelegate(string playlistUrl, string[] filenames); 786 | public delegate bool Playlist_RemoveAtDelegate(string playlistUrl, int index); 787 | public delegate bool Playlist_MoveFilesDelegate(string playlistUrl, int[] fromIndices, int toIndex); 788 | public delegate bool Playlist_PlayNowDelegate(string playlistUrl); 789 | public delegate string Pending_GetFileUrlDelegate(); 790 | public delegate string Pending_GetFilePropertyDelegate(FilePropertyType field); 791 | public delegate string Pending_GetFileTagDelegate(MetaDataType field); 792 | public delegate string Sync_FileStartDelegate(string filename); 793 | public delegate void Sync_FileEndDelegate(string filename, bool success, string errorMessage); 794 | 795 | [System.Security.SuppressUnmanagedCodeSecurity()] 796 | [DllImport("kernel32.dll")] 797 | private static extern void CopyMemory(ref MusicBeeApiInterface mbApiInterface, IntPtr src, int length); 798 | } 799 | } --------------------------------------------------------------------------------