Change Directory

This commit is contained in:
kokarare1212
2021-02-25 08:07:17 +09:00
parent 01dae8ada4
commit 8daf68831e
133 changed files with 221 additions and 38 deletions

View File

@@ -0,0 +1,12 @@
from librespot.audio.GeneralWritableStream import GeneralWritableStream
class AudioFile(GeneralWritableStream):
def write_chunk(self, buffer: bytearray, chunk_index: int, cached: bool):
pass
def write_header(self, chunk_id: int, b: bytearray, cached: bool):
pass
def stream_error(self, chunk_index: int, code: int):
pass

View File

@@ -0,0 +1,12 @@
from __future__ import annotations
import typing
if typing.TYPE_CHECKING:
from librespot.core.Session import Session
class AudioFileStreaming:
cache_handler = None
def __init__(self, session: Session):
pass

View File

@@ -0,0 +1,146 @@
from __future__ import annotations
import queue
from librespot.audio.storage import AudioFile
from librespot.common import Utils
from librespot.core import PacketsReceiver, Session
from librespot.crypto import Packet
from librespot.standard import BytesInputStream, BytesOutputStream, Closeable, Runnable
import concurrent.futures
import logging
import threading
class ChannelManager(Closeable, PacketsReceiver.PacketsReceiver):
CHUNK_SIZE: int = 128 * 1024
_LOGGER: logging = logging.getLogger(__name__)
_channels: dict[int, Channel] = dict()
_seqHolder: int = 0
_seqHolderLock: threading.Condition = threading.Condition()
_executorService: concurrent.futures.ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor(
)
_session: Session = None
def __init__(self, session: Session):
self._session = session
def request_chunk(self, file_id: bytes, index: int, file: AudioFile):
start = int(index * self.CHUNK_SIZE / 4)
end = int((index + 1) * self.CHUNK_SIZE / 4)
channel = ChannelManager.Channel(self, file, index)
self._channels[channel.chunkId] = channel
out = BytesOutputStream()
out.write_short(channel.chunkId)
out.write_int(0x00000000)
out.write_int(0x00000000)
out.write_int(0x00004e20)
out.write_int(0x00030d40)
out.write(file_id)
out.write_int(start)
out.write_int(end)
self._session.send(Packet.Type.stream_chunk, out.buffer)
def dispatch(self, packet: Packet) -> None:
payload = BytesInputStream(packet.payload)
if packet.is_cmd(Packet.Type.stream_chunk_res):
chunk_id = payload.read_short()
channel = self._channels.get(chunk_id)
if channel is None:
self._LOGGER.warning(
"Couldn't find channel, id: {}, received: {}".format(
chunk_id, len(packet.payload)))
return
channel._add_to_queue(payload)
elif packet.is_cmd(Packet.Type.channel_error):
chunk_id = payload.read_short()
channel = self._channels.get(chunk_id)
if channel is None:
self._LOGGER.warning(
"Dropping channel error, id: {}, code: {}".format(
chunk_id, payload.read_short()))
return
channel.stream_error(payload.read_short())
else:
self._LOGGER.warning(
"Couldn't handle packet, cmd: {}, payload: {}".format(
packet.cmd, Utils.Utils.bytes_to_hex(packet.payload)))
def close(self) -> None:
self._executorService.shutdown()
class Channel:
_channelManager: ChannelManager
chunkId: int
_q: queue.Queue = queue.Queue()
_file: AudioFile
_chunkIndex: int
_buffer: BytesOutputStream = BytesOutputStream()
_header: bool = True
def __init__(self, channel_manager: ChannelManager, file: AudioFile,
chunk_index: int):
self._channelManager = channel_manager
self._file = file
self._chunkIndex = chunk_index
with self._channelManager._seqHolderLock:
self.chunkId = self._channelManager._seqHolder
self._channelManager._seqHolder += 1
self._channelManager._executorService.submit(
lambda: ChannelManager.Channel.Handler(self))
def _handle(self, payload: BytesInputStream) -> bool:
if len(payload.buffer) == 0:
if not self._header:
self._file.write_chunk(bytearray(payload.buffer),
self._chunkIndex, False)
return True
self._channelManager._LOGGER.debug(
"Received empty chunk, skipping.")
return False
if self._header:
length: int
while len(payload.buffer) > 0:
length = payload.read_short()
if not length > 0:
break
header_id = payload.read_byte()
header_data = payload.read(length - 1)
self._file.write_header(int.from_bytes(header_id, "big"),
bytearray(header_data), False)
self._header = False
else:
self._buffer.write(payload.read(len(payload.buffer)))
return False
def _add_to_queue(self, payload):
self._q.put(payload)
def stream_error(self, code: int) -> None:
self._file.stream_error(self._chunkIndex, code)
class Handler(Runnable):
_channel: ChannelManager.Channel = None
def __init__(self, channel: ChannelManager.Channel):
self._channel = channel
def run(self) -> None:
self._channel._channelManager._LOGGER.debug(
"ChannelManager.Handler is starting")
with self._channel._q.all_tasks_done:
self._channel._channelManager._channels.pop(
self._channel.chunkId)
self._channel._channelManager._LOGGER.debug(
"ChannelManager.Handler is shutting down")

View File

@@ -0,0 +1,3 @@
from librespot.audio.storage.AudioFile import AudioFile
from librespot.audio.storage.AudioFileStreaming import AudioFileStreaming
from librespot.audio.storage.ChannelManager import ChannelManager