ajax_die($lang['MODULE_OFF']); } if ($bb_cfg['torr_server']['disable_for_guest'] && IS_GUEST) { $this->ajax_die($lang['NEED_TO_LOGIN_FIRST']); } $attach_id = $this->request['attach_id'] ?? ''; if (empty($attach_id) || !is_numeric($attach_id)) { $this->ajax_die($lang['INVALID_ATTACH_ID']); } $file_index = $this->request['file_index'] ?? ''; if (empty($file_index) || !is_numeric($file_index)) { $this->ajax_die("Invalid file index: $file_index"); } if (!$info_hash = (string)$this->request['info_hash'] or !ctype_xdigit($info_hash)) { $this->ajax_die("Invalid info_hash: $info_hash"); } $isAudio = isset($this->request['is_audio']) && $this->request['is_audio']; // Get ffprobe info from TorrServer $ffpInfo = (new \TorrentPier\TorrServerAPI())->getFfpInfo($info_hash, $file_index, $attach_id); $ffpInfo = $ffpInfo->{$file_index}; if (isset($ffpInfo->streams)) { // Video codec information $videoCodecIndex = array_search('video', array_column($ffpInfo->streams, 'codec_type')); if (is_int($videoCodecIndex)) { $videoCodecInfo = $ffpInfo->streams[$videoCodecIndex]; } // Audio codec information $audioTracks = array_filter($ffpInfo->streams, function ($e) { return $e->codec_type === 'audio'; }); // Audio tracks information $audioDub = array_map(function ($stream) { global $lang; $result = '' . sprintf($lang['AUDIO_TRACK'], (!isset($stream->index) || $stream->index === 0) ? 1 : $stream->index) . '
'; if (isset($stream->tags->language)) { if (isset($stream->tags->title)) { $result .= '' . mb_strtoupper($stream->tags->language, DEFAULT_CHARSET) . ' (' . $stream->tags->title . ')' . ''; } else { $result .= '' . mb_strtoupper($stream->tags->language, DEFAULT_CHARSET) . ''; } $result .= '
'; } if (!empty($stream->codec_name)) { $result .= sprintf($lang['AUDIO_CODEC'], $stream->codec_long_name, mb_strtoupper($stream->codec_name, DEFAULT_CHARSET)) . '
'; } if (!empty($stream->bit_rate)) { $result .= sprintf($lang['BITRATE'], humn_bitrate((int)$stream->bit_rate)) . '
'; } if (!empty($stream->sample_rate)) { $result .= sprintf($lang['SAMPLE_RATE'], humn_sample_rate((int)$stream->sample_rate)) . '
'; } if (!empty($stream->channels)) { $result .= sprintf($lang['CHANNELS'], $stream->channels) . '
'; } if (!empty($stream->channel_layout)) { $result .= sprintf($lang['CHANNELS_LAYOUT'], $stream->channel_layout); } return $result; }, $audioTracks); // Generate output data $data = [ 'filesize' => sprintf($lang['FILESIZE'] . ': %s', humn_size($ffpInfo->format->size)), 'resolution' => (!$isAudio && isset($videoCodecInfo)) ? sprintf($lang['RESOLUTION'], $videoCodecInfo->width . 'x' . $videoCodecInfo->height) : '', 'video_codec' => (!$isAudio && isset($videoCodecInfo->codec_name)) ? sprintf($lang['VIDEO_CODEC'], $videoCodecInfo->codec_long_name, mb_strtoupper($videoCodecInfo->codec_name, DEFAULT_CHARSET)) : '', 'audio_dub' => implode('
', $audioDub) ]; // Validate output data $result = '
'; if (!empty($data['resolution'])) { $result .= $data['resolution'] . '
'; } if (!empty($data['filesize'])) { $result .= $data['filesize'] . '
'; } if (!empty($data['video_codec'])) { $result .= $data['video_codec']; } if (!empty($data['audio_dub'])) { $result .= '
' . $data['audio_dub']; } $this->response['ffprobe_data'] = $result; } /** * Bitrate to human-readable format * * @param int $bitrate * @param string $space * @return string */ function humn_bitrate(int $bitrate, string $space = ' '): string { if ($bitrate >= 1000000) { $unit = 'Mbps'; $bitrate /= 1000000; } elseif ($bitrate >= 1000) { $unit = 'kbps'; $bitrate /= 1000; } else { $unit = 'bps'; } return sprintf('%d', commify($bitrate)) . $space . $unit; } /** * Sample rate to human-readable format * * @param int $sample_rate * @param string $space * @return string */ function humn_sample_rate(int $sample_rate, string $space = ' '): string { if ($sample_rate >= 1000000) { $unit = 'Mhz'; } elseif ($sample_rate >= 1000) { $unit = 'kHz'; } else { $unit = 'Hz'; } return sprintf('%.1f', commify($sample_rate)) . $space . $unit; } $this->response['file_index'] = $file_index;