├── README.md ├── Main.java ├── TikTokDownloaderV2.java └── TikTokDownloader.java /README.md: -------------------------------------------------------------------------------- 1 | # TikTok-downloader (Doesn't work. Looking for a fix. 8/24/2021) 2 | 3 | 4 | Before you look any further, please note that this code does not work at this moment. 5 | 6 | ... 7 | A simple java class that can parse and download a video from TikTok :) 8 | 9 | To download a tiktok, initialize the TikTokDownloaderV2 class with the required arguments. 10 | ```TikTokDownloaderV2 ttd = new TikTokDownloaderV2(String fileLocation, String videoURL);``` 11 | 12 | Next, call the download method. It may throw exceptions, so use a try/catch block 13 | ```ttd.download();``` 14 | 15 | You can view an example in the ```Main.class``` file. 16 | -------------------------------------------------------------------------------- /Main.java: -------------------------------------------------------------------------------- 1 | package com.main; 2 | 3 | import java.io.IOException; 4 | import java.net.MalformedURLException; 5 | 6 | public class Main{ 7 | 8 | 9 | /* 10 | * A simple tiktok downloader in java. 11 | * Please note: this will download videos WITH a watermark. 12 | * 13 | * If you are having problems downloading videos, 14 | * use your browser on your computer, visit a tiktok video, 15 | * and copy the link in the address bar and use that URL to 16 | * download the tiktok. 17 | */ 18 | 19 | final String TikTokSaveLocation = "C:\\Users\\Alex\\Desktop\\TikTok_" + System.currentTimeMillis() + ".mp4"; 20 | final String TikTokURL = "https://www.tiktok.com/@duncanyounot/video/6752667006530620678"; 21 | final String TikTokURL2 = "https://www.tiktok.com/@jay.gamao/video/6747120899637382402"; 22 | 23 | // Remove static context 24 | public static void main(String[] args) { new Main().mainMethod(); } 25 | 26 | 27 | // Main method 28 | public void mainMethod() { 29 | 30 | try { 31 | 32 | //Initialize the TikTokDownloaderV2 class 33 | TikTokDownloaderV2 ttd = new TikTokDownloaderV2(TikTokSaveLocation, TikTokURL); 34 | 35 | //Call the download method to download the video 36 | ttd.download(); 37 | 38 | } catch (MalformedURLException e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } catch (IOException e) { 42 | // TODO Auto-generated catch block 43 | e.printStackTrace(); 44 | } 45 | 46 | 47 | 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /TikTokDownloaderV2.java: -------------------------------------------------------------------------------- 1 | package com.main; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.net.MalformedURLException; 10 | import java.net.URL; 11 | import java.net.URLConnection; 12 | 13 | public class TikTokDownloaderV2 { 14 | 15 | //Set up variables 16 | private File file; 17 | private URL url; 18 | 19 | 20 | /* 21 | * This method sets the variables needed to download a video. 22 | * fileLocation is the location where the video is going to be saved 23 | * videoURL is the URL of the video to be downloaded 24 | */ 25 | public TikTokDownloaderV2(String fileLocation, String videoURL) throws MalformedURLException { 26 | file = new File(fileLocation); 27 | url = new URL(videoURL); 28 | System.out.println("Initialized TikTokDownloader version 2"); 29 | } 30 | 31 | 32 | 33 | /* 34 | * This method connects to the website from the given URL. 35 | * It removes useless content and grabs the video URL and thumbnail URL 36 | * from the webpage 37 | */ 38 | public void download() throws IOException { 39 | 40 | //Create a URL connection 41 | URLConnection conn = url.openConnection(); 42 | 43 | //Set the user agent so TikTok will think we're a person using a browser instead of a program 44 | conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); 45 | 46 | //Set up the bufferedReader 47 | BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 48 | 49 | /* 50 | * Read every line until we get 51 | * to a string with the text 'videoObject' 52 | * which is where misc. information about 53 | * the user is stored and where the video 54 | * URL is stored too 55 | */ 56 | String data; 57 | while((data = in.readLine()) !=null) { 58 | if(data.contains("videoObject")) { 59 | // Read up until we reach a string in the HTML file valled 'videoObject' 60 | break; 61 | } 62 | } 63 | 64 | //Close the bufferedReader as we don't need it anymore 65 | in.close(); 66 | 67 | /* 68 | * Because we are viewing the raw source code from 69 | * the website, there's a lot of trash including but not 70 | * limited to HTML tags, javascript, random text, and so 71 | * on. We don't want that. That's why it will be cropped 72 | * out down below 73 | */ 74 | 75 | //Crop out the useless tags and code behind the VideoObject string 76 | data = data.substring(data.indexOf("VideoObject"), data.length()); 77 | 78 | 79 | //Grab the thumb nail URL 80 | String thumbnailURL = data.substring(data.indexOf("thumbnailUrl") + 16); 81 | thumbnailURL = thumbnailURL.substring(0, thumbnailURL.indexOf("\"")); 82 | 83 | // Print out the thumbnail URL 84 | System.out.println("ThumbnailURL: " + thumbnailURL); 85 | 86 | //Grab content URL (video file) 87 | String contentURL = data.substring(data.indexOf("contentUrl") + 13); 88 | contentURL = contentURL.substring(0, contentURL.indexOf("?")); 89 | 90 | //Print out the video URL 91 | System.out.println("ContentURL: " + contentURL); 92 | 93 | //Now that we have the Thumbnail and Video URL, we can download them! 94 | downloadVideoFile(contentURL); 95 | } 96 | 97 | 98 | /* 99 | * This method actually downloads the video 100 | */ 101 | private void downloadVideoFile(String url) throws MalformedURLException, IOException { 102 | 103 | //Set up the stream and connect to the video URL 104 | InputStream inputStream = new URL(url).openStream(); 105 | 106 | //Set up the buffer to store the inputstream bytes into 107 | //It can be anything, but 512 is an okay buffer size 108 | byte[] videoBuffer = new byte[512]; 109 | 110 | //Set up the file output stream 111 | FileOutputStream fileOutputStream = new FileOutputStream(file); 112 | 113 | /* 114 | * When the streams ends (which means we downloaded the whole video) 115 | * it will return '-1' 116 | * While we store the bytes into the videoBuffer from inputStream 117 | * and the stream doesn't equal -1, write each byte from the buffer into the file. 118 | * When the stream equals -1, close the file as the video is complete 119 | */ 120 | int len; 121 | while((len = inputStream.read(videoBuffer)) != -1) { 122 | fileOutputStream.write(videoBuffer, 0, len); 123 | } 124 | 125 | //Close the file stream 126 | fileOutputStream.close(); 127 | 128 | //Done message 129 | System.out.println("Video Downloaded!"); 130 | 131 | 132 | 133 | 134 | } 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /TikTokDownloader.java: -------------------------------------------------------------------------------- 1 | package com.main; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.net.URL; 9 | import java.net.URLConnection; 10 | 11 | public class TikTokDownloader{ 12 | 13 | //Class-wide variables 14 | private int oldProg = 0; 15 | private File fileLocation; 16 | 17 | 18 | /* 19 | * Just call this method and you're good to go :) 20 | */ 21 | public void download(String TikTokURL, File fileLocation) throws Exception{ 22 | this.fileLocation = fileLocation; 23 | 24 | messageCallback("INIT", "Checking url..."); 25 | 26 | //If the URL is from the TikTok website. 27 | if (TikTokURL.contains("tiktok")) { 28 | messageCallback("INIT", "It's a TikTok!"); 29 | //Find the video URL using this parser. 30 | ParseTikTok(TikTokURL); 31 | } else { 32 | messageCallback("INIT", "It doens't look like this video is a TikTok!"); 33 | } 34 | 35 | } 36 | 37 | 38 | /* 39 | * Can be overridden by some class 40 | * so you can have control of the output info 41 | */ 42 | public void messageCallback(String title, String text) { 43 | System.out.println("[" + title + "] " + text); 44 | } 45 | 46 | 47 | 48 | private void ParseTikTok(String url) throws Exception { 49 | 50 | /* 51 | * Only used on android 8.0+ devices. 52 | * Android no longer connects to un-secure websites 53 | * and although TikTok is a secure website, when 54 | * shared, the URL oddly is not in HTTPS form, 55 | * but HTTP. Weird, right? 56 | */ 57 | if (url.startsWith("http:")) { 58 | url = url.replace("http:", "https:"); 59 | } 60 | 61 | messageCallback("HTTPS","Loading url..."); 62 | 63 | /* 64 | * Create a basic connection to the website. 65 | */ 66 | URL link = new URL(url); 67 | URLConnection urlConnection = link.openConnection(); 68 | urlConnection.connect(); 69 | 70 | BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); 71 | 72 | /* 73 | * In the website, down below in some JSON or Javascript code (cant remember) 74 | * there's a little variable in the big-ass array called "play_addr" 75 | * which contains the video URL. This simply finds it, and crops 76 | * it out from the rest of the useless content after it which we 77 | * don't need. The continueSearch boolean is there because there 78 | * are multiple "play_addr" variables after the first one. So 79 | * once we grab the first one -- which is thankfully the video URL, 80 | * we can tell the while loop to stop because if it got to the next 81 | * one, it would override the current playHeader String variable 82 | * with some other useless thing it found. 83 | */ 84 | String playHeader = "NULL"; 85 | String temp; 86 | boolean continueSearch = true; 87 | while ((temp = in.readLine()) != null) { 88 | if (temp.contains("play_addr") && continueSearch) { 89 | continueSearch = false; 90 | messageCallback("HTTPS", "Found Play Header!"); 91 | playHeader = temp.substring(temp.indexOf("play_addr"), temp.indexOf("\",\"\\/\\/")); 92 | } 93 | } 94 | 95 | in.close(); 96 | 97 | /* 98 | * Some more cropping of the String to make it a bare-bone URL 99 | */ 100 | playHeader = "https:" + playHeader.substring(25, playHeader.length()).replace("\\/", "/"); 101 | 102 | messageCallback("HTTPS", "Video URL located at: " + playHeader); 103 | messageCallback("HTTPS","Starting download..."); 104 | 105 | Download(playHeader); 106 | } 107 | 108 | private void Download(String url) throws Exception { 109 | File videoFile = new File(fileLocation + ".mp4"); 110 | URL vidUrl = new URL(url); 111 | 112 | /* 113 | * Make a basic connection to the video URL 114 | */ 115 | URLConnection urlConnection = vidUrl.openConnection(); 116 | urlConnection.connect(); 117 | final int file_size = urlConnection.getContentLength(); 118 | InputStream in = urlConnection.getInputStream(); 119 | FileOutputStream fos = new FileOutputStream(videoFile); 120 | 121 | /* 122 | * Once the inputstream and fileoutputstream have been 123 | * a simple 8 byte buffer has been made, after that 124 | * download it and write it to a file while keeping 125 | * track of the amount of bytes downloaded for 126 | * progress results 127 | */ 128 | 129 | byte[] buffer = new byte[8]; 130 | int len; 131 | long total = 0; 132 | while ((len = in.read(buffer)) != -1) { 133 | total += len; 134 | 135 | final int prog = (int) ((total * 100) / file_size); 136 | 137 | if (oldProg != prog) { 138 | messageCallback("PROGRESS", prog + "%"); 139 | } 140 | 141 | oldProg = prog; 142 | 143 | fos.write(buffer, 0, len); 144 | } 145 | 146 | fos.close(); 147 | /* 148 | * And we're done! :) 149 | */ 150 | messageCallback("COMPLETE", "Looks like your video is done downloading!"); 151 | 152 | } 153 | 154 | } 155 | --------------------------------------------------------------------------------