@@ -236,3 +236,77 @@ describe('normalizeAudioFile', () => {
236236 expect ( args [ iIndex + 1 ] ) . toBe ( TRACK . file_path ) ;
237237 } ) ;
238238} ) ;
239+
240+ // ── Artist detection from filename ────────────────────────────────────────────
241+
242+ import { ffprobe } from '../audio/ffmpeg.js' ;
243+
244+ describe ( 'importAudioFile — artist detection from filename' , ( ) => {
245+ it ( 'uses ID3 artist tag when present, ignoring filename' , async ( ) => {
246+ ffprobe . mockResolvedValueOnce ( {
247+ format : {
248+ format_name : 'mp3' ,
249+ duration : '180.0' ,
250+ bit_rate : '320000' ,
251+ tags : { title : 'My Song' , artist : 'Tag Artist' } ,
252+ } ,
253+ streams : [ ] ,
254+ } ) ;
255+
256+ await importAudioFile ( '/music/Someone Else - My Song.mp3' ) ;
257+
258+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . artist ) . toBe ( 'Tag Artist' ) ;
259+ } ) ;
260+
261+ it ( 'parses artist from "Artist - Title" filename when artist tag is missing' , async ( ) => {
262+ ffprobe . mockResolvedValueOnce ( {
263+ format : {
264+ format_name : 'mp3' ,
265+ duration : '180.0' ,
266+ bit_rate : '320000' ,
267+ tags : { title : '' , artist : '' } ,
268+ } ,
269+ streams : [ ] ,
270+ } ) ;
271+
272+ await importAudioFile ( '/music/Deadmau5 - Some Chords.mp3' ) ;
273+
274+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . artist ) . toBe ( 'Deadmau5' ) ;
275+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . title ) . toBe ( 'Some Chords' ) ;
276+ } ) ;
277+
278+ it ( 'leaves artist empty when no tag and no dash in filename' , async ( ) => {
279+ ffprobe . mockResolvedValueOnce ( {
280+ format : {
281+ format_name : 'mp3' ,
282+ duration : '180.0' ,
283+ bit_rate : '320000' ,
284+ tags : { title : '' , artist : '' } ,
285+ } ,
286+ streams : [ ] ,
287+ } ) ;
288+
289+ await importAudioFile ( '/music/untitled_track.mp3' ) ;
290+
291+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . artist ) . toBe ( '' ) ;
292+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . title ) . toBe ( 'untitled_track' ) ;
293+ } ) ;
294+
295+ it ( 'keeps ID3 title when artist is missing but filename has dash' , async ( ) => {
296+ ffprobe . mockResolvedValueOnce ( {
297+ format : {
298+ format_name : 'mp3' ,
299+ duration : '180.0' ,
300+ bit_rate : '320000' ,
301+ tags : { title : 'ID3 Title' , artist : '' } ,
302+ } ,
303+ streams : [ ] ,
304+ } ) ;
305+
306+ await importAudioFile ( '/music/Filename Artist - Other Title.mp3' ) ;
307+
308+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . artist ) . toBe ( 'Filename Artist' ) ;
309+ // ID3 title wins over filename-derived title
310+ expect ( mockAddTrack . mock . calls [ 0 ] [ 0 ] . title ) . toBe ( 'ID3 Title' ) ;
311+ } ) ;
312+ } ) ;
0 commit comments