"""All constants for Music Assistant."""
-__version__ = "0.0.78"
+__version__ = "0.0.79"
REQUIRED_PYTHON_VER = "3.7"
# configuration keys/attributes
right_albums = right_track.albums or [right_track.album]
if not (
compare_albums(left_albums, right_albums)
- or abs(left_track.duration - right_track.duration) <= 5
+ or abs(left_track.duration - right_track.duration) <= 3
):
return False
# 100% match, all criteria passed
# workaround that is compatible with uvloop
def __init__(
- self,
- process_args: List,
- enable_write: bool = False,
- enable_shell=False,
+ self, process_args: List, enable_write: bool = False, enable_shell=False
):
"""Initialize."""
self._proc = subprocess.Popen(
# prevent subprocess deadlocking, send terminate and read remaining bytes
await self.loop.run_in_executor(None, self._proc.terminate)
await self.loop.run_in_executor(None, self.__read)
- LOGGER.debug("process finished")
del self._proc
+ return exc_type not in (GeneratorExit, asyncio.CancelledError)
async def iterate_chunks(
self, chunksize: int = DEFAULT_CHUNKSIZE
"""Yield chunks from the process stdout. Generator."""
while True:
chunk = await self.read(chunksize)
- if not chunk:
- break
yield chunk
+ if len(chunk) < chunksize:
+ # last chunk
+ break
async def read(self, chunksize: int = DEFAULT_CHUNKSIZE) -> bytes:
"""Read x bytes from the process stdout."""
"""Write bytes to process and read back results."""
if self._cancelled:
raise asyncio.CancelledError()
- stdout, _ = await self.loop.run_in_executor(
- None, self._proc.communicate, input_data
- )
- return stdout
+ return await self.loop.run_in_executor(None, self._proc.communicate, input_data)
class AsyncProcessBroken:
full_track = media_item
else:
full_track = await self.async_get_track(
- media_item.item_id, media_item.provider, refresh=True
+ media_item.item_id, media_item.provider
)
# sort by quality and check track availability
for prov_media in sorted(
output_format: SoxOutputFormat = SoxOutputFormat.FLAC,
resample: Optional[int] = None,
gain_db_adjust: Optional[float] = None,
- chunk_size: int = 1000000,
+ chunk_size: int = 4000000,
) -> AsyncGenerator[Tuple[bool, bytes], None]:
"""Get the sox manipulated audio data for the given streamdetails."""
# collect all args for sox
"""Forward audio chunks to sox stdin."""
# feed audio data into sox stdin for processing
async for chunk in self.async_get_media_stream(streamdetails):
- if not chunk:
- break
await sox_proc.write(chunk)
await sox_proc.write_eof()
fill_buffer_task = self.mass.loop.create_task(fill_buffer())
- await asyncio.sleep(1)
# yield chunks from stdout
# we keep 1 chunk behind to detect end of stream properly
prev_chunk = b""
async for chunk in self.async_queue_stream_pcm(
player_id, sample_rate, 32
):
- if not chunk:
- break
await sox_proc.write(chunk)
fill_buffer_task = self.mass.loop.create_task(fill_buffer())