def test_SimpleConvertTask_can_keep_or_remove_album_art(tmp_path): """SimpleConvertTask can convert an audio file""" src = tmp_path.joinpath("sine.flac") mp3_art = tmp_path.joinpath("sine_art.mp3") mp3_noart = tmp_path.joinpath("sine_noart.mp3") ogg_art = tmp_path.joinpath("sine_art.ogg") ogg_noart = tmp_path.joinpath("sine_noart.ogg") sound = generators.Sine(440).to_audio_segment() sound.export(src, format="flac") # setup a source flac file with a cover image image_file = _utils.get_project_root().joinpath("tests/data/cover.jpg") with open(image_file, 'rb') as f: cover = f.read() cover = mediafile.Image(data=cover, desc=u'album cover', type=mediafile.ImageType.front) f = MediaFile(src) f.images = [cover] f.save() # by default, the converters preserve the album art # .. for PydubConverter tasks.SimpleConvertTask(src, mp3_art, converter=converters.PydubConverter()).start() g = MediaFile(mp3_art) assert f.images[0].data == cover.data assert f.images[0].mime_type == 'image/jpeg' assert f.images[0].data == g.images[0].data # ... for PydubConverter tasks.SimpleConvertTask(src, ogg_art, converter=converters.PydubConverter()).start() g = MediaFile(ogg_art) assert f.images[0].data == cover.data assert f.images[0].mime_type == 'image/jpeg' assert f.images[0].data == g.images[0].data # remove_art=True removes art # ... for PydubConverter tasks.SimpleConvertTask( src, mp3_noart, converter=converters.PydubConverter(remove_art=True)).start() g = MediaFile(mp3_noart) assert f.images[0].data == cover.data assert g.images == [] # remove_art=True removes art # ... for PydubConverter tasks.SimpleConvertTask( src, ogg_noart, converter=converters.PydubConverter(remove_art=True)).start() g = MediaFile(ogg_noart) assert f.images[0].data == cover.data assert g.images == []
def test_SimpleConvertTask_passes_on_params(tmp_path): """ConvertTask can convert an audio file in a two-step process""" src = tmp_path.joinpath("sine.flac") dst_lq = tmp_path.joinpath("sine-lq.mp3") dst_hq = tmp_path.joinpath("sine-hq.mp3") sound = generators.Sine(440).to_audio_segment() sound.export(src, format="flac") tasks.SimpleConvertTask( src, dst_lq, converter=converters.PydubConverter(parameters=['-q:a', '9'])).start() assert dst_lq.exists() tasks.SimpleConvertTask( src, dst_hq, converter=converters.PydubConverter(parameters=['-q:a', '0'])).start() assert dst_hq.exists() assert src.exists() assert MediaFile(dst_lq).bitrate < MediaFile(dst_hq).bitrate
def test_SimpleConvertTask(tmp_path): """SimpleConvertTask can convert an audio file""" src = tmp_path.joinpath("sine.flac") dst = tmp_path.joinpath("sine.mp3") sound = generators.Sine(440).to_audio_segment() sound.export(src, format="flac") tsk = tasks.SimpleConvertTask(src, dst, converter=converters.PydubConverter()) tsk.start() assert src.exists() assert dst.exists()
def test_TaskQueue_can_run_convert_tasks(tmp_path): """Ensure all TaskQueue transfer and convert processes are closed after the queue finishes processing all tasks""" # test this on a ConvertTask because that launches additional processes that we also want to ensure are shut down sound = generators.Sine(440).to_audio_segment() src = tmp_path.joinpath("sine.flac") dst = tmp_path.joinpath("sine.mp3") sound.export(src, format="flac") q = tasks.TaskQueue(tmp_path.joinpath("qop.db")) q.put(tasks.ConvertTask(src, dst, converter=converters.PydubConverter())) q.start() wait_for_queue(q) assert src.exists() assert dst.exists() assert q.n_active == 0 assert q.active_processes() == 0
def test_ConvertTask(tmp_path): """ConvertTask can convert an audio file in a two-step process""" src = tmp_path.joinpath("sine.flac") dst = tmp_path.joinpath("sine.mp3") sound = generators.Sine(440).to_audio_segment() sound.export(src, format="flac") tsk = tasks.ConvertTask(src, dst, converter=converters.PydubConverter(), tempdir=tmp_path) tsk.start() assert src.exists() assert not dst.exists() # mock `oid` that is used to match a task to its follow_up_task under production conditions. oid fulfils no function # if the follow_up_task is not executed by a TaskQueue. tsk.oid = 1 tsk.spawn().start() assert src.exists() assert dst.exists()
def handle_copy_convert_move(args, client) -> Dict: sources = args.paths[:-1] dst_dir = Path(args.paths[-1]).resolve() is_queue_active = client.is_queue_active() assert isinstance(dst_dir, Path) assert len(sources) > 0 assert sources != dst_dir # for use by `qop re` args_cache = Path( appdirs.user_cache_dir('qop')).joinpath('last_args.pickle') if args_cache.exists(): args_cache.unlink() with open(args_cache, 'wb') as f: args.parser = None pickle.dump(args, f, pickle.HIGHEST_PROTOCOL) # setup scanner if args.include is not None: scanner = scanners.IncludeScanner(args.include) elif args.exclude is not None: scanner = scanners.ExcludeScanner(args.exclude) elif args.mode == "convert": scanner = scanners.Scanner() else: scanner = scanners.PassScanner() # setup converter (if necessary) if args.mode == "convert": conv = converters.PydubConverter(remove_art=args.remove_art, parameters=args.parameters) # TODO conv_copy = converters.CopyConverter(remove_art=args.remove_art) if args.convert_only is not None: conv_mode = "include" conv_exts = ["." + e for e in args.convert_only] elif args.convert_not is not None: conv_mode = "exclude" conv_exts = ["." + e for e in args.convert_not] elif args.convert_none: conv_mode = "none" conv_exts = None else: conv_mode = "all" conv_exts = None else: conv_mode = None conv_exts = None conv = None conv_copy = None for source in sources: root = Path(source).resolve().parent children = scanner.scan(source) for src in children: lg.debug(f"inserting {src}") src = Path(src).resolve() dst = Path(dst_dir).resolve().joinpath(src.relative_to(root)) # setup convert task if args.mode == "convert": if conv_mode == "all": dst = dst.with_suffix("." + conv.ext) tsk = tasks.ConvertTask(src=src, dst=dst, converter=conv) elif conv_mode == "include" and src.suffix in conv_exts: dst = dst.with_suffix("." + conv.ext) tsk = tasks.ConvertTask(src=src, dst=dst, converter=conv) elif conv_mode == "exclude" and src.suffix not in conv_exts: dst = dst.with_suffix("." + conv.ext) tsk = tasks.ConvertTask(src=src, dst=dst, converter=conv) elif args.remove_art: tsk = tasks.SimpleConvertTask(src=src, dst=dst, converter=conv_copy) else: tsk = tasks.CopyTask(src=src, dst=dst) elif args.mode == "move": tsk = tasks.MoveTask(src=src, dst=dst) elif args.mode == "copy": tsk = tasks.CopyTask(src=src, dst=dst) else: raise ValueError rsp = client.send_command(Command.QUEUE_PUT, payload=tsk) if not is_queue_active and not args.enqueue_only: client.send_command(Command.QUEUE_START) is_queue_active = True if args.verbose: print(format_response(rsp)) print(format_response_summary(client.stats), end="\r") if not args.enqueue_only: client.send_command(Command.QUEUE_START) return {"status": Status.OK, "msg": "enqueue finished"}