summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Oesterholt <hans@oesterholt.net>2013-01-09 00:17:04 +0100
committerHans Oesterholt <hans@oesterholt.net>2013-01-09 00:17:04 +0100
commit7f19b3743c8785bf3434e720c1343dfc394b55b4 (patch)
tree748da1e517410430e196b190b0fed3136f919fd4
parent4c62e969139f119c95c5a5ee3be7af27d382c548 (diff)
CueSheets extension
-rw-r--r--Extensions.sln10
-rw-r--r--configure.ac2
-rw-r--r--po/banshee-community-extensions.pot34
-rw-r--r--src/CueSheets/Banshee.CueSheets/CueSheet.cs222
-rw-r--r--src/CueSheets/Banshee.CueSheets/CueSheetEntry.cs101
-rw-r--r--src/CueSheets/Banshee.CueSheets/CueSheetsSource.cs582
-rw-r--r--src/CueSheets/CueSheets.addin.xml84
-rw-r--r--src/CueSheets/CueSheets.csproj109
-rw-r--r--src/CueSheets/Makefile.am11
-rw-r--r--src/CueSheets/ThemeIcons/128x128/categories/cueplay.pngbin0 -> 15850 bytes
-rw-r--r--src/CueSheets/ThemeIcons/22x22/categories/cueplay.pngbin0 -> 749 bytes
-rw-r--r--src/CueSheets/ThemeIcons/32x32/categories/cueplay.pngbin0 -> 1844 bytes
-rw-r--r--src/CueSheets/ThemeIcons/48x48/categories/cueplay.pngbin0 -> 2036 bytes
-rw-r--r--src/CueSheets/ThemeIcons/64x64/categories/cueplay.pngbin0 -> 3070 bytes
-rw-r--r--src/Makefile.am1
15 files changed, 1139 insertions, 17 deletions
diff --git a/Extensions.sln b/Extensions.sln
index 0621213..319fd61 100644
--- a/Extensions.sln
+++ b/Extensions.sln
@@ -1,6 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CueSheets", "src\CueSheets\CueSheets.csproj", "{}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuplicateSongDetector", "src\DuplicateSongDetector\DuplicateSongDetector.csproj", "{1725FB8A-DF47-4CAF-A322-59EE97AAB5DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlbumArtWriter", "src\AlbumArtWriter\AlbumArtWriter.csproj", "{5D56E36A-AB9F-4BAA-BC42-D7503AC0A3A5}"
@@ -87,7 +89,11 @@ Global
Release|x86 = Release|x86
Windows|Any CPU = Windows|Any CPU
EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {}.Debug|x86.Build.0 = Debug|Any CPU
+ {}.Release|x86.ActiveCfg = Release|Any CPU
+ {}.Release|x86.Build.0 = Release|Any CPU
{04568A95-2430-41EB-82D6-939F5E7E8403}.Debug|x86.ActiveCfg = Debug|Any CPU
{04568A95-2430-41EB-82D6-939F5E7E8403}.Debug|x86.Build.0 = Debug|Any CPU
{04568A95-2430-41EB-82D6-939F5E7E8403}.Release|x86.ActiveCfg = Release|Any CPU
diff --git a/configure.ac b/configure.ac
index d91a378..7c882ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -134,6 +134,7 @@ help/Makefile
po/Makefile.in
src/Makefile
+src/CueSheets/Makefile
src/AssemblyInfo.cs
src/AlarmClock/Makefile
@@ -203,6 +204,7 @@ ${PACKAGE}-${VERSION}
User Help: ${enable_user_help} (requires gnome-doc-utils >= 0.17.3)
Extensions:
+ CueSheets: yes
Alarm Clock: ${enable_AlarmClock}
AlbumArtWriter: ${enable_AlbumArtWriter}
Ampache: ${enable_Ampache}
diff --git a/po/banshee-community-extensions.pot b/po/banshee-community-extensions.pot
index f1d3fd8..c3ff106 100644
--- a/po/banshee-community-extensions.pot
+++ b/po/banshee-community-extensions.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-04-01 20:05+0200\n"
+"POT-Creation-Date: 2013-01-09 00:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -414,23 +414,23 @@ msgstr ""
msgid "Are you sure you want to remove the selected items from your Library?"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:43
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:44
msgid "Sync to Folder"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:46
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:47
msgid "Synchronize to Folder"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:125
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:126
msgid "Preparing sync"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:197
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:220
msgid "Copying"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:215
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncController.cs:238
msgid "Done!"
msgstr ""
@@ -442,36 +442,40 @@ msgstr ""
msgid "Stop"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:83
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:85
msgid "Start sync"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:90
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:92
msgid "Choose target sync folder"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:93
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:95
msgid "Create M3U Playlist"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:95
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:97
msgid "Overwrite existing files"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:97
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:99
+msgid "Create as symbolic link"
+msgstr ""
+
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:101
msgid "Create subfolders"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:99
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:153
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:103
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:158
msgid "Subfolder depth"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:112
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:116
msgid "Options"
msgstr ""
-#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:139
+#: ../src/FolderSync/Banshee.FolderSync/FolderSyncView.cs:143
msgid "Sync to folder:"
msgstr ""
diff --git a/src/CueSheets/Banshee.CueSheets/CueSheet.cs b/src/CueSheets/Banshee.CueSheets/CueSheet.cs
new file mode 100644
index 0000000..990c5a9
--- /dev/null
+++ b/src/CueSheets/Banshee.CueSheets/CueSheet.cs
@@ -0,0 +1,222 @@
+//
+// CueSheet.cs
+//
+// Authors:
+// Cool Extension Author <hans@oesterholt.net>
+//
+// Copyright (C) 2013 Hans Oesterholt
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.IO;
+using System.Text.RegularExpressions;
+using Banshee.CueSheets;
+using Banshee.Collection;
+using Banshee.Base;
+
+namespace Banshee.CueSheets
+{
+ public class CueSheet : MemoryTrackListModel
+ {
+ private string _image_file_name;
+ private string _img_full_path;
+ private string _music_file_name;
+ private string _title;
+ private string _performer;
+ private CueSheetEntry [] _tracks;
+ private string _cuefile;
+
+ private void append(CueSheetEntry e) {
+ if (_tracks==null) {
+ _tracks=new CueSheetEntry[1];
+ _tracks[0]=e;
+ } else {
+ CueSheetEntry [] es=new CueSheetEntry[_tracks.Length+1];
+ int i=0;
+ for(i=0;i<_tracks.Length;i++) {
+ es[i]=_tracks[i];
+ }
+ es[i]=e;
+ _tracks=es;
+ }
+ this.Add (e);
+ }
+
+ public string imageFileName() {
+ return _image_file_name;
+ }
+
+ public string cueFile() {
+ return _cuefile;
+ }
+
+ public string musicFileName() {
+ return _music_file_name;
+ }
+
+ public string title() {
+ return _title;
+ }
+
+ public string performer() {
+ return _performer;
+ }
+
+ public CueSheetEntry entry(int i) {
+ return _tracks[i];
+ }
+
+ public int nEntries() {
+ if (_tracks==null) { return 0; }
+ else {
+ return _tracks.Length;
+ }
+ }
+
+ public int searchIndex(double offset) {
+ int k,N;
+ for(k=0,N=nEntries ();k<N && offset>_tracks[k].offset ();k++);
+ return k-1;
+ }
+
+ private string getArtId() {
+ string aaid=CoverArtSpec.CreateArtistAlbumId (_performer,_title);
+ if (!CoverArtSpec.CoverExists (aaid)) {
+ if (File.Exists (_img_full_path)) {
+ string path=CoverArtSpec.GetPathForNewFile (aaid,_img_full_path);
+ File.Copy (_img_full_path,path);
+ Console.WriteLine ("coverartpath="+path);
+ }
+ }
+ string path1=CoverArtSpec.GetPath (aaid);
+ Console.WriteLine ("coverartpath1="+path1);
+ return aaid;
+ }
+
+ public CueSheet (string filename,string directory) {
+ _cuefile=filename;
+ Boolean _in_tracks=false;
+ _image_file_name="";
+ _img_full_path="";
+ _music_file_name="";
+ _title="";
+ _performer="";
+ _tracks=null;
+
+ string e_perf="";
+ string e_title="";
+ double e_offset=-1.0;
+ string aaid="";
+ int nr=0;
+
+ using (System.IO.StreamReader sr = System.IO.File.OpenText(filename)) {
+ string line = "";
+ while ((line = sr.ReadLine()) != null) {
+ line=line.Trim ();
+ if (line!="") {
+ //Console.WriteLine ("it="+_in_tracks+", "+line);
+ if (!_in_tracks) {
+ if (line.Substring (0,9).ToLower()=="performer") {
+ string p=line.Substring (9).Trim ();
+ p=Regex.Replace (p,"[\"]","");
+ _performer=p;
+ } else if (line.Substring (0,5).ToLower ()=="title") {
+ _title=Regex.Replace (line.Substring (5).Trim (),"[\"]","");
+ } else if (line.Substring (0,4).ToLower ()=="file") {
+ _music_file_name=line.Substring (4).Trim ();
+ Match m=Regex.Match (_music_file_name,"([\"][^\"]+[\"])");
+ Console.WriteLine ("match="+m);
+ _music_file_name=m.ToString ();
+ Console.WriteLine ("result="+_music_file_name);
+ _music_file_name=Regex.Replace (_music_file_name,"[\"]","").Trim ();
+ _music_file_name=directory+"/"+_music_file_name;
+ Console.WriteLine ("music file="+_music_file_name);
+ } else if (line.Substring(0,5).ToLower ()=="track") {
+ _in_tracks=true;
+ } else if (line.Substring (0,3).ToLower ()=="rem") {
+ line=line.Substring (3).Trim ();
+ if (line.Substring (0,5).ToLower ()=="image") {
+ _image_file_name=line.Substring (5).Trim ();
+ _image_file_name=Regex.Replace (_image_file_name,"[\"]","").Trim ();
+ _img_full_path=directory+"/"+_image_file_name;
+ }
+ }
+ }
+
+
+ if (_in_tracks) {
+ if (aaid=="") { aaid=getArtId (); }
+
+ Console.WriteLine ("line="+line);
+ if (line.Substring (0,5).ToLower ()=="track") {
+ if (e_offset>=0) {
+ nr+=1;
+ CueSheetEntry e=new CueSheetEntry(_music_file_name,aaid,nr,-1,e_title,e_perf,_title,e_offset);
+ append (e);
+ if (nr>1) {
+ CueSheetEntry ePrev;
+ ePrev=this.entry (nr-2);
+ ePrev.setLength(e.offset ()-ePrev.offset());
+ }
+ }
+ e_perf=_performer;
+ e_title="";
+ e_offset=-1.0;
+ } else if (line.Substring (0,5).ToLower ()=="title") {
+ e_title=Regex.Replace (line.Substring (5).Trim (),"[\"]","");
+ } else if (line.Substring (0,9).ToLower ()=="performer") {
+ e_perf=Regex.Replace (line.Substring (9).Trim (),"[\"]","");
+ } else if (line.Substring (0,5).ToLower ()=="index") {
+ string s=line.Substring (5).Trim ();
+ s=Regex.Replace (s,"^\\s*[0-9]+\\s*","");
+ string []parts=Regex.Split(s,"[:]");
+ Console.WriteLine ("parts="+parts[0]+","+parts[1]+","+parts[2]);
+ int min=Convert.ToInt32(parts[0]);
+ int secs=Convert.ToInt32(parts[1]);
+ int hsecs=Convert.ToInt32(parts[2]);
+ e_offset=min*60+secs+(hsecs/100.0);
+
+ }
+ }
+ }
+ }
+ if (e_offset>=0) {
+ nr+=1;
+ CueSheetEntry e=new CueSheetEntry(_music_file_name,aaid,nr,-1,e_title,e_perf,_title,e_offset);
+ append (e);
+ if (nr>1) {
+ CueSheetEntry ePrev;
+ ePrev=this.entry (nr-2);
+ ePrev.setLength(e.offset ()-ePrev.offset());
+ }
+ }
+
+ {
+ int i;
+ for(i=0;i<nEntries();i++) {
+ entry (i).setNrOfTracks(nr);
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/CueSheets/Banshee.CueSheets/CueSheetEntry.cs b/src/CueSheets/Banshee.CueSheets/CueSheetEntry.cs
new file mode 100644
index 0000000..cf4f308
--- /dev/null
+++ b/src/CueSheets/Banshee.CueSheets/CueSheetEntry.cs
@@ -0,0 +1,101 @@
+//
+// CueSheetEntry.cs
+//
+// Authors:
+// Cool Extension Author <hans@oesterholt.net>
+//
+// Copyright (C) 2013 Hans Oesterholt
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+
+using Banshee.Collection;
+using Banshee.Base;
+
+namespace Banshee.CueSheets
+{
+ public class CueSheetEntry : TrackInfo
+ {
+ double _offset;
+ string _performer;
+ string _title;
+ string _file;
+ double _length;
+ string _art="";
+
+ public override string ArtworkId {
+ get { return _art; }
+ }
+
+ public string file() {
+ return _file;
+ }
+
+ public string title() {
+ return _title;
+ }
+
+ public string performer() {
+ return _performer;
+ }
+
+ public double offset() {
+ return _offset;
+ }
+
+ public void setNrOfTracks(int n) {
+ this.TrackCount=n;
+ }
+
+ public double length() {
+ return _length;
+ }
+
+ public void setLength(double l) {
+ _length=l;
+ System.Int64 ticks_100nanosecs=(System.Int64) (l*10000000); // 10 miljoen
+ this.Duration=new TimeSpan(ticks_100nanosecs);
+ }
+
+ public CueSheetEntry (string file,String artId,int nr,int cnt,string title,string performer,string album,double offset) {
+ _file=file;
+ _title=title;
+ _performer=performer;
+ _offset=offset;
+ _length=-1.0;
+
+ _art=artId;
+ this.AlbumArtist=performer;
+ this.TrackTitle=title;
+ this.AlbumTitle=album;
+ this.ArtistName=performer;
+ this.TrackNumber=nr;
+ this.TrackCount=cnt;
+ this.DiscNumber=1;
+ this.CanPlay=true;
+ this.CanSaveToDatabase=false;
+ this.Duration=new System.TimeSpan(0,0,10,0);
+ Console.WriteLine ("file="+_file);
+ this.Uri=new Hyena.SafeUri(_file,false);
+ }
+ }
+}
+
diff --git a/src/CueSheets/Banshee.CueSheets/CueSheetsSource.cs b/src/CueSheets/Banshee.CueSheets/CueSheetsSource.cs
new file mode 100644
index 0000000..c4cb87b
--- /dev/null
+++ b/src/CueSheets/Banshee.CueSheets/CueSheetsSource.cs
@@ -0,0 +1,582 @@
+//
+// CueSheetsSource.cs
+//
+// Authors:
+// Cool Extension Author <hans@oesterholt.net>
+//
+// Copyright (C) 2013 Hans Oesterholt
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+using Mono.Addins;
+
+using Banshee.Base;
+using Banshee.Sources;
+using Banshee.Sources.Gui;
+
+// Other namespaces you might want:
+using Banshee.ServiceStack;
+using Banshee.Preferences;
+using Banshee.MediaEngine;
+using Banshee.PlaybackController;
+using System.IO;
+
+using Banshee.CueSheets;
+using System.Text.RegularExpressions;
+using Banshee.Collection;
+using Banshee.Library;
+
+namespace Banshee.CueSheets
+{
+ // We are inheriting from Source, the top-level, most generic type of Source.
+ // Other types include (inheritance indicated by indentation):
+ // DatabaseSource - generic, DB-backed Track source; used by PlaylistSource
+ // PrimarySource - 'owns' tracks, used by DaapSource, DapSource
+ // LibrarySource - used by Music, Video, Podcasts, and Audiobooks
+ public class CueSheetsSource : Source, IBasicPlaybackController, ITrackModelSource
+ {
+ // In the sources TreeView, sets the order value for this source, small on top
+ const int sort_order = 50;
+ CustomView _view;
+ TrackListModel _nullModel;
+ double pbsize=-1.0;
+
+
+ public CueSheetsSource () : base (AddinManager.CurrentLocalizer.GetString ("CueSheets"),
+ AddinManager.CurrentLocalizer.GetString ("CueSheets"),
+ sort_order,
+ "hod-cuesheets-2013-01-06")
+ {
+ _view=new CustomView(this);
+ _nullModel=new MemoryTrackListModel();
+ Properties.Set<ISourceContents> ("Nereid.SourceContents", _view);
+ Properties.SetString ("Icon.Name", "cueplay");
+
+ Hyena.Log.Information ("CueSheets source has been instantiated.");
+ }
+
+ // A count of 0 will be hidden in the source TreeView
+ public override int Count {
+ get {
+ CueSheet s=_view.getSheet ();
+ if (s==null) { return 0; }
+ else { return s.nEntries (); }
+ }
+ }
+
+ public CueSheet getSheet() {
+ return _view.getSheet();
+ }
+
+ #region IBasicPlaybackController implementation
+ public bool First ()
+ {
+ Console.WriteLine ("First called");
+ return true;
+ }
+
+ public bool Next (bool restart, bool changeImmediately)
+ {
+ //Console.WriteLine ("next called");
+ return _view.next ();
+ }
+
+ public bool Previous (bool restart)
+ {
+ //Console.WriteLine ("previous:"+restart);
+ return _view.previous ();
+ }
+ #endregion
+
+ #region ITrackModelSource implementation
+ public void Reload () {
+ Console.WriteLine ("reloading");
+ _view.reLoad();
+ }
+
+ public TrackListModel TrackModel {
+ get {
+ CueSheet s=_view.getSheet ();
+ if (s==null) {
+ return _nullModel;
+ } else {
+ return s;
+ }
+ }
+ }
+
+ public bool HasDependencies { get { return false; } }
+
+ public bool CanAddTracks { get { return false; } }
+
+ public bool CanRemoveTracks { get { return false; } }
+
+ public bool CanDeleteTracks { get { return false; } }
+
+ public bool ConfirmRemoveTracks { get { return false; } }
+
+ public bool CanRepeat { get { return true; } }
+
+ public bool CanShuffle { get { return true; } }
+
+ public bool ShowBrowser { get { return false; } }
+
+ public bool Indexable { get { return true; } }
+
+ public void RemoveTracks (Hyena.Collections.Selection selection) {
+ }
+
+ public void DeleteTracks (Hyena.Collections.Selection selection) {
+ }
+ #endregion
+
+ public void OnConfigure (object o, EventArgs ea) {
+ new CueSheetsConfigDialog (this);
+ return;
+ }
+
+ public double getPbSize() {
+ if (pbsize<0.0) {
+ pbsize=Banshee.Configuration.ConfigurationClient.Get<double>("cuesheets_zoom",1.0);
+ }
+ return pbsize;
+ }
+
+ public void setPbSize(double s) {
+ pbsize=s;
+ Banshee.Configuration.ConfigurationClient.Set<double>("cuesheets_zoom",s);
+ }
+
+ public string getCueSheetDir() {
+ string dir=Banshee.Configuration.ConfigurationClient.Get<string>("cuesheets_dir","");
+ //string dir=Properties.Get<string>("cuesheets_dir","");
+ if (dir=="") {
+ dir=System.Environment.GetEnvironmentVariable ("HOME");
+ }
+ Console.WriteLine ("getcuesheetdir="+dir);
+ return dir;
+ }
+
+ public void setCueSheetDir(string dir) {
+ //Console.WriteLine ("setcuesheetdir:"+dir);
+ //Properties.SetString ("cuesheets_dir",dir);
+ Banshee.Configuration.ConfigurationClient.Set<string>("cuesheets_dir",dir);
+ }
+
+ private class CueSheetsConfigDialog : Gtk.Dialog {
+ public CueSheetsConfigDialog(CueSheetsSource src) {
+
+ string dir=src.getCueSheetDir();
+ Gtk.Label lbl=new Gtk.Label("CueSheet Music Directory:");
+ Gtk.FileChooserButton btn=new Gtk.FileChooserButton("CueSheet Music Directory:",Gtk.FileChooserAction.SelectFolder);
+ btn.SelectFilename (dir);
+ Gtk.HBox box=new Gtk.HBox();
+ box.Add (lbl);
+ box.Add (btn);
+ box.ShowAll ();
+
+ double d=src.getPbSize ();
+ Gtk.HScale hs=new Gtk.HScale(1.0,3.0,0.25);
+ hs.Value=d;
+ Gtk.Label lbl1=new Gtk.Label("Size of music icons:");
+ Gtk.HBox box1=new Gtk.HBox();
+ box1.Add (lbl1);
+ box1.Add (hs);
+ box1.ShowAll ();
+
+ this.VBox.Add (box);
+ this.VBox.Add (box1);
+ this.AddButton (Gtk.Stock.Ok,1);
+ this.AddButton (Gtk.Stock.Cancel,2);
+ this.Title="CueSheets Preferences";
+ int result=this.Run ();
+ if (result==1) {
+ dir=btn.Filename;
+ src.setCueSheetDir(dir);
+ src.setPbSize (hs.Value);
+ }
+ this.Destroy ();
+ }
+ }
+
+ private class CustomView : ISourceContents
+ {
+ //Gtk.Button up;
+ Gtk.ListStore store;
+ Gtk.TreeView view;
+ //Gtk.Image img;
+ Gtk.VBox box;
+ string type="directory";
+ CueSheet sheet;
+ //Gtk.Table table;
+ Gtk.ScrolledWindow scroll;
+ int index=-1;
+ private CueSheetsSource MySource=null;
+
+ uint _position=0;
+ bool _set_position=false;
+
+ const int IMG_NOIMAGE=0;
+ const int IMG_NOIMAGE_DIR=1;
+ const int IMG_DIRECTORY=2;
+
+ Gdk.Pixbuf _img_dir=null;
+ Gdk.Pixbuf _img_playlist=null;
+ Gdk.Pixbuf _pb_size=null;
+
+
+ private Gdk.Pixbuf GetDefaultPixBuf(int type) {
+ Gdk.Pixbuf img=_img_playlist;
+ if (type==1000) { img=_pb_size; }
+ if (type==IMG_DIRECTORY) {
+ img=_img_dir;
+ }
+ return img;
+ }
+
+ private int getPixbufWidth() {
+ return (int) (_pb_size.Width*MySource.getPbSize());
+ }
+
+ private int getPixbufHeight() {
+ return (int) (_pb_size.Height*MySource.getPbSize());
+ }
+
+ public CueSheet getSheet() {
+ return sheet;
+ }
+
+ private String basedir=null;
+ private String cwdir=null;
+
+ public string basename(string f) {
+ string bn=Regex.Replace (f,"^([^/]*[/])+","");
+ return bn;
+ }
+
+ public string cuename(string f) {
+ string cn=Regex.Replace(basename (f),"[.]cue$","");
+ return cn;
+ }
+
+ public void fill(Gtk.ListStore store) {
+ type="directory";
+ store.Clear ();
+ if (basedir==null) {
+ basedir=MySource.getCueSheetDir ();
+ }
+ if (cwdir==null) { cwdir=basedir; }
+ string [] dirs=Directory.GetDirectories(cwdir, "*");
+ string [] sheets=Directory.GetFiles (cwdir,"*.cue");
+ int i=0;
+ foreach (string file in sheets) {
+ i=i+1;
+ string name=cuename(file);
+ CueSheet s=new CueSheet(file,cwdir);
+ Gdk.Pixbuf pb;
+ if (s.imageFileName ()!="") {
+ string imgf=cwdir+"/"+s.imageFileName ();
+ pb=new Gdk.Pixbuf(imgf,getPixbufWidth(),getPixbufHeight());
+ } else {
+ pb=GetDefaultPixBuf(IMG_NOIMAGE_DIR);
+ }
+ store.AppendValues(i,pb,name);
+ }
+ foreach (string dir in dirs) {
+ string name=basename (dir);
+ if (name.Substring (0,1)!=".") {
+ i=i+1;
+ Gdk.Pixbuf pb=GetDefaultPixBuf(IMG_DIRECTORY);
+ store.AppendValues(i,pb,name);
+ }
+ }
+ }
+
+ public void seekSong(int i) {
+ CueSheetEntry e=sheet.entry (i);
+ double offset=e.offset ();
+ //Console.WriteLine ("Offset="+offset+", current="+ServiceManager.PlayerEngine.Position+
+ // ", msecs="+offset*1000.0
+ // );
+ //ServiceManager.PlayerEngine.SetNextTrack (e);
+ //ServiceManager.PlayerEngine.Open(e);
+ ServiceManager.PlayerEngine.SetCurrentTrack(e);
+ _position=(uint) (offset*1000.0);
+ _set_position=true;
+ mscount=chgcount-(1000/timeout);
+ //ServiceManager.PlayerEngine.PlayAt((uint) (offset*1000.0));
+ //ServiceManager.PlayerEngine.Position=_position;
+
+ }
+
+ public void reLoad() {
+ index=0;
+ ServiceManager.PlayerEngine.SetAccurateSeek(true);
+ CueSheetEntry e=sheet.entry(index);
+ ServiceManager.PlayerEngine.Open (e);
+ ServiceManager.PlayerEngine.Play ();
+ //ServiceManager.PlayerEngine.PlayAt ((uint) (e.offset ()*1000.0));
+ if (ServiceManager.PlaybackController.Source!=MySource) {
+ ServiceManager.PlaybackController.Source=MySource;
+ }
+ if (ServiceManager.PlaybackController.NextSource!=MySource) {
+ ServiceManager.PlaybackController.NextSource=MySource;
+ }
+ ServiceManager.PlaybackController.SetSeekMode (true);
+ mscount=chgcount-1;
+ }
+
+ // Every N ms
+ private int timeout=100;
+ private int mscount=0;
+ private int chgcount=3000/100; // every 3 seconds
+
+ public bool PositionDisplay() {
+ if (ServiceManager.PlaybackController.Source==MySource) {
+ if (sheet!=null) {
+ mscount+=1;
+ if (mscount>chgcount) { mscount=0; }
+
+ // Position if necessary
+ if (_set_position) {
+ _set_position=false;
+ ServiceManager.PlayerEngine.Position=_position;
+ }
+
+ // Track number
+ uint pos=ServiceManager.PlayerEngine.Position;
+ double p=((double) pos)/1000.0;
+ int i=sheet.searchIndex(p);
+ //Console.WriteLine ("Position="+p+", i="+i+", index="+index);
+ if (i!=index && i>=0) {
+ // Handle repeat track
+ if (ServiceManager.PlaybackController.RepeatMode==PlaybackRepeatMode.RepeatSingle) {
+ seekSong (index);
+ } else {
+ // Every 2 seconds
+ if (mscount==0) {
+ index=i;
+ CueSheetEntry e=sheet.entry(index);
+ ServiceManager.PlayerEngine.SetCurrentTrack (e);
+ }
+ }
+ }
+
+ if (type=="cuesheet" && mscount==0) {
+ int [] idx=new int[1];
+ idx[0]=index;
+
+ Gtk.TreePath path=new Gtk.TreePath(idx);
+ Gtk.TreeViewColumn c=new Gtk.TreeViewColumn();
+ Gtk.TreePath pp;
+ view.GetCursor (out pp,out c);
+ if (pp==null || pp.Indices[0]!=index) {
+ view.SetCursor (path,null,false);
+ }
+ }
+
+ }
+ }
+ return true;
+ }
+
+ public Boolean next() {
+ if (sheet==null) { return false; }
+ if (index<sheet.nEntries ()-1) {
+ index+=1;
+ } else {
+ index=0;
+ }
+ seekSong(index);
+ return true;
+ }
+
+ public Boolean previous() {
+ if (sheet==null) { return false; }
+ if (index>0) {
+ index-=1;
+ } else {
+ index=sheet.nEntries ()-1;
+ }
+ seekSong(index);
+ return true;
+ }
+
+ public void loadCueSheet(string file,Gtk.ListStore store) {
+ type="cuesheet";
+ //Console.WriteLine ("loadCueSheet:"+file);
+ store.Clear ();
+ sheet=new CueSheet(file,cwdir);
+ Gdk.Pixbuf pb;
+ /*if (sheet.imageFileName ()!="") {
+ string imgf=cwdir+"/"+sheet.imageFileName ();
+ pb=new Gdk.Pixbuf(imgf,getPixbufWidth(),getPixbufHeight());
+ } else {*/
+ pb=GetDefaultPixBuf(IMG_NOIMAGE);
+ /*}*/
+ int i=0;
+ for(i=0;i<sheet.nEntries ();i++) {
+ store.AppendValues (i+1,pb,sheet.entry (i).title ());
+ }
+ //Console.WriteLine (type+", image="+sheet.imageFileName ());
+
+ /*if (File.Exists (imgf)) {
+ Gdk.Rectangle a=img.Allocation;
+ Gdk.Pixbuf pb=new Gdk.Pixbuf(imgf,a.Width,a.Height);
+ img.Pixbuf=pb;
+ }*/
+ reLoad ();
+ }
+
+ public CustomView(CueSheetsSource ms) {
+ MySource=ms;
+ {
+ Gtk.Label w=new Gtk.Label();
+ _pb_size=w.RenderIcon (Gtk.Stock.Index.ToString (),Gtk.IconSize.Button,null);
+ _img_dir=w.RenderIcon (Gtk.Stock.Directory.ToString (),Gtk.IconSize.Button,null);
+ _img_playlist=w.RenderIcon(Gtk.Stock.Index.ToString (),Gtk.IconSize.Button,null);
+ }
+
+
+ store = new Gtk.ListStore(typeof(int),typeof(Gdk.Pixbuf),typeof(string));
+ view = new Gtk.TreeView();
+ Gtk.CellRendererPixbuf cpb=new Gtk.CellRendererPixbuf();
+ view.AppendColumn ("Nr.", new Gtk.CellRendererText (), "text", 0);
+ view.AppendColumn ("Icon.",cpb,"pixbuf",1);
+ view.AppendColumn ("Track/Album", new Gtk.CellRendererText (), "text", 2);
+ view.CursorChanged += new EventHandler(EvtCursorChanged);
+ view.RowActivated += new Gtk.RowActivatedHandler(EvtRowActivated);
+ view.Model = store;
+ scroll=new Gtk.ScrolledWindow();
+ scroll.Add (view);
+
+ Gtk.Toolbar bar=new Gtk.Toolbar();
+
+ Gtk.Image icn_up=new Gtk.Image(Gtk.Stock.GoUp,Gtk.IconSize.Button);
+ Gtk.Button up=new Gtk.Button(icn_up);
+ up.Clicked+=new EventHandler(handleUp);
+ bar.Add (up);
+
+ Gtk.Image icn_set=new Gtk.Image(Gtk.Stock.Preferences,Gtk.IconSize.Button);
+ Gtk.Button prefs=new Gtk.Button(icn_set);
+ prefs.Clicked+=new EventHandler(handleSet);
+ bar.Add (prefs);
+
+ Gtk.Image icn_about=new Gtk.Image(Gtk.Stock.About,Gtk.IconSize.Button);
+ Gtk.Button about=new Gtk.Button(icn_about);
+ about.Clicked+=new EventHandler(handleAbout);
+ bar.Add (about);
+
+ fill(store);
+ box = new Gtk.VBox();
+ box.PackStart (bar,false,true,0);
+ box.PackStart(scroll);
+ box.ShowAll();
+
+ GLib.Timeout.Add ((uint) timeout,(GLib.TimeoutHandler) PositionDisplay);
+ }
+
+ public void handleUp(object sender,EventArgs a) {
+ if (cwdir==basedir) {
+ // do nothing
+ } else {
+ if (type!="cuesheet") {
+ cwdir=Regex.Replace (cwdir,"[/][^/]*$","");
+ }
+ fill (store);
+ }
+ }
+
+ public void handleSet(object sender,EventArgs a) {
+ MySource.OnConfigure (sender,a);
+ string d=MySource.getCueSheetDir ();
+ if (basedir!=d) {
+ basedir=d;
+ cwdir=d;
+ fill (store);
+ }
+ }
+
+ public void handleAbout(object sender,EventArgs a) {
+ Gtk.AboutDialog ab=new Gtk.AboutDialog();
+ ab.Title="About the CueSheets extension";
+ ab.Authors=new string[] {"Hans Oesterholt"};
+ ab.Authors[0]="Hans Oesterholt";
+ ab.Version="0.0.1";
+ ab.Comments="CueSheets is an extension that allows you to play music from cuesheets in banshee";
+ ab.Website="http://oesterholt.net?env=data&page=banshee-cuesheets";
+ ab.Run ();
+ ab.Destroy ();
+ }
+
+ public void EvtCursorChanged(object sender,EventArgs a) {
+ mscount=0; // Reset cursor change timer
+ }
+
+ public void EvtRowActivated(object sender, Gtk.RowActivatedArgs a) {
+ Gtk.TreeSelection selection = (sender as Gtk.TreeView).Selection;
+ Gtk.TreeModel model;
+ Gtk.TreeIter iter;
+ // THE ITER WILL POINT TO THE SELECTED ROW
+ Console.WriteLine ("source="+ServiceManager.PlaybackController.Source);
+ Console.WriteLine ("this="+this);
+ if (selection.GetSelected(out model, out iter)) {
+ if (this.type=="cuesheet") {
+ if (ServiceManager.PlaybackController.Source != MySource) {
+ reLoad ();
+ //this.type="";
+ //EvtRowActivated (sender,a);
+ }
+ int track=(int) model.GetValue (iter,0);
+ int i=track-1;
+ seekSong (i);
+ index=i;
+ } else {
+ string name=model.GetValue (iter,2).ToString ();
+ string file=cwdir+"/"+name;
+ string cuef=file+".cue";
+ Console.WriteLine ("File="+file);
+ Console.WriteLine ("CueF="+cuef);
+ if (Directory.Exists (file)) {
+ Console.WriteLine ("Directory");
+ cwdir=file;
+ fill (store);
+ } else {
+ if (File.Exists (cuef)) {
+ Console.WriteLine ("CueSheet");
+ loadCueSheet(cuef,store);
+ }
+ }
+ }
+ }
+ }
+
+
+ public bool SetSource (ISource source) { return true; }
+ public void ResetSource () { }
+ public Gtk.Widget Widget { get { return box; } }
+ public ISource Source { get { return null; } }
+ }
+
+ }
+}
diff --git a/src/CueSheets/CueSheets.addin.xml b/src/CueSheets/CueSheets.addin.xml
new file mode 100644
index 0000000..9d52bc9
--- /dev/null
+++ b/src/CueSheets/CueSheets.addin.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Addin
+ id="Banshee.CueSheets"
+ version="1.0"
+ compatVersion="1.0"
+ copyright="Copyright © 2013 Hans Oesterholt. Licensed under the MIT X11 license."
+ name="CueSheet support for Banshee"
+ category="Community Extensions"
+ description="Support for playback of audio files with cuesheets"
+ author="Hans Oesterholt"
+ url="http://oesterholt.net"
+ defaultEnabled="true">
+
+ <Localizer type="Gettext" catalog="banshee-community-extensions" location="../../../share/locale"/>
+
+ <Dependencies>
+ <Addin id="Banshee.Services" version="1.0"/>
+ <Addin id="Banshee.ThickClient" version="1.0"/>
+ </Dependencies>
+
+ <!-- Extensions are loaded by Banshee via Mono.Addins by extending a
+ particular ExtensionPoint.
+
+ There is a very general ExtensionPoint called
+ /Banshee/ServiceManager/Service, and there are several much more
+ specific ones. A Service extension will be instantiated when Banshee
+ starts, and can do whatever it wants with the Banshee API. Where an
+ ImportSource extension will be loaded when the user opens the Import
+ Dialog.
+
+ Here is an example of how to define an extension point:
+
+ <Extension path="ExtensionPointPath">
+ <ExtensionPointType class="Banshee.CueSheets.CueSheetsExtensionPointType"/>
+ </Extension>
+
+ An extension must have one or more such definitions.
+
+ Here are the ExtensionPoints in Banshee:
+
+ Path: /Banshee/ServiceManager/Service
+ Type: Service
+ Desc: General purpose, run any code, instantiated at startup
+
+ Path: /Banshee/SourceManager/Source
+ Type: Source
+ Desc: Create a Source in the source list
+
+ Path: /Banshee/Library/ImportSource
+ Type: ImportSource
+ Desc: Add an entry to the Import Dialog dropdown.
+
+ Path: /Banshee/Gui/TrackEditor/NotebookPage
+ Type: TrackEditorPage
+ Desc: Add a tab ("page") to the Edit Track Information or Properties
+ dialogs.
+
+ Path: /Banshee/Gui/TrackEditor/Modifier
+ Type: Modifier
+ Desc: Defines an extension for the track editor that can modify it in
+ some way.
+
+ Path: /Banshee/ThickClient/ContextPane
+ Type: ContextPage
+ Desc: Defines a new GTK+ context page, for showing contextual
+ information beneath the main track source view.
+
+ There are quite a few other ExtensionPoints, but they are mostly related to
+ providing platform-specific backends for hardware integration and the like.
+ -->
+
+ <!-- Define a Service extension. This will instantiate the specified class on startup,
+ letting us do whatever we want.
+ <Extension path="/Banshee/ServiceManager/Service">
+ <Service class="Banshee.CueSheets.CueSheetsService"/>
+ </Extension>-->
+
+ <!-- Define a Source extension. This will instantiate a new Source object,
+ listed in the left-most Source TreeView. -->
+ <Extension path="/Banshee/SourceManager/Source">
+ <Source class="Banshee.CueSheets.CueSheetsSource"/>
+ </Extension>
+
+</Addin>
diff --git a/src/CueSheets/CueSheets.csproj b/src/CueSheets/CueSheets.csproj
new file mode 100644
index 0000000..81f6daa
--- /dev/null
+++ b/src/CueSheets/CueSheets.csproj
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <ProjectGuid>{}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <UseParentDirectoryAsNamespace>true</UseParentDirectoryAsNamespace>
+ <AssemblyName>Banshee.CueSheets</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <Optimize>true</Optimize>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ <RootNamespace>Banshee.CueSheets</RootNamespace>
+ <AssemblyOriginatorKeyFile>.</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <OutputPath>..\..\..\bin</OutputPath>
+ <CustomCommands>
+ <CustomCommands>
+ <Command type="Execute" command="make run" workingdir="${SolutionDir}" />
+ </CustomCommands>
+ </CustomCommands>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <OutputPath>..\..\..\bin</OutputPath>
+ <PlatformTarget>x86</PlatformTarget>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+ <Package>gtk-sharp-2.0</Package>
+ </Reference>
+ <Reference Include="Mono.Posix" />
+ <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+ <Package>gtk-sharp-2.0</Package>
+ </Reference>
+ <Reference Include="Mono.Cairo" />
+ <Reference Include="Mono.Addins">
+ <Package>mono-addins</Package>
+ </Reference>
+ <Reference Include="Hyena, Version=1.7.0.0, Culture=neutral">
+ <Package>banshee-hyena</Package>
+ </Reference>
+ <Reference Include="Hyena.Data.Sqlite, Version=1.7.0.0, Culture=neutral">
+ <Package>banshee-hyena-data-sqlite</Package>
+ </Reference>
+ <Reference Include="Hyena.Gui, Version=1.7.0.0, Culture=neutral">
+ <Package>banshee-hyena-gui</Package>
+ </Reference>
+ <Reference Include="System.Core" />
+ <Reference Include="Banshee.Services">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.Services.dll</HintPath>
+ </Reference>
+ <Reference Include="Banshee.CollectionIndexer">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.CollectionIndexer.dll</HintPath>
+ </Reference>
+ <Reference Include="Banshee.Core">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Banshee.ThickClient">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.ThickClient.dll</HintPath>
+ </Reference>
+ <Reference Include="Banshee.WebBrowser">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.WebBrowser.dll</HintPath>
+ </Reference>
+ <Reference Include="Banshee.Widgets">
+ <HintPath>..\..\..\..\..\..\usr\local\banshee\lib\banshee\Banshee.Widgets.dll</HintPath>
+ </Reference>
+ <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+ <Private>False</Private>
+ <Package>glib-sharp-2.0</Package>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="CueSheets.addin.xml">
+ <LogicalName>CueSheets.addin.xml</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Banshee.CueSheets\CueSheetsSource.cs" />
+ <Compile Include="Banshee.CueSheets\CueSheet.cs" />
+ <Compile Include="Banshee.CueSheets\CueSheetEntry.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <MonoDevelop>
+ <Properties>
+ <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="Makefile.am">
+ <BuildFilesVar Sync="true" Name="SOURCES" />
+ <DeployFilesVar />
+ <ResourcesVar Sync="true" Name="RESOURCES" />
+ <OthersVar />
+ <GacRefVar />
+ <AsmRefVar />
+ <ProjectRefVar />
+ </MonoDevelop.Autotools.MakefileInfo>
+ </Properties>
+ </MonoDevelop>
+ </ProjectExtensions>
+</Project>
diff --git a/src/CueSheets/Makefile.am b/src/CueSheets/Makefile.am
new file mode 100644
index 0000000..bc4e196
--- /dev/null
+++ b/src/CueSheets/Makefile.am
@@ -0,0 +1,11 @@
+ASSEMBLY = Banshee.CueSheets
+LINK = $(BANSHEE_LIBS)
+
+SOURCES = \
+ Banshee.CueSheets/CueSheet.cs \
+ Banshee.CueSheets/CueSheetEntry.cs \
+ Banshee.CueSheets/CueSheetsSource.cs
+
+RESOURCES = CueSheets.addin.xml
+
+include $(top_srcdir)/build/build.mk
diff --git a/src/CueSheets/ThemeIcons/128x128/categories/cueplay.png b/src/CueSheets/ThemeIcons/128x128/categories/cueplay.png
new file mode 100644
index 0000000..e41c0ab
--- /dev/null
+++ b/src/CueSheets/ThemeIcons/128x128/categories/cueplay.png
Binary files differ
diff --git a/src/CueSheets/ThemeIcons/22x22/categories/cueplay.png b/src/CueSheets/ThemeIcons/22x22/categories/cueplay.png
new file mode 100644
index 0000000..0597905
--- /dev/null
+++ b/src/CueSheets/ThemeIcons/22x22/categories/cueplay.png
Binary files differ
diff --git a/src/CueSheets/ThemeIcons/32x32/categories/cueplay.png b/src/CueSheets/ThemeIcons/32x32/categories/cueplay.png
new file mode 100644
index 0000000..a4b470a
--- /dev/null
+++ b/src/CueSheets/ThemeIcons/32x32/categories/cueplay.png
Binary files differ
diff --git a/src/CueSheets/ThemeIcons/48x48/categories/cueplay.png b/src/CueSheets/ThemeIcons/48x48/categories/cueplay.png
new file mode 100644
index 0000000..ae76eb8
--- /dev/null
+++ b/src/CueSheets/ThemeIcons/48x48/categories/cueplay.png
Binary files differ
diff --git a/src/CueSheets/ThemeIcons/64x64/categories/cueplay.png b/src/CueSheets/ThemeIcons/64x64/categories/cueplay.png
new file mode 100644
index 0000000..b79a3e0
--- /dev/null
+++ b/src/CueSheets/ThemeIcons/64x64/categories/cueplay.png
Binary files differ
diff --git a/src/Makefile.am b/src/Makefile.am
index e80fff0..dbdee7e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,5 @@
SUBDIRS = \
+ CueSheets \
AlarmClock \
AlbumArtWriter \
Ampache \