├── README.md ├── composer.json └── fileassistantbot.php /README.md: -------------------------------------------------------------------------------- 1 | # fileassistantbot 2 | Simple download link generator and URL uploader bot for Telegram - Based on MadelineProto 3 | 4 | Required PHP version: **>=5.6** 5 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "amphp/process": "^1.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /fileassistantbot.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | onUpdateNewMessage($update); 40 | } 41 | 42 | public function onUpdateNewMessage($update) 43 | { 44 | try { 45 | $files = yield Amp\File\scandir(FILES_PATH); 46 | echo json_encode($files); 47 | foreach ($files as $file) { 48 | $ctime = yield Amp\File\ctime(FILES_PATH.'/'.$file); 49 | echo(time() - $ctime).PHP_EOL.PHP_EOL.PHP_EOL.PHP_EOL.PHP_EOL; 50 | if (time() - $ctime > FILES_EXPIRE_TIME) { 51 | yield Amp\File\unlink(FILES_PATH.'/'.$file); 52 | } 53 | } 54 | } catch (Exception $e) { 55 | } 56 | if (isset($update['message']['out']) && $update['message']['out']) { 57 | return; 58 | } 59 | 60 | try { 61 | if (isset($update['message']['media']) && ($update['message']['media']['_'] == 'messageMediaPhoto' || $update['message']['media']['_'] == 'messageMediaDocument')) { 62 | $message_id = $update['message']['id']; 63 | $sent_message = yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Generating download link… 0%', 'reply_to_msg_id' => $message_id]); 64 | $time = time(); 65 | $last_progress = 0; 66 | $queue_id = $this->randomString().time(); 67 | $output_file_name = yield $this->download_to_dir($update, new \danog\MadelineProto\FileCallback( 68 | FILES_PATH, 69 | function ($progress) use ($update, $sent_message, &$last_progress, $queue_id) { 70 | $progress = round($progress); 71 | if ($progress > $last_progress + 4) { 72 | $last_progress = $progress; 73 | 74 | try { 75 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => 'Generating download link… '.$progress.'%'], ['queue' => $queue_id]); 76 | } catch (Exception $e) { 77 | } 78 | } 79 | } 80 | )); 81 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => 'Download link Generated in '.(time() - $time)." seconds!\n\n💾 ".basename($output_file_name)."\n\n📥 ".rtrim(WEBSERVER_BASE_URL, '/').'/'.str_replace(__DIR__.'/', '', str_replace(' ', '%20', $output_file_name))."\n\nThis link will be expired in 24 hours.", 'reply_to_msg_id' => $message_id], ['queue' => $queue_id]); 82 | } elseif (isset($update['message']['message'])) { 83 | $message_id = $update['message']['id']; 84 | $text = $update['message']['message']; 85 | $chat_id = $update['message']['from_id']; 86 | if ($text == '/start') { 87 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Hi! please send me any file url or file uploaded in Telegram and I will upload to Telegram as file or generate download link of that file.', 'reply_to_msg_id' => $message_id]); 88 | 89 | return; 90 | } 91 | if ($text == '/speedtest') { 92 | if (isset($this->latest_speedtest[$chat_id]) && time() - $this->latest_speedtest[$chat_id] < 3600) { 93 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'You can test speed once per hour.', 'reply_to_msg_id' => $message_id]); 94 | 95 | return; 96 | } 97 | $this->latest_speedtest[$chat_id] = time(); 98 | $sent_message = yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Testing download and upload speed…', 'reply_to_msg_id' => $message_id]); 99 | $process = new Amp\Process\Process('speedtest'); 100 | yield $process->start(); 101 | $output = yield Amp\ByteStream\buffer($process->getStdout()); 102 | if (preg_match_all('/(Down|Up)load:.*/', $output, $output)) { 103 | $result = ''; 104 | foreach ($output[0] as $line) { 105 | $result .= $line."\n"; 106 | } 107 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => $result]); 108 | } else { 109 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => 'Error while testing speed.']); 110 | } 111 | 112 | return; 113 | } 114 | $url = filter_var($text, FILTER_VALIDATE_URL); 115 | if ($url === false) { 116 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'URL format is incorrect. make sure your URL starts with either http:// or https://.', 'reply_to_msg_id' => $message_id]); 117 | 118 | return; 119 | } 120 | $filename = explode('|', $text); 121 | if (!empty($filename[1])) { 122 | $filename = $filename[1]; 123 | } else { 124 | $filename = basename($url); 125 | } 126 | if (empty($filename)) { 127 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Can you check your URL? I\'m unable to detect filename from the URL.', 'reply_to_msg_id' => $message_id]); 128 | 129 | return; 130 | } 131 | $filename_length = $filename; 132 | if ($filename_length > 60) { 133 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Your filename contains '.$filename_length.' characters. Maximum limit allowed in Telegram is 60 characters. Please shorten your filename and try again.', 'reply_to_msg_id' => $message_id]); 134 | 135 | return; 136 | } 137 | $client = new Amp\Artax\DefaultClient(); 138 | $promise = $client->request($url, [Amp\Artax\Client::OP_MAX_BODY_BYTES => (int) (1.5 * (1024 ** 3))]); 139 | $response = yield $promise; 140 | $headers = $response->getHeaders(); 141 | if (empty($headers['content-length'][0])) { 142 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Unable to obtain file size.', 'reply_to_msg_id' => $message_id]); 143 | 144 | return; 145 | } 146 | $filesize = $headers['content-length'][0]; 147 | if ($filesize > 1024 ** 3) { 148 | yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Your file should be snakker than 1 GB.', 'reply_to_msg_id' => $message_id]); 149 | 150 | return; 151 | } 152 | $sent_message = yield $this->messages->sendMessage(['peer' => $update, 'message' => 'Downloading file from URL…', 'reply_to_msg_id' => $message_id]); 153 | $filepath = FILES_PATH.'/'.time().rand().'_'.$filename; 154 | $file = yield Amp\File\open($filepath, 'w'); 155 | yield Amp\ByteStream\pipe($response->getBody(), $file); 156 | yield $file->close(); 157 | Amp\File\StatCache::clear($filepath); 158 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => "📤 Your request is in the queue. Do not send another request. Please be patient…\n🗂 File: ".$filename."\n🔗 URL: ".$url."\n💿 File Size: ".$this->formatBytes($filesize)."\n\n⌛ Upload progress: 0%"]); 159 | $time = time(); 160 | $last_progress = 0; 161 | $queue_id = $this->randomString().time(); 162 | yield $this->messages->sendMedia([ 163 | 'peer' => $update, 164 | 'media' => [ 165 | '_' => 'inputMediaUploadedDocument', 166 | 'file' => new \danog\MadelineProto\FileCallback($filepath, function ($progress) use ($update, $sent_message, &$last_progress, $filename, $filesize, $url, $queue_id) { 167 | $progress = round($progress); 168 | if ($progress > $last_progress + 4) { 169 | $last_progress = $progress; 170 | 171 | try { 172 | yield $this->messages->editMessage(['peer' => $update, 'id' => $sent_message['id'], 'message' => "📤 Your request is in the queue. Do not send another request. Please be patient…\n🗂 File: ".$filename."\n🔗 URL: ".$url."\n💿 File Size: ".$this->formatBytes($filesize)."\n\n⌛ Upload progress: ".$progress.'%'], ['queue' => $queue_id]); 173 | } catch (Exception $e) { 174 | } 175 | } 176 | }), 177 | 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => $filename]], 178 | ], 179 | 'reply_to_msg_id' => $message_id, 180 | ]); 181 | $time = explode(':', gmdate('H:i:s', time() - $time)); 182 | foreach ($time as &$value) { 183 | $value = ltrim($value, '0'); 184 | } 185 | $text = 'Uploaded… 100% in'; 186 | if (!empty($time[0])) { 187 | $text .= ' '.$time[0].'h'; 188 | } 189 | if (!empty($time[1])) { 190 | $text .= ' '.$time[1].'m'; 191 | } 192 | if (!empty($time[2])) { 193 | $text .= ' '.$time[2].'s'; 194 | } 195 | yield $this->messages->editMessage(['id' => $sent_message['id'], 'peer' => $update, 'message' => $text], ['queue' => $queue_id]); 196 | if (file_exists($filepath)) { 197 | unlink($filepath); 198 | } 199 | } 200 | } catch (Exception $e) { 201 | } 202 | } 203 | 204 | private function formatBytes($bytes, $precision = 2) 205 | { 206 | $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 207 | $bytes = max($bytes, 0); 208 | $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 209 | $pow = min($pow, count($units) - 1); 210 | $bytes /= pow(1024, $pow); 211 | 212 | return round($bytes, $precision).' '.$units[$pow]; 213 | } 214 | 215 | private function randomString($length = 10) 216 | { 217 | $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 218 | $charactersLength = strlen($characters); 219 | $randomString = ''; 220 | for ($i = 0; $i < $length; $i++) { 221 | $randomString .= $characters[rand(0, $charactersLength - 1)]; 222 | } 223 | 224 | return $randomString; 225 | } 226 | } 227 | 228 | $MadelineProto = new \danog\MadelineProto\API('filer.madeline'); 229 | $MadelineProto->async(true); 230 | $MadelineProto->loop(function () use ($MadelineProto) { 231 | yield $MadelineProto->start(); 232 | yield $MadelineProto->setEventHandler('\EventHandler'); 233 | }); 234 | 235 | try { 236 | $MadelineProto->loop(); 237 | } catch (Exception $e) { 238 | } 239 | --------------------------------------------------------------------------------