├── LyricsReloaded ├── .gitignore ├── app.config ├── Filters │ ├── Filter.cs │ ├── README.md │ └── FilterCollection.cs ├── Configs │ ├── musixmatch.com-asian.yml │ ├── www.hindilyrics.net.yml │ ├── smriti.com.yml │ ├── urbanlyrics.com.yml │ ├── letras.mus.br.yml │ ├── cuspajz.com.yml │ ├── lyrics.wikia.com.yml │ ├── lyrics.wikia.com-gn.yml │ ├── teksty.org.yml │ ├── songlyrics.com.yml │ ├── oldielyrics.com.yml │ ├── metrolyrics.com.yml │ ├── azlyrics.com.yml │ ├── genius.com.yml │ ├── musixmatch.com.yml │ └── example.yml ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.resx │ └── Resources.Designer.cs ├── packages.config ├── mb_LyricsReloaded.csproj.DotSettings ├── Validation │ ├── README.md │ ├── Validator.cs │ └── ValidationCollection.cs ├── LyricsLoader.cs ├── Provider │ ├── Loader │ │ ├── LyricsLoader.cs │ │ └── StaticLoader.cs │ ├── Variable.cs │ ├── RateLimit.cs │ ├── Provider.cs │ └── ProviderManager.cs ├── README.md ├── Logger.cs ├── mb_LyricsReloaded.csproj ├── Plugin.cs ├── LyricsReloaded.cs └── WebClient.cs ├── LyricsTester.exe ├── LyricsReloaded.suo ├── LyricsTester ├── App.config ├── LyricsTester.csproj.DotSettings ├── Properties │ └── AssemblyInfo.cs ├── LyricsTester.csproj └── Program.cs ├── LyricsNUnit ├── packages.config ├── Test.cs ├── AzLyricsTests.cs ├── PinkRadioTests.cs ├── RapGeniusTests.cs ├── CuspajzTests.cs ├── TekstyTests.cs ├── HindiLyricsTests.cs ├── SmritiTests.cs ├── SongLyricsTests.cs ├── TekstowoTests.cs ├── UrbanLyricsTests.cs ├── OldiesLyricsTests.cs ├── LetrasMusBrTests.cs ├── LyricsTests.cs ├── MetroLyricsTests.cs ├── LyricWikiTests.cs └── LyricsNUnit.csproj ├── .travis.yml ├── README.md ├── providers.txt ├── .gitignore └── LyricsReloaded.sln /LyricsReloaded/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /obj/ 3 | -------------------------------------------------------------------------------- /LyricsTester.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfrankz/LyricsReloaded/HEAD/LyricsTester.exe -------------------------------------------------------------------------------- /LyricsReloaded.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfrankz/LyricsReloaded/HEAD/LyricsReloaded.suo -------------------------------------------------------------------------------- /LyricsReloaded/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /LyricsReloaded/Filters/Filter.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfrankz/LyricsReloaded/HEAD/LyricsReloaded/Filters/Filter.cs -------------------------------------------------------------------------------- /LyricsReloaded/Configs/musixmatch.com-asian.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfrankz/LyricsReloaded/HEAD/LyricsReloaded/Configs/musixmatch.com-asian.yml -------------------------------------------------------------------------------- /LyricsTester/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LyricsNUnit/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LyricsNUnit/Test.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace LyricsNUnit 5 | { 6 | [TestFixture ()] 7 | public class Test 8 | { 9 | [Test ()] 10 | public void TestCase () 11 | { 12 | } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | solution: LyricsReloaded.sln 3 | sudo: false 4 | script: 5 | - xbuild /p:Configuration=Release LyricsReloaded.sln 6 | - mono ./packages/NUnit.Console.3.0.0/tools/nunit3-console.exe LyricsNUnit/bin/Release/LyricsNUnit.dll 7 | -------------------------------------------------------------------------------- /LyricsReloaded/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /LyricsReloaded/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LyricsReloaded/Configs/www.hindilyrics.net.yml: -------------------------------------------------------------------------------- 1 | name: Hindi Lyrics 2 | 3 | variables: 4 | title: 5 | type: title 6 | filters: 7 | - urlencode 8 | 9 | config: 10 | url: "http://www.hindilyrics.net/lyrics/of-{title}.html" 11 | pattern: ['(?.*?)', s] 12 | 13 | post-filters: 14 | - trim 15 | - utf8_encode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LyricsReloaded 2 | ============== 3 | 4 | A rewrite of the Lyrics plugin of MusicBee. 5 | 6 | New version [1.1.14 here](https://github.com/mbfrankz/LyricsReloaded/releases/tag/1.1.14/) 7 | 8 | Bug Tracker 9 | ----------- 10 | GitHub: [LyricsReloaded](https://github.com/mbfrankz/LyricsReloaded/issues) 11 | 12 | Documentation 13 | ------------- 14 | [LyricsReloaded/README.md](LyricsReloaded/README.md) 15 | -------------------------------------------------------------------------------- /LyricsTester/LyricsTester.csproj.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | No -------------------------------------------------------------------------------- /LyricsReloaded/mb_LyricsReloaded.csproj.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | No -------------------------------------------------------------------------------- /LyricsReloaded/Configs/smriti.com.yml: -------------------------------------------------------------------------------- 1 | name: Smriti 2 | 3 | variables: 4 | title: 5 | type: title 6 | filters: 7 | - lowercase 8 | - [regex, '[^\sa-z0-9]\s*', ""] 9 | - [strip_nonascii, -] 10 | 11 | config: 12 | url: "http://smriti.com/hindi-songs/{title}" 13 | pattern: ['
(?.*?)
', s] 14 | 15 | post-filters: 16 | - strip_html 17 | - trim 18 | - utf8_encode -------------------------------------------------------------------------------- /LyricsReloaded/Configs/urbanlyrics.com.yml: -------------------------------------------------------------------------------- 1 | name: Urban Lyrics 2 | 3 | variables: 4 | artist: 5 | type: artist 6 | filters: 7 | - lowercase 8 | - strip_nonascii 9 | title: 10 | type: title 11 | filters: artist 12 | 13 | config: 14 | url: "http://www.urbanlyrics.com/lyrics/{artist}/{title}.html" 15 | pattern: ['(?.+?)', s] 16 | 17 | post-filters: 18 | - strip_html 19 | - utf8_encode -------------------------------------------------------------------------------- /LyricsReloaded/Configs/letras.mus.br.yml: -------------------------------------------------------------------------------- 1 | name: "Letras de músicas" 2 | 3 | variables: 4 | artist: 5 | type: artist 6 | filters: 7 | - lowercase 8 | - [strip_nonascii, -] 9 | title: 10 | type: title 11 | filters: artist 12 | 13 | config: 14 | url: "http://letras.mus.br/{artist}/{title}/" 15 | pattern: ['
]*>(?.*?)
', s] 16 | 17 | post-filters: 18 | - p2break 19 | - strip_html 20 | - clean_spaces 21 | - utf8_encode -------------------------------------------------------------------------------- /LyricsReloaded/Configs/cuspajz.com.yml: -------------------------------------------------------------------------------- 1 | name: "Cušpajz" 2 | 3 | variables: 4 | artist: 5 | type: artist 6 | filters: 7 | - strip_diacritics 8 | - lowercase 9 | - [strip_nonascii, -] 10 | title: 11 | type: title 12 | filters: artist 13 | 14 | config: 15 | url: "http://cuspajz.com/tekstovi-pjesama/pjesma/{artist}/{title}.html" 16 | pattern: ['(?[\s\S]*?)

', s] 17 | 18 | post-filters: 19 | - strip_html 20 | - entity_decode -------------------------------------------------------------------------------- /LyricsReloaded/Configs/lyrics.wikia.com.yml: -------------------------------------------------------------------------------- 1 | name: LyricWiki Reloaded 2 | 3 | variables: 4 | artist: 5 | type: artist 6 | filters: 7 | - [regex, "\\s+", _] 8 | - urlencode 9 | title: 10 | type: title 11 | filters: artist 12 | 13 | post-filters: 14 | - br2nl 15 | - p2break 16 | - strip_html 17 | - entity_decode 18 | - utf8_encode 19 | - trim 20 | 21 | config: 22 | url: "http://lyrics.wikia.com/{artist}:{title}" 23 | pattern: "'lyricbox'>.*?(?.*?)(?.+?)', s] 19 | 20 | post-filters: 21 | - strip_html 22 | - trim 23 | - utf8_encode -------------------------------------------------------------------------------- /LyricsReloaded/Validation/README.md: -------------------------------------------------------------------------------- 1 | Validators 2 | ========== 3 | 4 | Validators are meant to verify the loaded lyrics. 5 | An example where this would be necessary: 6 | A website that doesn't return an error 404 when lyrics were not found, 7 | but instead show a page with the exact same format, but a "not found"-message 8 | instead of lyrics. 9 | The result of validators can be inverted by prefixing their name with "not ". 10 | 11 | Examples: 12 | * [contains, lyrics] 13 | * [not contains, not found] 14 | 15 | contains 16 | -------- 17 | This validator checks whether the content contains a given string (first argument). 18 | 19 | 20 | matches 21 | ------- 22 | This validator checks whether the given regex matches something in the content. 23 | It takes a regular expression (first argument) and options for it (second argument) 24 | -------------------------------------------------------------------------------- /LyricsReloaded/Configs/genius.com.yml: -------------------------------------------------------------------------------- 1 | name: Genius 2 | 3 | variables: 4 | artist: 5 | type: artist 6 | filters: 7 | - strip_diacritics 8 | - lowercase 9 | - [replace, "!!!", "chk-chik-chick"] 10 | - [regex, '(?<=\W|\s)+(feat.+|ft[\W\s]+|(f\.\s)).+', ""] 11 | - [regex, '\.+|,+|(\W+(?=$))|(^\W+)', ""] 12 | - [regex, "'", ""] 13 | - [regex, '(?<=[a-z0-9%])[^\sa-z0-9%]+(?=[a-z0-9%]+)', "-"] 14 | - [regex, '((?<=\s)([^a-z0-9\s-])+(\s|\W)+)|((?<=\w)([^a-z0-9-])+(\s|\W)+)', " "] 15 | - [strip_nonascii, -] 16 | - [regex, '\s&(?=\s)', " and"] 17 | title: 18 | type: title 19 | filters: artist 20 | 21 | config: 22 | url: "https://genius.com/{artist}-{title}-lyrics" 23 | pattern: ['
(?.*)
(?.*?)
]*"lyrics-report".*?>', s] 29 | 30 | post-filters: 31 | - [regex, "", "", s] 32 | - [regex, '
', "\n", s] 33 | - strip_html 34 | - utf8_encode 35 | - entity_decode 36 | - clean_spaces -------------------------------------------------------------------------------- /LyricsReloaded/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Dieser Code wurde von einem Tool generiert. 4 | // Laufzeitversion:4.0.30319.18047 5 | // 6 | // Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn 7 | // der Code erneut generiert wird. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CubeIsland.LyricsReloaded.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.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 | -------------------------------------------------------------------------------- /providers.txt: -------------------------------------------------------------------------------- 1 | Lrc123.com requires search 2 | LYRDB uses an API 3 | chartLyrics.com uses an API 4 | AZ Lyrics working 5 | Dark Lyrics required title for search 6 | Lyrics Time broken 7 | SongMeanings.net required search 8 | LoloLyrics required search 9 | RapGenius working 10 | PLyrics.com working 11 | UrbanLyrics.com working 12 | http://www.oldielyrics.com working 13 | http://www.tekstowo.pl/ working mostly, needs parameterized filters 14 | http://www.teksciory.pl/ requires search 15 | http://teksty.org/ working 16 | http://www.jpopasia.com requires search 17 | http://lyrics.wikia.com/Lyrics_Wiki requires entity decoder 18 | http://www.maxilyrics.com requires search 19 | http://letras.mus.br/ working 20 | musica.com requires search 21 | http://www.metrolyrics.com working 22 | www.songlyrics.com working 23 | tunewiki.com possible 24 | viewlyrics.com possible 25 | -------------------------------------------------------------------------------- /LyricsReloaded/Configs/example.yml: -------------------------------------------------------------------------------- 1 | # the name of the provider. this will be shown in MusicBee's settings 2 | name: 'Example' 3 | 4 | # the loader for this provider: static, search, api 5 | loader: static 6 | 7 | # prepare the input 8 | variables: 9 | # filters to apply to the artist 10 | artist: 11 | type: artist # the source of the value 12 | filters: 13 | - strip_diacritics 14 | - [stripdown, _] 15 | - urlencode 16 | 17 | # filters to apply to the album 18 | # album: skip entry omitted as it isn't needed 19 | 20 | # filters to apply to the title 21 | title: 22 | type: title 23 | filters: artist # reference the filters of artist 24 | 25 | post-filters: 26 | - strip_html 27 | - utf8_encode 28 | - trim 29 | 30 | validations: 31 | - [not contains, Click here to submit these lyrics] 32 | 33 | config: 34 | # the URL to request. {artist}, {album} and {title} are placeholders for the values from the song. 35 | url: "http://www.azlyrics.com/lyrics/{artist}/{title}.html" 36 | 37 | # The regular expression to apply to the content of the website. The pattern must contain a named capturing group called "lyrics" like: (?.+?) 38 | # variables are allowed as well 39 | pattern: '(?.+?)' 40 | 41 | # The options for the pattern: 42 | # - i: case insensitive 43 | # 44 | # more to come 45 | pattern-options: 'i' 46 | -------------------------------------------------------------------------------- /LyricsNUnit/AzLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class AzLyricsTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void azLyricsBasics() 33 | { 34 | String lyr = getProvider("A-Z Lyrics Universe").getLyrics("Skillet", "I Can", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/PinkRadioTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class PinkRadioTests : BaseTest 29 | { 30 | [Timeout(4000)] 31 | [Test] 32 | public void pinkRadioBasics() 33 | { 34 | String lyr = getProvider("Pink Radio").getLyrics("", "Sa tvojih usana", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/RapGeniusTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class RapGeniusTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void rapGeniusBasics() 33 | { 34 | String lyr = getProvider("Rap Genius").getLyrics("Nesli", "Niente Di Più", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/CuspajzTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class CuspajzTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void cuspajzBasics() 33 | { 34 | String lyr = getProvider("Cušpajz").getLyrics("Zabranjeno pušenje", "Kada dernek utihne", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/TekstyTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class TekstyTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void tekstyBasics() 33 | { 34 | String lyr = getProvider("Teksty").getLyrics("Daniel Olbrychski", "Wyrzeźbiłem twoją twarz", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/HindiLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class HindiLyricsTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void hindiLyricsBasics() 33 | { 34 | String lyr = getProvider("Hindi Lyrics").getLyrics("", "Raanjhna Hua Main Tera", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/SmritiTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class SmritiTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void smritiBasics() 33 | { 34 | String lyr = getProvider("Smriti").getLyrics("", "ba.Dii mushkil se huaa teraa meraa saath piyaa", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/SongLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class SongLyricsTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void songLyricsBasics() 33 | { 34 | String lyr = getProvider("Song Lyrics").getLyrics("die Ärzte", "Schrei nach Liebe", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/TekstowoTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class TekstowoTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void tekstowoBasics() 33 | { 34 | String lyr = getProvider("Tekstowo").getLyrics("Daniel Olbrychski", "Wyrzeźbiłem twoją twarz", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/UrbanLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class UrbanLyricsTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void urbanLyricsBasics() 33 | { 34 | String lyr = getProvider("Urban Lyrics").getLyrics("50 Cent", "Buzzin' (Remix)", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/OldiesLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class OldiesLyrics : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void oldiesLyricsBasics() 33 | { 34 | String lyr = getProvider("Oldies Lyrics").getLyrics("RODNEY CROWELL", "Why Don't We Talk About It", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LyricsNUnit/LetrasMusBrTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using CubeIsland.LyricsReloaded.Provider; 23 | using NUnit.Framework; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | [Ignore("requires searching now")] 29 | public class LetrasMusBrTests : BaseTest 30 | { 31 | [Timeout(3000)] 32 | [Test] 33 | public void letrasMusBrBasics() 34 | { 35 | String lyr = getProvider("Letras de músicas").getLyrics("Mc Anitta", "Show Das Poderosas", ""); 36 | 37 | Console.WriteLine(lyr); 38 | 39 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LyricsNUnit/LyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded; 24 | using CubeIsland.LyricsReloaded.Provider; 25 | 26 | namespace LyricsUnitTests 27 | { 28 | public class BaseTest 29 | { 30 | 31 | private LyricsReloaded lr; 32 | 33 | [SetUp] 34 | public void setUp() 35 | { 36 | this.lr = new LyricsReloaded("."); 37 | lr.loadConfigurations(); 38 | 39 | } 40 | 41 | public Provider getProvider(string name) 42 | { 43 | Provider p = this.lr.getProviderManager().getProvider(name); 44 | Assert.IsNotNull(p, "Provider '" + name + "' not found!"); 45 | return p; 46 | } 47 | 48 | [TearDown] 49 | public void tearDown() 50 | { 51 | this.lr.shutdown (); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /LyricsTester/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die mit einer Assembly verknüpft sind. 8 | [assembly: AssemblyTitle("LyricsTester")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LyricsTester")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 18 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("7722b1af-655a-4db3-ae9d-54c4699a04f7")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 33 | // übernehmen, indem Sie "*" eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LyricsNUnit/MetroLyricsTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class MetroLyricsTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void metroLyricsBasics() 33 | { 34 | String lyr = getProvider("MetroLyrics").getLyrics("Lil Wayne", "We Be Steady Mobbin''", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | 41 | [Timeout(3000)] 42 | [Test] 43 | public void metroLyricsNonAsciiSpaceEdgeCase() 44 | { 45 | String lyr = getProvider("MetroLyrics").getLyrics("Lil Wayne", "Mr. Carter", ""); 46 | 47 | Console.WriteLine(lyr); 48 | 49 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /LyricsNUnit/LyricWikiTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using NUnit.Framework; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | 25 | namespace LyricsUnitTests 26 | { 27 | [TestFixture] 28 | public class LyricWikiTests : BaseTest 29 | { 30 | [Timeout(3000)] 31 | [Test] 32 | public void lyricWikiNormalBasics() 33 | { 34 | String lyr = getProvider("LyricWiki").getLyrics("Magic!", "Rude", ""); 35 | 36 | Console.WriteLine(lyr); 37 | 38 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 39 | } 40 | 41 | [Timeout(3000)] 42 | [Test] 43 | [Ignore("seems not available anymore")] 44 | public void lyricWikiGracenoteBasics() 45 | { 46 | String lyr = getProvider("LyricWiki Gracenote").getLyrics("112", "Anywhere (Ft. Lil Zane)", ""); 47 | 48 | Console.WriteLine(lyr); 49 | 50 | Assert.IsFalse(String.IsNullOrWhiteSpace(lyr), "Lyrics not found!"); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LyricsReloaded/LyricsLoader.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using YamlDotNet.RepresentationModel; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | 25 | namespace CubeIsland.LyricsReloaded.Provider.Loader 26 | { 27 | public interface LyricsLoader 28 | { 29 | Lyrics getLyrics(Dictionary variables); 30 | } 31 | 32 | public interface LyricsLoaderFactory 33 | { 34 | string getName(); 35 | LyricsLoader newLoader(string name, YamlMappingNode configuration); 36 | } 37 | 38 | public class Lyrics 39 | { 40 | private readonly string content; 41 | private readonly Encoding encoding; 42 | 43 | public Lyrics(string content, Encoding encoding) 44 | { 45 | this.content = content; 46 | this.encoding = encoding; 47 | } 48 | 49 | public string getContent() 50 | { 51 | return this.content; 52 | } 53 | 54 | public Encoding getEncoding() 55 | { 56 | return this.encoding; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/Loader/LyricsLoader.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using YamlDotNet.RepresentationModel; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | 25 | namespace CubeIsland.LyricsReloaded.Provider.Loader 26 | { 27 | public interface LyricsLoader 28 | { 29 | Lyrics getLyrics(Provider provider, Dictionary variables); 30 | } 31 | 32 | public interface LyricsLoaderFactory 33 | { 34 | string getName(); 35 | LyricsLoader newLoader(YamlMappingNode configuration); 36 | } 37 | 38 | public class Lyrics 39 | { 40 | private readonly string content; 41 | private readonly Encoding encoding; 42 | 43 | public Lyrics(string content, Encoding encoding) 44 | { 45 | this.content = content; 46 | this.encoding = encoding; 47 | } 48 | 49 | public string getContent() 50 | { 51 | return content; 52 | } 53 | 54 | public Encoding getEncoding() 55 | { 56 | return encoding; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /LyricsReloaded/README.md: -------------------------------------------------------------------------------- 1 | Plugin documentation 2 | ==================== 3 | 4 | Links 5 | ----- 6 | * [Filter](Filters/README.md) 7 | * [Validator](Validation/README.md) 8 | * [Example configuration](Configs/example.yml) 9 | 10 | Regular expressions 11 | ------------------- 12 | This plugin relies heavily on Microsoft-flavored regular expression 13 | for its functionality. Tutorials and tools to write these expressions 14 | are all over the internet, for example [RegExr](http://www.regexr.com/) 15 | which is a greate tool to write and test regular expressions. 16 | 17 | Using these regexes is usually done in 2 ways: 18 | 1. a single string, which specifies only the regex 19 | 2. an array of 2 strings that specifies the regex in its first element 20 | and regex options as its second element. Example: ["regex", is] 21 | 22 | There are 2 things to watch out for: 23 | * backslashes (\\) must be escaped when using double quotes ("), as it is a meta character in the YAML format: \s -> \\\s 24 | * named capturing groups are defined like this: (?\.*?) with "lyrics" being the name of the group 25 | 26 | Regex options 27 | ------------- 28 | The regex options are specified as a string that contains the characters 29 | for the options. A lowercase character enables the options, an uppercase 30 | character disables the options. 31 | 32 | The options: 33 | 34 | * **i**: the regex is case insensitive 35 | * **s**: the input string is seen as a single line 36 | * **m**: the input is seen as multiple lines 37 | * **c**: the regex will be compiled (improves execution performance, but slows startup) 38 | * **x**: whitespace in the regex will be ignored (nice for complex regexes) 39 | * **d**: the regex will go from right to left though the string 40 | * **e**: only named capturing groups will be used 41 | * **j**: the regex will be ECMA script compatible 42 | * **l**: the regex will be culture invariant 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | .vs/ 40 | 41 | # Visual C++ cache files 42 | ipch/ 43 | *.aps 44 | *.ncb 45 | *.opensdf 46 | *.sdf 47 | 48 | # Visual Studio profiler 49 | *.psess 50 | *.vsp 51 | *.vspx 52 | 53 | # Guidance Automation Toolkit 54 | *.gpState 55 | 56 | # ReSharper is a .NET coding add-in 57 | _ReSharper* 58 | 59 | # NCrunch 60 | *.ncrunch* 61 | .*crunch*.local.xml 62 | 63 | # Installshield output folder 64 | [Ee]xpress 65 | 66 | # DocProject is a documentation generator add-in 67 | DocProject/buildhelp/ 68 | DocProject/Help/*.HxT 69 | DocProject/Help/*.HxC 70 | DocProject/Help/*.hhc 71 | DocProject/Help/*.hhk 72 | DocProject/Help/*.hhp 73 | DocProject/Help/Html2 74 | DocProject/Help/html 75 | 76 | # Click-Once directory 77 | publish 78 | 79 | # Publish Web Output 80 | *.Publish.xml 81 | 82 | # NuGet Packages Directory 83 | packages 84 | !packages/repositories.config 85 | .nuget 86 | 87 | # Windows Azure Build Output 88 | csx 89 | *.build.csdef 90 | 91 | # Windows Store app package directory 92 | AppPackages/ 93 | 94 | # Others 95 | [Bb]in 96 | [Oo]bj 97 | sql 98 | TestResults 99 | [Tt]est[Rr]esult* 100 | *.Cache 101 | ClientBin 102 | [Ss]tyle[Cc]op.* 103 | ~$* 104 | *.dbmdl 105 | Generated_Code #added for RIA/Silverlight projects 106 | 107 | # Backup & report files from converting an old project file to a newer 108 | # Visual Studio version. Backup files are not needed, because we have git ;-) 109 | _UpgradeReport_Files/ 110 | Backup*/ 111 | UpgradeLog*.XML 112 | 113 | # Monodevelop 114 | *.userprefs 115 | 116 | /LyricsReloaded/MusicBeeInterfaceOLD.cs 117 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/Variable.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using CubeIsland.LyricsReloaded.Filters; 22 | using System.Text; 23 | 24 | namespace CubeIsland.LyricsReloaded.Provider 25 | { 26 | public class Variable 27 | { 28 | private readonly string name; 29 | private readonly Type type; 30 | private readonly FilterCollection filters; 31 | 32 | public Variable(string name, Type type, FilterCollection filters = null) 33 | { 34 | this.name = name; 35 | this.type = type; 36 | if (filters == null || filters.getSize() <= 0) 37 | { 38 | this.filters = null; 39 | } 40 | else 41 | { 42 | this.filters = filters; 43 | } 44 | } 45 | 46 | public string getName() 47 | { 48 | return name; 49 | } 50 | 51 | public Type getType() 52 | { 53 | return type; 54 | } 55 | 56 | public FilterCollection getFilters() 57 | { 58 | return filters; 59 | } 60 | 61 | public string process(string input, Encoding encoding) 62 | { 63 | if (filters == null) 64 | { 65 | return input; 66 | } 67 | return filters.applyFilters(input, encoding); 68 | } 69 | 70 | public enum Type 71 | { 72 | ARTIST, TITLE, ALBUM 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /LyricsReloaded/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System.Reflection; 22 | using System.Runtime.CompilerServices; 23 | using System.Runtime.InteropServices; 24 | using System.Resources; 25 | 26 | // Allgemeine Informationen über eine Assembly werden über die folgenden 27 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 28 | // die mit einer Assembly verknüpft sind. 29 | [assembly: AssemblyTitle("LyricsReloaded")] 30 | [assembly: AssemblyDescription("Enhanced Lyric Fetching for MusicBee")] 31 | [assembly: AssemblyConfiguration("")] 32 | [assembly: AssemblyCompany("Authored by Cube Island, Maintained by Frank")] 33 | [assembly: AssemblyProduct("LyricsReloaded")] 34 | [assembly: AssemblyCopyright("Copyright © 2013-2022")] 35 | [assembly: AssemblyTrademark("")] 36 | [assembly: AssemblyCulture("")] 37 | 38 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 39 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 40 | // COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. 41 | [assembly: ComVisible(false)] 42 | 43 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 44 | [assembly: Guid("4409193a-89bb-4762-b4a9-3d524cdcb5e7")] 45 | 46 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 47 | // 48 | // Hauptversion 49 | // Nebenversion 50 | // Buildnummer 51 | // Revision 52 | // 53 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 54 | // übernehmen, indem Sie "*" eingeben: 55 | // [assembly: AssemblyVersion("1.0.*")] 56 | [assembly: AssemblyVersion("1.1.14.0")] 57 | [assembly: AssemblyFileVersion("1.1.14.0")] 58 | [assembly: NeutralResourcesLanguageAttribute("en")] 59 | -------------------------------------------------------------------------------- /LyricsReloaded/Logger.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Text; 23 | using System.IO; 24 | 25 | namespace CubeIsland.LyricsReloaded 26 | { 27 | public class Logger 28 | { 29 | private readonly FileInfo fileInfo; 30 | private StreamWriter writer; 31 | 32 | public Logger(string path) 33 | { 34 | fileInfo = new FileInfo(path); 35 | writer = null; 36 | } 37 | 38 | public FileInfo getFileInfo() 39 | { 40 | return fileInfo; 41 | } 42 | 43 | private void write(string type, string message, object[] args) 44 | { 45 | if (writer == null) 46 | { 47 | writer = new StreamWriter(fileInfo.FullName, true, Encoding.UTF8); 48 | writer.AutoFlush = false; 49 | } 50 | writer.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss") + " [" + type.ToUpper() + "] " + string.Format(message, args)); 51 | writer.Flush(); 52 | } 53 | 54 | public void close() 55 | { 56 | if (writer != null) 57 | { 58 | try 59 | { 60 | writer.Close(); 61 | } 62 | catch (ObjectDisposedException) 63 | {} 64 | } 65 | } 66 | 67 | public void debug(string message, params object[] args) 68 | { 69 | write("debug", message, args); 70 | } 71 | 72 | public void info(string message, params object[] args) 73 | { 74 | write("info", message, args); 75 | } 76 | 77 | public void warn(string message, params object[] args) 78 | { 79 | write("warn", message, args); 80 | } 81 | 82 | public void error(string message, params object[] args) 83 | { 84 | write("error", message, args); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /LyricsReloaded.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2018 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mb_LyricsReloaded", "LyricsReloaded\mb_LyricsReloaded.csproj", "{0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LyricsTester", "LyricsTester\LyricsTester.csproj", "{9BB223A4-A756-4530-9B61-A2E0CE6E2937}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LyricsNUnit", "LyricsNUnit\LyricsNUnit.csproj", "{029CDB6C-8690-42D5-AA53-16F53BE33A66}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Package|Any CPU = Package|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Debug|Any CPU.ActiveCfg = Release|Any CPU 20 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Debug|Any CPU.Build.0 = Release|Any CPU 21 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Package|Any CPU.ActiveCfg = Package|Any CPU 22 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Package|Any CPU.Build.0 = Package|Any CPU 23 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Package|Any CPU.ActiveCfg = Package|Any CPU 28 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Package|Any CPU.Build.0 = Package|Any CPU 29 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Package|Any CPU.ActiveCfg = Package|Any CPU 34 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Package|Any CPU.Build.0 = Package|Any CPU 35 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {029CDB6C-8690-42D5-AA53-16F53BE33A66}.Release|Any CPU.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {A081A26B-6CB8-43C0-BD28-5728F96F64C1} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /LyricsNUnit/LyricsNUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {029CDB6C-8690-42D5-AA53-16F53BE33A66} 7 | Library 8 | LyricsNUnit 9 | LyricsNUnit 10 | 11 | 12 | true 13 | full 14 | false 15 | bin\Debug 16 | DEBUG; 17 | prompt 18 | 4 19 | false 20 | 21 | 22 | full 23 | true 24 | bin\Release 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | full 31 | true 32 | bin\Release 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | ..\packages\NUnit.3.0.0\lib\net40\nunit.framework.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC} 67 | mb_LyricsReloaded 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /LyricsReloaded/Validation/Validator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System.Text.RegularExpressions; 22 | using CubeIsland.LyricsReloaded.Provider; 23 | using CubeIsland.LyricsReloaded.Provider.Loader; 24 | 25 | namespace CubeIsland.LyricsReloaded.Validation 26 | { 27 | public interface Validator 28 | { 29 | string getName(); 30 | bool validate(string content, string[] args); 31 | } 32 | 33 | public class Validation 34 | { 35 | private readonly Validator validator; 36 | private readonly bool inverted; 37 | private readonly string[] args; 38 | 39 | public Validation(Validator validator, bool inverted, string[] args) 40 | { 41 | this.validator = validator; 42 | this.inverted = inverted; 43 | this.args = args; 44 | } 45 | 46 | public bool execute(string content) 47 | { 48 | bool result = validator.validate(content, args); 49 | if (inverted) 50 | { 51 | result = !result; 52 | } 53 | return result; 54 | } 55 | } 56 | 57 | public class ContainsValidator : Validator 58 | { 59 | public string getName() 60 | { 61 | return "contains"; 62 | } 63 | 64 | public bool validate(string content, string[] args) 65 | { 66 | if (args.Length < 1) 67 | { 68 | throw new InvalidConfigurationException("The contains validator needs at least 1 argument: contains, [, ]"); 69 | } 70 | if (args.Length > 1) 71 | { 72 | return content.ToLower().Contains(args[0].ToLower()); 73 | } 74 | return content.Contains(args[0]); 75 | } 76 | } 77 | 78 | public class MatchesValidator : Validator 79 | { 80 | public string getName() 81 | { 82 | return "matches"; 83 | } 84 | 85 | public bool validate(string content, string[] args) 86 | { 87 | if (args.Length < 1) 88 | { 89 | throw new InvalidConfigurationException("The matches validator needs at least one parameter: matches, "); 90 | } 91 | RegexOptions options = RegexOptions.None; 92 | if (args.Length > 1) 93 | { 94 | options = Pattern.regexOptionsFromString(args[2].Trim()); 95 | } 96 | 97 | return (new Regex(args[0], options)).Match(content).Success; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /LyricsReloaded/Filters/README.md: -------------------------------------------------------------------------------- 1 | Filter 2 | ====== 3 | 4 | Filters are small functions that can modify the given content. 5 | Filters can currently be applied to variable values and the lyrics 6 | content. 7 | 8 | ***Important***: The filters are executed in the specified order, so stripping HTML-tags 9 | before converting \ tags to newlines won't get you far. 10 | 11 | 12 | strip_html 13 | ---------- 14 | This filter removes all HTML tags from the content. 15 | 16 | 17 | entity_decode 18 | ------------- 19 | This filter decodes HTML entities like \© -> ©. 20 | 21 | 22 | strip_links 23 | ----------- 24 | This filter removes links from the lyrics. 25 | 26 | 27 | utf8_encode 28 | ----------- 29 | This filter converts the content's encoding to UTF-8 (without BOM). 30 | 31 | 32 | br2ln 33 | ----- 34 | This filter converts \ tags to newlines (\n). 35 | 36 | 37 | p2break 38 | ------- 39 | This filter converts \ tags to 2 newlines (\n) indicating a new paragraph. 40 | 41 | 42 | clean_spaces 43 | ------------ 44 | This filter cleans up the whitespace of the content by normalizing line endings, 45 | converting tabs to spaces, vertical tabs to newlines and 46 | removing unnecessary newlines and spaces. 47 | 48 | 49 | trim 50 | ---- 51 | This filter removes whitespace from the beginning and the end of the content. 52 | 53 | 54 | lowercase 55 | --------- 56 | This filter converts the whole content to lower case. 57 | Optionally you can provide a culture name as the first argument. 58 | 59 | By default the conversion is culture unaware. 60 | 61 | 62 | uppercase 63 | --------- 64 | This filter converts the while content to upper case 65 | Optionally you can provide a culture name as the first argument. 66 | 67 | By default the conversion is culture unaware. 68 | 69 | 70 | diacritics2ascii 71 | ---------------- 72 | This filter removes diacritics from the content, so "äöüß" becomes "aous". 73 | 74 | 75 | umlauts2ascii 76 | ------------- 77 | This filter is specialized version of diacritics2ascii that handles 78 | only the german umlauts and replaces them with their two character 79 | representation, so "äöüß" becomes "aeoeuess". 80 | 81 | 82 | urlencode 83 | --------- 84 | This filter URL-encodes the content where necessary, so a space becomes +. 85 | 86 | urlencode 87 | --------- 88 | This filter URL-encodes the content where necessary, so a space becomes %20. 89 | 90 | 91 | regex 92 | ----- 93 | This filter does a regex replace, the first argument is the regex (which will be cached) 94 | and the second argument is the replacement which may contain backreferences. 95 | Optionally a third argument can be given which specifies regex options 96 | 97 | Example usage: [regex, '\\s+?', " "] 98 | 99 | 100 | strip_nonascii 101 | -------------- 102 | This filter removes all non-ASCII characters. 103 | The filter has 2 optional arguments: The first is a replacement for 104 | the removed character and the second one specifies whether the replacement 105 | can be inserted multiple times in a row. 106 | 107 | Examples: 108 | 109 | * strip_nonascii -> "test *** test" -> "testtest" 110 | * [strip_nonascii, -] -> "test *** test" -> "test-test" 111 | * [strip_nonascii, -, duplicate] -> "test *** test" -> "test-----test" 112 | 113 | 114 | replace 115 | ------- 116 | This filter replaces the given search string (first argument) with 117 | the replacment (second argument). 118 | 119 | Example usage: [replace, search, replace] 120 | -------------------------------------------------------------------------------- /LyricsTester/LyricsTester.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9BB223A4-A756-4530-9B61-A2E0CE6E2937} 8 | Exe 9 | Properties 10 | LyricsTester 11 | LyricsTester 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | pdbonly 36 | true 37 | bin\Release\ 38 | TRACE 39 | prompt 40 | 4 41 | AnyCPU 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC} 57 | mb_LyricsReloaded 58 | 59 | 60 | 61 | 68 | 69 | 70 | 71 | %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/RateLimit.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | 23 | namespace CubeIsland.LyricsReloaded.Provider 24 | { 25 | public class RateLimit 26 | { 27 | private long periodStart; 28 | private readonly long periodLength; 29 | private readonly int requestsPerPeriod; 30 | private volatile int currentRequests; 31 | 32 | public RateLimit(long periodLength, int requestsPerPeriod) 33 | { 34 | reset(); 35 | this.periodLength = periodLength; 36 | this.requestsPerPeriod = requestsPerPeriod; 37 | } 38 | 39 | private void reset() 40 | { 41 | periodStart = -1; 42 | currentRequests = 0; 43 | } 44 | 45 | public bool tryIncrement() 46 | { 47 | if ((Environment.TickCount - periodStart) > periodLength) 48 | { 49 | reset(); 50 | } 51 | if (currentRequests > requestsPerPeriod) 52 | { 53 | return false; 54 | } 55 | 56 | if (periodStart == -1) 57 | { 58 | periodStart = Environment.TickCount; 59 | } 60 | ++currentRequests; 61 | return true; 62 | } 63 | 64 | public static RateLimit parse(string input) 65 | { 66 | string[] parts = input.Split('/'); 67 | 68 | int requestsPerPeriod; 69 | try 70 | { 71 | requestsPerPeriod = Convert.ToInt32(parts[0].Trim()); 72 | } 73 | catch (FormatException) 74 | { 75 | return null; 76 | } 77 | long periodLength = 1000 * 60 * 60; // 1 hour 78 | 79 | if (parts.Length > 1) 80 | { 81 | switch (parts[1].Trim().ToLower()) 82 | { 83 | case "second": 84 | periodLength = 1000L; 85 | break; 86 | case "minute": 87 | periodLength = 1000L * 60; 88 | break; 89 | case "hour": 90 | periodLength = 1000L * 60 * 60; 91 | break; 92 | case "day": 93 | periodLength = 1000L * 60 * 60 * 24; 94 | break; 95 | case "week": 96 | periodLength = 1000L * 60 * 60 * 24 * 7; 97 | break; 98 | case "month": 99 | periodLength = 1000L * 60 * 60 * 24 * 30; 100 | break; 101 | } 102 | } 103 | 104 | return new RateLimit(periodLength, requestsPerPeriod); 105 | } 106 | 107 | public void shutdown() 108 | { 109 | // TODO implement period start persistence 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /LyricsTester/Program.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Text; 23 | using CubeIsland.LyricsReloaded; 24 | using CubeIsland.LyricsReloaded.Provider; 25 | 26 | namespace LyricsTester 27 | { 28 | class Program 29 | { 30 | static int Main(string[] args) 31 | { 32 | Console.Title = "LyricsReloaded!"; 33 | Console.OutputEncoding = Encoding.UTF8; 34 | Console.InputEncoding = Encoding.UTF8; 35 | Console.CancelKeyPress += (sender, eventArgs) => Console.WriteLine("Bye!"); 36 | 37 | String providerName = null; 38 | String artist = null; 39 | String title = null; 40 | String album = null; 41 | 42 | int result = 0; 43 | 44 | int argc = args.Length; 45 | 46 | if (argc > 0) 47 | { 48 | providerName = args[0]; 49 | } 50 | if (argc > 1) 51 | { 52 | artist = args[1]; 53 | } 54 | if (argc > 2) 55 | { 56 | title = args[2]; 57 | } 58 | if (argc > 3) 59 | { 60 | album = args[3]; 61 | } 62 | 63 | LyricsReloaded lyricsReloaded = new LyricsReloaded("."); 64 | lyricsReloaded.loadConfigurations(); 65 | 66 | lyricsReloaded.checkForNewVersion(newAvailable => 67 | { 68 | if (newAvailable) 69 | { 70 | Console.WriteLine(); 71 | Console.ForegroundColor = ConsoleColor.White; 72 | Console.BackgroundColor = ConsoleColor.Red; 73 | Console.Write("A new version is available!"); 74 | Console.ResetColor(); 75 | Console.WriteLine(); 76 | } 77 | }); 78 | 79 | if (String.IsNullOrWhiteSpace(providerName)) 80 | { 81 | Console.WriteLine("The providers:"); 82 | foreach (Provider p in lyricsReloaded.getProviderManager().getProviders()) 83 | { 84 | Console.WriteLine(" - {0}", p.getName()); 85 | } 86 | Console.Write("Enter the provider: "); 87 | providerName = Console.ReadLine(); 88 | if (providerName != null) 89 | { 90 | providerName = providerName.Trim(); 91 | } 92 | } 93 | if (String.IsNullOrWhiteSpace(artist)) 94 | { 95 | Console.Write("Enter the artist: "); 96 | artist = Console.ReadLine(); 97 | if (artist != null) 98 | { 99 | artist = artist.Trim(); 100 | } 101 | } 102 | if (String.IsNullOrWhiteSpace(title)) 103 | { 104 | Console.Write("Enter the title: "); 105 | title = Console.ReadLine(); 106 | if (title != null) 107 | { 108 | title = title.Trim(); 109 | } 110 | } 111 | 112 | 113 | Provider provider = lyricsReloaded.getProviderManager().getProvider(providerName); 114 | if (provider == null) 115 | { 116 | lyricsReloaded.getLogger().error("Provider {0} not found!", providerName); 117 | result = 1; 118 | } 119 | else 120 | { 121 | Console.Write("Provider {0}: ", providerName); 122 | try 123 | { 124 | String lyrics = provider.getLyrics(artist, title, album); 125 | if (String.IsNullOrWhiteSpace(lyrics)) 126 | { 127 | Console.WriteLine("failed (not found)"); 128 | lyricsReloaded.getLogger().error("Lyrics not found!"); 129 | } 130 | else 131 | { 132 | Console.WriteLine("success\n\n" + lyrics); 133 | } 134 | } 135 | catch (Exception e) 136 | { 137 | Console.WriteLine("failed (internal error)"); 138 | Console.WriteLine(e.ToString()); 139 | } 140 | } 141 | 142 | Console.WriteLine("\nPress any key to exit..."); 143 | Console.ReadKey(); 144 | 145 | return result; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/Provider.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using CubeIsland.LyricsReloaded.Filters; 22 | using CubeIsland.LyricsReloaded.Validation; 23 | using CubeIsland.LyricsReloaded.Provider.Loader; 24 | using System; 25 | using System.Text; 26 | using System.Collections.Generic; 27 | 28 | namespace CubeIsland.LyricsReloaded.Provider 29 | { 30 | public class Provider : IComparable 31 | { 32 | private readonly LyricsReloaded lyricsReloaded; 33 | private readonly string name; 34 | private readonly ushort quality; 35 | private readonly IDictionary variables; 36 | private readonly FilterCollection postFilters; 37 | private readonly ValidationCollection validations; 38 | private readonly IDictionary headers; 39 | private readonly LyricsLoader loader; 40 | private readonly RateLimit rateLimit; 41 | 42 | public Provider(LyricsReloaded lyricsReloaded, string name, ushort quality, IDictionary variables, FilterCollection postFilters, ValidationCollection validations, IDictionary headers, LyricsLoader loader, RateLimit rateLimit = null) 43 | { 44 | this.lyricsReloaded = lyricsReloaded; 45 | this.name = name; 46 | this.quality = quality; 47 | this.variables = variables; 48 | this.postFilters = postFilters; 49 | this.validations = validations; 50 | this.headers = headers; 51 | this.loader = loader; 52 | this.rateLimit = rateLimit; 53 | } 54 | 55 | public string getName() 56 | { 57 | return name; 58 | } 59 | 60 | public ushort getQuality() 61 | { 62 | return quality; 63 | } 64 | 65 | public object getVariables() 66 | { 67 | return variables; 68 | } 69 | 70 | public FilterCollection getPostFilters() 71 | { 72 | return postFilters; 73 | } 74 | 75 | public ValidationCollection getValidations() 76 | { 77 | return validations; 78 | } 79 | 80 | public IDictionary getHeaders() 81 | { 82 | return headers; 83 | } 84 | 85 | public LyricsLoader getLoader() 86 | { 87 | return loader; 88 | } 89 | 90 | public String getLyrics(String artist, String title, String album) 91 | { 92 | if (rateLimit != null && !rateLimit.tryIncrement()) 93 | { 94 | return null; 95 | } 96 | 97 | Dictionary variableValues = new Dictionary(variables.Count); 98 | 99 | Variable var; 100 | foreach (KeyValuePair entry in variables) 101 | { 102 | var = entry.Value; 103 | switch (var.getType()) 104 | { 105 | case Variable.Type.ARTIST: 106 | variableValues.Add(entry.Key, var.process(artist, Encoding.UTF8)); 107 | break; 108 | case Variable.Type.TITLE: 109 | variableValues.Add(entry.Key, var.process(title, Encoding.UTF8)); 110 | break; 111 | case Variable.Type.ALBUM: 112 | variableValues.Add(entry.Key, var.process(album, Encoding.UTF8)); 113 | break; 114 | } 115 | } 116 | 117 | 118 | lyricsReloaded.getLogger().info("{0} tries to load the lyrics...", name); 119 | Lyrics lyrics = loader.getLyrics(this, variableValues); 120 | 121 | if (lyrics == null) 122 | { 123 | lyricsReloaded.getLogger().info("No lyrics found."); 124 | return null; 125 | } 126 | 127 | string filteredLyrics = postFilters.applyFilters(lyrics.getContent(), lyrics.getEncoding()); 128 | 129 | if (!validations.executeValidations(filteredLyrics)) 130 | { 131 | lyricsReloaded.getLogger().info("Validation failed."); 132 | return null; 133 | } 134 | 135 | return filteredLyrics; 136 | } 137 | 138 | public int CompareTo(Provider other) 139 | { 140 | return other.quality - quality; 141 | } 142 | 143 | public void shutdown() 144 | { 145 | if (rateLimit != null) 146 | { 147 | rateLimit.shutdown(); 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /LyricsReloaded/Filters/FilterCollection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using CubeIsland.LyricsReloaded.Provider; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | using YamlDotNet.RepresentationModel; 25 | 26 | namespace CubeIsland.LyricsReloaded.Filters 27 | { 28 | public class FilterCollection 29 | { 30 | private static class Node 31 | { 32 | public static readonly YamlScalarNode NAME = new YamlScalarNode("name"); 33 | public static readonly YamlScalarNode ARGS = new YamlScalarNode("args"); 34 | } 35 | 36 | private readonly LinkedList> filters; 37 | 38 | public FilterCollection() 39 | { 40 | filters = new LinkedList>(); 41 | } 42 | 43 | public void Add(KeyValuePair filter) 44 | { 45 | filters.AddLast(filter); 46 | } 47 | 48 | public void Add(Filter filter, string[] args) 49 | { 50 | Add(new KeyValuePair(filter, args)); 51 | } 52 | 53 | public int getSize() 54 | { 55 | return filters.Count; 56 | } 57 | 58 | public string applyFilters(string content, Encoding encoding) 59 | { 60 | foreach (KeyValuePair entry in filters) 61 | { 62 | content = entry.Key.filter(content, entry.Value, encoding); 63 | } 64 | return content; 65 | } 66 | 67 | public static FilterCollection parseList(YamlSequenceNode list, Dictionary filterMap) 68 | { 69 | FilterCollection collection = new FilterCollection(); 70 | 71 | if (list != null) 72 | { 73 | foreach (YamlNode node in list.Children) 74 | { 75 | parseFilterNode(collection, filterMap, node); 76 | } 77 | } 78 | 79 | return collection; 80 | } 81 | private static void parseFilterNode(FilterCollection filterCollection, Dictionary filterMap, YamlNode node) 82 | { 83 | string name; 84 | string[] args; 85 | if (node is YamlScalarNode) 86 | { 87 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 88 | args = new string[0]; 89 | } 90 | else if (node is YamlSequenceNode) 91 | { 92 | IEnumerator it = ((YamlSequenceNode)node).Children.GetEnumerator(); 93 | if (!it.MoveNext()) 94 | { 95 | throw new InvalidConfigurationException("An empty list as a filter is not valid!"); 96 | } 97 | node = it.Current; 98 | if (!(node is YamlScalarNode)) 99 | { 100 | throw new InvalidConfigurationException("Filter definitions as a list my only contain strings!"); 101 | } 102 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 103 | args = readFilterArgs(it); 104 | } 105 | else if (node is YamlMappingNode) 106 | { 107 | YamlMappingNode filterConfig = (YamlMappingNode)node; 108 | IDictionary childNodes = filterConfig.Children; 109 | node = (childNodes.ContainsKey(Node.NAME) ? childNodes[Node.NAME] : null); 110 | if (!(node is YamlScalarNode)) 111 | { 112 | throw new InvalidConfigurationException("The filter name is missing or invalid!"); 113 | } 114 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 115 | 116 | node = (childNodes.ContainsKey(Node.ARGS) ? childNodes[Node.ARGS] : null); 117 | if (node is YamlSequenceNode) 118 | { 119 | args = readFilterArgs(((YamlSequenceNode)node).Children.GetEnumerator()); 120 | } 121 | else 122 | { 123 | args = new string[0]; 124 | } 125 | } 126 | else 127 | { 128 | throw new InvalidConfigurationException("Invalid filter configuration"); 129 | } 130 | 131 | if (!filterMap.ContainsKey(name)) 132 | { 133 | throw new InvalidConfigurationException("Unknown filter " + name); 134 | } 135 | 136 | 137 | filterCollection.Add(filterMap[name], args); 138 | } 139 | 140 | private static string[] readFilterArgs(IEnumerator it) 141 | { 142 | LinkedList args = new LinkedList(); 143 | 144 | YamlNode node; 145 | while (it.MoveNext()) 146 | { 147 | node = it.Current; 148 | if (!(node is YamlScalarNode)) 149 | { 150 | throw new InvalidConfigurationException("Filter args may only be strings!"); 151 | } 152 | args.AddLast(((YamlScalarNode)node).Value); 153 | } 154 | 155 | string[] argArray = new string[args.Count]; 156 | if (argArray.Length == 0) 157 | { 158 | return argArray; 159 | } 160 | 161 | args.CopyTo(argArray, 0); 162 | return argArray; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /LyricsReloaded/Validation/ValidationCollection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | using YamlDotNet.RepresentationModel; 25 | 26 | namespace CubeIsland.LyricsReloaded.Validation 27 | { 28 | public class ValidationCollection 29 | { 30 | private static class Node 31 | { 32 | public static readonly YamlScalarNode NAME = new YamlScalarNode("name"); 33 | public static readonly YamlScalarNode ARGS = new YamlScalarNode("args"); 34 | } 35 | 36 | private readonly LinkedList validations; 37 | 38 | public ValidationCollection() 39 | { 40 | this.validations = new LinkedList(); 41 | } 42 | 43 | public void Add(Validation validation) 44 | { 45 | this.validations.AddLast(validation); 46 | } 47 | 48 | public void Add(Validator validator, bool inverted, string[] args) 49 | { 50 | this.Add(new Validation(validator, inverted, args)); 51 | } 52 | 53 | public int getSize() 54 | { 55 | return this.validations.Count; 56 | } 57 | 58 | public bool executeValidations(string content) 59 | { 60 | foreach (Validation validation in this.validations) 61 | { 62 | if (!validation.execute(content)) 63 | { 64 | return false; 65 | } 66 | } 67 | return true; 68 | } 69 | 70 | public static ValidationCollection parseList(YamlSequenceNode list, Dictionary validatorMap) 71 | { 72 | ValidationCollection collection = new ValidationCollection(); 73 | 74 | if (list != null) 75 | { 76 | foreach (YamlNode node in list.Children) 77 | { 78 | parseFilterNode(collection, validatorMap, node); 79 | } 80 | } 81 | 82 | return collection; 83 | } 84 | private static void parseFilterNode(ValidationCollection filterCollection, Dictionary validatorMap, YamlNode node) 85 | { 86 | string name; 87 | string[] args; 88 | if (node is YamlScalarNode) 89 | { 90 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 91 | args = new string[0]; 92 | } 93 | else if (node is YamlSequenceNode) 94 | { 95 | IEnumerator it = ((YamlSequenceNode)node).Children.GetEnumerator(); 96 | if (!it.MoveNext()) 97 | { 98 | throw new InvalidConfigurationException("An empty list as a filter is not valid!"); 99 | } 100 | node = it.Current; 101 | if (!(node is YamlScalarNode)) 102 | { 103 | throw new InvalidConfigurationException("Filter definitions as a list my only contain strings!"); 104 | } 105 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 106 | args = readFilterArgs(it); 107 | } 108 | else if (node is YamlMappingNode) 109 | { 110 | YamlMappingNode filterConfig = (YamlMappingNode)node; 111 | IDictionary childNodes = filterConfig.Children; 112 | node = (childNodes.ContainsKey(Node.NAME) ? childNodes[Node.NAME] : null); 113 | if (!(node is YamlScalarNode)) 114 | { 115 | throw new InvalidConfigurationException("The filter name is missing or invalid!"); 116 | } 117 | name = ((YamlScalarNode)node).Value.Trim().ToLower(); 118 | 119 | node = (childNodes.ContainsKey(Node.ARGS) ? childNodes[Node.ARGS] : null); 120 | if (node is YamlSequenceNode) 121 | { 122 | args = readFilterArgs(((YamlSequenceNode)node).Children.GetEnumerator()); 123 | } 124 | else 125 | { 126 | args = new string[0]; 127 | } 128 | } 129 | else 130 | { 131 | throw new InvalidConfigurationException("Invalid validator configuration"); 132 | } 133 | 134 | bool inverted = false; 135 | int spaceIndex = name.IndexOf(" ", System.StringComparison.Ordinal); 136 | if (spaceIndex == 3 && name.Substring(0, 3).Equals("not", StringComparison.OrdinalIgnoreCase)) 137 | { 138 | inverted = true; 139 | name = name.Substring(4).Trim(); 140 | } 141 | 142 | if (!validatorMap.ContainsKey(name)) 143 | { 144 | throw new InvalidConfigurationException("Unknown validator " + name); 145 | } 146 | 147 | 148 | filterCollection.Add(validatorMap[name], inverted, args); 149 | } 150 | 151 | private static string[] readFilterArgs(IEnumerator it) 152 | { 153 | LinkedList args = new LinkedList(); 154 | 155 | YamlNode node; 156 | while (it.MoveNext()) 157 | { 158 | node = it.Current; 159 | if (!(node is YamlScalarNode)) 160 | { 161 | throw new InvalidConfigurationException("Filter args may only be strings!"); 162 | } 163 | args.AddLast(((YamlScalarNode)node).Value); 164 | } 165 | 166 | string[] argArray = new string[args.Count]; 167 | if (argArray.Length == 0) 168 | { 169 | return argArray; 170 | } 171 | 172 | args.CopyTo(argArray, 0); 173 | return argArray; 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /LyricsReloaded/mb_LyricsReloaded.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {0EBB89EE-8500-4DD9-B7E9-52D5AE85DEFC} 7 | Library 8 | Properties 9 | CubeIsland.LyricsReloaded 10 | mb_LyricsReloaded 11 | v4.0 12 | 512 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\Debug\ 19 | DEBUG 20 | prompt 21 | 4 22 | 23 | 24 | pdbonly 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | false 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release 36 | prompt 37 | 4 38 | false 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ..\packages\NUnit.3.0.0\lib\net40\nunit.framework.dll 50 | 51 | 52 | 53 | ..\packages\YamlDotNet.Core.2.2.0\lib\net35\YamlDotNet.Core.dll 54 | 55 | 56 | ..\packages\YamlDotNet.RepresentationModel.2.2.0\lib\net35\YamlDotNet.RepresentationModel.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | True 66 | True 67 | Resources.resx 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | True 82 | True 83 | Settings.settings 84 | 85 | 86 | 87 | 88 | 89 | PublicResXFileCodeGenerator 90 | Designer 91 | Resources.Designer.cs 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | SettingsSingleFileGenerator 107 | Settings.Designer.cs 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | if "$(ConfigurationName)"=="Release" ( 122 | if not exist "$(TargetDir)merged" mkdir "$(TargetDir)merged" 123 | 124 | "$(SolutionDir)packages\ilmerge.2.13.0307\ILMerge.exe" "/out:$(TargetDir)merged\$(TargetFileName)" "$(TargetPath)" "$(TargetDir)YamlDotNet.Core.dll" "$(TargetDir)YamlDotNet.RepresentationModel.dll" 125 | ) 126 | 127 | 134 | 135 | 136 | 137 | %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) 138 | 139 | 140 | %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /LyricsReloaded/Plugin.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using CubeIsland.LyricsReloaded; 22 | using CubeIsland.LyricsReloaded.Provider; 23 | using System; 24 | using System.Drawing; 25 | using System.Collections.Generic; 26 | using System.Net; 27 | using System.Windows.Forms; 28 | 29 | namespace MusicBeePlugin 30 | { 31 | public partial class Plugin 32 | { 33 | private MusicBeeApiInterface musicBee; 34 | private PluginInfo info = new PluginInfo(); 35 | private LyricsReloaded lyricsReloaded; 36 | 37 | // Called from MusicBee 38 | public PluginInfo Initialise(IntPtr apiPtr) 39 | { 40 | //MessageBox.Show("Initialised(" + apiPtr + ")"); 41 | musicBee = new MusicBeeApiInterface(); 42 | musicBee.Initialise(apiPtr); 43 | 44 | info.PluginInfoVersion = PluginInfoVersion; 45 | info.Name = "Lyrics Reloaded"; 46 | info.Description = "Enhanced Lyrics Retrieval for MusicBee"; 47 | info.Author = "Created by Phillip Schichtel , Maintained by Frank"; 48 | info.TargetApplication = "MusicBee"; 49 | info.Type = PluginType.LyricsRetrieval; 50 | info.VersionMajor = 1; 51 | info.VersionMinor = 1; 52 | info.Revision = 11; 53 | info.MinInterfaceVersion = 20; 54 | info.MinApiRevision = 25; 55 | info.ReceiveNotifications = ReceiveNotificationFlags.StartupOnly; 56 | info.ConfigurationPanelHeight = 20; 57 | 58 | try 59 | { 60 | lyricsReloaded = new LyricsReloaded(musicBee.Setting_GetPersistentStoragePath()); 61 | } 62 | catch (Exception e) 63 | { 64 | MessageBox.Show("An error occurred during plugin startup: " + e.Message); 65 | throw; 66 | } 67 | 68 | try 69 | { 70 | lyricsReloaded.loadConfigurations(); 71 | } 72 | catch (Exception e) 73 | { 74 | MessageBox.Show("An error occurred during plugin startup, send this file to the developer:\n\n" + 75 | lyricsReloaded.getLogger().getFileInfo().FullName); 76 | lyricsReloaded.getLogger().error(e.Message); 77 | throw; 78 | } 79 | 80 | return info; 81 | } 82 | 83 | public void ReceiveNotification(String source, NotificationType type) 84 | { 85 | //MessageBox.Show("ReceiveNotification(" + source + ", " + type + ")"); 86 | lyricsReloaded.getLogger().debug("Received a notification of type {0}", type); 87 | switch (type) 88 | { 89 | case NotificationType.PluginStartup: 90 | String proxySetting = musicBee.Setting_GetWebProxy(); 91 | if (!string.IsNullOrEmpty(proxySetting)) 92 | { 93 | lyricsReloaded.getLogger().debug("Proxy setting found"); 94 | string[] raw = proxySetting.Split(Convert.ToChar(0)); 95 | WebProxy proxy = new WebProxy(raw[0]); 96 | if (raw.Length >= 3) 97 | { 98 | lyricsReloaded.getLogger().debug("Proxy credentials found"); 99 | proxy.Credentials = new NetworkCredential(raw[1], raw[2]); 100 | } 101 | lyricsReloaded.setProxy(proxy); 102 | } 103 | 104 | lyricsReloaded.checkForNewVersion(newAvailable => { 105 | if (newAvailable) 106 | { 107 | MessageBox.Show("A new version is available!", "LyricsReloaded!"); 108 | } 109 | }); 110 | 111 | break; 112 | } 113 | } 114 | 115 | public void Close(PluginCloseReason reason) 116 | { 117 | //MessageBox.Show("Close(" + reason + ")"); 118 | lyricsReloaded.getLogger().info("Plugin disabled"); 119 | lyricsReloaded.shutdown(); 120 | lyricsReloaded = null; 121 | } 122 | 123 | public String[] GetProviders() 124 | { 125 | IList providers = lyricsReloaded.getProviderManager().getProviders(); 126 | string[] providerNames = new string[providers.Count]; 127 | 128 | int i = 0; 129 | foreach (Provider provider in providers) 130 | { 131 | providerNames[i++] = provider.getName(); 132 | } 133 | 134 | return providerNames; 135 | } 136 | 137 | public String RetrieveLyrics(String source, String artist, String title, String album, bool preferSynced, String providerName) 138 | { 139 | lyricsReloaded.getLogger().debug("Lyrics request: {0} - {1} - {2} - {3}", artist, title, album, providerName); 140 | Provider provider = lyricsReloaded.getProviderManager().getProvider(providerName); 141 | if (provider == null) 142 | { 143 | lyricsReloaded.getLogger().warn("The provider {0} was not found!", providerName); 144 | return null; 145 | } 146 | 147 | String lyrics = provider.getLyrics(artist, title, album); 148 | 149 | if (String.IsNullOrWhiteSpace(lyrics)) 150 | { 151 | lyricsReloaded.getLogger().debug("no lyrics found from {0}", providerName); 152 | return null; 153 | } 154 | 155 | lyricsReloaded.getLogger().debug("lyrics found from {0}!", providerName); 156 | 157 | return lyrics; 158 | } 159 | 160 | public void Uninstall() 161 | { 162 | lyricsReloaded.uninstall(); 163 | } 164 | 165 | public bool Configure(IntPtr panelHandle) 166 | { 167 | // save any persistent settings in a sub-folder of this path 168 | string dataPath = musicBee.Setting_GetPersistentStoragePath(); 169 | // panelHandle will only be set if you set about.ConfigurationPanelHeight to a non-zero value 170 | // keep in mind the panel width is scaled according to the font the user has selected 171 | // if about.ConfigurationPanelHeight is set to 0, you can display your own popup window 172 | if (panelHandle != IntPtr.Zero) 173 | { 174 | Panel configPanel = (Panel)Panel.FromHandle(panelHandle); 175 | Label prompt = new Label(); 176 | prompt.AutoSize = true; 177 | prompt.Location = new Point(0, 0); 178 | prompt.Text = "Manage providers at Edit->Edit Preferences->Tags(2)->auto-tagging->lyrics:"; 179 | configPanel.Controls.AddRange(new Control[] {prompt}); 180 | } 181 | 182 | 183 | return false; 184 | } 185 | 186 | // called by MusicBee when the user clicks Apply or Save in the MusicBee Preferences screen. 187 | // its up to you to figure out whether anything has changed and needs updating 188 | public void SaveSettings() 189 | { 190 | // save any persistent settings in a sub-folder of this path 191 | string dataPath = musicBee.Setting_GetPersistentStoragePath(); 192 | } 193 | 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /LyricsReloaded/LyricsReloaded.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Threading; 23 | using CubeIsland.LyricsReloaded.Provider; 24 | using CubeIsland.LyricsReloaded.Provider.Loader; 25 | using System.IO; 26 | using System.Net; 27 | using System.Reflection; 28 | using System.Text.RegularExpressions; 29 | 30 | namespace CubeIsland.LyricsReloaded 31 | { 32 | public class LyricsReloaded 33 | { 34 | public static class FolderNames 35 | { 36 | public const string PROVIDERS = "providers"; 37 | public const string DATA = "data"; 38 | } 39 | 40 | private readonly string name; 41 | private readonly string dataFolder; 42 | private readonly Logger logger; 43 | private readonly ProviderManager providerManager; 44 | private string defaultUserAgent; 45 | private WebProxy proxy; 46 | private bool down = false; 47 | 48 | public LyricsReloaded(string configurationPath) 49 | { 50 | Assembly asm = Assembly.GetAssembly(GetType()); 51 | name = asm.GetName().Name; 52 | dataFolder = Path.Combine(configurationPath, name); 53 | Directory.CreateDirectory(dataFolder); 54 | logger = new Logger(Path.Combine(dataFolder, name + ".log")); 55 | 56 | logger.info("{0} in version {1} started!", name, asm.GetName().Version.ToString()); 57 | 58 | providerManager = new ProviderManager(this); 59 | 60 | providerManager.registerLoaderFactory(new StaticLoaderFactory(this)); 61 | 62 | defaultUserAgent = "Firefox"; 63 | proxy = null; 64 | } 65 | 66 | ~LyricsReloaded() 67 | { 68 | shutdown(); 69 | } 70 | 71 | public Logger getLogger() 72 | { 73 | return logger; 74 | } 75 | 76 | public ProviderManager getProviderManager() 77 | { 78 | return providerManager; 79 | } 80 | 81 | public void setDefaultUserAgent(string userAgent) 82 | { 83 | defaultUserAgent = userAgent; 84 | } 85 | 86 | public string getDefaultUserAgent() 87 | { 88 | return defaultUserAgent; 89 | } 90 | 91 | public void setProxy(WebProxy newProxy) 92 | { 93 | proxy = newProxy; 94 | } 95 | 96 | public WebProxy getProxy() 97 | { 98 | return proxy; 99 | } 100 | 101 | public void shutdown() 102 | { 103 | if (!down) 104 | { 105 | down = true; 106 | providerManager.shutdown(); 107 | logger.close(); 108 | } 109 | } 110 | 111 | public void uninstall() 112 | { 113 | DirectoryInfo di = new DirectoryInfo(Path.Combine(dataFolder, FolderNames.PROVIDERS)); 114 | 115 | if (di.GetFiles("*.yml").Length <= 0) 116 | { 117 | try 118 | { 119 | logger.debug("Removing the providers folder..."); 120 | di.Delete(true); 121 | } 122 | catch (Exception e) 123 | { 124 | logger.warn("Failed to remove provider folder: {0}", e.Message); 125 | } 126 | } 127 | 128 | try 129 | { 130 | logger.debug("Removing the data folder..."); 131 | (new DirectoryInfo(Path.Combine(dataFolder, FolderNames.DATA))).Delete(true); 132 | } 133 | catch (Exception e) 134 | { 135 | logger.warn("Failed to remove provider folder: {0}", e.Message); 136 | } 137 | } 138 | 139 | public delegate void UpdateCheckerCallback(bool updateAvailable); 140 | 141 | public void checkForNewVersion(UpdateCheckerCallback callback) 142 | { 143 | Version local = Assembly.GetAssembly(GetType()).GetName().Version; 144 | 145 | LyricsReloaded lr = this; 146 | 147 | Thread updateChecker = new Thread(() => { 148 | WebClient cl = new WebClient(lr, 5000); 149 | try 150 | { 151 | bool result = false; 152 | WebResponse respone = cl.get("https://raw.githubusercontent.com/mbfrankz/LyricsReloaded/stable/LyricsReloaded/Properties/AssemblyInfo.cs"); 153 | if (respone != null) 154 | { 155 | String content = respone.getContent(); 156 | if (!String.IsNullOrWhiteSpace(content)) 157 | { 158 | Regex versionRegex = new Regex("AssemblyVersion\\(\"(?[^\\s\\*]+)\"\\)", RegexOptions.Compiled | RegexOptions.Singleline); 159 | Match match = versionRegex.Match(content); 160 | if (match.Success) 161 | { 162 | Version remote = Version.Parse(match.Groups["version"].Value); 163 | result = remote.CompareTo(local) > 0; 164 | } 165 | } 166 | 167 | } 168 | 169 | callback(result); 170 | } 171 | catch (Exception e) 172 | { 173 | lr.logger.error("Failed to check for updates: {0}", e.Message); 174 | } 175 | }) { 176 | IsBackground = true, 177 | Name = "LyricsReloaded - Version Check" 178 | }; 179 | updateChecker.Start(); 180 | 181 | } 182 | 183 | #region "internal helpers" 184 | 185 | public void loadConfigurations() 186 | { 187 | loadDefaultConfiguration(); 188 | 189 | DirectoryInfo di = new DirectoryInfo(Path.Combine(dataFolder, FolderNames.PROVIDERS)); 190 | if (!di.Exists) 191 | { 192 | try 193 | { 194 | di.Create(); 195 | } 196 | catch (IOException e) 197 | { 198 | logger.warn("Failed to create the providers folder: {0}", e.Message); 199 | } 200 | } 201 | 202 | foreach (FileInfo fi in di.GetFiles("*.yml", SearchOption.TopDirectoryOnly)) 203 | { 204 | try 205 | { 206 | providerManager.loadProvider(fi); 207 | } 208 | catch (InvalidConfigurationException e) 209 | { 210 | logger.error("Failed to load a configuration:"); 211 | logger.error(e.Message); 212 | if (e.InnerException != null) 213 | { 214 | logger.error(e.InnerException.ToString()); 215 | } 216 | } 217 | } 218 | } 219 | 220 | private void loadDefaultConfiguration() 221 | { 222 | foreach (PropertyInfo propInfo in typeof (Properties.Resources).GetProperties(BindingFlags.Public | BindingFlags.Static)) 223 | { 224 | if (!propInfo.Name.StartsWith("provider_", StringComparison.OrdinalIgnoreCase)) 225 | { 226 | continue; 227 | } 228 | object value = propInfo.GetValue(null, null); 229 | if (value is String) 230 | { 231 | logger.debug("Loading config from field {0}", propInfo.Name); 232 | providerManager.loadProvider(value as String); 233 | } 234 | } 235 | } 236 | 237 | #endregion 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /LyricsReloaded/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 | 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 | 122 | ..\Configs\azlyrics.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 123 | 124 | 125 | ..\configs\cuspajz.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 126 | 127 | 128 | ..\Configs\genius.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 129 | 130 | 131 | ..\configs\www.hindilyrics.net.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 132 | 133 | 134 | ..\configs\letras.mus.br.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 135 | 136 | 137 | ..\configs\metrolyrics.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 138 | 139 | 140 | ..\Configs\musixmatch.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 141 | 142 | 143 | ..\Configs\musixmatch.com-asian.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 144 | 145 | 146 | ..\configs\oldielyrics.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 147 | 148 | 149 | ..\configs\smriti.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 150 | 151 | 152 | ..\configs\songlyrics.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 153 | 154 | 155 | ..\configs\teksty.org.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 156 | 157 | 158 | ..\configs\urbanlyrics.com.yml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 159 | 160 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/Loader/StaticLoader.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Text.RegularExpressions; 24 | using System.Net; 25 | using YamlDotNet.RepresentationModel; 26 | 27 | namespace CubeIsland.LyricsReloaded.Provider.Loader 28 | { 29 | public class StaticLoader : LyricsLoader 30 | { 31 | private readonly LyricsReloaded lyricsReloaded; 32 | private readonly string urlTemplate; 33 | private readonly Pattern pattern; 34 | private readonly WebClient client; 35 | 36 | public StaticLoader(LyricsReloaded lyricsReloaded, WebClient client, string urlTemplate, Pattern pattern) 37 | { 38 | this.lyricsReloaded = lyricsReloaded; 39 | this.urlTemplate = urlTemplate; 40 | this.pattern = pattern; 41 | this.client = client; 42 | } 43 | 44 | private string constructUrl(Dictionary variables) 45 | { 46 | string url = urlTemplate; 47 | 48 | foreach (KeyValuePair entry in variables) 49 | { 50 | url = url.Replace("{" + entry.Key + "}", entry.Value); 51 | } 52 | 53 | return url; 54 | } 55 | 56 | public Lyrics getLyrics(Provider provider, Dictionary variables) 57 | { 58 | string url = constructUrl(variables); 59 | 60 | lyricsReloaded.getLogger().debug("The constructed URL: {0}", url); 61 | 62 | try 63 | { 64 | WebResponse response = client.get(url, provider.getHeaders()); 65 | String lyrics = pattern.apply(response.getContent()); 66 | if (lyrics == null) 67 | { 68 | lyricsReloaded.getLogger().warn("The pattern {0} didn't match!", pattern); 69 | return null; 70 | } 71 | 72 | return new Lyrics(lyrics, response.getEncoding()); 73 | } 74 | catch (WebException e) 75 | { 76 | if (isStatus(e, HttpStatusCode.NotFound)) 77 | { 78 | return null; 79 | } 80 | throw; 81 | } 82 | } 83 | 84 | private static bool isStatus(WebException e, HttpStatusCode code) 85 | { 86 | System.Net.WebResponse r = e.Response; 87 | if (r == null) 88 | { 89 | if (e.InnerException != null && e.InnerException is WebException) 90 | { 91 | return isStatus(e.InnerException as WebException, code); 92 | } 93 | } 94 | else if (r is HttpWebResponse && ((HttpWebResponse)r).StatusCode == code) 95 | { 96 | return true; 97 | } 98 | return false; 99 | } 100 | } 101 | 102 | public class StaticLoaderFactory : LyricsLoaderFactory 103 | { 104 | private static class Node 105 | { 106 | public static readonly YamlScalarNode URL = new YamlScalarNode("url"); 107 | public static readonly YamlScalarNode PATTERN = new YamlScalarNode("pattern"); 108 | } 109 | 110 | private readonly LyricsReloaded lyricsReloaded; 111 | private readonly WebClient webClient; 112 | 113 | public StaticLoaderFactory(LyricsReloaded lyricsReloaded) 114 | { 115 | this.lyricsReloaded = lyricsReloaded; 116 | webClient = new WebClient(lyricsReloaded, 5000); 117 | } 118 | 119 | public string getName() 120 | { 121 | return "static"; 122 | } 123 | 124 | public LyricsLoader newLoader(YamlMappingNode configuration) 125 | { 126 | YamlNode node; 127 | IDictionary configNodes = configuration.Children; 128 | 129 | string url; 130 | node = (configNodes.ContainsKey(Node.URL) ? configNodes[Node.URL] : null); 131 | if (node is YamlScalarNode) 132 | { 133 | url = ((YamlScalarNode)node).Value; 134 | } 135 | else 136 | { 137 | throw new InvalidConfigurationException("No URL specified!"); 138 | } 139 | 140 | if (!configNodes.ContainsKey(Node.PATTERN)) 141 | { 142 | throw new InvalidConfigurationException("No pattern specified!"); 143 | } 144 | 145 | return new StaticLoader(lyricsReloaded, webClient, url, Pattern.fromYamlNode(configNodes[Node.PATTERN])); 146 | } 147 | } 148 | 149 | public class Pattern 150 | { 151 | private static class Node 152 | { 153 | public static readonly YamlScalarNode REGEX = new YamlScalarNode("regex"); 154 | public static readonly YamlScalarNode OPTIONS = new YamlScalarNode("options"); 155 | } 156 | 157 | private const RegexOptions DEFAULT_OPTIONS = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant; 158 | 159 | private readonly Regex regex; 160 | 161 | public Pattern(Regex regex) 162 | { 163 | this.regex = regex; 164 | } 165 | 166 | public Pattern(string regex, string options) 167 | : this(new Regex(regex, DEFAULT_OPTIONS | regexOptionsFromString(options))) 168 | { } 169 | 170 | public String apply(string content) 171 | { 172 | Match match = regex.Match(content); 173 | if (match.Success) 174 | { 175 | return match.Groups["lyrics"].ToString(); 176 | } 177 | return null; 178 | } 179 | 180 | public static Pattern fromYamlNode(YamlNode node) 181 | { 182 | if (node == null) 183 | { 184 | return null; 185 | } 186 | return new Pattern(regexFromYamlNode(node, DEFAULT_OPTIONS)); 187 | } 188 | 189 | public static Regex regexFromYamlNode(YamlNode node, RegexOptions options) 190 | { 191 | string regex; 192 | string regexOptions = ""; 193 | if (node is YamlScalarNode) 194 | { 195 | regex = ((YamlScalarNode)node).Value; 196 | } 197 | else if (node is YamlSequenceNode) 198 | { 199 | IEnumerator it = ((YamlSequenceNode)node).Children.GetEnumerator(); 200 | if (!it.MoveNext()) 201 | { 202 | throw new InvalidConfigurationException("The pattern needs at least the regex defined!"); 203 | } 204 | if (!(it.Current is YamlScalarNode)) 205 | { 206 | throw new InvalidConfigurationException("The pattern may only contain string value!"); 207 | } 208 | regex = ((YamlScalarNode)it.Current).Value; 209 | 210 | if (it.MoveNext() && it.Current is YamlScalarNode) 211 | { 212 | regexOptions = ((YamlScalarNode)it.Current).Value; 213 | } 214 | } 215 | else if (node is YamlMappingNode) 216 | { 217 | IDictionary patternConfig = ((YamlMappingNode)node).Children; 218 | node = (patternConfig.ContainsKey(Node.REGEX) ? patternConfig[Node.REGEX] : null); 219 | if (!(node is YamlScalarNode)) 220 | { 221 | throw new InvalidConfigurationException("Invalid regex value!"); 222 | } 223 | regex = ((YamlScalarNode)node).Value; 224 | 225 | node = (patternConfig.ContainsKey(Node.OPTIONS) ? patternConfig[Node.OPTIONS] : null); 226 | if (node is YamlScalarNode) 227 | { 228 | regexOptions = ((YamlScalarNode)node).Value; 229 | } 230 | } 231 | else 232 | { 233 | throw new InvalidConfigurationException("No pattern specified!"); 234 | } 235 | 236 | return new Regex(regex, options | regexOptionsFromString(regexOptions)); 237 | } 238 | 239 | private static readonly Dictionary REGEX_OPTION_MAP = new Dictionary { 240 | {'i', RegexOptions.IgnoreCase}, 241 | {'s', RegexOptions.Singleline}, 242 | {'m', RegexOptions.Multiline}, 243 | {'c', RegexOptions.Compiled}, 244 | {'x', RegexOptions.IgnorePatternWhitespace}, 245 | {'d', RegexOptions.RightToLeft}, 246 | {'e', RegexOptions.ExplicitCapture}, 247 | {'j', RegexOptions.ECMAScript}, 248 | {'l', RegexOptions.CultureInvariant} 249 | }; 250 | 251 | public static RegexOptions regexOptionsFromString(string optionString) 252 | { 253 | RegexOptions options = RegexOptions.None; 254 | 255 | char lc; 256 | foreach (char c in optionString) 257 | { 258 | lc = Char.ToLower(c); 259 | if (REGEX_OPTION_MAP.ContainsKey(lc)) 260 | { 261 | RegexOptions option = REGEX_OPTION_MAP[lc]; 262 | if (Char.IsLower(c)) 263 | { 264 | options |= option; 265 | } 266 | else 267 | { 268 | options &= ~option; 269 | } 270 | } 271 | } 272 | 273 | return options; 274 | } 275 | 276 | public override string ToString() 277 | { 278 | return regex.ToString(); 279 | } 280 | } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /LyricsReloaded/WebClient.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Text; 24 | using System.Text.RegularExpressions; 25 | using System.Web; 26 | using System.Net; 27 | using System.IO; 28 | using System.IO.Compression; 29 | using System.Reflection; 30 | 31 | namespace CubeIsland.LyricsReloaded 32 | { 33 | public class WebClient 34 | { 35 | private static readonly Regex ENCODING_REGEX = new Regex("]*>|<\\?xml.+?encoding=\"([^\"]).*?\\?>", RegexOptions.Compiled | RegexOptions.IgnoreCase); 36 | 37 | private readonly LyricsReloaded lyricsReloaded; 38 | private readonly int timeout; 39 | 40 | public WebClient(LyricsReloaded lyricsReloaded, int timeout) 41 | { 42 | this.lyricsReloaded = lyricsReloaded; 43 | this.timeout = timeout; 44 | } 45 | 46 | protected HttpWebRequest newRequest(string method, string url, IDictionary headers) 47 | { 48 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 49 | request.Method = method; 50 | request.Timeout = timeout; 51 | request.Proxy = lyricsReloaded.getProxy(); 52 | if (headers != null) 53 | { 54 | foreach (KeyValuePair header in headers) 55 | { 56 | this.setHeader(request, header.Key, header.Value); 57 | } 58 | } 59 | 60 | return request; 61 | } 62 | 63 | protected String headerToProperty(String header) 64 | { 65 | StringBuilder property = new StringBuilder(); 66 | 67 | bool nextUpper = true; 68 | foreach (char c in header) 69 | { 70 | if (c == '-') 71 | { 72 | nextUpper = true; 73 | continue; 74 | } 75 | if (nextUpper) 76 | { 77 | property.Append(Char.ToUpper(c)); 78 | nextUpper = false; 79 | } 80 | else 81 | { 82 | property.Append(Char.ToLower(c)); 83 | } 84 | } 85 | 86 | return property.ToString(); 87 | } 88 | 89 | protected void setHeader(HttpWebRequest request, String name, String value) 90 | { 91 | name = name.ToLower(); 92 | String prop = headerToProperty(name); 93 | PropertyInfo propInfo = request.GetType().GetProperty(prop); 94 | 95 | if (propInfo.CanWrite) 96 | { 97 | if (propInfo.PropertyType == typeof(String)) 98 | { 99 | propInfo.SetValue(request, value, null); 100 | return; 101 | } 102 | else if (propInfo.PropertyType == typeof(DateTime)) 103 | { 104 | propInfo.SetValue(request, DateTime.Parse(value), null); 105 | return; 106 | } 107 | } 108 | 109 | if (name.Equals("range")) 110 | { 111 | // request.AddRange() 112 | // break; 113 | return; 114 | } 115 | 116 | request.Headers.Set(name, value); 117 | } 118 | 119 | public int getTimeout() 120 | { 121 | return timeout; 122 | } 123 | 124 | public WebResponse get(string url, IDictionary headers = null) 125 | { 126 | return executeRequest(newRequest("GET", url, headers)); 127 | } 128 | 129 | public WebResponse post(string url, Dictionary data, IDictionary headers = null) 130 | { 131 | HttpWebRequest request = newRequest("POST", url, headers); 132 | 133 | request.ContentType = "application/x-www-form-urlencoded"; 134 | request.ContentLength = 0; 135 | 136 | if (data != null) 137 | { 138 | Stream stream; 139 | try 140 | { 141 | stream = request.GetRequestStream(); 142 | } 143 | catch (WebException e) 144 | { 145 | if (e.Status == WebExceptionStatus.Timeout) 146 | { 147 | throw new WebException("The operation has timed out."); 148 | } 149 | throw; 150 | } 151 | using (stream) 152 | { 153 | stream.WriteTimeout = timeout; 154 | string queryString = generateQueryString(data); 155 | byte[] byteData = new byte[Encoding.UTF8.GetByteCount(queryString)]; 156 | Encoding.UTF8.GetBytes(queryString, 0, queryString.Length, byteData, 0); 157 | stream.Write(byteData, 0, byteData.Length); 158 | request.ContentLength += byteData.Length; 159 | } 160 | } 161 | 162 | return executeRequest(request); 163 | } 164 | 165 | public static string generateQueryString(IEnumerable> data) 166 | { 167 | StringBuilder queryString = new StringBuilder(""); 168 | IEnumerator> it = data.GetEnumerator(); 169 | 170 | if (it.MoveNext()) 171 | { 172 | queryString.Append(HttpUtility.UrlEncode(it.Current.Key, Encoding.UTF8)) 173 | .Append('=') 174 | .Append(HttpUtility.UrlEncode(it.Current.Value, Encoding.UTF8)); 175 | 176 | while (it.MoveNext()) 177 | { 178 | queryString.Append('&').Append(HttpUtility.UrlEncode(it.Current.Key, Encoding.UTF8)) 179 | .Append('=').Append(HttpUtility.UrlEncode(it.Current.Value, Encoding.UTF8)); 180 | } 181 | } 182 | 183 | 184 | return queryString.ToString(); 185 | } 186 | 187 | protected WebResponse executeRequest(HttpWebRequest request) 188 | { 189 | // request configration 190 | string[] acceptEncodingValues = request.Headers.GetValues("Accept-Encoding"); 191 | if (acceptEncodingValues == null || acceptEncodingValues.Length == 0) 192 | { 193 | // we support gzip if nothing else was specified. 194 | request.Headers.Add("Accept-Encoding", "gzip"); 195 | } 196 | if (request.UserAgent == null) 197 | { 198 | request.UserAgent = lyricsReloaded.getDefaultUserAgent(); 199 | } 200 | 201 | request.Accept = "*/*"; 202 | request.Headers.Add("Accept-Encoding", "gzip"); 203 | 204 | // load the response 205 | WebResponse webResponse; 206 | String contentString = null; 207 | Encoding encoding = Encoding.ASCII; // default encoding as the last fallback 208 | HttpWebResponse response; 209 | try 210 | { 211 | response = (HttpWebResponse) request.GetResponse(); 212 | } 213 | catch (WebException e) 214 | { 215 | if (e.Status == WebExceptionStatus.Timeout) 216 | { 217 | throw new WebException("The operation has timed out.", e); 218 | } 219 | else if (e.Status == WebExceptionStatus.ProtocolError || e.Status == WebExceptionStatus.UnknownError) 220 | { 221 | throw new WebException("Ops, something went wrong. (Report this please)", e); 222 | } 223 | throw; 224 | } 225 | using (response) 226 | { 227 | if (response.CharacterSet != null) 228 | { 229 | encoding = Encoding.GetEncoding(response.CharacterSet); // the response encoding specified by the server. this should be enough 230 | } 231 | 232 | Stream responsesStream = response.GetResponseStream(); 233 | if (responsesStream != null) 234 | { 235 | responsesStream.ReadTimeout = timeout; 236 | if (String.Compare(response.ContentEncoding, "gzip", StringComparison.OrdinalIgnoreCase) == 0) 237 | { 238 | // gzip compression detected, wrap the stream with a decompressing gzip stream 239 | lyricsReloaded.getLogger().debug("gzip compression detected"); 240 | responsesStream = new GZipStream(responsesStream, CompressionMode.Decompress); 241 | } 242 | MemoryStream content = new MemoryStream(); 243 | const int bufferSize = 4096; 244 | byte[] buffer = new byte[bufferSize]; 245 | int bytesRead; 246 | 247 | do 248 | { 249 | bytesRead = responsesStream.Read(buffer, 0, bufferSize); 250 | if (bytesRead <= 0) 251 | { 252 | break; 253 | } 254 | content.Write(buffer, 0, bytesRead); 255 | } 256 | while (bytesRead > 0); 257 | responsesStream.Close(); 258 | 259 | contentString = encoding.GetString(content.GetBuffer()); // decode the data with the currently known encoding 260 | Match match = ENCODING_REGEX.Match(contentString); // search for a encoding specified in the content 261 | if (match.Success) 262 | { 263 | try 264 | { 265 | Encoding tmp = Encoding.GetEncoding(match.Groups[1].ToString()); // try to get a encoding from the name 266 | if (!encoding.Equals(tmp)) 267 | { 268 | encoding = tmp; 269 | contentString = encoding.GetString(content.GetBuffer()); // decode again with the newly found encoding 270 | } 271 | } 272 | catch (ArgumentException) 273 | {} 274 | } 275 | content.Close(); 276 | } 277 | webResponse = new WebResponse(contentString, encoding, response.Headers); 278 | } 279 | 280 | return webResponse; 281 | } 282 | } 283 | 284 | public class WebResponse 285 | { 286 | private readonly string content; 287 | private readonly Encoding encoding; 288 | private readonly WebHeaderCollection headers; 289 | 290 | public WebResponse(string content, Encoding encoding, WebHeaderCollection headers) 291 | { 292 | this.content = content; 293 | this.encoding = encoding; 294 | this.headers = headers; 295 | } 296 | 297 | public string getContent() 298 | { 299 | return content; 300 | } 301 | 302 | public Encoding getEncoding() 303 | { 304 | return encoding; 305 | } 306 | 307 | public WebHeaderCollection getHeaders() 308 | { 309 | return headers; 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /LyricsReloaded/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 CubeIsland.LyricsReloaded.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", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public 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 | public 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("CubeIsland.LyricsReloaded.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 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to name: A-Z Lyrics Universe 65 | /// 66 | ///variables: 67 | /// artist: 68 | /// type: artist 69 | /// filters: 70 | /// - lowercase 71 | /// - strip_nonascii 72 | /// title: 73 | /// type: title 74 | /// filters: artist 75 | /// 76 | ///headers: 77 | /// User-Agent: 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0' # Firefox 30 Win x64 user agent 78 | /// 79 | ///config: 80 | /// url: "http://www.azlyrics.com/lyrics/{artist}/{title}.html" 81 | /// pattern: ['<!-- Usage of azlyrics.com content by any third-party lyrics provider is prohibited by [rest of string was truncated]";. 82 | /// 83 | public static string provider_azlyrics_com { 84 | get { 85 | return ResourceManager.GetString("provider_azlyrics_com", resourceCulture); 86 | } 87 | } 88 | 89 | /// 90 | /// Looks up a localized string similar to name: "Cušpajz" 91 | /// 92 | ///variables: 93 | /// artist: 94 | /// type: artist 95 | /// filters: 96 | /// - strip_diacritics 97 | /// - lowercase 98 | /// - [strip_nonascii, -] 99 | /// title: 100 | /// type: title 101 | /// filters: artist 102 | /// 103 | ///config: 104 | /// url: "http://cuspajz.com/tekstovi-pjesama/pjesma/{artist}/{title}.html" 105 | /// pattern: ['<p\sclass="text\sclearfix">(?<lyrics>[\s\S]*?)</p>', s] 106 | /// 107 | ///post-filters: 108 | ///- strip_html 109 | ///- entity_decode. 110 | /// 111 | public static string provider_cuspajz_com { 112 | get { 113 | return ResourceManager.GetString("provider_cuspajz_com", resourceCulture); 114 | } 115 | } 116 | 117 | /// 118 | /// Looks up a localized string similar to name: Genius 119 | /// 120 | ///variables: 121 | /// artist: 122 | /// type: artist 123 | /// filters: 124 | /// - strip_diacritics 125 | /// - lowercase 126 | /// - [replace, "!!!", "chk-chik-chick"] 127 | /// - [regex, '(?<=\W|\s)+(feat.+|ft[\W\s]+|(f\.\s)).+', ""] 128 | /// - [regex, '\.+|,+|(\W+(?=$))|(^\W+)', ""] 129 | /// - [regex, "'", ""] 130 | /// - [regex, '(?<=[a-z0-9%])[^\sa-z0-9%]+(?=[a-z0-9%]+)', "-"] 131 | /// - [regex, '((?<=\s)([^a-z0-9\s-])+(\s|\W)+)|((?<=\w)([^a-z0-9-])+(\s|\W)+)', " "] 132 | /// - [strip_nonascii, -] 133 | /// [rest of string was truncated]";. 134 | /// 135 | public static string provider_genius_com { 136 | get { 137 | return ResourceManager.GetString("provider_genius_com", resourceCulture); 138 | } 139 | } 140 | 141 | /// 142 | /// Looks up a localized string similar to name: Hindi Lyrics 143 | /// 144 | ///variables: 145 | /// title: 146 | /// type: title 147 | /// filters: 148 | /// - urlencode 149 | /// 150 | ///config: 151 | /// url: "http://www.hindilyrics.net/lyrics/of-{title}.html" 152 | /// pattern: ['<font face="verdana">(?<lyrics>.*?)</font>', s] 153 | /// 154 | ///post-filters: 155 | ///- trim 156 | ///- utf8_encode. 157 | /// 158 | public static string provider_hindilyrics_net { 159 | get { 160 | return ResourceManager.GetString("provider_hindilyrics_net", resourceCulture); 161 | } 162 | } 163 | 164 | /// 165 | /// Looks up a localized string similar to name: "Letras de músicas" 166 | /// 167 | ///variables: 168 | /// artist: 169 | /// type: artist 170 | /// filters: 171 | /// - lowercase 172 | /// - [strip_nonascii, -] 173 | /// title: 174 | /// type: title 175 | /// filters: artist 176 | /// 177 | ///config: 178 | /// url: "http://letras.mus.br/{artist}/{title}/" 179 | /// pattern: ['<div id="div_letra"[^>]*>(?<lyrics>.*?)</div>', s] 180 | /// 181 | ///post-filters: 182 | ///- p2break 183 | ///- strip_html 184 | ///- clean_spaces 185 | ///- utf8_encode. 186 | /// 187 | public static string provider_letras_mus_br { 188 | get { 189 | return ResourceManager.GetString("provider_letras_mus_br", resourceCulture); 190 | } 191 | } 192 | 193 | /// 194 | /// Looks up a localized string similar to name: MetroLyrics 195 | /// 196 | ///variables: 197 | /// artist: 198 | /// type: artist 199 | /// filters: 200 | /// - strip_diacritics 201 | /// - lowercase 202 | /// - [regex, '[^\sa-z0-9]\s*', ""] 203 | /// - [strip_nonascii, -] 204 | /// title: 205 | /// type: title 206 | /// filters: artist 207 | /// 208 | ///config: 209 | /// url: "http://www.metrolyrics.com/{title}-lyrics-{artist}.html" 210 | /// pattern: ['<div id="lyrics-body">(?<lyrics>.*?)</div>', s] 211 | /// 212 | ///post-filters: 213 | ///- br2nl 214 | ///- strip_html 215 | ///- strip_links 216 | ///- entity_decode 217 | ///- clean_spaces 218 | ///- utf8_encod [rest of string was truncated]";. 219 | /// 220 | public static string provider_metrolyrics_com { 221 | get { 222 | return ResourceManager.GetString("provider_metrolyrics_com", resourceCulture); 223 | } 224 | } 225 | 226 | /// 227 | /// Looks up a localized string similar to name: Musixmatch 228 | /// 229 | ///variables: 230 | /// artist: 231 | /// type: artist 232 | /// filters: 233 | /// - strip_diacritics 234 | /// - lowercase 235 | /// - [regex, "'", ""] 236 | /// - [regex, "/", " "] 237 | /// - [regex, '\s&(?=\s)', " "] 238 | /// - [regex, '(?<=\W|\s)+(feat.+|ft[\W\s]+|(f\.\s)).+', ""] 239 | /// - [regex, '[^\sa-z0-9]\s*', ""] 240 | /// - [strip_nonascii, -] 241 | /// title: 242 | /// type: title 243 | /// filters: 244 | /// - strip_diacritics 245 | /// - lowercase 246 | /// - [regex, " '|' |/", " "] 247 | /// - [ [rest of string was truncated]";. 248 | /// 249 | public static string provider_musixmatch_com { 250 | get { 251 | return ResourceManager.GetString("provider_musixmatch_com", resourceCulture); 252 | } 253 | } 254 | 255 | /// 256 | /// Looks up a localized string similar to name: "Musixmatch_Asian" 257 | /// 258 | ///variables: 259 | /// artist: 260 | /// type: artist 261 | /// filters: 262 | /// - [regex, ",|[.]", ""] 263 | /// - [regex, "'|/| ", "-"] 264 | /// - [regex, '\s&(?=\s)', "-"] 265 | /// - [regex, '[-]+', "-"] 266 | /// title: 267 | /// type: title 268 | /// filters: 269 | /// - [regex, ",|[.]", ""] 270 | /// - [regex, " '|' ", " "] 271 | /// - [regex, " |'|/", "-"] 272 | /// - [regex, '[-]+', "-"] 273 | /// 274 | ///config: 275 | /// url: "http://www.musixmatch.com/lyrics/{artist}/{title}" 276 | /// pattern: ['<p class="mxm-ly [rest of string was truncated]";. 277 | /// 278 | public static string provider_musixmatch_com_asian { 279 | get { 280 | return ResourceManager.GetString("provider_musixmatch_com_asian", resourceCulture); 281 | } 282 | } 283 | 284 | /// 285 | /// Looks up a localized string similar to name: Oldies Lyrics 286 | /// 287 | ///variables: 288 | /// artist: 289 | /// type: artist 290 | /// filters: 291 | /// - strip_diacritics 292 | /// - lowercase 293 | /// - [regex, '[^\sa-z0-9]\s*', ""] 294 | /// - [strip_nonascii, _] 295 | /// title: 296 | /// type: title 297 | /// filters: artist 298 | /// 299 | ///config: 300 | /// url: "http://oldielyrics.com/lyrics/{artist}/{title}.html" 301 | /// pattern: ['<div\s+class="lyrics"[^>]*>\s*<p>(?<lyrics>.+)</p>\s*</div>', s] 302 | /// 303 | ///post-filters: 304 | ///- br2nl 305 | ///- p2break 306 | ///- strip_html 307 | ///- strip_links 308 | ///- entity_decode 309 | ///- clean_spaces 310 | ///- utf8_enco [rest of string was truncated]";. 311 | /// 312 | public static string provider_oldielyrics_com { 313 | get { 314 | return ResourceManager.GetString("provider_oldielyrics_com", resourceCulture); 315 | } 316 | } 317 | 318 | /// 319 | /// Looks up a localized string similar to name: Smriti 320 | /// 321 | ///variables: 322 | /// title: 323 | /// type: title 324 | /// filters: 325 | /// - lowercase 326 | /// - [regex, '[^\sa-z0-9]\s*', ""] 327 | /// - [strip_nonascii, -] 328 | /// 329 | ///config: 330 | /// url: "http://smriti.com/hindi-songs/{title}" 331 | /// pattern: ['<div class="songbody">(?<lyrics>.*?)</div>', s] 332 | /// 333 | ///post-filters: 334 | ///- strip_html 335 | ///- trim 336 | ///- utf8_encode. 337 | /// 338 | public static string provider_smriti_com { 339 | get { 340 | return ResourceManager.GetString("provider_smriti_com", resourceCulture); 341 | } 342 | } 343 | 344 | /// 345 | /// Looks up a localized string similar to name: Song Lyrics 346 | /// 347 | ///variables: 348 | /// artist: 349 | /// type: artist 350 | /// filters: 351 | /// - lowercase 352 | /// - [regex, '[^\sa-z0-9]', ""] 353 | /// - [strip_nonascii, -] 354 | /// title: 355 | /// type: title 356 | /// filters: artist 357 | /// 358 | ///config: 359 | /// url: "http://www.songlyrics.com/{artist}/{title}-lyrics/" 360 | /// pattern: ['<div id="songLyricsDiv-outer">(?<lyrics>.*?)</div>', s] 361 | /// 362 | ///post-filters: 363 | ///- strip_html 364 | ///- entity_decode 365 | ///- clean_spaces 366 | ///- utf8_encode 367 | ///- [fix_broken_chars, 'Ã', ISO-8859-1] 368 | ///- [replace, 'þ', 'ß']. 369 | /// 370 | public static string provider_songlyrics_com { 371 | get { 372 | return ResourceManager.GetString("provider_songlyrics_com", resourceCulture); 373 | } 374 | } 375 | 376 | /// 377 | /// Looks up a localized string similar to name: Teksty 378 | /// 379 | ///variables: 380 | /// artist: 381 | /// type: artist 382 | /// filters: 383 | /// - strip_diacritics 384 | /// - [replace, 'ł', l] 385 | /// - lowercase 386 | /// - [strip_nonascii, -] 387 | /// title: 388 | /// type: title 389 | /// filters: artist 390 | /// 391 | ///config: 392 | /// url: "http://teksty.org/{artist},{title},tekst-piosenki" 393 | /// pattern: ['<div\s+class="songText"[^>]*>(?<lyrics>.*?)</div>', s] 394 | /// 395 | ///post-filters: 396 | ///- strip_html 397 | ///- clean_spaces 398 | ///- utf8_encode. 399 | /// 400 | public static string provider_teksty_org { 401 | get { 402 | return ResourceManager.GetString("provider_teksty_org", resourceCulture); 403 | } 404 | } 405 | 406 | /// 407 | /// Looks up a localized string similar to name: Urban Lyrics 408 | /// 409 | ///variables: 410 | /// artist: 411 | /// type: artist 412 | /// filters: 413 | /// - lowercase 414 | /// - strip_nonascii 415 | /// title: 416 | /// type: title 417 | /// filters: artist 418 | /// 419 | ///config: 420 | /// url: "http://www.urbanlyrics.com/lyrics/{artist}/{title}.html" 421 | /// pattern: ['<!-- lyrics start -->(?<lyrics>.+?)<!-- lyrics end -->', s] 422 | /// 423 | ///post-filters: 424 | ///- strip_html 425 | ///- utf8_encode. 426 | /// 427 | public static string provider_urbanlyrics_com { 428 | get { 429 | return ResourceManager.GetString("provider_urbanlyrics_com", resourceCulture); 430 | } 431 | } 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /LyricsReloaded/Provider/ProviderManager.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Phillip Schichtel 3 | 4 | This file is part of LyricsReloaded. 5 | 6 | LyricsReloaded is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | LyricsReloaded is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with LyricsReloaded. If not, see . 18 | 19 | */ 20 | 21 | using CubeIsland.LyricsReloaded.Filters; 22 | using CubeIsland.LyricsReloaded.Provider.Loader; 23 | using CubeIsland.LyricsReloaded.Validation; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.IO; 27 | using System.Reflection; 28 | using System.Text; 29 | using YamlDotNet.RepresentationModel; 30 | 31 | namespace CubeIsland.LyricsReloaded.Provider 32 | { 33 | public class ProviderManager 34 | { 35 | private static class Node 36 | { 37 | public static readonly YamlScalarNode NAME = new YamlScalarNode("name"); 38 | public static readonly YamlScalarNode QUALITY = new YamlScalarNode("quality"); 39 | public static readonly YamlScalarNode RATE_LIMIT = new YamlScalarNode("rate-limit"); 40 | public static readonly YamlScalarNode LOADER = new YamlScalarNode("loader"); 41 | public static readonly YamlScalarNode POST_FILTERS = new YamlScalarNode("post-filters"); 42 | public static readonly YamlScalarNode VALIDATIONS = new YamlScalarNode("validations"); 43 | public static readonly YamlScalarNode CONFIG = new YamlScalarNode("config"); 44 | 45 | public static readonly YamlScalarNode VARIABLES = new YamlScalarNode("variables"); 46 | public static class Variables 47 | { 48 | public static readonly YamlScalarNode TYPE = new YamlScalarNode("type"); 49 | public static readonly YamlScalarNode FILTERS = new YamlScalarNode("filters"); 50 | } 51 | 52 | public static readonly YamlScalarNode HEADERS = new YamlScalarNode("headers"); 53 | } 54 | 55 | private readonly LyricsReloaded lyricsReloaded; 56 | private readonly Logger logger; 57 | private readonly object providerLock = new object(); 58 | private readonly Dictionary providers; 59 | private readonly Dictionary loaderFactories; 60 | private readonly Dictionary filters; 61 | private readonly Dictionary validators; 62 | 63 | private static readonly Dictionary VARIABLE_TYPES = new Dictionary { 64 | {"artist", Variable.Type.ARTIST}, 65 | {"title", Variable.Type.TITLE}, 66 | {"album", Variable.Type.ALBUM} 67 | }; 68 | 69 | public ProviderManager(LyricsReloaded lyricsReloaded) 70 | { 71 | this.lyricsReloaded = lyricsReloaded; 72 | logger = lyricsReloaded.getLogger(); 73 | providers = new Dictionary(); 74 | loaderFactories = new Dictionary(); 75 | filters = new Dictionary(); 76 | validators = new Dictionary(); 77 | 78 | loadFilters(); 79 | loadValidators(); 80 | } 81 | 82 | private void loadFilters() 83 | { 84 | Type filterType = typeof(Filter); 85 | foreach (Type type in Assembly.GetAssembly(filterType).GetTypes()) 86 | { 87 | if (filterType.IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface) 88 | { 89 | Filter filter = (Filter)Activator.CreateInstance(type); 90 | filters.Add(filter.getName(), filter); 91 | } 92 | } 93 | } 94 | 95 | private void loadValidators() 96 | { 97 | Type validatorType = typeof(Validator); 98 | foreach (Type type in Assembly.GetAssembly(validatorType).GetTypes()) 99 | { 100 | if (validatorType.IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface) 101 | { 102 | Validator validator = (Validator)Activator.CreateInstance(type); 103 | validators.Add(validator.getName(), validator); 104 | } 105 | } 106 | } 107 | 108 | public void registerLoaderFactory(LyricsLoaderFactory factory) 109 | { 110 | if (factory != null) 111 | { 112 | loaderFactories.Add(factory.getName().ToLower(), factory); 113 | } 114 | } 115 | 116 | public Filter getFilter(string name) 117 | { 118 | name = name.ToLower(); 119 | if (filters.ContainsKey(name)) 120 | { 121 | return filters[name]; 122 | } 123 | return null; 124 | } 125 | 126 | public Provider getProvider(string providerName) 127 | { 128 | if (providerName == null) 129 | { 130 | return null; 131 | } 132 | lock (providerLock) 133 | { 134 | if (providers.ContainsKey(providerName)) 135 | { 136 | return providers[providerName]; 137 | } 138 | } 139 | return null; 140 | } 141 | 142 | public IList getProviders() 143 | { 144 | lock (providerLock) 145 | { 146 | List providerList = new List(providers.Values); 147 | providerList.Sort(); 148 | return providerList; 149 | } 150 | } 151 | 152 | public void loadProvider(FileInfo fileInfo) 153 | { 154 | using (FileStream stream = fileInfo.OpenRead()) 155 | { 156 | logger.debug("Loading config from file: {0}", fileInfo.FullName); 157 | loadProvider(new StreamReader(stream)); 158 | } 159 | } 160 | 161 | public void loadProvider(String resourceText) 162 | { 163 | loadProvider(new StringReader(resourceText)); 164 | } 165 | 166 | public void loadProvider(byte[] resourceData) 167 | { 168 | loadProvider(new StreamReader(new MemoryStream(resourceData), Encoding.UTF8)); 169 | } 170 | 171 | /// 172 | /// Loads a configuration from any TextReader 173 | /// 174 | /// the reader 175 | /// if an error occurs during configuration loading 176 | public void loadProvider(TextReader configReader) 177 | { 178 | YamlStream yaml = new YamlStream(); 179 | try 180 | { 181 | yaml.Load(configReader); 182 | } 183 | catch (Exception e) 184 | { 185 | throw new InvalidConfigurationException(e.Message, e); 186 | } 187 | 188 | YamlNode node; 189 | IDictionary rootNodes = ((YamlMappingNode)yaml.Documents[0].RootNode).Children; 190 | 191 | string loaderName; 192 | node = (rootNodes.ContainsKey(Node.LOADER) ? rootNodes[Node.LOADER] : null); 193 | if (node is YamlScalarNode) 194 | { 195 | loaderName = ((YamlScalarNode)node).Value.Trim().ToLower(); 196 | } 197 | else 198 | { 199 | loaderName = "static"; 200 | } 201 | if (!loaderFactories.ContainsKey(loaderName)) 202 | { 203 | throw new InvalidConfigurationException("Unknown provider type " + loaderName + ", skipping"); 204 | } 205 | LyricsLoaderFactory loaderFactory = loaderFactories[loaderName]; 206 | 207 | node = (rootNodes.ContainsKey(Node.NAME) ? rootNodes[Node.NAME] : null); 208 | if (!(node is YamlScalarNode)) 209 | { 210 | throw new InvalidConfigurationException("No provider name given!"); 211 | } 212 | string name = ((YamlScalarNode)node).Value.Trim(); 213 | 214 | ushort quality = 50; 215 | node = (rootNodes.ContainsKey(Node.QUALITY) ? rootNodes[Node.QUALITY] : null); 216 | if (node is YamlScalarNode) 217 | { 218 | try 219 | { 220 | quality = Convert.ToUInt16(((YamlScalarNode)node).Value.Trim()); 221 | } 222 | catch (FormatException e) 223 | { 224 | throw new InvalidConfigurationException("Invalid quality value given, only positive numbers >= 0 are allowed!", e); 225 | } 226 | } 227 | 228 | RateLimit rateLimit = null; 229 | node = (rootNodes.ContainsKey(Node.RATE_LIMIT) ? rootNodes[Node.RATE_LIMIT] : null); 230 | if (node is YamlScalarNode) 231 | { 232 | rateLimit = RateLimit.parse(((YamlScalarNode) node).Value.Trim()); 233 | } 234 | 235 | node = (rootNodes.ContainsKey(Node.VARIABLES) ? rootNodes[Node.VARIABLES] : null); 236 | Dictionary variables = new Dictionary(); 237 | if (node is YamlMappingNode) 238 | { 239 | foreach (KeyValuePair preparationEntry in ((YamlMappingNode)node).Children) 240 | { 241 | node = preparationEntry.Key; 242 | if (node is YamlScalarNode) 243 | { 244 | string variableName = ((YamlScalarNode)node).Value.ToLower(); 245 | 246 | if (variables.ContainsKey(variableName)) 247 | { 248 | throw InvalidConfigurationException.fromFormat("{0}: Variable already defined!", variableName); 249 | } 250 | 251 | node = preparationEntry.Value; 252 | // variable value without filters 253 | if (node is YamlScalarNode) 254 | { 255 | string typeString = ((YamlScalarNode)node).Value.ToLower(); 256 | try 257 | { 258 | Variable.Type variableType = VARIABLE_TYPES[typeString]; 259 | variables.Add(variableName, new Variable(variableName, variableType)); 260 | } 261 | catch 262 | { 263 | throw InvalidConfigurationException.fromFormat("{0}: Unknown variable type {1}!", variableName, typeString); 264 | } 265 | } 266 | // value with filters expected 267 | else if (node is YamlMappingNode) 268 | { 269 | YamlMappingNode variableConfig = (YamlMappingNode)node; 270 | 271 | node = variableConfig.Children[Node.Variables.TYPE]; 272 | if (!(node is YamlScalarNode)) 273 | { 274 | throw InvalidConfigurationException.fromFormat("{0}: Invalid variable type!", variableName); 275 | } 276 | 277 | Variable.Type type; 278 | string typeString = ((YamlScalarNode)node).Value.ToLower(); 279 | try 280 | { 281 | type = VARIABLE_TYPES[typeString]; 282 | } 283 | catch 284 | { 285 | throw InvalidConfigurationException.fromFormat("{0}: Unknown variable type {1}!", variableName, typeString); 286 | } 287 | 288 | FilterCollection filterCollection; 289 | 290 | node = (variableConfig.Children.ContainsKey(Node.Variables.FILTERS) ? variableConfig.Children[Node.Variables.FILTERS] : null); 291 | // variable reference 292 | if (node is YamlScalarNode) 293 | { 294 | string referencedVar = ((YamlScalarNode)node).Value.ToLower(); 295 | try 296 | { 297 | filterCollection = variables[referencedVar].getFilters(); 298 | } 299 | catch 300 | { 301 | throw InvalidConfigurationException.fromFormat("{0}: Unknown variable {1} referenced!", variableName, referencedVar); 302 | } 303 | } 304 | // a list of filters 305 | else if (node is YamlSequenceNode) 306 | { 307 | filterCollection = FilterCollection.parseList((YamlSequenceNode)node, filters); 308 | } 309 | else 310 | { 311 | throw new InvalidConfigurationException("Invalid filter option specified!"); 312 | } 313 | 314 | variables.Add(variableName, new Variable(variableName, type, filterCollection)); 315 | } 316 | } 317 | else 318 | { 319 | throw new InvalidConfigurationException("Invalid configration, aborting the configuration."); 320 | } 321 | } 322 | } 323 | 324 | foreach (KeyValuePair entry in VARIABLE_TYPES) 325 | { 326 | if (!variables.ContainsKey(entry.Key)) 327 | { 328 | variables.Add(entry.Key, new Variable(entry.Key, entry.Value)); 329 | } 330 | } 331 | 332 | node = (rootNodes.ContainsKey(Node.POST_FILTERS) ? rootNodes[Node.POST_FILTERS] : null); 333 | FilterCollection postFilters; 334 | if (node is YamlSequenceNode) 335 | { 336 | postFilters = FilterCollection.parseList((YamlSequenceNode)node, filters); 337 | } 338 | else 339 | { 340 | postFilters = new FilterCollection(); 341 | } 342 | 343 | node = (rootNodes.ContainsKey(Node.VALIDATIONS) ? rootNodes[Node.VALIDATIONS] : null); 344 | ValidationCollection validations; 345 | if (node is YamlSequenceNode) 346 | { 347 | validations = ValidationCollection.parseList((YamlSequenceNode)node, validators); 348 | } 349 | else 350 | { 351 | validations = new ValidationCollection(); 352 | } 353 | 354 | IDictionary headers = new Dictionary(); 355 | node = (rootNodes.ContainsKey(Node.HEADERS) ? rootNodes[Node.HEADERS] : null); 356 | if (node is YamlMappingNode) 357 | { 358 | foreach (KeyValuePair entry in (YamlMappingNode)node) 359 | { 360 | if (entry.Key is YamlScalarNode && entry.Value is YamlScalarNode) 361 | { 362 | headers.Add(((YamlScalarNode)entry.Key).Value.Trim(), ((YamlScalarNode)entry.Value).Value); 363 | } 364 | } 365 | } 366 | 367 | YamlMappingNode configNode; 368 | node = (rootNodes.ContainsKey(Node.CONFIG) ? rootNodes[Node.CONFIG] : null); 369 | if (node is YamlMappingNode) 370 | { 371 | configNode = (YamlMappingNode)node; 372 | } 373 | else 374 | { 375 | configNode = new YamlMappingNode(); 376 | } 377 | 378 | LyricsLoader loader = loaderFactory.newLoader(configNode); 379 | 380 | Provider provider = new Provider(lyricsReloaded, name, quality, variables, postFilters, validations, headers, loader, rateLimit); 381 | logger.info("Provider loaded: " + provider.getName()); 382 | 383 | lock (providerLock) 384 | { 385 | if (providers.ContainsKey(provider.getName())) 386 | { 387 | logger.info("The provider {0} does already exist and will be replaced.", provider.getName()); 388 | providers.Remove(provider.getName()); 389 | } 390 | providers.Add(provider.getName(), provider); 391 | } 392 | } 393 | 394 | public void clean() 395 | { 396 | lock (providerLock) 397 | { 398 | providers.Clear(); 399 | loaderFactories.Clear(); 400 | filters.Clear(); 401 | } 402 | } 403 | 404 | public void shutdown() 405 | { 406 | lock (providerLock) 407 | { 408 | foreach (Provider provider in providers.Values) 409 | { 410 | provider.shutdown(); 411 | } 412 | clean(); 413 | } 414 | } 415 | } 416 | 417 | public class InvalidConfigurationException : Exception 418 | { 419 | public InvalidConfigurationException(String message) : base(message) 420 | {} 421 | 422 | public InvalidConfigurationException(string message, Exception innerException) : base(message, innerException) 423 | {} 424 | 425 | public static InvalidConfigurationException fromFormat(string format, params object[] args) 426 | { 427 | return new InvalidConfigurationException(String.Format(format, args)); 428 | } 429 | } 430 | } 431 | --------------------------------------------------------------------------------