Skip to content

Commit 926f818

Browse files
authored
Support subfolders in local song storage (#42)
This change allows subfolders in the local song storage. It changes the song list to work recursively and also allows to use e.g. "Existing Folder/Song name" when saving a new song. Otherwise this does not really advertise the subfolder possibility, existing subfolders can be used, but there is no special support for them in the UI. - Support subfolders in local song storage - Support saving into existing local subfolders
1 parent 6f5abd7 commit 926f818

File tree

4 files changed

+45
-20
lines changed

4 files changed

+45
-20
lines changed

WordsLive.Core/Songs/Storage/LocalSongStorage.cs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,16 @@ public override IEnumerable<SongData> All()
5353
// TODO: implement caching
5454
SongData data;
5555

56-
foreach (string file in Directory.GetFiles(directory))
56+
foreach (string file in Directory.EnumerateFiles(directory, "*.*", SearchOption.AllDirectories))
5757
{
5858
data = null;
5959

6060
try
6161
{
62-
var song = new Song(new Uri("song:///" + Path.GetFileName(file)), new SongUriResolver(this));
62+
var relativePath = new Uri(directory + Path.DirectorySeparatorChar)
63+
.MakeRelativeUri(new Uri(file))
64+
.ToString();
65+
var song = new Song(new Uri("song:///" + relativePath), new SongUriResolver(this));
6366
data = SongData.Create(song);
6467
}
6568
catch { }
@@ -84,7 +87,7 @@ public override Task<IEnumerable<SongData>> AllAsync()
8487
/// <exception cref="FileNotFoundException">The resource was not found.</exception>
8588
public override SongStorageEntry Get(string name)
8689
{
87-
if (name.Contains("\\") || name.Contains("/"))
90+
if (Path.IsPathRooted(name))
8891
throw new ArgumentException("Song filename must not contain a full path.");
8992

9093
string fullPath = Path.Combine(directory, name);
@@ -125,25 +128,41 @@ public override bool Exists(string name)
125128
return File.Exists(Path.Combine(directory, name));
126129
}
127130

131+
public override bool IsValidName(string name)
132+
{
133+
if (string.IsNullOrEmpty(name) || name.IndexOfAny(Path.GetInvalidPathChars()) != -1)
134+
return false;
135+
136+
if (Path.IsPathRooted(name))
137+
return false;
138+
139+
var fileName = Path.GetFileName(name);
140+
if (string.IsNullOrEmpty(fileName) || fileName.IndexOfAny(Path.GetInvalidFileNameChars()) != -1)
141+
return false;
142+
143+
var subdirectoryName = Path.GetDirectoryName(name);
144+
if (!Directory.Exists(Path.Combine(directory, subdirectoryName)))
145+
return false;
146+
147+
var fullPath = Path.GetFullPath(Path.Combine(directory, name));
148+
if (!fullPath.StartsWith(directory + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
149+
return false;
150+
151+
return true;
152+
}
153+
128154
public override Uri TryRewriteUri(Uri uri)
129155
{
130156
if (uri.IsFile)
131157
{
132158
// rewrite local song URIs to song:// schema
133-
var store = DataManager.Songs as LocalSongStorage;
134-
try
135-
{
136-
FileInfo fi1 = new FileInfo(Uri.UnescapeDataString(uri.AbsolutePath));
137-
var name = Uri.UnescapeDataString(uri.Segments[uri.Segments.Length - 1]);
138-
var fi2 = store.GetLocal(name);
139-
if (fi1.Exists && fi2.Exists && fi1.FullName == fi2.FullName)
140-
{
141-
return new Uri("song:///" + name);
142-
}
143-
}
144-
catch (FileNotFoundException)
159+
var filePath = Path.GetFullPath(Uri.UnescapeDataString(uri.LocalPath));
160+
var rootPath = Path.GetFullPath(directory) + Path.DirectorySeparatorChar;
161+
162+
if (filePath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase))
145163
{
146-
return uri;
164+
var relativePath = filePath.Substring(rootPath.Length).Replace(Path.DirectorySeparatorChar, '/');
165+
return new Uri("song:///" + relativePath);
147166
}
148167
}
149168

WordsLive.Core/Songs/Storage/SongData.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
*/
1818

1919
using System;
20-
using System.IO;
2120
using System.Linq;
2221
using System.Text.RegularExpressions;
2322
using Newtonsoft.Json;
@@ -144,7 +143,7 @@ public static SongData Create(Song song)
144143
return new SongData
145144
{
146145
Title = song.Title,
147-
Filename = Path.GetFileName(Uri.UnescapeDataString(song.Uri.Segments.Last())),
146+
Filename = Uri.UnescapeDataString(String.Join("", song.Uri.Segments.Skip(1))),
148147
Text = song.TextWithoutChords,
149148
Translation = song.TranslationWithoutChords,
150149
Copyright = String.Join(" ", song.Copyright.Split('\n').Select(line => line.Trim())),

WordsLive.Core/Songs/Storage/SongStorage.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ public virtual int Count()
112112

113113
public abstract bool Exists(string name);
114114

115+
/// <summary>
116+
/// Check if the given name of the song is allowed (independent of whether it already exists
117+
/// or not; checks the general format and checks especially for invalid characters).
118+
/// </summary>
119+
/// <param name="name">The name of the song.</param>
120+
/// <returns>True if the song name can be used for saving a song.</returns>
121+
public abstract bool IsValidName(string name);
122+
115123
//public Song Read(string name, ISongReader reader)
116124
//{
117125
// throw new NotImplementedException();

WordsLive/Editor/SaveFilenameDialog.xaml.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
*/
1818

1919
using System.ComponentModel;
20-
using System.IO;
2120
using System.Windows;
2221
using WordsLive.Core;
2322
using WordsLive.Resources;
@@ -103,7 +102,7 @@ public string this[string name]
103102
switch (name)
104103
{
105104
case "FilenameWithoutExtension":
106-
if (string.IsNullOrEmpty(this.filename) || this.filename.IndexOfAny(Path.GetInvalidFileNameChars()) != -1)
105+
if (!DataManager.Songs.IsValidName(this.filename))
107106
return Resource.sfInvalidFilename;
108107

109108
break;

0 commit comments

Comments
 (0)