├── .gitignore ├── src ├── Response │ ├── Model │ │ ├── Artist.php │ │ ├── ExternalSongInfo.php │ │ ├── ExtraAttr.php │ │ ├── ReviewResult.php │ │ ├── ChallengeList.php │ │ ├── Data.php │ │ ├── Position.php │ │ ├── GroupIdList.php │ │ ├── Room.php │ │ ├── SearchHighlight.php │ │ ├── Action.php │ │ ├── LimitsInfo.php │ │ ├── Icon.php │ │ ├── Media.php │ │ ├── LabelTop.php │ │ ├── CommerceInfo.php │ │ ├── Thumbnail.php │ │ ├── MatchedPgcSound.php │ │ ├── RiskInfos.php │ │ ├── Download.php │ │ ├── DownloadGeneral.php │ │ ├── DownloadMaskPanel.php │ │ ├── ShareGeneral.php │ │ ├── Extra.php │ │ ├── TextExtra.php │ │ ├── MatchedSong.php │ │ ├── BitRate.php │ │ ├── AwemeAcl.php │ │ ├── Play.php │ │ ├── UserSearchItem.php │ │ ├── Anchor.php │ │ ├── StickerDetail.php │ │ ├── Statistics.php │ │ ├── Status.php │ │ ├── VideoControl.php │ │ ├── ShareInfo.php │ │ ├── Comment.php │ │ ├── TikTok.php │ │ ├── MusicSearchItem.php │ │ ├── ChaListItem.php │ │ ├── ChallengeInfo.php │ │ ├── Video.php │ │ ├── Author.php │ │ ├── Lives.php │ │ ├── Music.php │ │ └── AwemeDetail.php │ └── APIResponse.php ├── Exception │ ├── NetworkException.php │ ├── ForbiddenException.php │ ├── NotFoundException.php │ ├── BadRequestException.php │ ├── ProxyAuthException.php │ ├── TooManyRequestsException.php │ └── TikTokException.php ├── AutoPropertyMapper.php ├── Response.php ├── Request.php └── TikTok.php ├── LICENSE ├── composer.json ├── examples ├── getUnshortenedUrl.php ├── getNoWatermarkUrl.php ├── getNoWatermarkUrlByID.php ├── getVideoByID.php ├── getVideoByUrl.php ├── searchMusic.php ├── searchVideo.php ├── searchHashtag.php ├── searchUser.php ├── searchLive.php ├── getCommentsByID.php └── getCommentsByUrl.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode -------------------------------------------------------------------------------- /src/Response/Model/Artist.php: -------------------------------------------------------------------------------- 1 | 'bool' 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /src/Response/Model/ReviewResult.php: -------------------------------------------------------------------------------- 1 | 'int' 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /src/AutoPropertyMapper.php: -------------------------------------------------------------------------------- 1 | 'ChallengeInfo', 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /src/Response/Model/Data.php: -------------------------------------------------------------------------------- 1 | 'int', 23 | 'lives' => 'Lives' 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /src/Response/Model/Position.php: -------------------------------------------------------------------------------- 1 | 'int', 23 | 'end' => 'int' 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /src/Response/Model/GroupIdList.php: -------------------------------------------------------------------------------- 1 | '', 23 | 'GroupdIdList1' => '' 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /src/Response/Model/Room.php: -------------------------------------------------------------------------------- 1 | 'bool', 24 | 'is_battle' => 'bool' 25 | ]; 26 | } 27 | -------------------------------------------------------------------------------- /src/Response/Model/SearchHighlight.php: -------------------------------------------------------------------------------- 1 | 'string', 23 | 'positions' => 'Position[]' 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /src/Response/Model/Action.php: -------------------------------------------------------------------------------- 1 | 'Icon', 28 | 'schema' => 'string', 29 | 'action_type' => 'int' 30 | ]; 31 | } 32 | -------------------------------------------------------------------------------- /src/Response/Model/LimitsInfo.php: -------------------------------------------------------------------------------- 1 | 'string', 27 | 'requests_count' => 'int', 28 | 'requests_limit' => 'int', 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /src/Response/Model/Icon.php: -------------------------------------------------------------------------------- 1 | 'string', 31 | 'url_list' => 'string[]', 32 | 'width' => 'int', 33 | 'height' => 'int' 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/Response/Model/Media.php: -------------------------------------------------------------------------------- 1 | 'string', 31 | 'url_list' => 'string[]', 32 | 'width' => 'int', 33 | 'height' => 'int' 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/Response/Model/LabelTop.php: -------------------------------------------------------------------------------- 1 | 'string', 31 | 'url_list' => 'string[]', 32 | 'width' => 'int', 33 | 'height' => 'int' 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/Response/Model/CommerceInfo.php: -------------------------------------------------------------------------------- 1 | 'bool', 27 | 'with_comment_filter_words' => 'bool', 28 | 'adv_promotable' => 'bool' 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /src/Response/Model/Thumbnail.php: -------------------------------------------------------------------------------- 1 | 'int', 31 | 'uri' => 'string', 32 | 'url_list' => 'string[]', 33 | 'width' => 'int' 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/Response/Model/MatchedPgcSound.php: -------------------------------------------------------------------------------- 1 | 'string', 31 | 'mixed_author' => 'string', 32 | 'author' => 'string', 33 | 'title' => 'string' 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2024 Evelode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Response/Model/RiskInfos.php: -------------------------------------------------------------------------------- 1 | 'bool', 35 | 'war' => 'bool', 36 | 'risk_sink' => 'bool', 37 | 'type' => 'int', 38 | 'content' => 'string' 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Response/Model/Download.php: -------------------------------------------------------------------------------- 1 | 'string', 35 | 'url_list' => 'string[]', 36 | 'width' => 'int', 37 | 'height' => 'int', 38 | 'data_size' => 'int', 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Response/Model/DownloadGeneral.php: -------------------------------------------------------------------------------- 1 | 'int', 35 | 'show_type' => 'int', 36 | 'transcode' => 'int', 37 | 'mute' => 'bool', 38 | 'extra' => 'string' 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Response/Model/DownloadMaskPanel.php: -------------------------------------------------------------------------------- 1 | 'int', 35 | 'show_type' => 'int', 36 | 'transcode' => 'int', 37 | 'mute' => 'bool', 38 | 'extra' => 'string' 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Response/Model/ShareGeneral.php: -------------------------------------------------------------------------------- 1 | 'int', 39 | 'show_type' => 'int', 40 | 'transcode' => 'int', 41 | 'mute' => 'bool', 42 | 'extra' => 'string', 43 | 'toast_msg' => 'string' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /src/Exception/TikTokException.php: -------------------------------------------------------------------------------- 1 | _response !== null ? true : false; 29 | } 30 | 31 | /** 32 | * Get the full server response. 33 | * 34 | * @return Response|null The full response if one exists, otherwise NULL. 35 | * 36 | * @see TikTokException::hasResponse() 37 | */ 38 | public function getResponse() 39 | { 40 | return $this->_response; 41 | } 42 | 43 | /** 44 | * Internal. Sets the value of the full server response. 45 | * 46 | * @param Response|null $response The response value. 47 | */ 48 | public function setResponse( 49 | Response $response = null) 50 | { 51 | $this->_response = $response; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Response/Model/Extra.php: -------------------------------------------------------------------------------- 1 | 'int', 39 | 'hashtag_id' => 'string', 40 | 'hashtag_name' => 'string', 41 | 'is_commerce' => 'bool', 42 | 'start' => 'int', 43 | 'type' => 'int' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /src/Response/Model/TextExtra.php: -------------------------------------------------------------------------------- 1 | 'int', 39 | 'hashtag_id' => 'string', 40 | 'hashtag_name' => 'string', 41 | 'is_commerce' => 'bool', 42 | 'start' => 'int', 43 | 'type' => 'int' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /src/Response/Model/MatchedSong.php: -------------------------------------------------------------------------------- 1 | 'string', 39 | 'author' => 'string', 40 | 'title' => 'string', 41 | 'h5_url' => 'string', 42 | 'cover_medium' => 'Media', 43 | 'performers' => '' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /src/Response/Model/BitRate.php: -------------------------------------------------------------------------------- 1 | 'string', 39 | 'quality_type' => 'int', 40 | 'bit_rate' => 'int', 41 | 'play_addr' => 'Play', 42 | 'is_bytevc1' => 'int', 43 | 'dub_infos' => '' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evelode/tiktok-api-php", 3 | "description": "TikTok REST API wrapper for PHP", 4 | "homepage": "https://github.com/evelode/tiktok-api-php", 5 | "type": "library", 6 | "require": { 7 | "php": ">=7.0", 8 | "sergeykomlev/lazyjsonmapper": "^2.0.0", 9 | "guzzlehttp/guzzle": "^7.4", 10 | "ext-curl": "*", 11 | "ext-mbstring": "*", 12 | "ext-gd": "*", 13 | "ext-exif": "*", 14 | "ext-zlib": "*", 15 | "ext-bcmath": "*" 16 | }, 17 | "license": "MIT", 18 | "authors": [ 19 | { 20 | "name": "Evelode", 21 | "email": "contact@evelode.com", 22 | "homepage": "https://evelode.com", 23 | "role": "Developer" 24 | } 25 | ], 26 | "suggest": { 27 | "ext-curl": "Required for CURL handler support in requests" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "TikTokRESTAPI\\": "src/" 32 | } 33 | }, 34 | "keywords": [ 35 | "php", 36 | "php7", 37 | "rest-api", 38 | "php-library", 39 | "php-fpm", 40 | "scrapper", 41 | "php8", 42 | "tiktok", 43 | "tiktok-scraper", 44 | "tiktok-api", 45 | "tiktokapi", 46 | "tiktok-automation", 47 | "tiktok-downloader", 48 | "tiktok-signature", 49 | "ttencrypt", 50 | "nowatermark", 51 | "xgorgon", 52 | "xkhonos", 53 | "xtyhon", 54 | "xladon" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /src/Response/Model/AwemeAcl.php: -------------------------------------------------------------------------------- 1 | 'DownloadGeneral', 35 | 'download_mask_panel' => 'DownloadMaskPanel', 36 | 'share_list_status' => 'int', 37 | 'share_general' => 'ShareGeneral', 38 | 'platform_list' => '' 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /src/Response/Model/Play.php: -------------------------------------------------------------------------------- 1 | 'string', 47 | 'url_list' => 'string[]', 48 | 'width' => 'int', 49 | 'height' => 'int', 50 | 'url_key' => 'string', 51 | 'data_size' => 'int', 52 | 'file_hash' => 'string', 53 | 'file_cs' => 'string' 54 | ]; 55 | } 56 | -------------------------------------------------------------------------------- /src/Response/APIResponse.php: -------------------------------------------------------------------------------- 1 | 'string', 39 | 'message' => 'string', 40 | 'limits_info' => 'Model\LimitsInfo', 41 | 'rate_limit_reached' => 'bool', 42 | 'tiktok' => 'Model\TikTok', 43 | 'timestamp' => 'string' 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /src/Response/Model/UserSearchItem.php: -------------------------------------------------------------------------------- 1 | '', 47 | 'effects' => '', 48 | 'items' => '', 49 | 'mix_list' => '', 50 | 'musics' => '', 51 | 'position' => '', 52 | 'uniqid_position' => '', 53 | 'user_info' => 'User' 54 | ]; 55 | } 56 | -------------------------------------------------------------------------------- /src/Response/Model/Anchor.php: -------------------------------------------------------------------------------- 1 | 'string', 47 | 'thumbnail' => 'Thumbnail', 48 | 'actions' => 'Action[]', 49 | 'keyword' => 'string', 50 | 'id' => 'string', 51 | 'type' => 'int', 52 | 'icon' => 'Icon', 53 | 'log_extra' => '' 54 | ]; 55 | } 56 | -------------------------------------------------------------------------------- /src/Response/Model/StickerDetail.php: -------------------------------------------------------------------------------- 1 | 'string', 43 | 'name' => 'string', 44 | 'children' => '', 45 | 'owner_id' => 'string', 46 | 'tags' => 'string', 47 | 'sec_uid' => 'string', 48 | 'linked_anchors' => '' 49 | ]; 50 | } 51 | -------------------------------------------------------------------------------- /src/Response.php: -------------------------------------------------------------------------------- 1 | 'string', 28 | ]; 29 | 30 | /** @var HttpResponseInterface */ 31 | public $httpResponse; 32 | 33 | /** 34 | * Checks if the response was successful. 35 | * 36 | * @return bool 37 | */ 38 | public function isOk() 39 | { 40 | return $this->_getProperty('status') === self::STATUS_OK; 41 | } 42 | 43 | /** 44 | * Gets the message. 45 | * 46 | * This function overrides the normal getter with some special processing 47 | * to handle unusual multi-error message values in certain responses. 48 | * 49 | * @throws RuntimeException If the message object is of an unsupported type. 50 | * 51 | * @return string|null A message string if one exists, otherwise NULL. 52 | */ 53 | public function getMessage() 54 | { 55 | // Example: 56 | // {"message":"NO_POSITION","data":{}} 57 | 58 | $message = $this->_getProperty('message'); 59 | if ($message === null || is_string($message)) { 60 | // Single error string or nothing at all. 61 | return $message; 62 | } else { 63 | throw new RuntimeException('Unknown message type in response.'); 64 | } 65 | } 66 | 67 | /** 68 | * Gets the HTTP response. 69 | * 70 | * @return HttpResponseInterface 71 | */ 72 | public function getHttpResponse() 73 | { 74 | return $this->httpResponse; 75 | } 76 | 77 | /** 78 | * Sets the HTTP response. 79 | * 80 | * @param HttpResponseInterface $response 81 | */ 82 | public function setHttpResponse( 83 | HttpResponseInterface $response) 84 | { 85 | $this->httpResponse = $response; 86 | } 87 | 88 | /** 89 | * Checks if an HTTP response value exists. 90 | * 91 | * @return bool 92 | */ 93 | public function isHttpResponse() 94 | { 95 | return $this->httpResponse !== null; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Response/Model/Statistics.php: -------------------------------------------------------------------------------- 1 | 'int', 59 | 'lose_comment_count' => 'int', 60 | 'aweme_id' => 'string', 61 | 'comment_count' => 'int', 62 | 'play_count' => 'int', 63 | 'share_count' => 'int', 64 | 'forward_count' => 'int', 65 | 'whatsapp_share_count' => 'int', 66 | 'digg_count' => 'int', 67 | 'download_count' => 'int', 68 | 'collect_count' => 'int' 69 | ]; 70 | } 71 | -------------------------------------------------------------------------------- /examples/getUnshortenedUrl.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video URL 21 | // This is an example how to get $video_url from Console/Terminal 22 | if (empty($video_url)) { 23 | echo 'Enter the short TikTok video URL:'; 24 | $video_url = trim(fgets(STDIN)); 25 | } 26 | 27 | $resp = $tiktok->getUnshortenedUrl($video_url); 28 | if ($resp->isOk() && $resp->isTiktok() && $resp->getTiktok()->isUrl()) { 29 | echo sprintf('Full TikTok video URL: %s.', $resp->getTiktok()->getUrl()); 30 | } 31 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 32 | // Request not performed because some data is missing or incorrect. 33 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 34 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 35 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 36 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 37 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 38 | // Requested resource doesn't exist in TikTok. 39 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 40 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 41 | // Proxy auth data is missing or incorrect. 42 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 43 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 44 | // Too many requests sent to TikTok. 45 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 46 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 47 | // Couldn't establish connection with REST API server 48 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 49 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 50 | // Invalid argument, missing or invalid data in request 51 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 52 | } catch (Exception $e) { 53 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 54 | echo var_dump($e->getTrace()); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /examples/getNoWatermarkUrl.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video URL 21 | // This is an example how to get $video_url from Console/Terminal 22 | if (empty($video_url)) { 23 | echo 'Enter the TikTok video URL:'; 24 | $video_url = trim(fgets(STDIN)); 25 | } 26 | 27 | $resp = $tiktok->getNoWatermarkUrl($video_url); 28 | if ($resp->isOk() && $resp->isTiktok()) { 29 | $video_url = $resp->getTiktok()->getUrl(); 30 | if (!empty($video_url)) { 31 | echo sprintf('Non-watermarked Video URL: %s', $video_url) . "\n"; 32 | } 33 | } 34 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 35 | // Request not performed because some data is missing or incorrect. 36 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 37 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 38 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 39 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 40 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 41 | // Requested resource doesn't exist in TikTok. 42 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 43 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 44 | // Proxy auth data is missing or incorrect. 45 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 46 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 47 | // Too many requests sent to TikTok. 48 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 49 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 50 | // Couldn't establish connection with REST API server 51 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 52 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 53 | // Invalid argument, missing or invalid data in request 54 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 55 | } catch (Exception $e) { 56 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 57 | echo var_dump($e->getTrace()); 58 | } -------------------------------------------------------------------------------- /src/Response/Model/Status.php: -------------------------------------------------------------------------------- 1 | 'string', 60 | 'allow_comment' => 'bool', 61 | 'private_status' => 'int', 62 | 'in_reviewing' => 'bool', 63 | 'reviewed' => 'int', 64 | 'review_result' => 'ReviewResult', 65 | 'is_delete' => 'bool', 66 | 'allow_share' => 'bool', 67 | 'self_see' => 'bool', 68 | 'is_prohibited' => 'bool', 69 | 'download_status' => 'int' 70 | ]; 71 | } 72 | -------------------------------------------------------------------------------- /examples/getNoWatermarkUrlByID.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video ID 21 | // This is an example how to get $video_id from Console/Terminal 22 | if (empty($video_id)) { 23 | echo 'Enter the TikTok video ID:'; 24 | $video_id = trim(fgets(STDIN)); 25 | } 26 | 27 | $resp = $tiktok->getNoWatermarkUrlByID($video_id); 28 | if ($resp->isOk() && $resp->isTiktok()) { 29 | $video_url = $resp->getTiktok()->getUrl(); 30 | if (!empty($video_url)) { 31 | echo sprintf('Non-watermarked Video URL: %s', $video_url) . "\n"; 32 | } 33 | } 34 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 35 | // Request not performed because some data is missing or incorrect. 36 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 37 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 38 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 39 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 40 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 41 | // Requested resource doesn't exist in TikTok. 42 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 43 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 44 | // Proxy auth data is missing or incorrect. 45 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 46 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 47 | // Too many requests sent to TikTok. 48 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 49 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 50 | // Couldn't establish connection with REST API server 51 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 52 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 53 | // Invalid argument, missing or invalid data in request 54 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 55 | } catch (Exception $e) { 56 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 57 | echo var_dump($e->getTrace()); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/Response/Model/VideoControl.php: -------------------------------------------------------------------------------- 1 | 'int', 59 | 'draft_progress_bar' => 'int', 60 | 'timer_status' => 'int', 61 | 'allow_stitch' => 'bool', 62 | 'allow_download' => 'bool', 63 | 'show_progress_bar' => 'int', 64 | 'allow_duet' => 'bool', 65 | 'allow_react' => 'bool', 66 | 'prevent_download_type' => 'int', 67 | 'allow_dynamic_wallpaper' => 'bool', 68 | 'allow_music' => 'bool' 69 | ]; 70 | } 71 | -------------------------------------------------------------------------------- /examples/getVideoByID.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video ID 21 | // This is an example how to get $video_id from Console/Terminal 22 | if (empty($video_id)) { 23 | echo 'Enter the TikTok video ID:'; 24 | $video_id = trim(fgets(STDIN)); 25 | } 26 | 27 | $resp = $tiktok->getVideoByID($video_id); 28 | if ($resp->isOk() && $resp->isTiktok() && $resp->getTiktok()->isAwemeDetail()) { 29 | $aweme_detail = $resp->getTiktok()->getAwemeDetail(); 30 | if ($aweme_detail->isAuthor() && $aweme_detail->isStatistics()) { 31 | echo sprintf( 32 | 'Video published by @%s (%s) and have %s likes, %s plays and %s comments.', 33 | $aweme_detail->getAuthor()->getUniqueId(), 34 | $aweme_detail->getAuthor()->getNickname(), 35 | number_format($aweme_detail->getStatistics()->getDiggCount(), 0 , '.' , ' ' ), 36 | number_format($aweme_detail->getStatistics()->getPlayCount(), 0 , '.' , ' ' ), 37 | number_format($aweme_detail->getStatistics()->getCommentCount(), 0 , '.' , ' ' ) 38 | ) . "\n"; 39 | } 40 | } 41 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 42 | // Request not performed because some data is missing or incorrect. 43 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 44 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 45 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 46 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 47 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 48 | // Requested resource doesn't exist in TikTok. 49 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 50 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 51 | // Proxy auth data is missing or incorrect. 52 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 53 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 54 | // Too many requests sent to TikTok. 55 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 56 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 57 | // Couldn't establish connection with REST API server 58 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 59 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 60 | // Invalid argument, missing or invalid data in request 61 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 62 | } catch (Exception $e) { 63 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 64 | echo var_dump($e->getTrace()); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /examples/getVideoByUrl.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video URL 21 | // This is an example how to get $video_url from Console/Terminal 22 | if (empty($video_url)) { 23 | echo 'Enter the TikTok video URL:'; 24 | $video_url = trim(fgets(STDIN)); 25 | } 26 | 27 | $resp = $tiktok->getVideoByID($video_url); 28 | if ($resp->isOk() && $resp->isTiktok() && $resp->getTiktok()->isAwemeDetail()) { 29 | $aweme_detail = $resp->getTiktok()->getAwemeDetail(); 30 | if ($aweme_detail->isAuthor() && $aweme_detail->isStatistics()) { 31 | echo sprintf( 32 | 'Video published by @%s (%s) and have %s likes, %s plays and %s comments.', 33 | $aweme_detail->getAuthor()->getUniqueId(), 34 | $aweme_detail->getAuthor()->getNickname(), 35 | number_format($aweme_detail->getStatistics()->getDiggCount(), 0 , '.' , ' ' ), 36 | number_format($aweme_detail->getStatistics()->getPlayCount(), 0 , '.' , ' ' ), 37 | number_format($aweme_detail->getStatistics()->getCommentCount(), 0 , '.' , ' ' ) 38 | ) . "\n"; 39 | } 40 | } 41 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 42 | // Request not performed because some data is missing or incorrect. 43 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 44 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 45 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 46 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 47 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 48 | // Requested resource doesn't exist in TikTok. 49 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 50 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 51 | // Proxy auth data is missing or incorrect. 52 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 53 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 54 | // Too many requests sent to TikTok. 55 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 56 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 57 | // Couldn't establish connection with REST API server 58 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 59 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 60 | // Invalid argument, missing or invalid data in request 61 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 62 | } catch (Exception $e) { 63 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 64 | echo var_dump($e->getTrace()); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /examples/searchMusic.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | if (empty($keyword)) { 21 | getKeyword: 22 | // Any text or keyword. 23 | // This is an example how to get $keyword from Console/Terminal 24 | echo 'Enter the text or keyword to search:'; 25 | $keyword = trim(fgets(STDIN)); 26 | } 27 | 28 | search: 29 | $resp = $tiktok->searchMusic($keyword); 30 | 31 | if ($resp->isOk() && $resp->isTiktok() && count($resp->getTiktok()->getMusic()) > 0) { 32 | 33 | $music_list = $resp->getTiktok()->getMusic(); 34 | echo sprintf('Music found by keyword "%s":', $keyword) . "\n"; 35 | 36 | foreach ($music_list as $key => $m) { 37 | 38 | $title = $m->getTitle(); 39 | $author = $m->getAuthor(); 40 | $album = $m->getAlbum(); 41 | 42 | echo sprintf('%s. %s | Author: %s | Album: %s', $key + 1, $title, $author, $album) . "\n"; 43 | } 44 | } else { 45 | echo sprintf('Music by keyword "%s" not found.', $keyword) . "\n"; 46 | } 47 | 48 | echo 'Do you want to use search again?' . "\n"; 49 | echo '1 - Yes' . "\n"; 50 | echo '2 - No' . "\n"; 51 | echo 'Your choice:'; 52 | $choice = trim(fgets(STDIN)); 53 | if ($choice == 1) { 54 | goto getKeyword; 55 | } 56 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 57 | // Request not performed because some data is missing or incorrect. 58 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 59 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 60 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 61 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 62 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 63 | // Requested resource doesn't exist in TikTok. 64 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 65 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 66 | // Proxy auth data is missing or incorrect. 67 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 68 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 69 | // Too many requests sent to TikTok. 70 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 71 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 72 | // Couldn't establish connection with REST API server 73 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 74 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 75 | // Invalid argument, missing or invalid data in request 76 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 77 | } catch (Exception $e) { 78 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 79 | echo var_dump($e->getTrace()); 80 | } -------------------------------------------------------------------------------- /examples/searchVideo.php: -------------------------------------------------------------------------------- 1 | searchVideo($keyword, 30); 24 | 25 | if ($resp->isOk() && $resp->isTiktok() && count($resp->getTiktok()->getAwemeList()) > 0) { 26 | 27 | echo sprintf('Videos found by keyword "%s":', $keyword) . "\n"; 28 | 29 | $video_list = $resp->getTiktok()->getAwemeList(); 30 | 31 | foreach ($video_list as $key => $video) { 32 | 33 | $aweme_id = $video->getAwemeId(); 34 | $nickname = $video->getAuthor()->getUniqueId(); 35 | $fullname = $video->getAuthor()->getNickname(); 36 | $inst_id = $video->getAuthor()->getInsId(); 37 | 38 | if (!empty($inst_id)) { 39 | echo sprintf('Video %s by @%s (%s) | Instagram @%s', 'https://www.tiktok.com/@' . $nickname . '/video/' . $aweme_id, $nickname, $fullname, $inst_id) . "\n"; 40 | } else { 41 | echo sprintf('Video %s by @%s (%s)', 'https://www.tiktok.com/@' . $nickname . '/video/' . $aweme_id, $nickname, $fullname) . "\n"; 42 | } 43 | } 44 | } 45 | 46 | echo 'Do you want to use search again?' . "\n"; 47 | echo '1 - Yes' . "\n"; 48 | echo '2 - No' . "\n"; 49 | echo 'Your choice:'; 50 | $choice = trim(fgets(STDIN)); 51 | if ($choice == 1) { 52 | goto getKeyword; 53 | } 54 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 55 | // Request not performed because some data is missing or incorrect. 56 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 57 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 58 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 59 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 60 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 61 | // Requested resource doesn't exist in TikTok. 62 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 63 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 64 | // Proxy auth data is missing or incorrect. 65 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 66 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 67 | // Too many requests sent to TikTok. 68 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 69 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 70 | // Couldn't establish connection with REST API server 71 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 72 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 73 | // Invalid argument, missing or invalid data in request 74 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 75 | } catch (Exception $e) { 76 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 77 | echo var_dump($e->getTrace()); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/Response/Model/ShareInfo.php: -------------------------------------------------------------------------------- 1 | 'string', 63 | 'share_signature_url' => 'string', 64 | 'share_quote' => 'string', 65 | 'share_desc_info' => 'string', 66 | 'share_url' => 'string', 67 | 'bool_persist' => 'int', 68 | 'share_title_other' => 'string', 69 | 'share_link_desc' => 'string', 70 | 'share_signature_desc' => 'string', 71 | 'whatsapp_desc' => 'string', 72 | 'share_desc' => 'string', 73 | 'share_title' => 'string' 74 | ]; 75 | } 76 | -------------------------------------------------------------------------------- /examples/searchHashtag.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | if (empty($keyword)) { 21 | getKeyword: 22 | // Any text or keyword. 23 | // This is an example how to get $keyword from Console/Terminal 24 | echo 'Enter the text or keyword to search:'; 25 | $keyword = trim(fgets(STDIN)); 26 | } 27 | 28 | search: 29 | $resp = $tiktok->searchHashtag($keyword); 30 | 31 | if ($resp->isOk() && $resp->isTiktok() && $resp->getTiktok()->isChallengeList() && count($resp->getTiktok()->getChallengeList()) > 0) { 32 | 33 | echo sprintf('Hashtags found by keyword "%s":', $keyword) . "\n"; 34 | 35 | $hashtags = $resp->getTiktok()->getChallengeList(); 36 | 37 | foreach ($hashtags as $key => $h) { 38 | 39 | $hashtag = $h->getChallengeInfo()->getChaName(); 40 | $use_count = number_format($h->getChallengeInfo()->getUseCount(), 0, '', ' '); 41 | $view_count = number_format($h->getChallengeInfo()->getViewCount(), 0, '', ' '); 42 | 43 | echo sprintf('%s. %s | Use Count: %s | View Count: %s', $key + 1, $hashtag, $use_count, $view_count) . "\n"; 44 | } 45 | } else { 46 | echo sprintf('Hashtags by keyword "%s" not found.', $keyword) . "\n"; 47 | } 48 | 49 | echo 'Do you want to use search again?' . "\n"; 50 | echo '1 - Yes' . "\n"; 51 | echo '2 - No' . "\n"; 52 | echo 'Your choice:'; 53 | $choice = trim(fgets(STDIN)); 54 | if ($choice == 1) { 55 | goto getKeyword; 56 | } 57 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 58 | // Request not performed because some data is missing or incorrect. 59 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 60 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 61 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 62 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 63 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 64 | // Requested resource doesn't exist in TikTok. 65 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 66 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 67 | // Proxy auth data is missing or incorrect. 68 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 69 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 70 | // Too many requests sent to TikTok. 71 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 72 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 73 | // Couldn't establish connection with REST API server 74 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 75 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 76 | // Invalid argument, missing or invalid data in request 77 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 78 | } catch (Exception $e) { 79 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 80 | echo var_dump($e->getTrace()); 81 | } -------------------------------------------------------------------------------- /examples/searchUser.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | if (empty($keyword)) { 21 | getKeyword: 22 | // Any text or keyword. 23 | // This is an example how to get $keyword from Console/Terminal 24 | echo 'Enter the text or keyword to search:'; 25 | $keyword = trim(fgets(STDIN)); 26 | } 27 | 28 | search: 29 | $resp = $tiktok->searchUser($keyword); 30 | 31 | if ($resp->isOk() && $resp->isTiktok() && count($resp->getTiktok()->getUserList()) > 0) { 32 | 33 | $user_list = $resp->getTiktok()->getUserList(); 34 | echo sprintf('Users found by keyword "%s":', $keyword) . "\n"; 35 | 36 | foreach ($user_list as $key => $user) { 37 | 38 | $nickname = $user->getUserInfo()->getUniqueId(); 39 | $fullname = $user->getUserInfo()->getNickname(); 40 | $inst_id = $user->getUserInfo()->getInsId(); 41 | 42 | if (!empty($inst_id)) { 43 | echo sprintf('@%s (%s) | Instagram @%s', $nickname, $fullname, $inst_id) . "\n"; 44 | } else { 45 | echo sprintf('@%s (%s)', $nickname, $fullname) . "\n"; 46 | } 47 | } 48 | } else { 49 | echo sprintf('Users by keyword "%s" not found.', $keyword) . "\n"; 50 | } 51 | 52 | echo 'Do you want to use search again?' . "\n"; 53 | echo '1 - Yes' . "\n"; 54 | echo '2 - No' . "\n"; 55 | echo 'Your choice:'; 56 | $choice = trim(fgets(STDIN)); 57 | if ($choice == 1) { 58 | goto getKeyword; 59 | } 60 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 61 | // Request not performed because some data is missing or incorrect. 62 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 63 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 64 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 65 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 66 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 67 | // Requested resource doesn't exist in TikTok. 68 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 69 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 70 | // Proxy auth data is missing or incorrect. 71 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 72 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 73 | // Too many requests sent to TikTok. 74 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 75 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 76 | // Couldn't establish connection with REST API server 77 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 78 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 79 | // Invalid argument, missing or invalid data in request 80 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 81 | } catch (Exception $e) { 82 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 83 | echo var_dump($e->getTrace()); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /examples/searchLive.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | if (empty($keyword)) { 21 | getKeyword: 22 | // Any text or keyword. 23 | // This is an example how to get $keyword from Console/Terminal 24 | echo 'Enter the text or keyword to search:'; 25 | $keyword = trim(fgets(STDIN)); 26 | } 27 | 28 | search: 29 | $resp = $tiktok->searchLive($keyword); 30 | 31 | if ($resp->isOk() && $resp->hasTiktok() && $resp->getTiktok()->hasData() && count($resp->getTiktok()->getData()) > 0) { 32 | 33 | $lives = $resp->getTiktok()->getData(); 34 | echo sprintf('Livestreams found by keyword "%s":', $keyword) . "\n"; 35 | 36 | foreach ($lives as $key => $l) { 37 | 38 | $title = $l->getLives()->getAuthor()->getRoomTitle() !== "" ? $l->getLives()->getAuthor()->getRoomTitle() : "Empty Title"; 39 | $nickname = $l->getLives()->getAuthor()->getNickname(); 40 | $unique_id = $l->getLives()->getAuthor()->getUniqueId(); 41 | $room_id = $l->getLives()->getAuthor()->getRoomId(); 42 | 43 | echo sprintf('%s. %s | Author: %s (@%s) | Room ID: %s', $key + 1, $title, $nickname, $unique_id, $room_id) . "\n"; 44 | } 45 | } else { 46 | echo sprintf('Livestreams by keyword "%s" not found.', $keyword) . "\n"; 47 | } 48 | 49 | echo 'Do you want to use search again?' . "\n"; 50 | echo '1 - Yes' . "\n"; 51 | echo '2 - No' . "\n"; 52 | echo 'Your choice:'; 53 | $choice = trim(fgets(STDIN)); 54 | if ($choice == 1) { 55 | goto getKeyword; 56 | } 57 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 58 | // Request not performed because some data is missing or incorrect. 59 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 60 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 61 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 62 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 63 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 64 | // Requested resource doesn't exist in TikTok. 65 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 66 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 67 | // Proxy auth data is missing or incorrect. 68 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 69 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 70 | // Too many requests sent to TikTok. 71 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 72 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 73 | // Couldn't establish connection with REST API server 74 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 75 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 76 | // Invalid argument, missing or invalid data in request 77 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 78 | } catch (Exception $e) { 79 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 80 | echo var_dump($e->getTrace()); 81 | } -------------------------------------------------------------------------------- /src/Response/Model/Comment.php: -------------------------------------------------------------------------------- 1 | 'string', 79 | 'cid' => 'string', 80 | 'create_time' => 'int', 81 | 'digg_count' => 'int', 82 | 'is_author_digged' => 'bool', 83 | 'label_list' => '', 84 | 'reply_comment' => '', 85 | 'reply_id' => 'string', 86 | 'reply_to_reply_id' => 'string', 87 | 'status' => 'int', 88 | 'stick_position' => 'int', 89 | 'text' => 'string', 90 | 'text_extra' => 'TextExtra', 91 | 'user' => 'User', 92 | 'user_buried' => 'bool', 93 | 'user_digged' => 'int' 94 | ]; 95 | } 96 | -------------------------------------------------------------------------------- /src/Response/Model/TikTok.php: -------------------------------------------------------------------------------- 1 | 'string', 75 | 'url' => 'string', 76 | 'status_code' => 'int', 77 | 'aweme_detail' => 'AwemeDetail', 78 | 'comments' => 'Comment[]', 79 | 'cursor' => 'int', 80 | 'has_more' => 'int', 81 | 'total' => 'int', 82 | 'input_keyword' => 'string', 83 | 'user_list' => 'UserSearchItem[]', 84 | 'aweme_list' => 'AwemeListItem[]', 85 | 'music' => 'MusicSearchItem[]', 86 | 'data' => 'Data[]', 87 | 'challenge_list' => 'ChallengeList[]', 88 | 'user' => 'User' 89 | ]; 90 | } 91 | -------------------------------------------------------------------------------- /examples/getCommentsByID.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video ID 21 | // This is an example how to get $video_id from Console/Terminal 22 | if (empty($video_id)) { 23 | getVideoID: 24 | echo 'Enter the TikTok video ID:'; 25 | $video_id = trim(fgets(STDIN)); 26 | } 27 | 28 | getComments: 29 | if (isset($cursor)) { 30 | $resp = $tiktok->getCommentsByID($video_id, $cursor); 31 | } else { 32 | $resp = $tiktok->getCommentsByID($video_id); 33 | } 34 | 35 | if ($resp->isOk() && $resp->isTiktok()) { 36 | 37 | $comments = $resp->getTiktok()->getComments(); 38 | 39 | if (count($comments) > 0) { 40 | $total = $resp->getTiktok()->getTotal(); 41 | 42 | if (isset($cursor)) { 43 | echo sprintf('Loading next %s comments.', number_format(count($comments), 0 , '.' , ' ' )) . "\n"; 44 | } else { 45 | echo sprintf('Video has %s comments.', number_format($total, 0 , '.' , ' ' )) . "\n"; 46 | echo sprintf('Loading last %s comments.', number_format(count($comments), 0 , '.' , ' ' )) . "\n"; 47 | } 48 | 49 | foreach ($comments as $key => $comment) { 50 | echo sprintf('Comment by @%s (%s)', $comment->getUser()->getUniqueId(), $comment->getUser()->getNickname()) . "\n"; 51 | echo sprintf('- %s', $comment->getText()) . "\n"; 52 | } 53 | 54 | $hasMore = $resp->getTiktok()->getHasMore(); 55 | $cursor = $resp->getTiktok()->getCursor(); 56 | 57 | if ($hasMore) { 58 | echo 'Do you want to load more comments?' . "\n"; 59 | echo '1 - Yes' . "\n"; 60 | echo '2 - No' . "\n"; 61 | echo '3 - Check another video' . "\n"; 62 | echo 'Your choice:'; 63 | $choice = trim(fgets(STDIN)); 64 | if ($choice == 1) { 65 | goto getComments; 66 | } elseif ($choice == 3) { 67 | goto getVideoID; 68 | } 69 | } else { 70 | echo "All video comments nas been loaded.\n"; 71 | } 72 | } else { 73 | echo "Video has no comments.\n"; 74 | } 75 | } 76 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 77 | // Request not performed because some data is missing or incorrect. 78 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 79 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 80 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 81 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 82 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 83 | // Requested resource doesn't exist in TikTok. 84 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 85 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 86 | // Proxy auth data is missing or incorrect. 87 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 88 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 89 | // Too many requests sent to TikTok. 90 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 91 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 92 | // Couldn't establish connection with REST API server 93 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 94 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 95 | // Invalid argument, missing or invalid data in request 96 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 97 | } catch (Exception $e) { 98 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 99 | echo var_dump($e->getTrace()); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /examples/getCommentsByUrl.php: -------------------------------------------------------------------------------- 1 | setCacheTimeout(3600); 18 | 19 | try { 20 | // Validate the TikTok video Url 21 | // This is an example how to get $video_url from Console/Terminal 22 | if (empty($video_url)) { 23 | getVideoUrl: 24 | echo 'Enter the TikTok video Url:'; 25 | $video_url = trim(fgets(STDIN)); 26 | } 27 | 28 | getComments: 29 | if (isset($cursor)) { 30 | $resp = $tiktok->getCommentsByUrl($video_url, $cursor); 31 | } else { 32 | $resp = $tiktok->getCommentsByUrl($video_url); 33 | } 34 | 35 | if ($resp->isOk() && $resp->isTiktok()) { 36 | 37 | $comments = $resp->getTiktok()->getComments(); 38 | 39 | if (count($comments) > 0) { 40 | $total = $resp->getTiktok()->getTotal(); 41 | 42 | if (isset($cursor)) { 43 | echo sprintf('Loading next %s comments.', number_format(count($comments), 0 , '.' , ' ' )) . "\n"; 44 | } else { 45 | echo sprintf('Video has %s comments.', number_format($total, 0 , '.' , ' ' )) . "\n"; 46 | echo sprintf('Loading last %s comments.', number_format(count($comments), 0 , '.' , ' ' )) . "\n"; 47 | } 48 | 49 | foreach ($comments as $key => $comment) { 50 | echo sprintf('Comment by @%s (%s)', $comment->getUser()->getUniqueId(), $comment->getUser()->getNickname()) . "\n"; 51 | echo sprintf('- %s', $comment->getText()) . "\n"; 52 | } 53 | 54 | $hasMore = $resp->getTiktok()->getHasMore(); 55 | $cursor = $resp->getTiktok()->getCursor(); 56 | 57 | if ($hasMore) { 58 | echo 'Do you want to load more comments?' . "\n"; 59 | echo '1 - Yes' . "\n"; 60 | echo '2 - No' . "\n"; 61 | echo '3 - Check another video' . "\n"; 62 | echo 'Your choice:'; 63 | $choice = trim(fgets(STDIN)); 64 | if ($choice == 1) { 65 | goto getComments; 66 | } elseif ($choice == 3) { 67 | goto getVideoUrl; 68 | } 69 | } else { 70 | echo "All video comments nas been loaded.\n"; 71 | } 72 | } else { 73 | echo "Video has no comments.\n"; 74 | } 75 | } 76 | } catch (TikTokRESTAPI\Exception\BadRequestException $e) { 77 | // Request not performed because some data is missing or incorrect. 78 | echo sprintf('BadRequestException Catched: %s', $e->getMessage()) . "\n"; 79 | } catch (TikTokRESTAPI\Exception\ForbiddenException $e) { 80 | // Request failed due to invalid, expired, revoked license or access to API is restricted. 81 | echo sprintf('ForbiddenException Catched: %s', $e->getMessage()) . "\n"; 82 | } catch (TikTokRESTAPI\Exception\NotFoundException $e) { 83 | // Requested resource doesn't exist in TikTok. 84 | echo sprintf('NotFoundException Catched: %s', $e->getMessage()) . "\n"; 85 | } catch (TikTokRESTAPI\Exception\ProxyAuthException $e) { 86 | // Proxy auth data is missing or incorrect. 87 | echo sprintf('ProxyAuthException Catched: %s', $e->getMessage()) . "\n"; 88 | } catch (TikTokRESTAPI\Exception\TooManyRequestsException $e) { 89 | // Too many requests sent to TikTok. 90 | echo sprintf('TooManyRequestsException Catched: %s', $e->getMessage()) . "\n"; 91 | } catch (TikTokRESTAPI\Exception\NetworkException $e) { 92 | // Couldn't establish connection with REST API server 93 | echo sprintf('NetworkException Catched: %s', $e->getMessage()) . "\n"; 94 | } catch (TikTokRESTAPI\Exception\TikTokException $e) { 95 | // Invalid argument, missing or invalid data in request 96 | echo sprintf('TikTokException Catched: %s', $e->getMessage()) . "\n"; 97 | } catch (Exception $e) { 98 | echo sprintf('Exception Catched: %s', $e->getMessage()) . "\n"; 99 | echo var_dump($e->getTrace()); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/Response/Model/MusicSearchItem.php: -------------------------------------------------------------------------------- 1 | 'int', 87 | 'id_str' => 'string', 88 | 'title' => 'string', 89 | 'author' => 'string', 90 | 'album' => 'string', 91 | 'cover_large' => 'Media', 92 | 'cover_medium' => 'Media', 93 | 'cover_thumb' => 'Media', 94 | 'play_url' => 'Media', 95 | 'source_platform' => 'int', 96 | 'duration' => 'int', 97 | 'extra' => '', 98 | 'user_count' => 'int', 99 | 'position' => '', 100 | 'collect_stat' => 'int', 101 | 'status' => 'int', 102 | 'offline_desc' => 'string', 103 | 'owner_nickname' => 'string', 104 | ]; 105 | } 106 | -------------------------------------------------------------------------------- /src/Response/Model/ChaListItem.php: -------------------------------------------------------------------------------- 1 | 'User', 99 | 'banner_list' => '', 100 | 'cha_attrs' => '', 101 | 'cha_name' => 'string', 102 | 'cid' => 'string', 103 | 'collect_stat' => 'int', 104 | 'connect_music' => '', 105 | 'desc' => 'string', 106 | 'extra_attr' => 'ExtraAttr', 107 | 'hashtag_profile' => 'string', 108 | 'is_challenge' => 'int', 109 | 'is_commerce' => 'bool', 110 | 'is_pgcshow' => 'bool', 111 | 'schema' => 'string', 112 | 'search_highlight' => '', 113 | 'share_info' => 'ShareInfo', 114 | 'show_items' => '', 115 | 'sub_type' => 'int', 116 | 'type' => 'int', 117 | 'user_count' => 'int', 118 | 'view_count' => 'int' 119 | ]; 120 | } 121 | -------------------------------------------------------------------------------- /src/Response/Model/ChallengeInfo.php: -------------------------------------------------------------------------------- 1 | 'mixed', 103 | 'cha_attrs' => 'mixed', 104 | 'cha_name' => 'string', 105 | 'cid' => 'string', 106 | 'collect_stat' => 'int', 107 | 'connect_music' => 'mixed', 108 | 'desc' => 'string', 109 | 'extra_attr' => 'ExtraAttr', 110 | 'hashtag_profile' => 'string', 111 | 'is_challenge' => 'int', 112 | 'is_commerce' => 'bool', 113 | 'is_pgcshow' => 'bool', 114 | 'schema' => 'string', 115 | 'search_cha_name' => 'string', 116 | 'search_highlight' => 'mixed', 117 | 'share_info' => 'ShareInfo', 118 | 'show_items' => 'mixed', 119 | 'sub_type' => 'int', 120 | 'type' => 'int', 121 | 'use_count' => 'int', 122 | 'user_count' => 'int', 123 | 'view_count' => 'int', 124 | ]; 125 | } 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TikTok REST API wrapper for PHP 2 | 3 | ![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/evelode/tiktok-api-php) 4 | ![GitHub last commit](https://img.shields.io/github/last-commit/evelode/tiktok-api-php) 5 | ![GitHub](https://img.shields.io/github/license/evelode/tiktok-api-php) 6 | 7 | [Run In Postman](https://app.getpostman.com/run-collection/24862082-d886cc87-4267-4e0c-b57a-2d083add50ad?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D24862082-d886cc87-4267-4e0c-b57a-2d083add50ad%26entityType%3Dcollection%26workspaceId%3D24af3158-f1f6-4911-be7b-9c245435502f) 8 | 9 | [evelode](https://app.getpostman.com/run-collection/24862082-d886cc87-4267-4e0c-b57a-2d083add50ad?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D24862082-d886cc87-4267-4e0c-b57a-2d083add50ad%26entityType%3Dcollection%26workspaceId%3D24af3158-f1f6-4911-be7b-9c245435502f) 10 | 11 | Easy to use [TikTok REST API](https://evelode.com/downloads/tiktok-rest-api/). Get TikTok public user data, feed, trends, hashtags, music, and non watermarked TikTok videos. 12 | 13 | Using our detailed multipurpose [API Documentation](https://evelode.com/tiktok-rest-api-documentation/) and following TikTok REST API wrapper for PHP you can explore and reach all TikTok REST API endpoints with ease. 14 | 15 | Try our [Trial license plan](https://evelode.com/downloads/tiktok-rest-api/) and test all API endpoints before buying a license. 16 | 17 | # Navigation 18 | 19 | - [Installation](#installation) 20 | - [Authentication](#authentication) 21 | - [Rate Limits](#rate-limits) 22 | - [License](#license) 23 | - [Support](#support) 24 | - [Endpoints](#endpoints) 25 | - [Examples](#examples) 26 | - [Video](#video) 27 | - [Search](#search) 28 | - [User](#user) 29 | - [Hashtag](#hashtag) 30 | - [Music](#music) 31 | 32 | # Installation 33 | 34 | If you want to install library **to exsiting project** using Composer: 35 | 36 | ```php 37 | cd /path-to-app/ 38 | composer require evelode/tiktok-api-php 39 | ``` 40 | 41 | - `/path-to-app/` project folder with existing `composer.json` file 42 | 43 | If you want to install library **to new project** using Composer: 44 | 45 | - If Composer not installed on your server/local machine, please follow this [installation guide](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-20-04) 46 | 47 | - Create blank file named as `composer.json` in project folder 48 | 49 | - Add following content to this file: 50 | 51 | ```php 52 | { 53 | "require": { 54 | "evelode/tiktok-api-php": "^1.0.0" 55 | } 56 | } 57 | ``` 58 | 59 | - After that install library using the following command: 60 | 61 | ```php 62 | cd /path-to-app/ 63 | composer update 64 | ``` 65 | 66 | - `/path-to-app/` project folder with existing `composer.json` file 67 | 68 | # Authentication 69 | 70 | Authentication occurs by passing the license key value through a query string named `license_key`, which can be purchased [here](https://evelode.com/downloads/tiktok-rest-api/). 71 | 72 | API Server Url: `https://tiktok.evelode.com/tiktok-api` 73 | 74 | # Rate Limits 75 | 76 | The developer `license_key` gives the right to use all methods within the TikTok REST API within the limit of requests for a specific period. Requests limit based on your license length and will be flushed when you renew or upgrade your license. Empty or invalid responses doesn't affect requests counter. 77 | 78 | Every license plan also have a requests per minute rate limit. More info about license plans you can check [here](https://evelode.com/downloads/tiktok-rest-api/). 79 | 80 | # License 81 | 82 | You can buy a valid `license_key` for TikTok REST API [here](https://evelode.com/downloads/tiktok-rest-api/). This license based on period of usage and requests count. 83 | 84 | **Demo Access**: We offer a Trial access with limited requests count, if you want to test REST API you can get license key [here](https://evelode.com/downloads/tiktok-rest-api/). Trial license can't be renewed, but can be upgraded to another licenses types. 85 | 86 | # Support 87 | 88 | This is a developer's portal for TikTok REST API wrapper for PHP and should not be used for support. Please [contact us via website chat](https://evelode.com/#chatraChatExpanded) if you need to submit a support request or have any question about API functionality. 89 | 90 | # Endpoints 91 | 92 | Using our detailed [Postman collection](https://www.postman.com/evelode/workspace/evelode/api/e2ed8e20-0dbd-41a3-9363-092d810217ed?action=share&creator=24862082) you can explore and test all TikTok REST API endpoints in real time. Try our Trial license plan and test all API endpoints before buying a license. 93 | 94 | # Examples 95 | 96 | ## Video 97 | 98 | - [getNoWatermarkUrl.php](/examples/getNoWatermarkUrl.php) 99 | - [getNoWatermarkUrlByID.php](/examples/getNoWatermarkUrlByID.php) 100 | - [getVideoByID.php](/examples/getVideoByID.php) 101 | - [getVideoByUrl.php](/examples/getVideoByUrl.php) 102 | - [getUnshortenedUrl.php](/examples/getUnshortenedUrl.php) 103 | - [getCommentsByUrl.php](/examples/getCommentsByUrl.php) 104 | - [getCommentsByID.php](/examples/getCommentsByID.php) 105 | 106 | ## Search 107 | 108 | - [searchUser.php](/examples/searchUser.php) 109 | - [searchVideo.php](/examples/searchVideo.php) 110 | - [searchMusic.php](/examples/searchMusic.php) 111 | - [searchLive.php](/examples/searchLive.php) 112 | - [searchHashtag.php](/examples/searchHashtag.php) 113 | 114 | ## User 115 | 116 | ## Hashtag 117 | 118 | ## Music 119 | -------------------------------------------------------------------------------- /src/Response/Model/Video.php: -------------------------------------------------------------------------------- 1 | 'bool', 115 | 'play_addr_h264' => 'Play', 116 | 'need_set_token' => 'bool', 117 | 'tags' => '', 118 | 'play_addr_bytevc1' => 'Play', 119 | 'ratio' => 'string', 120 | 'download_addr' => 'Download', 121 | 'bit_rate' => 'BitRate[]', 122 | 'duration' => 'int', 123 | 'cdn_url_expired' => 'int', 124 | 'misc_download_addrs' => '', 125 | 'meta' => '', 126 | 'cover' => 'Media', 127 | 'height' => 'string', 128 | 'animated_cover' => 'Media', 129 | 'is_callback' => 'bool', 130 | 'big_thumbs' => '', 131 | 'ai_dynamic_cover' => 'Media', 132 | 'ai_dynamic_cover_bak' => 'Media', 133 | 'play_addr' => 'Play', 134 | 'width' => 'int', 135 | 'dynamic_cover' => 'Media', 136 | 'origin_cover' => 'Media', 137 | 'is_bytevc1' => 'int', 138 | 'CoverTsp' => '' 139 | ]; 140 | } 141 | -------------------------------------------------------------------------------- /src/Response/Model/Author.php: -------------------------------------------------------------------------------- 1 | 'string', 143 | 'comment_filter_status' => 'int', 144 | 'short_id' => 'int', 145 | 'unique_id' => 'string', 146 | 'avatar_168x168' => 'Media', 147 | 'comment_setting' => 'int', 148 | 'custom_verify' => 'string', 149 | 'secret' => 'int', 150 | 'follow_status' => 'int', 151 | 'is_star' => 'bool', 152 | 'nickname' => 'string', 153 | 'avatar_medium' => 'Media', 154 | 'is_ad_fake' => 'bool', 155 | 'commerce_user_level' => 'int', 156 | 'prevent_download' => 'bool', 157 | 'avatar_thumb' => 'Media', 158 | 'duet_setting' => 'int', 159 | 'stitch_setting' => 'int', 160 | 'uid' => 'string', 161 | 'is_block' => 'bool', 162 | 'room_id' => 'int', 163 | 'room_title' => 'string', 164 | 'room_id_str' => 'string', 165 | 'search_user_name' => 'string', 166 | 'search_user_desc' => 'string', 167 | 'avatar_larger' => 'Media', 168 | 'follower_count' => 'int', 169 | 'language' => 'string', 170 | 'sec_uid' => 'string', 171 | 'ins_id' => 'string', 172 | 'enterprise_verify_reason' => 'string', 173 | 'download_setting' => 'int' 174 | ]; 175 | } 176 | -------------------------------------------------------------------------------- /src/Response/Model/Lives.php: -------------------------------------------------------------------------------- 1 | 'string', 176 | 'author' => 'Author', 177 | 'cha_list' => '', 178 | 'text_extra' => 'TextExtra', 179 | 'video_labels' => '', 180 | 'aweme_type' => 'int', 181 | 'image_infos' => '', 182 | 'position' => '', 183 | 'uniqid_position' => '', 184 | 'geofencing' => '', 185 | 'video_text' => '', 186 | 'label_top_text' => '', 187 | 'group_id' => 'string', 188 | 'nickname_position' => '', 189 | 'challenge_position' => '', 190 | 'long_video' => '', 191 | 'interaction_stickers' => '', 192 | 'origin_comment_ids' => '', 193 | 'commerce_config_data' => '', 194 | 'room' => 'Room', 195 | 'anchors' => '', 196 | 'rawdata' => '', 197 | 'hybrid_label' => '', 198 | 'geofencing_regions' => '', 199 | 'search_extra' => '', 200 | 'cover_labels' => '', 201 | 'mask_infos' => '', 202 | 'search_highlight' => '', 203 | 'green_screen_materials' => '', 204 | 'question_list' => '', 205 | 'content_desc_extra' => '', 206 | 'products_info' => '', 207 | 'branded_content_accounts' => '', 208 | 'tts_voice_ids' => '', 209 | 'reference_tts_voice_ids' => '', 210 | 'voice_filter_ids' => '', 211 | 'reference_voice_filter_ids' => '', 212 | 'muf_comment_info_v2' => '', 213 | 'behind_the_song_music_ids' => '', 214 | 'behind_the_song_video_music_ids' => '', 215 | 'operator_boost_info' => '' 216 | ]; 217 | } 218 | -------------------------------------------------------------------------------- /src/Response/Model/Music.php: -------------------------------------------------------------------------------- 1 | 'Media', 211 | 'tag_list' => '', 212 | 'video_duration' => 'int', 213 | 'cover_large' => 'Media', 214 | 'position' => '', 215 | 'sec_uid' => 'string', 216 | 'strong_beat_url' => 'Media', 217 | 'id' => 'int', 218 | 'owner_nickname' => 'string', 219 | 'binded_challenge_id' => 'int', 220 | 'duration' => 'int', 221 | 'shoot_duration' => 'int', 222 | 'mute_share' => 'bool', 223 | 'is_author_artist' => 'bool', 224 | 'matched_song' => 'MatchedSong', 225 | 'id_str' => 'string', 226 | 'author' => 'string', 227 | 'album' => 'string', 228 | 'is_original' => 'bool', 229 | 'author_deleted' => 'bool', 230 | 'author_position' => '', 231 | 'prevent_download' => 'bool', 232 | 'is_pgc' => 'bool', 233 | 'cover_medium' => 'Media', 234 | 'play_url' => 'Media', 235 | 'source_platform' => 'int', 236 | 'owner_id' => 'string', 237 | 'avatar_thumb' => 'Media', 238 | 'preview_start_time' => 'int', 239 | 'preview_end_time' => 'int', 240 | 'cover_thumb' => 'Media', 241 | 'user_count' => 'int', 242 | 'status' => 'int', 243 | 'owner_handle' => 'string', 244 | 'audition_duration' => 'int', 245 | 'title' => 'string', 246 | 'collect_stat' => 'int', 247 | 'offline_desc' => 'string', 248 | 'is_commerce_music' => 'bool', 249 | 'artists' => 'Artist[]', 250 | 'is_matched_metadata' => 'bool', 251 | 'matched_pgc_sound' => 'MatchedPgcSound', 252 | 'extra' => '', 253 | 'mid' => 'string', 254 | 'external_song_info' => 'ExternalSongInfo[]', 255 | 'is_audio_url_with_cookie' => 'bool', 256 | 'is_original_sound' => 'bool', 257 | 'lyric_short_position' => '', 258 | 'dmv_auto_show' => 'bool', 259 | ]; 260 | } 261 | -------------------------------------------------------------------------------- /src/Response/Model/AwemeDetail.php: -------------------------------------------------------------------------------- 1 | 'Statistics', 207 | 'is_vr' => 'bool', 208 | 'sort_label' => 'string', 209 | 'is_pgcshow' => 'bool', 210 | 'misc_info' => '', 211 | 'need_vs_entry' => 'bool', 212 | 'anchors' => 'Anchor[]', 213 | 'content_desc' => 'string', 214 | 'rate' => 'int', 215 | 'is_relieve' => 'bool', 216 | 'group_id' => 'string', 217 | 'prevent_download' => 'bool', 218 | 'distribute_type' => 'int', 219 | 'playlist_blocked' => 'bool', 220 | 'cmt_swt' => 'bool', 221 | 'label_top' => 'LabelTop', 222 | 'share_info' => 'ShareInfo', 223 | 'region' => 'string', 224 | 'stickers' => 'string', 225 | 'item_comment_settings' => 'int', 226 | 'sticker_detail' => 'StickerDetail', 227 | 'commerce_info' => 'CommerceInfo', 228 | 'desc' => 'string', 229 | 'item_stitch' => 'int', 230 | 'is_hash_tag' => 'int', 231 | 'collect_stat' => 'int', 232 | 'item_duet' => 'int', 233 | 'desc_language' => 'string', 234 | 'video_control' => 'VideoControl', 235 | 'has_vs_entry' => 'bool', 236 | 'aweme_acl' => 'AwemeAcl', 237 | 'risk_infos' => 'RiskInfos', 238 | 'share_url' => 'string', 239 | 'author' => 'Author', 240 | 'status' => 'Status', 241 | 'is_top' => 'int', 242 | 'aweme_type' => 'int', 243 | 'author_user_id' => 'int', 244 | 'bodydance_score' => 'int', 245 | 'create_time' => 'int', 246 | 'music' => 'Music', 247 | 'video' => 'Video', 248 | 'user_digged' => 'int', 249 | 'distance' => 'string', 250 | 'is_ads' => 'bool', 251 | 'without_watermark' => 'bool', 252 | 'follow_up_publish_from_id' => 'int', 253 | 'aweme_id' => 'string' 254 | ]; 255 | } 256 | -------------------------------------------------------------------------------- /src/Request.php: -------------------------------------------------------------------------------- 1 | _parent = $parent; 85 | $this->_endpoint = $endpoint; 86 | $this->_params['cache_timeout'] = $parent->cache_timeout; 87 | } 88 | 89 | /** 90 | * Add query param to request, overwriting any previous value. 91 | * 92 | * @param string $key 93 | * @param mixed $value 94 | * 95 | * @return self 96 | */ 97 | public function addParam( 98 | $key, 99 | $value) 100 | { 101 | if ($value === true) { 102 | $value = 'true'; 103 | } elseif ($value === false) { 104 | $value = 'false'; 105 | } 106 | $this->_params[$key] = $value; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * Get query param of request. 113 | * 114 | * @return array 115 | */ 116 | public function getParams() 117 | { 118 | return $this->_params; 119 | } 120 | 121 | /** 122 | * Add POST param to request, overwriting any previous value. 123 | * 124 | * @param string $key 125 | * @param mixed $value 126 | * 127 | * @return self 128 | */ 129 | public function addPost( 130 | $key, 131 | $value) 132 | { 133 | if ($value === true) { 134 | $value = 'true'; 135 | } elseif ($value === false) { 136 | $value = 'false'; 137 | } 138 | $this->_posts[$key] = $value; 139 | 140 | return $this; 141 | } 142 | 143 | /** 144 | * Get POST param of request. 145 | * 146 | * @return array 147 | */ 148 | public function getPosts() 149 | { 150 | return $this->_posts; 151 | } 152 | 153 | /** 154 | * Add custom header to request, overwriting any previous or default value. 155 | * 156 | * @param string $key 157 | * @param string $value 158 | * 159 | * @return self 160 | */ 161 | public function addHeader( 162 | $key, 163 | $value) 164 | { 165 | $this->_headers[$key] = $value; 166 | 167 | return $this; 168 | } 169 | 170 | /** 171 | * Get header of request. 172 | * 173 | * @param string $key 174 | * 175 | * @return mixed 176 | */ 177 | public function getHeader( 178 | $key) 179 | { 180 | if (!empty($this->_headers[$key])) { 181 | return $this->_headers[$key]; 182 | } 183 | return false; 184 | } 185 | 186 | /** 187 | * Checks is header is added. 188 | * 189 | * @param string $key 190 | * 191 | * @return bool 192 | */ 193 | public function hasHeader( 194 | $key) 195 | { 196 | if (isset($this->_headers[$key])) { 197 | return true; 198 | } 199 | return false; 200 | } 201 | 202 | /** 203 | * Get all headers of request. 204 | * 205 | * @param bool $keyValueArray 206 | * 207 | * @return mixed 208 | */ 209 | public function getHeaders( 210 | $keyValueArray = false) 211 | { 212 | if ($keyValueArray === false) { 213 | $headers = []; 214 | foreach ($this->_headers as $key => $value) { 215 | $headers[] = sprintf('%s: %s', $key, $value); 216 | } 217 | 218 | return $headers; 219 | } else { 220 | return $this->_headers; 221 | } 222 | } 223 | 224 | /** 225 | * Set encoding of the request. 226 | * 227 | * @param string $encoding Request encoding type. 228 | * 229 | * @return self 230 | */ 231 | public function setEncoding( 232 | $encoding) 233 | { 234 | $this->_encoding = $encoding; 235 | 236 | return $this; 237 | } 238 | 239 | /** 240 | * Get encoding of the request. 241 | * 242 | * @return string 243 | */ 244 | public function getEncoding() 245 | { 246 | return $this->_encoding; 247 | } 248 | 249 | /** 250 | * Get raw response of the request. 251 | * 252 | * @param bool $bool 253 | * 254 | * @return self 255 | */ 256 | public function getRaw( 257 | $bool = false) 258 | { 259 | $this->_getRaw = (bool) $bool; 260 | 261 | return $this; 262 | } 263 | 264 | /** 265 | * Is response is RAW response or not 266 | * 267 | * @return bool 268 | */ 269 | public function isGetRaw() 270 | { 271 | return $this->_getRaw; 272 | } 273 | 274 | /** 275 | * Get request URL. 276 | * 277 | * @return string 278 | */ 279 | public function getUrl() 280 | { 281 | if (strncmp($this->_endpoint, 'http:', 5) !== 0 && strncmp($this->_endpoint, 'https:', 6) !== 0) { 282 | return self::API_BASE . $this->_endpoint; 283 | } 284 | return $this->_endpoint; 285 | } 286 | 287 | /** 288 | * Get request body 289 | * 290 | * @return mixed 291 | */ 292 | public function getBody() 293 | { 294 | if ($this->getEncoding() === 'json') { 295 | return json_encode($this->getPosts()); 296 | } elseif ($this->getEncoding() === 'urlencode') { 297 | return http_build_query($this->getPosts()); 298 | } else { 299 | return null; 300 | } 301 | } 302 | 303 | /** 304 | * Return safely JSON-decoded HTTP response. 305 | * 306 | * This uses a special decoder which handles 64-bit numbers correctly. 307 | * 308 | * @param bool $assoc When FALSE, decode to object instead of associative array. 309 | * 310 | * @throws \TikTokRESTAPI\Exception\TikTokException 311 | * @throws \TikTokRESTAPI\Exception\BadRequestException 312 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 313 | * @throws \TikTokRESTAPI\Exception\NotFoundException 314 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 315 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 316 | * @throws \Exception 317 | * 318 | * @return mixed 319 | */ 320 | public function getResponse() 321 | { 322 | $curl_options = []; 323 | 324 | if ($this->getParams() !== null) { 325 | $url = $this->getUrl().'?'.urldecode(http_build_query($this->getParams())); 326 | } else { 327 | $url = $this->getUrl(); 328 | } 329 | 330 | if ($this->getPosts() !== null) { 331 | if ($this->getEncoding() === 'json') { 332 | $this->addHeader('content-type', 'application/json; charset=utf-8'); 333 | } else { 334 | $this->addHeader('content-type', 'application/x-www-form-urlencoded; charset=utf-8'); 335 | } 336 | $curl_options[CURLOPT_POST] = true; 337 | $curl_options[CURLOPT_HTTPHEADER] = $this->getHeaders(); 338 | $curl_options[CURLOPT_POSTFIELDS] = $this->getBody(); 339 | $method = "POST"; 340 | } else { 341 | $curl_options[CURLOPT_HTTPHEADER] = $this->getHeaders(); 342 | $method = "GET"; 343 | } 344 | 345 | $curl_options[CURLOPT_HEADER] = false; 346 | $curl_options[CURLOPT_ENCODING] = 'gzip'; 347 | $curl_options[CURLOPT_RETURNTRANSFER] = true; 348 | $curl_options[CURLOPT_SSL_VERIFYHOST] = false; 349 | $curl_options[CURLOPT_SSL_VERIFYPEER] = false; 350 | 351 | // Make http client work with HTTP 2/0 352 | $curl_options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0; 353 | $curl_options[CURLOPT_SSLVERSION] = 1; 354 | 355 | $request_options = [ 356 | "debug" => false, 357 | "verify" => file_exists('/etc/ssl/certs/cacert.pem') ? '/etc/ssl/certs/cacert.pem' : false, 358 | "timeout" => 30, 359 | 'decode_content' => true, // Decode gzip/deflate/etc HTTP responses. 360 | "curl" => $curl_options, 361 | // Tells Guzzle to stop throwing exceptions on non-"2xx" HTTP codes, 362 | // thus ensuring that it only triggers exceptions on socket errors! 363 | // We'll instead MANUALLY be throwing on certain other HTTP codes. 364 | 'http_errors' => false 365 | ]; 366 | 367 | // Request debug output 368 | if ($this->_parent->debug === true) { 369 | $this->pre_debug(); 370 | } 371 | 372 | // Perform the request to API server 373 | try { 374 | $client = new \GuzzleHttp\Client(); 375 | $response = $client->request($method, $url, $request_options); 376 | } catch (\Exception $e) { 377 | // Re-wrap Guzzle's exception using our own NetworkException. 378 | throw new NetworkException($e); 379 | } 380 | 381 | // Response debug output 382 | if ($this->_parent->debug === true) { 383 | $this->post_debug($response); 384 | } 385 | 386 | // Get RAW response body 387 | $rawResponse = (string) $response->getBody(); 388 | 389 | // Attempt to decode the raw JSON to an array 390 | $json = $this->api_body_decode($rawResponse, true); 391 | 392 | // Detect HTTP status codes in the response 393 | $httpCode = $response->getStatusCode(); 394 | 395 | // Trying to identify message in response 396 | $message = null; 397 | if (!empty($json['message'])) { 398 | $message = $json['message']; 399 | } 400 | 401 | // Iterate in HTTP status codes and throw correct exception 402 | switch ($httpCode) { 403 | case 200: // Request performed successfully. 404 | break; 405 | case 400: // Request not performed because some data is missing or incorrect. 406 | if (!empty($message)) { 407 | throw new BadRequestException($message); 408 | } else { 409 | throw new BadRequestException("Request not performed because some data is missing or incorrect."); 410 | } 411 | break; 412 | case 403: // Request failed due to invalid, expired, revoked license or access to API is restricted. 413 | if (!empty($message)) { 414 | throw new ForbiddenException($message); 415 | } else { 416 | throw new ForbiddenException("Request failed due to invalid, expired, revoked license or access to API is restricted."); 417 | } 418 | break; 419 | case 404: // Requested resource doesn't exist in TikTok. 420 | if (!empty($message)) { 421 | throw new NotFoundException($message); 422 | } else { 423 | throw new NotFoundException("Requested resource doesn't exist in TikTok."); 424 | } 425 | break; 426 | case 407: // Proxy auth data is missing or incorrect. 427 | if (!empty($message)) { 428 | throw new ProxyAuthException($message); 429 | } else { 430 | throw new ProxyAuthException("Proxy auth data is missing or incorrect."); 431 | } 432 | break; 433 | case 429: // Too many requests sent to TikTok. 434 | if (!empty($message)) { 435 | throw new TooManyRequestsException($message); 436 | } else { 437 | throw new TooManyRequestsException("Too many requests sent to TikTok."); 438 | } 439 | break; 440 | default: // Other errors 441 | if (!empty($message)) { 442 | throw new TikTokException($message); 443 | } else { 444 | throw new TikTokException($e->getMessage()); 445 | } 446 | break; 447 | } 448 | 449 | if ($this->isGetRaw()) { 450 | return $rawResponse; 451 | } 452 | 453 | return $json; 454 | } 455 | 456 | /** 457 | * Print request, if debug mode is enabled 458 | */ 459 | public function pre_debug() 460 | { 461 | echo "\033[1;35;m[REQUEST]\n"; 462 | 463 | $method = $this->getPosts() === null ? 'GET' : 'POST'; 464 | if ($this->getParams() !== null) { 465 | echo "\033[1;33;m".strtoupper($method).": \033[0m".$this->getUrl().'?'.urldecode(http_build_query($this->getParams()))."\n"; 466 | } else { 467 | echo "\033[1;33;m".strtoupper($method).": \033[0m".$this->getUrl()."\n"; 468 | } 469 | 470 | echo "\033[1;35;mHEADERS:\n"; 471 | foreach ($this->getHeaders() as $index => $value) { 472 | echo $value . "\n"; 473 | } 474 | 475 | echo "\033[1;35;mENCODING: \033[0m".$this->getEncoding()."\n"; 476 | 477 | if ($this->getPosts() !== null) { 478 | echo "\033[1;35;mDATA: \033[0m".$this->getBody()."\n\n"; 479 | } 480 | } 481 | 482 | /** 483 | * Print response, if debug mode is enabled 484 | */ 485 | public function post_debug( 486 | $response) 487 | { 488 | echo "\033[1;35;m[RESPONSE]\n"; 489 | echo "\033[1;32;mSTATUS: \033[0m".$response->getStatusCode()."\n"; 490 | if (!empty($response->getBody())) { 491 | // Human-Readable Response 492 | $rawResponse = (string) $response->getBody(); 493 | $json = $this->api_body_decode($rawResponse, false); 494 | if (is_object($json)) { 495 | $prettyJson = @json_encode( 496 | $json, 497 | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE 498 | ); 499 | if ($prettyJson !== false) { 500 | echo "\033[1;32;mRESPONSE: \033[0m".$prettyJson."\n\n"; 501 | } else { 502 | echo "\033[1;32;mRESPONSE: \033[0m".$response->getBody()->getContents()."\n\n"; 503 | } 504 | } else { 505 | echo "\033[1;32;mRESPONSE: \033[0m".$response->getBody()->getContents()."\n\n"; 506 | } 507 | } else { 508 | echo "\033[1;32;mRESPONSE:\n\n"; 509 | } 510 | } 511 | 512 | /** 513 | * Decode a JSON reply from TikTok's API. 514 | * 515 | * WARNING: EXTREMELY IMPORTANT! NEVER, *EVER* USE THE BASIC "json_decode" 516 | * ON API REPLIES! ALWAYS USE THIS METHOD INSTEAD, TO ENSURE PROPER DECODING 517 | * OF BIG NUMBERS! OTHERWISE YOU'LL TRUNCATE VARIOUS INSTAGRAM API FIELDS! 518 | * 519 | * @param string $json The body (JSON string) of the API response. 520 | * @param bool $assoc When FALSE, decode to object instead of associative array. 521 | * 522 | * @return object|array|null Object if assoc false, Array if assoc true, 523 | * or NULL if unable to decode JSON. 524 | */ 525 | public static function api_body_decode( 526 | $json, 527 | $assoc = true) 528 | { 529 | return @json_decode($json, $assoc, 512, JSON_BIGINT_AS_STRING); 530 | } 531 | } -------------------------------------------------------------------------------- /src/TikTok.php: -------------------------------------------------------------------------------- 1 | licenseKey = $licenseKey; 44 | $this->debug = $debug; 45 | } 46 | 47 | /** 48 | * Set the API cache timeout 49 | * 50 | * By default we use caching system with 3600 seconds window to speed up similar requests to API. 51 | * If you want to disable caching, you can set 0 here. 52 | * 53 | * @param int $value Cache timeout in seconds 54 | */ 55 | public function setCacheTimeout( 56 | $value) 57 | { 58 | $value = (int) $value; 59 | if ($value >= 0) { 60 | $this->cache_timeout = $value; 61 | } 62 | } 63 | 64 | /** 65 | * Set the API cache timeout back to default value 66 | * 67 | * By default we use caching system with 3600 seconds window to speed up similar requests to API. 68 | */ 69 | public function unsetCacheTimeout() 70 | { 71 | $this->cache_timeout = 3600; 72 | } 73 | 74 | /** 75 | * Get non watermarked video URL. 76 | * 77 | * @param string $video_url TikTok video URL. 78 | * 79 | * @throws \TikTokRESTAPI\Exception\TikTokException 80 | * @throws \TikTokRESTAPI\Exception\BadRequestException 81 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 82 | * @throws \TikTokRESTAPI\Exception\NotFoundException 83 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 84 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 85 | * @throws \Exception 86 | * 87 | * @return \TikTokRESTAPI\Response\APIResponse 88 | */ 89 | public function getNoWatermarkUrl( 90 | $video_url = '') 91 | { 92 | if (empty($video_url)) { 93 | throw new TikTokException("Empty video URL."); 94 | } 95 | 96 | $response = $this->request('getNoWatermarkUrl') 97 | ->addParam('license_key', $this->licenseKey) 98 | ->addParam('video_url', $video_url) 99 | ->getResponse(); 100 | 101 | return new Response\APIResponse($response); 102 | } 103 | 104 | /** 105 | * Get non watermarked video url by video ID. 106 | * 107 | * @param string $video_id TikTok video ID. 108 | * 109 | * @throws \TikTokRESTAPI\Exception\TikTokException 110 | * @throws \TikTokRESTAPI\Exception\BadRequestException 111 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 112 | * @throws \TikTokRESTAPI\Exception\NotFoundException 113 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 114 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 115 | * @throws \Exception 116 | * 117 | * @return \TikTokRESTAPI\Response\APIResponse 118 | */ 119 | public function getNoWatermarkUrlByID( 120 | $video_id = '') 121 | { 122 | if (empty($video_id)) { 123 | throw new TikTokException("Empty video ID."); 124 | } 125 | 126 | $response = $this->request('getNoWatermarkUrlByID') 127 | ->addParam('license_key', $this->licenseKey) 128 | ->addParam('video_id', $video_id) 129 | ->getResponse(); 130 | 131 | return new Response\APIResponse($response); 132 | } 133 | 134 | /** 135 | * Get video info by ID. 136 | * 137 | * @param string $video_id TikTok video ID. 138 | * 139 | * @throws \TikTokRESTAPI\Exception\TikTokException 140 | * @throws \TikTokRESTAPI\Exception\BadRequestException 141 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 142 | * @throws \TikTokRESTAPI\Exception\NotFoundException 143 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 144 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 145 | * @throws \Exception 146 | * 147 | * @return \TikTokRESTAPI\Response\APIResponse 148 | */ 149 | public function getVideoByID( 150 | $video_id = '') 151 | { 152 | if (empty($video_id)) { 153 | throw new TikTokException("Empty video ID."); 154 | } 155 | 156 | $response = $this->request('getVideoByID') 157 | ->addParam('license_key', $this->licenseKey) 158 | ->addParam('video_id', $video_id) 159 | ->getResponse(); 160 | 161 | return new Response\APIResponse($response); 162 | } 163 | 164 | /** 165 | * Get video info by URL 166 | * 167 | * @param string $video_url TikTok video URL. 168 | * 169 | * @throws \TikTokRESTAPI\Exception\TikTokException 170 | * @throws \TikTokRESTAPI\Exception\BadRequestException 171 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 172 | * @throws \TikTokRESTAPI\Exception\NotFoundException 173 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 174 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 175 | * @throws \Exception 176 | * 177 | * @return \TikTokRESTAPI\Response\APIResponse 178 | */ 179 | public function getVideoByUrl( 180 | $video_url = '') 181 | { 182 | if (empty($video_url)) { 183 | throw new TikTokException("Empty video URL."); 184 | } 185 | 186 | $response = $this->request('getVideoByUrl') 187 | ->addParam('license_key', $this->licenseKey) 188 | ->addParam('video_url', $video_url) 189 | ->getResponse(); 190 | 191 | return new Response\APIResponse($response); 192 | } 193 | 194 | /** 195 | * Convert short TikTok video URL to full TikTok video URL 196 | * 197 | * @param string $video_url TikTok video URL. 198 | * 199 | * @throws \TikTokRESTAPI\Exception\TikTokException 200 | * @throws \TikTokRESTAPI\Exception\BadRequestException 201 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 202 | * @throws \TikTokRESTAPI\Exception\NotFoundException 203 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 204 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 205 | * @throws \Exception 206 | * 207 | * @return \TikTokRESTAPI\Response\APIResponse 208 | */ 209 | public function getUnshortenedUrl( 210 | $video_url = '') 211 | { 212 | if (empty($video_url)) { 213 | throw new TikTokException("Empty video URL."); 214 | } 215 | 216 | $response = $this->request('getUnshortenedUrl') 217 | ->addParam('license_key', $this->licenseKey) 218 | ->addParam('video_url', $video_url) 219 | ->getResponse(); 220 | 221 | return new Response\APIResponse($response); 222 | } 223 | 224 | /** 225 | * Get comments list by video URL 226 | * 227 | * @param string $video_url TikTok video URL. 228 | * @param string $cursor Used for scrolling (pagination) in comments items, you can get cursor value from the previous response. 229 | * @param int $count Number of comments you want to get. For example: 30. 230 | * 231 | * @throws \TikTokRESTAPI\Exception\TikTokException 232 | * @throws \TikTokRESTAPI\Exception\BadRequestException 233 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 234 | * @throws \TikTokRESTAPI\Exception\NotFoundException 235 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 236 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 237 | * @throws \Exception 238 | * 239 | * @return \TikTokRESTAPI\Response\APIResponse 240 | */ 241 | public function getCommentsByUrl( 242 | $video_url = '', 243 | $cursor = '', 244 | $count = 30) 245 | { 246 | if (empty($video_url)) { 247 | throw new TikTokException("Empty video URL."); 248 | } 249 | 250 | $response = $this->request('getCommentsByUrl') 251 | ->addParam('license_key', $this->licenseKey) 252 | ->addParam('video_url', $video_url) 253 | ->addParam('cursor', $cursor) 254 | ->addParam('count', $count) 255 | ->getResponse(); 256 | 257 | return new Response\APIResponse($response); 258 | } 259 | 260 | /** 261 | * Get comments list by video ID 262 | * 263 | * @param string $video_id TikTok video ID. 264 | * @param string $cursor Used for scrolling (pagination) in comments items, you can get cursor value from the previous response. 265 | * @param int $count Number of comments you want to get. For example: 30. 266 | * 267 | * @throws \TikTokRESTAPI\Exception\TikTokException 268 | * @throws \TikTokRESTAPI\Exception\BadRequestException 269 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 270 | * @throws \TikTokRESTAPI\Exception\NotFoundException 271 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 272 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 273 | * @throws \Exception 274 | * 275 | * @return \TikTokRESTAPI\Response\APIResponse 276 | */ 277 | public function getCommentsByID( 278 | $video_id = '', 279 | $cursor = '', 280 | $count = 30) 281 | { 282 | if (empty($video_id)) { 283 | throw new TikTokException("Empty video ID."); 284 | } 285 | 286 | $response = $this->request('getCommentsByID') 287 | ->addParam('license_key', $this->licenseKey) 288 | ->addParam('video_id', $video_id) 289 | ->addParam('cursor', $cursor) 290 | ->addParam('count', $count) 291 | ->getResponse(); 292 | 293 | return new Response\APIResponse($response); 294 | } 295 | 296 | /** 297 | * Search for user by keyword 298 | * 299 | * @param string $keyword Any text or keyword 300 | * @param string $cursor Used for scrolling (pagination) in the list of users, you can get cursor value from the previous response. 301 | * @param int $count Number of users you want to get. For example: 10. 302 | * 303 | * @throws \TikTokRESTAPI\Exception\TikTokException 304 | * @throws \TikTokRESTAPI\Exception\BadRequestException 305 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 306 | * @throws \TikTokRESTAPI\Exception\NotFoundException 307 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 308 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 309 | * @throws \Exception 310 | * 311 | * @return \TikTokRESTAPI\Response\APIResponse 312 | */ 313 | public function searchUser( 314 | $keyword = '', 315 | $cursor = '', 316 | $count = 10) 317 | { 318 | if (empty($keyword)) { 319 | throw new TikTokException("Empty keyword."); 320 | } 321 | 322 | $response = $this->request('searchUser') 323 | ->addParam('license_key', $this->licenseKey) 324 | ->addParam('keyword', $keyword) 325 | ->addParam('cursor', $cursor) 326 | ->addParam('count', $count) 327 | ->getResponse(); 328 | 329 | return new Response\APIResponse($response); 330 | } 331 | 332 | /** 333 | * Search for video by keyword 334 | * 335 | * @param string $keyword Any text or keyword 336 | * @param string $cursor Used for scrolling (pagination) in the list of videos, you can get cursor value from the previous response. 337 | * @param int $count Number of videos you want to get. For example: 10. 338 | * @param string $date_posted How long ago was the video posted. Valid values: 'yesterday', 'this-week', 'this-month', 'last-3-months', 'last-6-months' and 'all-time'. 339 | * @param string $sort_by Sort videos by metrics. Valid values: 'most-liked' or 'relevance'. 340 | * 341 | * @throws \TikTokRESTAPI\Exception\TikTokException 342 | * @throws \TikTokRESTAPI\Exception\BadRequestException 343 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 344 | * @throws \TikTokRESTAPI\Exception\NotFoundException 345 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 346 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 347 | * @throws \Exception 348 | * 349 | * @return \TikTokRESTAPI\Response\APIResponse 350 | */ 351 | public function searchVideo( 352 | $keyword = '', 353 | $cursor = '', 354 | $count = 10, 355 | $date_posted = 'all-time', 356 | $sort_by = 'relevance') 357 | { 358 | if (empty($keyword)) { 359 | throw new TikTokException("Empty keyword."); 360 | } 361 | 362 | $response = $this->request('searchVideo') 363 | ->addParam('license_key', $this->licenseKey) 364 | ->addParam('keyword', $keyword) 365 | ->addParam('cursor', $cursor) 366 | ->addParam('count', $count) 367 | ->addParam('date_posted', $date_posted) 368 | ->addParam('sort_by', $sort_by) 369 | ->getResponse(); 370 | 371 | return new Response\APIResponse($response); 372 | } 373 | 374 | /** 375 | * Search for music by keyword 376 | * 377 | * @param string $keyword Any text or keyword 378 | * @param string $cursor Used for scrolling (pagination) in the list of music tracks, you can get cursor value from the previous response. 379 | * @param int $count Number of music tracks you want to get. For example: 10. 380 | * 381 | * @throws \TikTokRESTAPI\Exception\TikTokException 382 | * @throws \TikTokRESTAPI\Exception\BadRequestException 383 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 384 | * @throws \TikTokRESTAPI\Exception\NotFoundException 385 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 386 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 387 | * @throws \Exception 388 | * 389 | * @return \TikTokRESTAPI\Response\APIResponse 390 | */ 391 | public function searchMusic( 392 | $keyword = '', 393 | $cursor = '', 394 | $count = 10) 395 | { 396 | if (empty($keyword)) { 397 | throw new TikTokException("Empty keyword."); 398 | } 399 | 400 | $response = $this->request('searchMusic') 401 | ->addParam('license_key', $this->licenseKey) 402 | ->addParam('keyword', $keyword) 403 | ->addParam('cursor', $cursor) 404 | ->addParam('count', $count) 405 | ->getResponse(); 406 | 407 | return new Response\APIResponse($response); 408 | } 409 | 410 | /** 411 | * Search for live by keyword 412 | * 413 | * @param string $keyword Any text or keyword 414 | * @param string $offset Used for scrolling (pagination) in the list of lives, you can get cursor value from the previous response. 415 | * @param string $count Number of lives you want to get. For example: 10. 416 | * 417 | * @throws \TikTokRESTAPI\Exception\TikTokException 418 | * @throws \TikTokRESTAPI\Exception\BadRequestException 419 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 420 | * @throws \TikTokRESTAPI\Exception\NotFoundException 421 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 422 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 423 | * @throws \Exception 424 | * 425 | * @return \TikTokRESTAPI\Response\APIResponse 426 | */ 427 | public function searchLive( 428 | $keyword = '', 429 | $offset = '', 430 | $count = 10) 431 | { 432 | if (empty($keyword)) { 433 | throw new TikTokException("Empty keyword."); 434 | } 435 | 436 | $response = $this->request('searchLive') 437 | ->addParam('license_key', $this->licenseKey) 438 | ->addParam('keyword', $keyword) 439 | ->addParam('offset', $offset) 440 | ->addParam('count', $count) 441 | ->getResponse(); 442 | 443 | return new Response\APIResponse($response); 444 | } 445 | 446 | /** 447 | * Search for hashtag by keyword 448 | * 449 | * @param string $keyword Any text or keyword 450 | * @param string $cursor Used for scrolling (pagination) in the list of lives, you can get cursor value from the previous response. 451 | * @param string $count Number of lives you want to get. For example: 10. 452 | * 453 | * @throws \TikTokRESTAPI\Exception\TikTokException 454 | * @throws \TikTokRESTAPI\Exception\BadRequestException 455 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 456 | * @throws \TikTokRESTAPI\Exception\NotFoundException 457 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 458 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 459 | * @throws \Exception 460 | * 461 | * @return \TikTokRESTAPI\Response\APIResponse 462 | */ 463 | public function searchHashtag( 464 | $keyword = '', 465 | $cursor = '', 466 | $count = 10) 467 | { 468 | if (empty($keyword)) { 469 | throw new TikTokException("Empty keyword."); 470 | } 471 | 472 | $response = $this->request('searchHashtag') 473 | ->addParam('license_key', $this->licenseKey) 474 | ->addParam('keyword', $keyword) 475 | ->addParam('cursor', $cursor) 476 | ->addParam('count', $count) 477 | ->getResponse(); 478 | 479 | return new Response\APIResponse($response); 480 | } 481 | 482 | /** 483 | * Get user info by profile URL or nickname 484 | * 485 | * @param string $query TikTok username 486 | * 487 | * @throws \TikTokRESTAPI\Exception\TikTokException 488 | * @throws \TikTokRESTAPI\Exception\BadRequestException 489 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 490 | * @throws \TikTokRESTAPI\Exception\NotFoundException 491 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 492 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 493 | * @throws \Exception 494 | * 495 | * @return \TikTokRESTAPI\Response\APIResponse 496 | */ 497 | public function getUserInfo( 498 | $query = '') 499 | { 500 | if (empty($query)) { 501 | throw new TikTokException("Empty username."); 502 | } 503 | 504 | $response = $this->request('getUserInfo') 505 | ->addParam('license_key', $this->licenseKey) 506 | ->addParam('query', $query) 507 | ->getResponse(); 508 | 509 | return new Response\APIResponse($response); 510 | } 511 | 512 | /** 513 | * Create a custom API request. 514 | * 515 | * Used internally, but can also be used by end-users if they want 516 | * to create completely custom API queries without modifying this library. 517 | * 518 | * @param string $endpoint 519 | * 520 | * @throws \TikTokRESTAPI\Exception\TikTokException 521 | * @throws \TikTokRESTAPI\Exception\BadRequestException 522 | * @throws \TikTokRESTAPI\Exception\ForbiddenException 523 | * @throws \TikTokRESTAPI\Exception\NotFoundException 524 | * @throws \TikTokRESTAPI\Exception\ProxyAuthException 525 | * @throws \TikTokRESTAPI\Exception\TooManyRequestsException 526 | * @throws \Exception 527 | * 528 | * @return \TikTokRESTAPI\Request 529 | */ 530 | public function request( 531 | $endpoint = '') 532 | { 533 | return new Request($this, $endpoint); 534 | } 535 | } --------------------------------------------------------------------------------