diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx
index 5b1141a40..46582bf4b 100644
--- a/src/SongUpdate.cxx
+++ b/src/SongUpdate.cxx
@@ -96,12 +96,8 @@ Song::UpdateFile(Storage &storage)
 				     full_tag_handler, &tag_builder))
 			return false;
 	} else {
-		if (!tag_file_scan(path_fs, full_tag_handler, &tag_builder))
+		if (!tag_file_scan(path_fs, tag_builder))
 			return false;
-
-		if (tag_builder.IsEmpty())
-			ScanGenericTags(path_fs, full_tag_handler,
-					&tag_builder);
 	}
 
 	mtime = info.mtime;
@@ -149,12 +145,9 @@ DetachedSong::LoadFile(Path path)
 		return false;
 
 	TagBuilder tag_builder;
-	if (!tag_file_scan(path, full_tag_handler, &tag_builder))
+	if (!tag_file_scan(path, tag_builder))
 		return false;
 
-	if (tag_builder.IsEmpty())
-		ScanGenericTags(path, full_tag_handler, &tag_builder);
-
 	mtime = fi.GetModificationTime();
 	tag_builder.Commit(tag);
 	return true;
diff --git a/src/TagFile.cxx b/src/TagFile.cxx
index 3d076ca0d..593c1fcb2 100644
--- a/src/TagFile.cxx
+++ b/src/TagFile.cxx
@@ -19,6 +19,9 @@
 
 #include "config.h"
 #include "TagFile.hxx"
+#include "tag/Generic.hxx"
+#include "tag/TagHandler.hxx"
+#include "tag/TagBuilder.hxx"
 #include "fs/Path.hxx"
 #include "util/UriUtil.hxx"
 #include "util/Error.hxx"
@@ -94,3 +97,15 @@ tag_file_scan(Path path_fs, const TagHandler &handler, void *handler_ctx)
 			return tfs.Scan(plugin);
 		});
 }
+
+bool
+tag_file_scan(Path path, TagBuilder &builder)
+{
+	if (!tag_file_scan(path, full_tag_handler, &builder))
+		return false;
+
+	if (builder.IsEmpty())
+		ScanGenericTags(path, full_tag_handler, &builder);
+
+	return true;
+}
diff --git a/src/TagFile.hxx b/src/TagFile.hxx
index 0813f89e0..7facea8d1 100644
--- a/src/TagFile.hxx
+++ b/src/TagFile.hxx
@@ -24,6 +24,7 @@
 
 class Path;
 struct TagHandler;
+class TagBuilder;
 
 /**
  * Scan the tags of a song file.  Invokes matching decoder plugins,
@@ -35,4 +36,15 @@ struct TagHandler;
 bool
 tag_file_scan(Path path, const TagHandler &handler, void *handler_ctx);
 
+/**
+ * Scan the tags of a song file.  Invokes matching decoder plugins,
+ * and falls back to generic scanners (APE and ID3) if no tags were
+ * found (but the file was recognized).
+ *
+ * @return true if the file was recognized (even if no metadata was
+ * found)
+ */
+bool
+tag_file_scan(Path path, TagBuilder &builder);
+
 #endif