diff --git a/app/src/main/java/de/qspool/clementineremote/backend/downloader/ClementineSongDownloader.java b/app/src/main/java/de/qspool/clementineremote/backend/downloader/ClementineSongDownloader.java index 9cdb9d67..2832f9a8 100644 --- a/app/src/main/java/de/qspool/clementineremote/backend/downloader/ClementineSongDownloader.java +++ b/app/src/main/java/de/qspool/clementineremote/backend/downloader/ClementineSongDownloader.java @@ -401,14 +401,25 @@ String buildRelativeDir(ResponseSongFileChunk chunk) { } private static void appendDir(StringBuilder sb, String name) { - String dir = Utilities.removeInvalidFileCharacters(name).trim(); + String dir = safeName(name).trim(); if (!dir.isEmpty()) { sb.append(dir).append('/'); } } + /** The song's file name, or its title if that leaves nothing. */ static String buildFileName(ResponseSongFileChunk chunk) { - return Utilities.removeInvalidFileCharacters(chunk.getSongMetadata().getFilename()); + String name = safeName(chunk.getSongMetadata().getFilename()); + return name.isEmpty() ? safeName(chunk.getSongMetadata().getTitle()) : name; + } + + /** + * [name] without the characters file names can't have. A name of only dots, such as "..", is + * dropped too, so no song is saved outside the download location. + */ + private static String safeName(String name) { + String safe = Utilities.removeInvalidFileCharacters(name); + return safe.trim().matches("\\.*") ? "" : safe; } public DownloadItem getItem() { diff --git a/app/src/test/java/de/qspool/clementineremote/backend/downloader/DownloadStorageTest.java b/app/src/test/java/de/qspool/clementineremote/backend/downloader/DownloadStorageTest.java index d721fe9a..d99d1afb 100644 --- a/app/src/test/java/de/qspool/clementineremote/backend/downloader/DownloadStorageTest.java +++ b/app/src/test/java/de/qspool/clementineremote/backend/downloader/DownloadStorageTest.java @@ -199,6 +199,21 @@ public void emptyTagsDoNotMakeEmptyFolders() { assertEquals("", downloader.buildRelativeDir(chunk("", "", ""))); } + @Test + public void savesNothingOutsideTheDownloadLocation() { + ClementineSongDownloader downloader = new ClementineSongDownloader(); + downloader.setCreateArtistDir(true); + downloader.setCreateAlbumDir(true); + downloader.setIsPlaylist(true, "..."); + downloader.setCreatePlaylistDir(true); + assertEquals("", downloader.buildRelativeDir(chunk("..", "", " .. "))); + + ResponseSongFileChunk chunk = ResponseSongFileChunk.newBuilder() + .setSongMetadata(SongMetadata.newBuilder().setFilename("..").setTitle("Aria")) + .build(); + assertEquals("Aria", ClementineSongDownloader.buildFileName(chunk)); + } + @Test public void unknownFileTypesAreSavedAsAudio() { assertEquals("audio/mpeg", MediaStoreDownloadStorage.mimeType("song"));