├── .gitattributes ├── .gitignore ├── Beenius Tester ├── Beenius Tester.csproj └── Program.cs ├── Beenius.sln ├── Beenius ├── Beenius.csproj ├── GeniusClient.cs ├── MusicBeeInterface.cs ├── Plugin.cs ├── Properties │ └── AssemblyInfo.cs ├── Util.cs ├── beenius.conf.template └── packages.config └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /Beenius Tester/Beenius Tester.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | Beenius_Tester 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Beenius Tester/Program.cs: -------------------------------------------------------------------------------- 1 | using Beenius; 2 | 3 | namespace Beenius_Tester 4 | { 5 | internal class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | GeniusClient client = new GeniusClient(""); 10 | client.getLyrics("GERM", "SORRY MOM I WAS FRIED [YEP]"); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Beenius.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32414.318 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Beenius", "Beenius\Beenius.csproj", "{3C722447-CCB8-4062-A8B8-8005DCACE15D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Beenius Tester", "Beenius Tester\Beenius Tester.csproj", "{41C09670-9127-4EC5-B1E0-E6F6BAAAE060}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3C722447-CCB8-4062-A8B8-8005DCACE15D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {3C722447-CCB8-4062-A8B8-8005DCACE15D}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {3C722447-CCB8-4062-A8B8-8005DCACE15D}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {3C722447-CCB8-4062-A8B8-8005DCACE15D}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {41C09670-9127-4EC5-B1E0-E6F6BAAAE060}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {41C09670-9127-4EC5-B1E0-E6F6BAAAE060}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {41C09670-9127-4EC5-B1E0-E6F6BAAAE060}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {41C09670-9127-4EC5-B1E0-E6F6BAAAE060}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E77D7F3E-6C64-4D06-B9C4-EEE21C8650D7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Beenius/Beenius.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3C722447-CCB8-4062-A8B8-8005DCACE15D} 8 | Library 9 | Properties 10 | Beenius 11 | Beenius 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\NLog.5.0.1\lib\net46\NLog.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ..\packages\Topten.JsonKit.1.1.135\lib\net46\Topten.JsonKit.dll 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | PreserveNewest 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Beenius/GeniusClient.cs: -------------------------------------------------------------------------------- 1 | using MusicBeePlugin; 2 | using NLog; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Specialized; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using Topten.JsonKit; 12 | 13 | namespace Beenius 14 | { 15 | public class GeniusClient 16 | { 17 | private static Logger Logger = LogManager.GetLogger(Plugin.name); 18 | 19 | private HttpClient client = new HttpClient(); 20 | 21 | private string LyricsProviderName; 22 | 23 | private string Token = "ZTejoT_ojOEasIkT9WrMBhBQOz6eYKK5QULCMECmOhvwqjRZ6WbpamFe3geHnvp3"; //anonymous Android app token 24 | private string ApiURL = "https://api.genius.com"; 25 | private int AllowedDistance = 5; //a number of edits needed to get from one title to another 26 | private char[] Delimiters = { }; //delimiters to remove additional authors from the string 27 | private int MaxResults = 1; //maximum search results to analyze 28 | private bool AddLyricsSource = false; 29 | private bool TrimTitle = false; 30 | private bool RemoveTags = false; 31 | public GeniusClient(string lyricsProviderName = null) 32 | { 33 | LyricsProviderName = lyricsProviderName; 34 | 35 | client.DefaultRequestHeaders.Remove("User-Agent"); 36 | client.DefaultRequestHeaders.Add("User-Agent", "okhttp/4.9.1"); 37 | client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token); 38 | 39 | if (File.Exists(Plugin.configFile)) 40 | { 41 | string data = File.ReadAllText(Plugin.configFile); 42 | dynamic config = Json.Parse(data); 43 | if (Util.PropertyExists(config, "allowedDistance")) 44 | AllowedDistance = (int)config.allowedDistance; 45 | if (Util.PropertyExists(config, "delimiters")) 46 | Delimiters = ((List)config.delimiters).Select(x => char.Parse(x.ToString())).ToArray(); 47 | if (Util.PropertyExists(config, "token")) 48 | Token = config.token; 49 | if (Util.PropertyExists(config, "maxResults")) 50 | MaxResults = (int)config.maxResults; 51 | if (Util.PropertyExists(config, "addLyricsSource")) 52 | AddLyricsSource = (bool)config.addLyricsSource; 53 | if (Util.PropertyExists(config, "trimTitle")) 54 | TrimTitle = (bool)config.trimTitle; 55 | if (Util.PropertyExists(config, "removeTags")) 56 | RemoveTags = (bool)config.removeTags; 57 | 58 | Logger.Info("Configuration file was used: allowedDistance={allowedDistance}, delimiters={delimiters}, token={token}, maxResults={maxResults}, addLyricsSource={addLyricsSource}, trimTitle={trimTitle}", AllowedDistance, Delimiters, Token, MaxResults, AddLyricsSource, TrimTitle); 59 | } 60 | else { Logger.Info("No configuration file was provided, defaults were used"); } 61 | } 62 | 63 | private dynamic GeniusRequest(string path, NameValueCollection parameters = null) 64 | { 65 | string url = this.ApiURL + path; 66 | if (parameters == null) 67 | parameters = new NameValueCollection(); 68 | 69 | parameters.Add("from_background", "0"); 70 | 71 | url += "?" + Util.ToQueryString(parameters); 72 | HttpResponseMessage response = null; 73 | try 74 | { 75 | var task = Task.Run(() => client.GetAsync(url)); 76 | task.Wait(); 77 | response = task.Result; 78 | } 79 | catch (Exception) 80 | { 81 | throw; 82 | } 83 | dynamic result = null; 84 | try 85 | { 86 | string content = string.Empty; 87 | var task = Task.Run(() => response.Content.ReadAsStringAsync()); 88 | task.Wait(); 89 | content = task.Result; 90 | result = Json.Parse(content); 91 | } 92 | catch { throw; } 93 | return result; 94 | } 95 | 96 | public string getLyrics(string artist, string title) 97 | { 98 | artist = artist.Trim(); 99 | title = title.Trim(); 100 | 101 | if (TrimTitle) { title = Util.Trim(title); } 102 | 103 | Logger.Info("Attempting to search for {aritst} - {title}", artist, title); 104 | 105 | string result = search(artist, title); 106 | if (string.IsNullOrEmpty(result) && Delimiters.Length > 0) 107 | { 108 | var editedArtist = artist; 109 | 110 | foreach (char delimiter in Delimiters) editedArtist = editedArtist.Split(delimiter)[0].Trim(); 111 | 112 | if (editedArtist != artist) 113 | { 114 | Logger.Info("Nothing found, attempting to search for {aritst} - {title}", editedArtist, title); 115 | 116 | result = search(editedArtist, title); 117 | } 118 | } 119 | if (string.IsNullOrEmpty(result)) { Logger.Info("Nothing found at all"); } 120 | else { Logger.Info("Got a hit"); } 121 | return result; 122 | } 123 | 124 | private string search(string artist, string title, bool parseDom = true) 125 | { 126 | Logger.Debug("artist={artist}, title={title}", artist, title); 127 | 128 | var req = new NameValueCollection(); 129 | req.Add("q", artist + " " + title); 130 | dynamic searchResults = GeniusRequest("/search", req); 131 | var matches = searchResults.response.hits; 132 | if (matches.Count == 0) { return null; } 133 | 134 | dynamic chosenMatch = null; 135 | 136 | int analyzedMatches = 0; 137 | 138 | foreach (var match in matches) 139 | { 140 | if (analyzedMatches > MaxResults - 1) break; 141 | 142 | if (match.type != "song") continue; 143 | 144 | if (Util.ValidateResult(artist, title, match.result.primary_artist.name, match.result.title, AllowedDistance)) 145 | { 146 | chosenMatch = match; 147 | break; 148 | } 149 | 150 | Logger.Info("Let's check for aliases"); 151 | 152 | dynamic matchArtistResult = GeniusRequest(match.result.primary_artist.api_path); 153 | dynamic matchArtist = matchArtistResult.response.artist; 154 | if (matchArtist.alternate_names.Count == 0) { Logger.Info("No aliases"); } 155 | 156 | foreach (var alias in matchArtist.alternate_names) 157 | { 158 | if (Util.ValidateResult(artist, title, alias, match.result.title, AllowedDistance)) 159 | { 160 | chosenMatch = match; 161 | break; 162 | } 163 | } 164 | 165 | if (chosenMatch != null) break; 166 | 167 | analyzedMatches++; 168 | } 169 | 170 | if (chosenMatch == null) 171 | { 172 | Logger.Info("No results for this search"); 173 | 174 | return null; 175 | } 176 | 177 | string songApiPath = chosenMatch.result.api_path; 178 | 179 | string result = string.Empty; 180 | 181 | if (parseDom) 182 | { 183 | dynamic songPage = GeniusRequest(songApiPath); 184 | 185 | dynamic lyricsDom = songPage.response.song.lyrics.dom.children; 186 | 187 | result = parseLyricsDom(lyricsDom); 188 | } 189 | else //Won't use plain text since Genius returns it with a space before every line. Also I've already done DOM parsing so why bother. 190 | { 191 | req = new NameValueCollection(); 192 | req.Add("text_format", "plain"); 193 | 194 | dynamic songPage = GeniusRequest(songApiPath, req); 195 | 196 | result = songPage.response.song.lyrics.plain; 197 | } 198 | 199 | Logger.Info("Found lyrics"); 200 | 201 | if (AddLyricsSource) 202 | result = $"Source: {LyricsProviderName}\n\n" + result; 203 | 204 | if (RemoveTags) 205 | result = Regex.Replace(result, @"\[.*\]\s*?\r?\n", string.Empty); 206 | 207 | return result; 208 | } 209 | 210 | private string parseLyricsDom(dynamic lyricsDom) 211 | { 212 | string result = string.Empty; 213 | 214 | foreach (dynamic elem in lyricsDom) 215 | { 216 | if (elem is System.Dynamic.ExpandoObject) 217 | { 218 | if (Util.PropertyExists(elem, "tag") && elem.tag == "br") result += '\n'; 219 | if (!Util.PropertyExists(elem, "children")) continue; 220 | result += parseLyricsDom(elem.children); 221 | } 222 | else if (elem is string) 223 | { 224 | string entry = elem.ToString(); 225 | result += entry; 226 | } 227 | else 228 | { 229 | 230 | } 231 | } 232 | 233 | return result; 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /Beenius/MusicBeeInterface.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Collections.Generic; 4 | 5 | namespace MusicBeePlugin 6 | { 7 | public partial class Plugin 8 | { 9 | public const short PluginInfoVersion = 1; 10 | public const short MinInterfaceVersion = 41; 11 | public const short MinApiRevision = 53; 12 | 13 | [StructLayout(LayoutKind.Sequential)] 14 | public struct MusicBeeApiInterface 15 | { 16 | public void Initialise(IntPtr apiInterfacePtr) 17 | { 18 | CopyMemory(ref this, apiInterfacePtr, 4); 19 | if (MusicBeeVersion == MusicBeeVersion.v2_0) 20 | // MusicBee version 2.0 - Api methods > revision 25 are not available 21 | CopyMemory(ref this, apiInterfacePtr, 456); 22 | else if (MusicBeeVersion == MusicBeeVersion.v2_1) 23 | CopyMemory(ref this, apiInterfacePtr, 516); 24 | else if (MusicBeeVersion == MusicBeeVersion.v2_2) 25 | CopyMemory(ref this, apiInterfacePtr, 584); 26 | else if (MusicBeeVersion == MusicBeeVersion.v2_3) 27 | CopyMemory(ref this, apiInterfacePtr, 596); 28 | else if (MusicBeeVersion == MusicBeeVersion.v2_4) 29 | CopyMemory(ref this, apiInterfacePtr, 604); 30 | else if (MusicBeeVersion == MusicBeeVersion.v2_5) 31 | CopyMemory(ref this, apiInterfacePtr, 648); 32 | else if (MusicBeeVersion == MusicBeeVersion.v3_0) 33 | CopyMemory(ref this, apiInterfacePtr, 652); 34 | else 35 | CopyMemory(ref this, apiInterfacePtr, Marshal.SizeOf(this)); 36 | } 37 | public MusicBeeVersion MusicBeeVersion 38 | { 39 | get { 40 | if (ApiRevision <= 25) 41 | return MusicBeeVersion.v2_0; 42 | else if (ApiRevision <= 31) 43 | return MusicBeeVersion.v2_1; 44 | else if (ApiRevision <= 33) 45 | return MusicBeeVersion.v2_2; 46 | else if (ApiRevision <= 38) 47 | return MusicBeeVersion.v2_3; 48 | else if (ApiRevision <= 43) 49 | return MusicBeeVersion.v2_4; 50 | else if (ApiRevision <= 47) 51 | return MusicBeeVersion.v2_5; 52 | else if (ApiRevision <= 48) 53 | return MusicBeeVersion.v3_0; 54 | else 55 | return MusicBeeVersion.v3_1; 56 | } 57 | } 58 | public short InterfaceVersion; 59 | public short ApiRevision; 60 | public MB_ReleaseStringDelegate MB_ReleaseString; 61 | public MB_TraceDelegate MB_Trace; 62 | public Setting_GetPersistentStoragePathDelegate Setting_GetPersistentStoragePath; 63 | public Setting_GetSkinDelegate Setting_GetSkin; 64 | public Setting_GetSkinElementColourDelegate Setting_GetSkinElementColour; 65 | public Setting_IsWindowBordersSkinnedDelegate Setting_IsWindowBordersSkinned; 66 | public Library_GetFilePropertyDelegate Library_GetFileProperty; 67 | public Library_GetFileTagDelegate Library_GetFileTag; 68 | public Library_SetFileTagDelegate Library_SetFileTag; 69 | public Library_CommitTagsToFileDelegate Library_CommitTagsToFile; 70 | public Library_GetLyricsDelegate Library_GetLyrics; 71 | [Obsolete("Use Library_GetArtworkEx")] 72 | public Library_GetArtworkDelegate Library_GetArtwork; 73 | public Library_QueryFilesDelegate Library_QueryFiles; 74 | public Library_QueryGetNextFileDelegate Library_QueryGetNextFile; 75 | public Player_GetPositionDelegate Player_GetPosition; 76 | public Player_SetPositionDelegate Player_SetPosition; 77 | public Player_GetPlayStateDelegate Player_GetPlayState; 78 | public Player_ActionDelegate Player_PlayPause; 79 | public Player_ActionDelegate Player_Stop; 80 | public Player_ActionDelegate Player_StopAfterCurrent; 81 | public Player_ActionDelegate Player_PlayPreviousTrack; 82 | public Player_ActionDelegate Player_PlayNextTrack; 83 | public Player_ActionDelegate Player_StartAutoDj; 84 | public Player_ActionDelegate Player_EndAutoDj; 85 | public Player_GetVolumeDelegate Player_GetVolume; 86 | public Player_SetVolumeDelegate Player_SetVolume; 87 | public Player_GetMuteDelegate Player_GetMute; 88 | public Player_SetMuteDelegate Player_SetMute; 89 | public Player_GetShuffleDelegate Player_GetShuffle; 90 | public Player_SetShuffleDelegate Player_SetShuffle; 91 | public Player_GetRepeatDelegate Player_GetRepeat; 92 | public Player_SetRepeatDelegate Player_SetRepeat; 93 | public Player_GetEqualiserEnabledDelegate Player_GetEqualiserEnabled; 94 | public Player_SetEqualiserEnabledDelegate Player_SetEqualiserEnabled; 95 | public Player_GetDspEnabledDelegate Player_GetDspEnabled; 96 | public Player_SetDspEnabledDelegate Player_SetDspEnabled; 97 | public Player_GetScrobbleEnabledDelegate Player_GetScrobbleEnabled; 98 | public Player_SetScrobbleEnabledDelegate Player_SetScrobbleEnabled; 99 | public NowPlaying_GetFileUrlDelegate NowPlaying_GetFileUrl; 100 | public NowPlaying_GetDurationDelegate NowPlaying_GetDuration; 101 | public NowPlaying_GetFilePropertyDelegate NowPlaying_GetFileProperty; 102 | public NowPlaying_GetFileTagDelegate NowPlaying_GetFileTag; 103 | public NowPlaying_GetLyricsDelegate NowPlaying_GetLyrics; 104 | public NowPlaying_GetArtworkDelegate NowPlaying_GetArtwork; 105 | public NowPlayingList_ActionDelegate NowPlayingList_Clear; 106 | public Library_QueryFilesDelegate NowPlayingList_QueryFiles; 107 | public Library_QueryGetNextFileDelegate NowPlayingList_QueryGetNextFile; 108 | public NowPlayingList_FileActionDelegate NowPlayingList_PlayNow; 109 | public NowPlayingList_FileActionDelegate NowPlayingList_QueueNext; 110 | public NowPlayingList_FileActionDelegate NowPlayingList_QueueLast; 111 | public NowPlayingList_ActionDelegate NowPlayingList_PlayLibraryShuffled; 112 | public Playlist_QueryPlaylistsDelegate Playlist_QueryPlaylists; 113 | public Playlist_QueryGetNextPlaylistDelegate Playlist_QueryGetNextPlaylist; 114 | public Playlist_GetTypeDelegate Playlist_GetType; 115 | public Playlist_QueryFilesDelegate Playlist_QueryFiles; 116 | public Library_QueryGetNextFileDelegate Playlist_QueryGetNextFile; 117 | public MB_WindowHandleDelegate MB_GetWindowHandle; 118 | public MB_RefreshPanelsDelegate MB_RefreshPanels; 119 | public MB_SendNotificationDelegate MB_SendNotification; 120 | public MB_AddMenuItemDelegate MB_AddMenuItem; 121 | public Setting_GetFieldNameDelegate Setting_GetFieldName; 122 | [Obsolete("Use Library_QueryFilesEx", true)] 123 | public Library_QueryGetAllFilesDelegate Library_QueryGetAllFiles; 124 | [Obsolete("Use NowPlayingList_QueryFilesEx", true)] 125 | public Library_QueryGetAllFilesDelegate NowPlayingList_QueryGetAllFiles; 126 | [Obsolete("Use Playlist_QueryFilesEx", true)] 127 | public Library_QueryGetAllFilesDelegate Playlist_QueryGetAllFiles; 128 | public MB_CreateBackgroundTaskDelegate MB_CreateBackgroundTask; 129 | public MB_SetBackgroundTaskMessageDelegate MB_SetBackgroundTaskMessage; 130 | public MB_RegisterCommandDelegate MB_RegisterCommand; 131 | public Setting_GetDefaultFontDelegate Setting_GetDefaultFont; 132 | public Player_GetShowTimeRemainingDelegate Player_GetShowTimeRemaining; 133 | public NowPlayingList_GetCurrentIndexDelegate NowPlayingList_GetCurrentIndex; 134 | public NowPlayingList_GetFileUrlDelegate NowPlayingList_GetListFileUrl; 135 | public NowPlayingList_GetFilePropertyDelegate NowPlayingList_GetFileProperty; 136 | public NowPlayingList_GetFileTagDelegate NowPlayingList_GetFileTag; 137 | public NowPlaying_GetSpectrumDataDelegate NowPlaying_GetSpectrumData; 138 | public NowPlaying_GetSoundGraphDelegate NowPlaying_GetSoundGraph; 139 | public MB_GetPanelBoundsDelegate MB_GetPanelBounds; 140 | public MB_AddPanelDelegate MB_AddPanel; 141 | public MB_RemovePanelDelegate MB_RemovePanel; 142 | public MB_GetLocalisationDelegate MB_GetLocalisation; 143 | public NowPlayingList_IsAnyPriorTracksDelegate NowPlayingList_IsAnyPriorTracks; 144 | public NowPlayingList_IsAnyFollowingTracksDelegate NowPlayingList_IsAnyFollowingTracks; 145 | public Player_ShowEqualiserDelegate Player_ShowEqualiser; 146 | public Player_GetAutoDjEnabledDelegate Player_GetAutoDjEnabled; 147 | public Player_GetStopAfterCurrentEnabledDelegate Player_GetStopAfterCurrentEnabled; 148 | public Player_GetCrossfadeDelegate Player_GetCrossfade; 149 | public Player_SetCrossfadeDelegate Player_SetCrossfade; 150 | public Player_GetReplayGainModeDelegate Player_GetReplayGainMode; 151 | public Player_SetReplayGainModeDelegate Player_SetReplayGainMode; 152 | public Player_QueueRandomTracksDelegate Player_QueueRandomTracks; 153 | public Setting_GetDataTypeDelegate Setting_GetDataType; 154 | public NowPlayingList_GetNextIndexDelegate NowPlayingList_GetNextIndex; 155 | public NowPlaying_GetArtistPictureDelegate NowPlaying_GetArtistPicture; 156 | public NowPlaying_GetArtworkDelegate NowPlaying_GetDownloadedArtwork; 157 | // api version 16 158 | public MB_ShowNowPlayingAssistantDelegate MB_ShowNowPlayingAssistant; 159 | // api version 17 160 | public NowPlaying_GetLyricsDelegate NowPlaying_GetDownloadedLyrics; 161 | // api version 18 162 | public Player_GetShowRatingTrackDelegate Player_GetShowRatingTrack; 163 | public Player_GetShowRatingLoveDelegate Player_GetShowRatingLove; 164 | // api version 19 165 | public MB_CreateParameterisedBackgroundTaskDelegate MB_CreateParameterisedBackgroundTask; 166 | public Setting_GetLastFmUserIdDelegate Setting_GetLastFmUserId; 167 | public Playlist_GetNameDelegate Playlist_GetName; 168 | public Playlist_CreatePlaylistDelegate Playlist_CreatePlaylist; 169 | public Playlist_SetFilesDelegate Playlist_SetFiles; 170 | public Library_QuerySimilarArtistsDelegate Library_QuerySimilarArtists; 171 | public Library_QueryLookupTableDelegate Library_QueryLookupTable; 172 | public Library_QueryGetLookupTableValueDelegate Library_QueryGetLookupTableValue; 173 | public NowPlayingList_FilesActionDelegate NowPlayingList_QueueFilesNext; 174 | public NowPlayingList_FilesActionDelegate NowPlayingList_QueueFilesLast; 175 | // api version 20 176 | public Setting_GetWebProxyDelegate Setting_GetWebProxy; 177 | // api version 21 178 | public NowPlayingList_RemoveAtDelegate NowPlayingList_RemoveAt; 179 | // api version 22 180 | public Playlist_RemoveAtDelegate Playlist_RemoveAt; 181 | // api version 23 182 | public MB_SetPanelScrollableAreaDelegate MB_SetPanelScrollableArea; 183 | // api version 24 184 | public MB_InvokeCommandDelegate MB_InvokeCommand; 185 | public MB_OpenFilterInTabDelegate MB_OpenFilterInTab; 186 | // api version 25 187 | public MB_SetWindowSizeDelegate MB_SetWindowSize; 188 | public Library_GetArtistPictureDelegate Library_GetArtistPicture; 189 | public Pending_GetFileUrlDelegate Pending_GetFileUrl; 190 | public Pending_GetFilePropertyDelegate Pending_GetFileProperty; 191 | public Pending_GetFileTagDelegate Pending_GetFileTag; 192 | // api version 26 193 | public Player_GetButtonEnabledDelegate Player_GetButtonEnabled; 194 | // api version 27 195 | public NowPlayingList_MoveFilesDelegate NowPlayingList_MoveFiles; 196 | // api version 28 197 | public Library_GetArtworkDelegate Library_GetArtworkUrl; 198 | public Library_GetArtistPictureThumbDelegate Library_GetArtistPictureThumb; 199 | public NowPlaying_GetArtworkDelegate NowPlaying_GetArtworkUrl; 200 | public NowPlaying_GetArtworkDelegate NowPlaying_GetDownloadedArtworkUrl; 201 | public NowPlaying_GetArtistPictureThumbDelegate NowPlaying_GetArtistPictureThumb; 202 | // api version 29 203 | public Playlist_IsInListDelegate Playlist_IsInList; 204 | // api version 30 205 | public Library_GetArtistPictureUrlsDelegate Library_GetArtistPictureUrls; 206 | public NowPlaying_GetArtistPictureUrlsDelegate NowPlaying_GetArtistPictureUrls; 207 | // api version 31 208 | public Playlist_AddFilesDelegate Playlist_AppendFiles; 209 | // api version 32 210 | public Sync_FileStartDelegate Sync_FileStart; 211 | public Sync_FileEndDelegate Sync_FileEnd; 212 | // api version 33 213 | public Library_QueryFilesExDelegate Library_QueryFilesEx; 214 | public Library_QueryFilesExDelegate NowPlayingList_QueryFilesEx; 215 | public Playlist_QueryFilesExDelegate Playlist_QueryFilesEx; 216 | public Playlist_MoveFilesDelegate Playlist_MoveFiles; 217 | public Playlist_PlayNowDelegate Playlist_PlayNow; 218 | public NowPlaying_IsSoundtrackDelegate NowPlaying_IsSoundtrack; 219 | public NowPlaying_GetArtistPictureUrlsDelegate NowPlaying_GetSoundtrackPictureUrls; 220 | public Library_GetDevicePersistentIdDelegate Library_GetDevicePersistentId; 221 | public Library_SetDevicePersistentIdDelegate Library_SetDevicePersistentId; 222 | public Library_FindDevicePersistentIdDelegate Library_FindDevicePersistentId; 223 | public Setting_GetValueDelegate Setting_GetValue; 224 | public Library_AddFileToLibraryDelegate Library_AddFileToLibrary; 225 | public Playlist_DeletePlaylistDelegate Playlist_DeletePlaylist; 226 | public Library_GetSyncDeltaDelegate Library_GetSyncDelta; 227 | // api version 35 228 | public Library_GetFileTagsDelegate Library_GetFileTags; 229 | public NowPlaying_GetFileTagsDelegate NowPlaying_GetFileTags; 230 | public NowPlayingList_GetFileTagsDelegate NowPlayingList_GetFileTags; 231 | // api version 43 232 | public MB_AddTreeNodeDelegate MB_AddTreeNode; 233 | public MB_DownloadFileDelegate MB_DownloadFile; 234 | // api version 47 235 | public Setting_GetFileConvertCommandLineDelegate Setting_GetFileConvertCommandLine; 236 | public Player_OpenStreamHandleDelegate Player_OpenStreamHandle; 237 | public Player_UpdatePlayStatisticsDelegate Player_UpdatePlayStatistics; 238 | public Library_GetArtworkExDelegate Library_GetArtworkEx; 239 | public Library_SetArtworkExDelegate Library_SetArtworkEx; 240 | public MB_GetVisualiserInformationDelegate MB_GetVisualiserInformation; 241 | public MB_ShowVisualiserDelegate MB_ShowVisualiser; 242 | public MB_GetPluginViewInformationDelegate MB_GetPluginViewInformation; 243 | public MB_ShowPluginViewDelegate MB_ShowPluginView; 244 | public Player_GetOutputDevicesDelegate Player_GetOutputDevices; 245 | public Player_SetOutputDeviceDelegate Player_SetOutputDevice; 246 | // api version 48 247 | public MB_UninistallPluginDelegate MB_UninstallPlugin; 248 | // api version 50 249 | public Player_ActionDelegate Player_PlayPreviousAlbum; 250 | public Player_ActionDelegate Player_PlayNextAlbum; 251 | // api version 51 252 | public Podcasts_QuerySubscriptionsDelegate Podcasts_QuerySubscriptions; 253 | public Podcasts_GetSubscriptionDelegate Podcasts_GetSubscription; 254 | public Podcasts_GetSubscriptionArtworkDelegate Podcasts_GetSubscriptionArtwork; 255 | public Podcasts_GetSubscriptionEpisodesDelegate Podcasts_GetSubscriptionEpisodes; 256 | public Podcasts_GetSubscriptionEpisodeDelegate Podcasts_GetSubscriptionEpisode; 257 | // api version 52 258 | public NowPlaying_GetSoundGraphExDelegate NowPlaying_GetSoundGraphEx; 259 | // api version 53 260 | public Sync_FileStartDelegate Sync_FileDeleteStart; 261 | public Sync_FileEndDelegate Sync_FileDeleteEnd; 262 | } 263 | 264 | public enum MusicBeeVersion 265 | { 266 | v2_0 = 0, 267 | v2_1 = 1, 268 | v2_2 = 2, 269 | v2_3 = 3, 270 | v2_4 = 4, 271 | v2_5 = 5, 272 | v3_0 = 6, 273 | v3_1 = 7 274 | } 275 | 276 | public enum PluginType 277 | { 278 | Unknown = 0, 279 | General = 1, 280 | LyricsRetrieval = 2, 281 | ArtworkRetrieval = 3, 282 | PanelView = 4, 283 | DataStream = 5, 284 | InstantMessenger = 6, 285 | Storage = 7, 286 | VideoPlayer = 8, 287 | DSP = 9, 288 | TagRetrieval = 10, 289 | TagOrArtworkRetrieval = 11, 290 | Upnp = 12, 291 | WebBrowser = 13 292 | } 293 | 294 | [StructLayout(LayoutKind.Sequential)] 295 | public class PluginInfo 296 | { 297 | public short PluginInfoVersion; 298 | public PluginType Type; 299 | public string Name; 300 | public string Description; 301 | public string Author; 302 | public string TargetApplication; 303 | public short VersionMajor; 304 | public short VersionMinor; 305 | public short Revision; 306 | public short MinInterfaceVersion; 307 | public short MinApiRevision; 308 | public ReceiveNotificationFlags ReceiveNotifications; 309 | public int ConfigurationPanelHeight; 310 | } 311 | 312 | [Flags()] 313 | public enum ReceiveNotificationFlags 314 | { 315 | StartupOnly = 0x0, 316 | PlayerEvents = 0x1, 317 | DataStreamEvents = 0x2, 318 | TagEvents = 0x04, 319 | DownloadEvents = 0x08 320 | } 321 | 322 | public enum NotificationType 323 | { 324 | PluginStartup = 0, // notification sent after successful initialisation for an enabled plugin 325 | TrackChanging = 16, 326 | TrackChanged = 1, 327 | PlayStateChanged = 2, 328 | AutoDjStarted = 3, 329 | AutoDjStopped = 4, 330 | VolumeMuteChanged = 5, 331 | VolumeLevelChanged = 6, 332 | [Obsolete("Use PlayingTracksChanged")] NowPlayingListChanged = 7, 333 | NowPlayingListEnded = 18, 334 | NowPlayingArtworkReady = 8, 335 | NowPlayingLyricsReady = 9, 336 | TagsChanging = 10, 337 | TagsChanged = 11, 338 | RatingChanging = 15, 339 | RatingChanged = 12, 340 | PlayCountersChanged = 13, 341 | ScreenSaverActivating = 14, 342 | ShutdownStarted = 17, 343 | EmbedInPanel = 19, 344 | PlayerRepeatChanged = 20, 345 | PlayerShuffleChanged = 21, 346 | PlayerEqualiserOnOffChanged = 22, 347 | PlayerScrobbleChanged = 23, 348 | ReplayGainChanged = 24, 349 | FileDeleting = 25, 350 | FileDeleted = 26, 351 | ApplicationWindowChanged = 27, 352 | StopAfterCurrentChanged = 28, 353 | LibrarySwitched = 29, 354 | FileAddedToLibrary = 30, 355 | FileAddedToInbox = 31, 356 | SynchCompleted = 32, 357 | DownloadCompleted = 33, 358 | MusicBeeStarted = 34, 359 | PlayingTracksChanged = 35, 360 | PlayingTracksQueueChanged = 36, 361 | PlaylistCreated = 37, 362 | PlaylistUpdated = 38, 363 | PlaylistDeleted = 39 364 | } 365 | 366 | public enum PluginCloseReason 367 | { 368 | MusicBeeClosing = 1, 369 | UserDisabled = 2, 370 | StopNoUnload = 3 371 | } 372 | 373 | public enum CallbackType 374 | { 375 | SettingsUpdated = 1, 376 | StorageReady = 2, 377 | StorageFailed = 3, 378 | FilesRetrievedChanged = 4, 379 | FilesRetrievedNoChange = 5, 380 | FilesRetrievedFail = 6, 381 | LyricsDownloaded = 7, 382 | StorageEject = 8, 383 | SuspendPlayCounters = 9, 384 | ResumePlayCounters = 10, 385 | EnablePlugin = 11, 386 | DisablePlugin = 12, 387 | RenderingDevicesChanged = 13, 388 | FullscreenOn = 14, 389 | FullscreenOff = 15 390 | } 391 | 392 | public enum FilePropertyType 393 | { 394 | Url = 2, 395 | Kind = 4, 396 | Format = 5, 397 | Size = 7, 398 | Channels = 8, 399 | SampleRate = 9, 400 | Bitrate = 10, 401 | DateModified = 11, 402 | DateAdded = 12, 403 | LastPlayed = 13, 404 | PlayCount = 14, 405 | SkipCount = 15, 406 | Duration = 16, 407 | Status = 21, 408 | NowPlayingListIndex = 78, // only has meaning when called from NowPlayingList_* commands 409 | ReplayGainTrack = 94, 410 | ReplayGainAlbum = 95 411 | } 412 | 413 | public enum MetaDataType 414 | { 415 | TrackTitle = 65, 416 | Album = 30, 417 | AlbumArtist = 31, // displayed album artist 418 | AlbumArtistRaw = 34, // stored album artist 419 | Artist = 32, // displayed artist 420 | MultiArtist = 33, // individual artists, separated by a null char 421 | PrimaryArtist = 19, // first artist from multi-artist tagged file, otherwise displayed artist 422 | Artists = 144, 423 | ArtistsWithArtistRole = 145, 424 | ArtistsWithPerformerRole = 146, 425 | ArtistsWithGuestRole = 147, 426 | ArtistsWithRemixerRole = 148, 427 | Artwork = 40, 428 | BeatsPerMin = 41, 429 | Composer = 43, // displayed composer 430 | MultiComposer = 89, // individual composers, separated by a null char 431 | Comment = 44, 432 | Conductor = 45, 433 | Custom1 = 46, 434 | Custom2 = 47, 435 | Custom3 = 48, 436 | Custom4 = 49, 437 | Custom5 = 50, 438 | Custom6 = 96, 439 | Custom7 = 97, 440 | Custom8 = 98, 441 | Custom9 = 99, 442 | Custom10 = 128, 443 | Custom11 = 129, 444 | Custom12 = 130, 445 | Custom13 = 131, 446 | Custom14 = 132, 447 | Custom15 = 133, 448 | Custom16 = 134, 449 | DiscNo = 52, 450 | DiscCount = 54, 451 | Encoder = 55, 452 | Genre = 59, 453 | Genres = 143, 454 | GenreCategory = 60, 455 | Grouping = 61, 456 | Keywords = 84, 457 | HasLyrics = 63, 458 | Lyricist = 62, 459 | Lyrics = 114, 460 | Mood = 64, 461 | Occasion = 66, 462 | Origin = 67, 463 | Publisher = 73, 464 | Quality = 74, 465 | Rating = 75, 466 | RatingLove = 76, 467 | RatingAlbum = 104, 468 | Tempo = 85, 469 | TrackNo = 86, 470 | TrackCount = 87, 471 | Virtual1 = 109, 472 | Virtual2 = 110, 473 | Virtual3 = 111, 474 | Virtual4 = 112, 475 | Virtual5 = 113, 476 | Virtual6 = 122, 477 | Virtual7 = 123, 478 | Virtual8 = 124, 479 | Virtual9 = 125, 480 | Virtual10 = 135, 481 | Virtual11 = 136, 482 | Virtual12 = 137, 483 | Virtual13 = 138, 484 | Virtual14 = 139, 485 | Virtual15 = 140, 486 | Virtual16 = 141, 487 | Virtual17 = 149, 488 | Virtual18 = 150, 489 | Virtual19 = 151, 490 | Virtual20 = 152, 491 | Virtual21 = 153, 492 | Virtual22 = 154, 493 | Virtual23 = 155, 494 | Virtual24 = 156, 495 | Virtual25 = 157, 496 | Year = 88, 497 | SortTitle = 163, 498 | SortAlbum = 164, 499 | SortAlbumArtist = 165, 500 | SortArtist = 166, 501 | SortComposer = 167, 502 | Work = 168, 503 | MovementName = 169, 504 | MovementNo = 170, 505 | MovementCount = 171, 506 | ShowMovement = 172, 507 | Language = 173, 508 | OriginalArtist = 174, 509 | OriginalYear = 175, 510 | OriginalTitle = 177 511 | } 512 | 513 | public enum FileCodec 514 | { 515 | Unknown = -1, 516 | Mp3 = 1, 517 | Aac = 2, 518 | Flac = 3, 519 | Ogg = 4, 520 | WavPack = 5, 521 | Wma = 6, 522 | Tak = 7, 523 | Mpc = 8, 524 | Wave = 9, 525 | Asx = 10, 526 | Alac = 11, 527 | Aiff = 12, 528 | Pcm = 13, 529 | Opus = 15, 530 | Spx = 16, 531 | Dsd = 17, 532 | AacNoContainer = 18 533 | } 534 | 535 | public enum EncodeQuality 536 | { 537 | SmallSize = 1, 538 | Portable = 2, 539 | HighQuality = 3, 540 | Archiving = 4 541 | } 542 | 543 | [Flags()] 544 | public enum LibraryCategory 545 | { 546 | Music = 0, 547 | Audiobook = 1, 548 | Video = 2, 549 | Inbox = 4 550 | } 551 | 552 | public enum DeviceIdType 553 | { 554 | MusicBeeNativeId = 0, 555 | GooglePlay = 1, 556 | AppleDevice = 2, 557 | GooglePlay2 = 3, 558 | AppleDevice2 = 4, 559 | WebDrivePluginOneDrive = 5, 560 | WebDrivePluginGoogleDrive = 6, 561 | WebDrivePluginDropBox = 7 562 | } 563 | 564 | public enum DataType 565 | { 566 | String = 0, 567 | Number = 1, 568 | DateTime = 2, 569 | Rating = 3 570 | } 571 | 572 | public enum SettingId 573 | { 574 | CompactPlayerFlickrEnabled = 1, 575 | FileTaggingPreserveModificationTime = 2, 576 | LastDownloadFolder = 3, 577 | ArtistGenresOnly = 4, 578 | IgnoreNamePrefixes = 5, 579 | IgnoreNameChars = 6, 580 | PlayCountTriggerPercent = 7, 581 | PlayCountTriggerSeconds = 8, 582 | SkipCountTriggerPercent = 9, 583 | SkipCountTriggerSeconds = 10, 584 | CustomWebLinkName1 = 11, 585 | CustomWebLinkName2 = 12, 586 | CustomWebLinkName3 = 13, 587 | CustomWebLinkName4 = 14, 588 | CustomWebLinkName5 = 15, 589 | CustomWebLinkName6 = 16, 590 | CustomWebLinkName7 = 29, 591 | CustomWebLinkName8 = 30, 592 | CustomWebLinkName9 = 31, 593 | CustomWebLinkName10 = 32, 594 | CustomWebLink1 = 17, 595 | CustomWebLink2 = 18, 596 | CustomWebLink3 = 19, 597 | CustomWebLink4 = 20, 598 | CustomWebLink5 = 21, 599 | CustomWebLink6 = 22, 600 | CustomWebLink7 = 33, 601 | CustomWebLink8 = 34, 602 | CustomWebLink9 = 35, 603 | CustomWebLink10 = 36, 604 | CustomWebLinkNowPlaying1 = 23, 605 | CustomWebLinkNowPlaying2 = 24, 606 | CustomWebLinkNowPlaying3 = 25, 607 | CustomWebLinkNowPlaying4 = 26, 608 | CustomWebLinkNowPlaying5 = 27, 609 | CustomWebLinkNowPlaying6 = 28, 610 | CustomWebLinkNowPlaying7 = 37, 611 | CustomWebLinkNowPlaying8 = 38, 612 | CustomWebLinkNowPlaying9 = 39, 613 | CustomWebLinkNowPlaying10 = 40 614 | } 615 | 616 | public enum ComparisonType 617 | { 618 | Is = 0, 619 | IsNot = 1, 620 | Contains = 4, 621 | DoesNotContain = 5, 622 | StartsWith = 6, 623 | EndsWith = 7, 624 | IsSimilar = 20 625 | } 626 | 627 | public enum LyricsType 628 | { 629 | NotSpecified = 0, 630 | Synchronised = 1, 631 | UnSynchronised = 2 632 | } 633 | 634 | public enum PlayState 635 | { 636 | Undefined = 0, 637 | Loading = 1, 638 | Playing = 3, 639 | Paused = 6, 640 | Stopped = 7 641 | } 642 | 643 | public enum RepeatMode 644 | { 645 | None = 0, 646 | All = 1, 647 | One = 2 648 | } 649 | 650 | public enum PlayButtonType 651 | { 652 | PreviousTrack = 0, 653 | PlayPause = 1, 654 | NextTrack = 2, 655 | Stop = 3 656 | } 657 | 658 | public enum PlaylistFormat 659 | { 660 | Unknown = 0, 661 | M3u = 1, 662 | Xspf = 2, 663 | Asx = 3, 664 | Wpl = 4, 665 | Pls = 5, 666 | Auto = 7, 667 | M3uAscii = 8, 668 | AsxFile = 9, 669 | Radio = 10, 670 | M3uExtended = 11, 671 | Mbp = 12 672 | } 673 | 674 | public enum SkinElement 675 | { 676 | SkinSubPanel = 0, 677 | SkinInputControl = 7, 678 | SkinInputPanel = 10, 679 | SkinInputPanelLabel = 14, 680 | SkinTrackAndArtistPanel = -1 681 | } 682 | 683 | public enum ElementState 684 | { 685 | ElementStateDefault = 0, 686 | ElementStateModified = 6 687 | } 688 | 689 | public enum ElementComponent 690 | { 691 | ComponentBorder = 0, 692 | ComponentBackground = 1, 693 | ComponentForeground = 3 694 | } 695 | 696 | public enum PluginPanelDock 697 | { 698 | ApplicationWindow = 0, 699 | TrackAndArtistPanel = 1, 700 | TextBox = 3, 701 | ComboBox = 4, 702 | MainPanel = 5 703 | } 704 | 705 | 706 | public enum ReplayGainMode 707 | { 708 | Off = 0, 709 | Track = 1, 710 | Album = 2, 711 | Smart = 3 712 | } 713 | 714 | public enum PlayStatisticType 715 | { 716 | NoChange = 0, 717 | IncreasePlayCount = 1, 718 | IncreaseSkipCount = 2 719 | } 720 | 721 | public enum Command 722 | { 723 | NavigateTo = 1 724 | } 725 | 726 | public enum DownloadTarget 727 | { 728 | Inbox = 0, 729 | MusicLibrary = 1, 730 | SpecificFolder = 3 731 | } 732 | 733 | [Flags()] 734 | public enum PictureLocations: byte 735 | { 736 | None = 0, 737 | EmbedInFile = 1, 738 | LinkToOrganisedCopy = 2, 739 | LinkToSource = 4, 740 | FolderThumb = 8 741 | } 742 | 743 | public enum WindowState 744 | { 745 | Off = -1, 746 | Normal = 0, 747 | Fullscreen = 1, 748 | Desktop = 2 749 | } 750 | 751 | public enum SubscriptionMetaDataType 752 | { 753 | Id = 0, 754 | Title = 1, 755 | Grouping = 2, 756 | Genre = 3, 757 | Description = 4, 758 | DounloadedCount = 5 759 | } 760 | 761 | public enum EpisodeMetaDataType 762 | { 763 | Id = 0, 764 | Title = 1, 765 | DateTime = 2, 766 | Description = 3, 767 | Duration = 4, 768 | IsDownloaded = 5, 769 | HasBeenPlayed = 6 770 | } 771 | 772 | public delegate void MB_ReleaseStringDelegate(string p1); 773 | public delegate void MB_TraceDelegate(string p1); 774 | public delegate IntPtr MB_WindowHandleDelegate(); 775 | public delegate void MB_RefreshPanelsDelegate(); 776 | public delegate void MB_SendNotificationDelegate(CallbackType type); 777 | public delegate System.Windows.Forms.ToolStripItem MB_AddMenuItemDelegate(string menuPath, string hotkeyDescription, EventHandler handler); 778 | public delegate bool MB_AddTreeNodeDelegate(string treePath, string name, System.Drawing.Bitmap icon, EventHandler openHandler, EventHandler closeHandler); 779 | public delegate void MB_RegisterCommandDelegate(string command, EventHandler handler); 780 | public delegate void MB_CreateBackgroundTaskDelegate(System.Threading.ThreadStart taskCallback, System.Windows.Forms.Form owner); 781 | public delegate void MB_CreateParameterisedBackgroundTaskDelegate(System.Threading.ParameterizedThreadStart taskCallback, object parameters, System.Windows.Forms.Form owner); 782 | public delegate void MB_SetBackgroundTaskMessageDelegate(string message); 783 | public delegate System.Drawing.Rectangle MB_GetPanelBoundsDelegate(PluginPanelDock dock); 784 | public delegate bool MB_SetPanelScrollableAreaDelegate(System.Windows.Forms.Control panel, System.Drawing.Size scrollArea, bool alwaysShowScrollBar); 785 | public delegate System.Windows.Forms.Control MB_AddPanelDelegate(System.Windows.Forms.Control panel, PluginPanelDock dock); 786 | public delegate void MB_RemovePanelDelegate(System.Windows.Forms.Control panel); 787 | public delegate string MB_GetLocalisationDelegate(string id, string defaultText); 788 | public delegate bool MB_ShowNowPlayingAssistantDelegate(); 789 | public delegate bool MB_InvokeCommandDelegate(Command command, object parameter); 790 | public delegate bool MB_OpenFilterInTabDelegate(MetaDataType field1, ComparisonType comparison1, string value1, MetaDataType field2, ComparisonType comparison2, string value2); 791 | public delegate bool MB_SetWindowSizeDelegate(int width, int height); 792 | public delegate bool MB_DownloadFileDelegate(string url, DownloadTarget target, string targetFolder, bool cancelDownload); 793 | public delegate bool MB_GetVisualiserInformationDelegate(out string[] visualiserNames, out string defaultVisualiserName, out WindowState defaultState, out WindowState currentState); 794 | public delegate bool MB_ShowVisualiserDelegate(string visualiserName, WindowState state); 795 | public delegate bool MB_GetPluginViewInformationDelegate(string pluginFilename, out string[] viewNames, out string defaultViewName, out WindowState defaultState, out WindowState currentState); 796 | public delegate bool MB_ShowPluginViewDelegate(string pluginFilename, string viewName, WindowState state); 797 | public delegate bool MB_UninistallPluginDelegate(string pluginFilename, string password); 798 | public delegate string Setting_GetFieldNameDelegate(MetaDataType field); 799 | public delegate string Setting_GetPersistentStoragePathDelegate(); 800 | public delegate string Setting_GetSkinDelegate(); 801 | public delegate int Setting_GetSkinElementColourDelegate(SkinElement element, ElementState state, ElementComponent component); 802 | public delegate bool Setting_IsWindowBordersSkinnedDelegate(); 803 | public delegate System.Drawing.Font Setting_GetDefaultFontDelegate(); 804 | public delegate DataType Setting_GetDataTypeDelegate(MetaDataType field); 805 | public delegate string Setting_GetLastFmUserIdDelegate(); 806 | public delegate string Setting_GetWebProxyDelegate(); 807 | public delegate bool Setting_GetValueDelegate(SettingId settingId, out object value); 808 | public delegate string Setting_GetFileConvertCommandLineDelegate(FileCodec codec, EncodeQuality encodeQuality); 809 | public delegate string Library_GetFilePropertyDelegate(string sourceFileUrl, FilePropertyType type); 810 | public delegate string Library_GetFileTagDelegate(string sourceFileUrl, MetaDataType field); 811 | public delegate bool Library_GetFileTagsDelegate(string sourceFileUrl, MetaDataType[] fields, out string[] results); 812 | public delegate bool Library_SetFileTagDelegate(string sourceFileUrl, MetaDataType field, string value); 813 | public delegate string Library_GetDevicePersistentIdDelegate(string sourceFileUrl, DeviceIdType idType); 814 | public delegate bool Library_SetDevicePersistentIdDelegate(string sourceFileUrl, DeviceIdType idType, string value); 815 | public delegate bool Library_FindDevicePersistentIdDelegate(DeviceIdType idType, string[] ids, out string[] values); 816 | public delegate bool Library_CommitTagsToFileDelegate(string sourceFileUrl); 817 | public delegate string Library_AddFileToLibraryDelegate(string sourceFileUrl, LibraryCategory category); 818 | public delegate bool Library_GetSyncDeltaDelegate(string[] cachedFiles, DateTime updatedSince, LibraryCategory categories, out string[] newFiles, out string[] updatedFiles, out string[] deletedFiles); 819 | public delegate string Library_GetLyricsDelegate(string sourceFileUrl, LyricsType type); 820 | public delegate string Library_GetArtworkDelegate(string sourceFileUrl, int index); 821 | public delegate bool Library_GetArtworkExDelegate(string sourceFileUrl, int index, bool retrievePictureData, out PictureLocations pictureLocations, out string pictureUrl, out byte[] imageData); 822 | public delegate bool Library_SetArtworkExDelegate(string sourceFileUrl, int index, byte[] imageData); 823 | public delegate string Library_GetArtistPictureDelegate(string artistName, int fadingPercent, int fadingColor); 824 | public delegate bool Library_GetArtistPictureUrlsDelegate(string artistName, bool localOnly, out string[] urls); 825 | public delegate string Library_GetArtistPictureThumbDelegate(string artistName); 826 | public delegate bool Library_QueryFilesDelegate(string query); 827 | public delegate string Library_QueryGetNextFileDelegate(); 828 | public delegate string Library_QueryGetAllFilesDelegate(); 829 | public delegate bool Library_QueryFilesExDelegate(string query, out string[] files); 830 | public delegate string Library_QuerySimilarArtistsDelegate(string artistName, double minimumArtistSimilarityRating); 831 | public delegate bool Library_QueryLookupTableDelegate(string keyTags, string valueTags, string query); 832 | public delegate string Library_QueryGetLookupTableValueDelegate(string key); 833 | public delegate int Player_GetPositionDelegate(); 834 | public delegate bool Player_SetPositionDelegate(int position); 835 | public delegate PlayState Player_GetPlayStateDelegate(); 836 | public delegate bool Player_GetButtonEnabledDelegate(PlayButtonType button); 837 | public delegate bool Player_ActionDelegate(); 838 | public delegate int Player_QueueRandomTracksDelegate(int count); 839 | public delegate float Player_GetVolumeDelegate(); 840 | public delegate bool Player_SetVolumeDelegate(float volume); 841 | public delegate bool Player_GetMuteDelegate(); 842 | public delegate bool Player_SetMuteDelegate(bool mute); 843 | public delegate bool Player_GetShuffleDelegate(); 844 | public delegate bool Player_SetShuffleDelegate(bool shuffle); 845 | public delegate RepeatMode Player_GetRepeatDelegate(); 846 | public delegate bool Player_SetRepeatDelegate(RepeatMode repeat); 847 | public delegate bool Player_GetEqualiserEnabledDelegate(); 848 | public delegate bool Player_SetEqualiserEnabledDelegate(bool enabled); 849 | public delegate bool Player_GetDspEnabledDelegate(); 850 | public delegate bool Player_SetDspEnabledDelegate(bool enabled); 851 | public delegate bool Player_GetScrobbleEnabledDelegate(); 852 | public delegate bool Player_SetScrobbleEnabledDelegate(bool enabled); 853 | public delegate bool Player_GetShowTimeRemainingDelegate(); 854 | public delegate bool Player_GetShowRatingTrackDelegate(); 855 | public delegate bool Player_GetShowRatingLoveDelegate(); 856 | public delegate bool Player_ShowEqualiserDelegate(); 857 | public delegate bool Player_GetAutoDjEnabledDelegate(); 858 | public delegate bool Player_GetStopAfterCurrentEnabledDelegate(); 859 | public delegate bool Player_GetCrossfadeDelegate(); 860 | public delegate bool Player_SetCrossfadeDelegate(bool crossfade); 861 | public delegate ReplayGainMode Player_GetReplayGainModeDelegate(); 862 | public delegate bool Player_SetReplayGainModeDelegate(ReplayGainMode mode); 863 | public delegate int Player_OpenStreamHandleDelegate(string url, bool useMusicBeeSettings, bool enableDsp, ReplayGainMode gainType); 864 | public delegate bool Player_UpdatePlayStatisticsDelegate(string url, PlayStatisticType countType, bool disableScrobble); 865 | public delegate bool Player_GetOutputDevicesDelegate(out string[] deviceNames, out string activeDeviceName); 866 | public delegate bool Player_SetOutputDeviceDelegate(string deviceName); 867 | public delegate string NowPlaying_GetFileUrlDelegate(); 868 | public delegate int NowPlaying_GetDurationDelegate(); 869 | public delegate string NowPlaying_GetFilePropertyDelegate(FilePropertyType type); 870 | public delegate string NowPlaying_GetFileTagDelegate(MetaDataType field); 871 | public delegate bool NowPlaying_GetFileTagsDelegate(MetaDataType[] fields, out string[] results); 872 | public delegate string NowPlaying_GetLyricsDelegate(); 873 | public delegate string NowPlaying_GetArtworkDelegate(); 874 | public delegate string NowPlaying_GetArtistPictureDelegate(int fadingPercent); 875 | public delegate bool NowPlaying_GetArtistPictureUrlsDelegate(bool localOnly, out string[] urls); 876 | public delegate string NowPlaying_GetArtistPictureThumbDelegate(); 877 | public delegate bool NowPlaying_IsSoundtrackDelegate(); 878 | public delegate int NowPlaying_GetSpectrumDataDelegate(float[] fftData); 879 | public delegate bool NowPlaying_GetSoundGraphDelegate(float[] graphData); 880 | public delegate bool NowPlaying_GetSoundGraphExDelegate(float[] graphData, float[] peakData); 881 | public delegate int NowPlayingList_GetCurrentIndexDelegate(); 882 | public delegate int NowPlayingList_GetNextIndexDelegate(int offset); 883 | public delegate bool NowPlayingList_IsAnyPriorTracksDelegate(); 884 | public delegate bool NowPlayingList_IsAnyFollowingTracksDelegate(); 885 | public delegate string NowPlayingList_GetFileUrlDelegate(int index); 886 | public delegate string NowPlayingList_GetFilePropertyDelegate(int index, FilePropertyType type); 887 | public delegate string NowPlayingList_GetFileTagDelegate(int index, MetaDataType field); 888 | public delegate bool NowPlayingList_GetFileTagsDelegate(int index, MetaDataType[] fields, out string[] results); 889 | public delegate bool NowPlayingList_ActionDelegate(); 890 | public delegate bool NowPlayingList_FileActionDelegate(string sourceFileUrl); 891 | public delegate bool NowPlayingList_FilesActionDelegate(string[] sourceFileUrl); 892 | public delegate bool NowPlayingList_RemoveAtDelegate(int index); 893 | public delegate bool NowPlayingList_MoveFilesDelegate(int[] fromIndices, int toIndex); 894 | public delegate string Playlist_GetNameDelegate(string playlistUrl); 895 | public delegate PlaylistFormat Playlist_GetTypeDelegate(string playlistUrl); 896 | public delegate bool Playlist_QueryPlaylistsDelegate(); 897 | public delegate string Playlist_QueryGetNextPlaylistDelegate(); 898 | public delegate bool Playlist_IsInListDelegate(string playlistUrl, string filename); 899 | public delegate bool Playlist_QueryFilesDelegate(string playlistUrl); 900 | public delegate bool Playlist_QueryFilesExDelegate(string playlistUrl, out string[] filenames); 901 | public delegate string Playlist_CreatePlaylistDelegate(string folderName, string playlistName, string[] filenames); 902 | public delegate bool Playlist_DeletePlaylistDelegate(string playlistUrl); 903 | public delegate bool Playlist_SetFilesDelegate(string playlistUrl, string[] filenames); 904 | public delegate bool Playlist_AddFilesDelegate(string playlistUrl, string[] filenames); 905 | public delegate bool Playlist_RemoveAtDelegate(string playlistUrl, int index); 906 | public delegate bool Playlist_MoveFilesDelegate(string playlistUrl, int[] fromIndices, int toIndex); 907 | public delegate bool Playlist_PlayNowDelegate(string playlistUrl); 908 | public delegate string Pending_GetFileUrlDelegate(); 909 | public delegate string Pending_GetFilePropertyDelegate(FilePropertyType field); 910 | public delegate string Pending_GetFileTagDelegate(MetaDataType field); 911 | public delegate bool Podcasts_QuerySubscriptionsDelegate(string query, out string[] ids); 912 | public delegate bool Podcasts_GetSubscriptionDelegate(string id, out string[] subscription); 913 | public delegate bool Podcasts_GetSubscriptionArtworkDelegate(string id, int index, out byte[] imageData); 914 | public delegate bool Podcasts_GetSubscriptionEpisodesDelegate(string id, out string[] urls); 915 | public delegate bool Podcasts_GetSubscriptionEpisodeDelegate(string id, int index, out string[] episode); 916 | public delegate string Sync_FileStartDelegate(string filename); 917 | public delegate void Sync_FileEndDelegate(string filename, bool success, string errorMessage); 918 | 919 | [System.Security.SuppressUnmanagedCodeSecurity()] 920 | [DllImport("kernel32.dll")] 921 | private static extern void CopyMemory(ref MusicBeeApiInterface mbApiInterface, IntPtr src, int length); 922 | }; 923 | } 924 | -------------------------------------------------------------------------------- /Beenius/Plugin.cs: -------------------------------------------------------------------------------- 1 | using Beenius; 2 | using NLog; 3 | using System; 4 | using System.IO; 5 | using System.Windows; 6 | 7 | namespace MusicBeePlugin 8 | { 9 | public partial class Plugin 10 | { 11 | private static Logger Logger; 12 | 13 | public static string configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"MusicBee\Plugins\beenius.conf"); 14 | public static string logFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"MusicBee\beenius.log"); 15 | public static string name = "Beenius"; 16 | 17 | private MusicBeeApiInterface musicBee; 18 | private PluginInfo info = new PluginInfo(); 19 | private GeniusClient geniusClient; 20 | 21 | public PluginInfo Initialise(IntPtr apiPtr) 22 | { 23 | musicBee = new MusicBeeApiInterface(); 24 | musicBee.Initialise(apiPtr); 25 | 26 | info.PluginInfoVersion = PluginInfoVersion; 27 | info.Name = "Beenius"; 28 | info.Description = "Genius support for MusicBee"; 29 | info.Author = "slonopot"; 30 | info.TargetApplication = "MusicBee"; 31 | info.Type = PluginType.LyricsRetrieval; 32 | info.VersionMajor = 1; 33 | info.VersionMinor = 3; 34 | info.Revision = 7; 35 | info.MinInterfaceVersion = 20; 36 | info.MinApiRevision = 25; 37 | info.ReceiveNotifications = ReceiveNotificationFlags.StartupOnly; 38 | info.ConfigurationPanelHeight = 20; 39 | 40 | try 41 | { 42 | var target = new NLog.Targets.FileTarget(name) 43 | { 44 | FileName = logFile, 45 | Layout = "${date} | ${level} | ${callsite} | ${message}", 46 | DeleteOldFileOnStartup = true, 47 | Name = name 48 | }; 49 | if (LogManager.Configuration == null) 50 | { 51 | var config = new NLog.Config.LoggingConfiguration(); 52 | config.AddTarget(target); 53 | config.AddRuleForAllLevels(target, name); 54 | LogManager.Configuration = config; 55 | 56 | } 57 | else 58 | { 59 | LogManager.Configuration.AddTarget(target); 60 | LogManager.Configuration.AddRuleForAllLevels(target, name); 61 | } 62 | 63 | LogManager.ReconfigExistingLoggers(); 64 | 65 | Logger = LogManager.GetLogger(name); 66 | 67 | geniusClient = new GeniusClient(BeeniusLyricsProvider); 68 | } 69 | catch (Exception e) 70 | { 71 | MessageBox.Show("An error occurred during Beenius startup: " + e.Message); 72 | throw; 73 | } 74 | 75 | return info; 76 | } 77 | 78 | private string BeeniusLyricsProvider = "Genius via Beenius"; 79 | 80 | public String[] GetProviders() 81 | { 82 | return new string[] { BeeniusLyricsProvider }; 83 | } 84 | 85 | public String RetrieveLyrics(String source, String artist, String title, String album, bool preferSynced, String providerName) 86 | { 87 | Logger.Debug("source={source}, artist={artist}, title={title}, album={album}, preferSynced={preferSynced}, providerName={providerName}", source, artist, title, album, preferSynced, providerName); 88 | 89 | if (providerName != BeeniusLyricsProvider) return null; 90 | 91 | var lyrics = geniusClient.getLyrics(artist, title); 92 | return lyrics; 93 | } 94 | 95 | public void ReceiveNotification(String source, NotificationType type) { } 96 | 97 | public void SaveSettings() { } 98 | 99 | public bool Configure(IntPtr panelHandle) { return false; } //fixes the popup 100 | public void Uninstall() { MessageBox.Show("Just delete the plugin files from the Plugins folder yourself, this plugin is not very sophisticated to handle it itself."); } 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Beenius/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Общие сведения об этой сборке предоставляются следующим набором 6 | // набора атрибутов. Измените значения этих атрибутов для изменения сведений, 7 | // связанные со сборкой. 8 | [assembly: AssemblyTitle("Beenius")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Beenius")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми 18 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через 19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM 23 | [assembly: Guid("3c722447-ccb8-4062-a8b8-8005dcace15d")] 24 | 25 | // Сведения о версии сборки состоят из указанных ниже четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Редакция 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Beenius/Util.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.Specialized; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using System.Threading.Tasks; 9 | 10 | namespace Beenius 11 | { 12 | internal class Util 13 | { 14 | private static Logger Logger = LogManager.GetCurrentClassLogger(); 15 | 16 | public static string ToQueryString(NameValueCollection nvc) 17 | { 18 | var array = ( 19 | from key in nvc.AllKeys 20 | from value in nvc.GetValues(key) 21 | select string.Format( 22 | "{0}={1}", 23 | //HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)) 24 | Uri.EscapeDataString(key), Uri.EscapeDataString(value)) 25 | ).ToArray(); 26 | return string.Join("&", array); 27 | } 28 | 29 | public static bool PropertyExists(dynamic obj, string name) 30 | { 31 | if (obj == null) return false; 32 | if (obj is IDictionary dict) 33 | { 34 | return dict.ContainsKey(name); 35 | } 36 | return obj.GetType().GetProperty(name) != null; 37 | } 38 | 39 | 40 | public static int ComputeDistance(string s, string t) 41 | { 42 | int n = s.Length; 43 | int m = t.Length; 44 | int[,] d = new int[n + 1, m + 1]; 45 | 46 | // Step 1 47 | if (n == 0) 48 | { 49 | return m; 50 | } 51 | 52 | if (m == 0) 53 | { 54 | return n; 55 | } 56 | 57 | // Step 2 58 | for (int i = 0; i <= n; d[i, 0] = i++) 59 | { 60 | } 61 | 62 | for (int j = 0; j <= m; d[0, j] = j++) 63 | { 64 | } 65 | 66 | // Step 3 67 | for (int i = 1; i <= n; i++) 68 | { 69 | //Step 4 70 | for (int j = 1; j <= m; j++) 71 | { 72 | // Step 5 73 | int cost = (t[j - 1] == s[i - 1]) ? 0 : 1; 74 | 75 | // Step 6 76 | d[i, j] = Math.Min( 77 | Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), 78 | d[i - 1, j - 1] + cost); 79 | } 80 | } 81 | // Step 7 82 | return d[n, m]; 83 | } 84 | 85 | public static bool ValidateResult(string originalArtist, string originalTitle, string foundArtist, string foundTitle, int allowedDistance) 86 | { 87 | var originalEntry = $"{originalArtist} {originalTitle}".ToLower(); 88 | var foundEntry = $"{foundArtist} {foundTitle}".ToLower(); 89 | 90 | Logger.Info("Comparing {originalEntry} with {foundEntry}", originalEntry, foundEntry); 91 | 92 | if (Util.ComputeDistance(originalEntry, foundEntry) <= allowedDistance) 93 | { 94 | Logger.Info("It's good"); 95 | return true; 96 | } 97 | Logger.Info("It's not good"); 98 | return false; 99 | } 100 | 101 | public static string Trim(string title) 102 | { 103 | title = Regex.Replace(title, @"\[.*\]", ""); 104 | title = Regex.Replace(title, @"\(.*\)", ""); 105 | title = Regex.Replace(title, @"\<.*\>", ""); 106 | title = Regex.Replace(title, @"\{.*\}", ""); 107 | return title.Trim(); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Beenius/beenius.conf.template: -------------------------------------------------------------------------------- 1 | { 2 | "allowedDistance": 5, 3 | "delimiters": [ "&", ";", "," ], 4 | "maxResults": 1, 5 | "token": "ZTejoT_ojOEasIkT9WrMBhBQOz6eYKK5QULCMECmOhvwqjRZ6WbpamFe3geHnvp3", 6 | "addLyricsSource": false, 7 | "trimTitle": false, 8 | "removeTags": false 9 | } -------------------------------------------------------------------------------- /Beenius/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Beenius - Genius for MusicBee 2 | It's just a lyrics provider. 3 | 4 | ### Features 5 | Using Genius API instead of webpage parsing. 6 | 7 | ### Installation 8 | Get a release and extract all .dll files into `%APPDATA%\MusicBee\Plugins\` directory. 9 | 10 | ### Activation 11 | Preferences -> Plugins -> Enable Beenius. 12 | Preferences -> Tags (2) -> Lyrics -> Genius via Beenius. 13 | 14 | ### Configuration 15 | Create beenius.conf in the Plugins directory and use this template: 16 | 17 | { 18 | "allowedDistance": 5, 19 | "delimiters": ["&", ";", ","], 20 | "maxResults": 1, 21 | "token": "ZTejoT_ojOEasIkT9WrMBhBQOz6eYKK5QULCMECmOhvwqjRZ6WbpamFe3geHnvp3", 22 | "addLyricsSource": false, 23 | "trimTitle": false, 24 | "removeTags": false 25 | } 26 | 27 | beenius.conf includes several options. You are allowed to use only ones you need, just omit the line and don't forget about commas in JSON. 28 | 1. Configurable title distance for minor differences. Defaults to 5. This means that a present N-character difference in search results won't affect the filtering and be considered a hit. 29 | 2. Configurable artist delimiters ("A & B, C" => "A"). Defaults to none. Useful when you have several artists for the track but Genius includes only the main one. For example, track `$uicideboy$ & JGrxxn & Black Smurf & Ramirez` will be stripped down to `$uicideboy$` with current configuration and will hit [this page](https://genius.com/Uicideboy-grayscale-lyrics). 30 | 3. Configurable search results limit. Defaults to 1. Change if the songs you are searching for does not show up at the first place (not including other types of results) in the search. 31 | 4. Configurable token. Plugin is using an anonymous Android app token which might be eventually revoked so you're able to replace it with your personal one. 32 | 5. Configurable lyrics source marker. Plugin will append "Source: Genius via Beenius" to the lyrics' beginning if enabled. 33 | 6. Configurable title trim. This option will remove all content in brackets from the title. By default MusicBee removes only features in the round brackets, this option will remove all content in `[]`, `{}`, `<>` and `()`. 34 | 7. Configurable tag removal. This option will remove all [Intro], [Verse] and alike tags. 35 | Restart MusicBee to apply changes. 36 | 37 | ### Logic 38 | 39 | 1. Plugin gets either the "artist" field or the first artist in the extended list if you've edited it manually alongside with the "title". 40 | 2. Plugin searches for results just like they are. Results (artist + title) are allowed to differ no more than `allowedDistance` characters. Results are limited to `maxResults`. 41 | 3. Plugin checks for result artist aliases (Mos Def is Yasiin Bey even in his old tracks). 42 | 4. Plugin strips down the artist using the delimiters (if provided), searches and handles aliases. 43 | 44 | ### Log 45 | 46 | You can find log at `%APPDATA%\MusicBee\beenius.log`. 47 | 48 | ### Shoutouts 49 | https://github.com/toptensoftware/JsonKit 50 | 51 | https://nlog-project.org/ 52 | --------------------------------------------------------------------------------