From a9aeaedaf4a8c728e93696381a5b738e98d2b82e Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sun, 13 Aug 2023 17:46:04 +0200 Subject: [PATCH] Allow converting URLs and streams --- README.md | 1 + src/Db/MemoryArray.php | 2 ++ src/Db/MysqlArray.php | 2 ++ src/Db/PostgresArray.php | 2 ++ src/Db/PostgresArrayBytea.php | 2 ++ src/Db/RedisArray.php | 2 ++ src/Ogg.php | 48 ++++++++++++++++++++++++----------- 7 files changed, 44 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 913d29f81..d4b6a919a 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,7 @@ Want to add your own open-source project to this list? [Click here!](https://doc * Dismiss or approve a chat join request related to a specific chat or channel: messages.hideChatJoinRequest * Dismiss or approve all join requests related to a specific chat or channel: messages.hideAllChatJoinRequests * Download file to amphp/http-server response: downloadToResponse + * Download file to an amphp stream, returning it: downloadToReturnedStream * Download file to browser: downloadToBrowser * Download file to callable: downloadToCallable * Download file to directory: downloadToDir diff --git a/src/Db/MemoryArray.php b/src/Db/MemoryArray.php index b858c5a0e..bdd4bd378 100644 --- a/src/Db/MemoryArray.php +++ b/src/Db/MemoryArray.php @@ -121,3 +121,5 @@ final class MemoryArray extends ArrayIterator implements DbArray return $this; } } + +class_alias(MemoryArray::class, '\\danog\\MadelineProto\\Db\\NullCache\\MemoryArray'); \ No newline at end of file diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index 419cfce7b..54718f625 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -142,3 +142,5 @@ final class MysqlArray extends SqlArray "); } } + +class_alias(MysqlArray::class, '\\danog\\MadelineProto\\Db\\NullCache\\MysqlArray'); \ No newline at end of file diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index b4862b6fb..4c9d61365 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -109,3 +109,5 @@ final class PostgresArray extends PostgresArrayBytea "); } } + +class_alias(PostgresArray::class, '\\danog\\MadelineProto\\Db\\NullCache\\PostgresArray'); \ No newline at end of file diff --git a/src/Db/PostgresArrayBytea.php b/src/Db/PostgresArrayBytea.php index e01e55f25..739cd8dd9 100644 --- a/src/Db/PostgresArrayBytea.php +++ b/src/Db/PostgresArrayBytea.php @@ -127,3 +127,5 @@ class PostgresArrayBytea extends SqlArray "); } } + +class_alias(PostgresArrayBytea::class, '\\danog\\MadelineProto\\Db\\NullCache\\PostgresArrayBytea'); diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index 994fd0e7c..7d953d50a 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -155,3 +155,5 @@ final class RedisArray extends DriverArray } } } + +class_alias(RedisArray::class, '\\danog\\MadelineProto\\Db\\NullCache\\RedisArray'); diff --git a/src/Ogg.php b/src/Ogg.php index b1ecc4b0a..716e3eeb9 100644 --- a/src/Ogg.php +++ b/src/Ogg.php @@ -19,10 +19,15 @@ declare(strict_types=1); namespace danog\MadelineProto; use Amp\ByteStream\ReadableStream; -use Amp\File\Whence; +use Amp\ByteStream\WritableStream; +use Amp\Http\Client\HttpClientBuilder; +use Amp\Http\Client\Request; use AssertionError; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\BufferInterface; +use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream; +use danog\MadelineProto\Stream\ConnectionContext; +use danog\MadelineProto\Stream\Transport\PremadeStream; use FFI; use FFI\CData; use Webmozart\Assert\Assert; @@ -498,7 +503,7 @@ final class Ogg public static function convert( LocalFile|RemoteUrl|ReadableStream $wavIn, - string $oggOut + LocalFile|WritableStream $oggOut ): void { $opus = FFI::cdef(' typedef struct OpusEncoder OpusEncoder; @@ -542,23 +547,33 @@ final class Ogg $checkErr($opus->opus_encoder_ctl($encoder, self::OPUS_SET_BANDWIDTH_REQUEST, self::OPUS_BANDWIDTH_FULLBAND)); $checkErr($opus->opus_encoder_ctl($encoder, self::OPUS_SET_BITRATE_REQUEST, 130*1000)); - $in = openFile($wavIn, 'r'); - Assert::eq($in->read(length: 4), 'RIFF', "A .wav file must be provided!"); - $totalLength = \unpack('V', $in->read(length: 4))[1]; - Assert::eq($in->read(length: 4), 'WAVE'); + $in = $wavIn instanceof LocalFile + ? openFile($wavIn->file, 'r') + : ( + $wavIn instanceof RemoteUrl + ? HttpClientBuilder::buildDefault()->request(new Request($wavIn->url))->getBody() + : $wavIn + ); + + $ctx = (new ConnectionContext())->addStream(PremadeStream::class, $in)->addStream(SimpleBufferedRawStream::class); + /** @var SimpleBufferedRawStream */ + $in = $ctx->getStream(); + Assert::eq($in->bufferRead(length: 4), 'RIFF', "A .wav file must be provided!"); + $totalLength = \unpack('V', $in->bufferRead(length: 4))[1]; + Assert::eq($in->bufferRead(length: 4), 'WAVE'); do { - $type = $in->read(length: 4); - $length = \unpack('V', $in->read(length: 4))[1]; + $type = $in->bufferRead(length: 4); + $length = \unpack('V', $in->bufferRead(length: 4))[1]; if ($type === 'fmt ') { Assert::eq($length, 16); - $contents = $in->read(length: $length + ($length % 2)); + $contents = $in->bufferRead(length: $length + ($length % 2)); $header = \unpack('vaudioFormat/vchannels/VsampleRate/VbyteRate/vblockAlign/vbitsPerSample', $contents); Assert::eq($header['audioFormat'], 1); Assert::eq($header['sampleRate'], 48000); } elseif ($type === 'data') { break; } else { - $in->seek($length, Whence::Current); + $in->bufferRead($length); } } while (true); @@ -566,7 +581,9 @@ final class Ogg $chunkSize = (int) ($sampleCount * $header['channels'] * ($header['bitsPerSample'] >> 3)); $shift = (int) \log($header['channels'] * ($header['bitsPerSample'] >> 3), 2); - $out = openFile($oggOut, 'w'); + $out = $oggOut instanceof LocalFile + ? openFile($oggOut->file, 'w') + : $oggOut; $writePage = function (int $header_type_flag, int $granule, int $streamId, int &$streamSeqno, string $packet) use ($out): void { Assert::true(\strlen($packet) < 65025); @@ -638,19 +655,20 @@ final class Ogg $granule = 0; $buf = FFI::cast(FFI::type('char*'), FFI::addr($opus->new('char[1024]'))); - while (!$in->eof()) { - $chunk = \str_pad($in->read(length: $chunkSize), $chunkSize, "\0"); + do { + $chunkOrig = $in->bufferRead(length: $chunkSize); + $chunk = \str_pad($chunkOrig, $chunkSize, "\0"); $granuleDiff = \strlen($chunk) >> $shift; $len = $opus->opus_encode($encoder, $chunk, $granuleDiff, $buf, 1024); $checkErr($len); $writePage( - $in->eof() ? self::EOS : 0, + \strlen($chunk) !== \strlen($chunkOrig) ? self::EOS : 0, $granule += $granuleDiff, $streamId, $seqno, FFI::string($buf, $len) ); - } + } while (\strlen($chunk) === \strlen($chunkOrig)); $opus->opus_encoder_destroy($encoder); unset($buf, $encoder, $opus);