├── .gitignore ├── public ├── img │ ├── icon.png │ └── spinning-circles.svg ├── js │ ├── disabledButton.js │ ├── getUrl.js │ └── app.js ├── index.html └── css │ └── style.css ├── package.json ├── README.md ├── index.js └── src └── tiktokDL.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /public/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zalazarc20/tiktokDL/HEAD/public/img/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiktokdl", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "nodemon ./index.js", 9 | "start": "node index", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "axios": "^0.27.2", 17 | "body-parser": "^1.20.0", 18 | "express": "^4.18.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/js/disabledButton.js: -------------------------------------------------------------------------------- 1 | export const disabledButton = () => { 2 | let input = document.getElementById('url'); 3 | let submit = document.getElementById('submit'); 4 | 5 | document.addEventListener('DOMContentLoaded', e => { 6 | submit.disabled = true; 7 | }); 8 | 9 | input.addEventListener('input', e => { 10 | if(e.target.value !== ''){ 11 | submit.disabled = false; 12 | } 13 | if(e.target.value === '') { 14 | submit.disabled = true; 15 | } 16 | }) 17 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✅ Tiktok DL (Download videos of tiktok, No Watermark) ✌️ 2 | 3 | > ### ⚠️ **Warning!!** this project is not compatible with safari browser. ⚠️ 4 | 5 | a very simple web version, to download the video in the best quality. 6 | 7 | ### how to use the app locally? 8 | - `git clone https://github.com/zalazarc20/tiktokDL.git` 9 | - `npm install` 10 | - once the modules are installed, start the server with `npm run dev` (you need nodemon). 11 | - `npm install nodemon -g` 12 | 13 | ### This is my first application, but very soon I will bring new projects 😉👌 14 | -------------------------------------------------------------------------------- /public/js/getUrl.js: -------------------------------------------------------------------------------- 1 | export const getUrl = async (url) => { 2 | let content = document.getElementById('content'); 3 | let res = await fetch('/url', { 4 | method: 'POST', 5 | headers: { 6 | 'Accept': 'application/json', 7 | 'Content-Type': 'application/json' 8 | }, 9 | body: JSON.stringify({ videoUrl: url}) 10 | }) 11 | 12 | let {nowm, wm, music} = await res.json(); 13 | 14 | // agregamos la etiqueta video... 15 | let buttons = ` 16 | download audio 17 | `; 18 | let video = ` 19 | 22 | `; 23 | content.innerHTML = `${buttons} ${video}`; 24 | } -------------------------------------------------------------------------------- /public/js/app.js: -------------------------------------------------------------------------------- 1 | import { disabledButton } from "./disabledButton.js"; 2 | import { getUrl } from "./getUrl.js"; 3 | 4 | let app = document.getElementById('app'); 5 | let form = document.getElementById('form'); 6 | let content = document.getElementById('content'); 7 | 8 | disabledButton(); // disable button at the beginning and with empty input 9 | 10 | form.addEventListener('submit', e => { 11 | e.preventDefault(); 12 | 13 | content.innerHTML = 'loader'; 14 | 15 | let url = e.target.url.value; // get value of input 16 | let domain = url.split('/')[2]; // get domain 17 | 18 | if(domain === 'www.tiktok.com' || domain === 'vm.tiktok.com'){ 19 | getUrl(url); // get data video 20 | }else{ 21 | content.innerHTML = '

Error, The url is not a tiktok link!

' 22 | } 23 | e.target.reset(); 24 | }) 25 | 26 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import bodyParser from 'body-parser'; 3 | import { tiktokDL } from './src/tiktokDL.js'; 4 | import { fileURLToPath } from 'url'; 5 | import { dirname } from 'path'; 6 | 7 | const __filename = fileURLToPath(import.meta.url); 8 | const __dirname = dirname(__filename); 9 | 10 | const app = express(); 11 | const port = process.env.PORT || 3000; 12 | 13 | app.use(express.static(__dirname + '/public')); 14 | app.use(bodyParser.json()); 15 | 16 | app.post('/url', async (req, res) => { 17 | let { videoUrl } = req.body; 18 | 19 | // get url video 20 | let {nowm, wm, music} = await tiktokDL(videoUrl); 21 | res.send(JSON.stringify({nowm, wm, music})) 22 | }) 23 | 24 | app.listen(port, () => { 25 | console.log(`servidor activado - http://localhost:${port}`) 26 | console.log(`${process.env.RAILWAY_STATIC_URL}`) 27 | console.log(`server actived - port: ${port}`); 28 | }) -------------------------------------------------------------------------------- /src/tiktokDL.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export const tiktokDL = async url => { 4 | let domain = 'https://www.tikwm.com/'; 5 | let res = await axios.post(domain+'api/', {}, { 6 | headers: { 7 | 'accept': 'application/json, text/javascript, */*; q=0.01', 8 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 9 | // 'cookie': 'current_language=en; _ga=GA1.1.115940210.1660795490; _gcl_au=1.1.669324151.1660795490; _ga_5370HT04Z3=GS1.1.1660795489.1.1.1660795513.0.0.0', 10 | 'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"', 11 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' 12 | }, 13 | params: { 14 | url: url, 15 | count: 12, 16 | cursor: 0, 17 | web: 1, 18 | hd: 1 19 | } 20 | }) 21 | 22 | return { 23 | nowm: domain+res.data.data.play, 24 | wm: domain+res.data.data.wmplay, 25 | music: domain+res.data.data.music, 26 | } 27 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | TIKTOK DL - download tiktok videos without watermark 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |

Insert a valid link of tiktok

20 |
21 | 22 | 23 | 24 |
25 |
26 |
    27 |
  1. Copy link of some tiktok video
  2. 28 |
  3. Paste link in text box
  4. 29 |
  5. Click the GENERATE button
  6. 30 |
  7. Watch and Download the video without watermark
  8. 31 |
32 |
33 |
34 |
35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/img/spinning-circles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 17 | 18 | 22 | 23 | 24 | 28 | 29 | 30 | 34 | 35 | 36 | 40 | 41 | 42 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;700&display=swap'); 2 | 3 | :root{ 4 | --color-text: #525252; 5 | --color-primary: #7241FF; 6 | --color-primary-light: #7241FF70; 7 | --color-danger: #ff4141; 8 | --color-bg: #F5F1FF; 9 | --white: #ffffff; 10 | } 11 | 12 | *{ 13 | box-sizing: border-box; 14 | } 15 | 16 | body{ 17 | margin: 0; 18 | background-color: var(--color-bg); 19 | font-family: 'Poppins', sans-serif; 20 | } 21 | 22 | .container{ 23 | max-width: 80%; 24 | min-height: 90vh; 25 | width: 100%; 26 | margin: 0 auto; 27 | display: grid; 28 | place-content: center; 29 | } 30 | 31 | .card{ 32 | margin-top: 2rem; 33 | background-color: var(--white); 34 | padding: 1rem; 35 | border-radius: 10px; 36 | } 37 | 38 | .card h2{ 39 | color: var(--color-text); 40 | font-weight: 500; 41 | } 42 | .card h2 b{ 43 | color: var(--color-primary); 44 | } 45 | 46 | form{ 47 | display: flex; 48 | justify-content: space-between; 49 | } 50 | 51 | form input{ 52 | margin-right: 5px; 53 | } 54 | 55 | form input:nth-child(1){ 56 | width: 80%; 57 | padding: .7rem; 58 | border-radius: 10px; 59 | border: 2px solid var(--color-primary-light); 60 | background-color: var(--color-bg); 61 | color: var(--color-text); 62 | outline: none; 63 | font-weight: 500; 64 | transition: .3s ease-in-out; 65 | } 66 | 67 | form input:nth-child(1):focus, form input:nth-child(1):hover{ 68 | border: 2px solid var(--color-primary); 69 | } 70 | 71 | .btn-submit{ 72 | background-color: var(--color-primary); 73 | border: none; 74 | border-radius: 10px; 75 | font-weight: 500; 76 | color: var(--white); 77 | cursor: pointer; 78 | } 79 | 80 | .btn{ 81 | margin-bottom: 1rem; 82 | padding: 0.4rem; 83 | background-color: var(--color-primary); 84 | color: var(--white); 85 | border-radius: 10px; 86 | text-decoration: none; 87 | text-align: center; 88 | } 89 | 90 | .btn-submit:disabled{ 91 | background-color: var(--color-primary-light); 92 | } 93 | 94 | .content{ 95 | min-width: 300px; 96 | border-radius: 10px; 97 | margin-top: 1rem; 98 | min-height: 300px; 99 | background-color: var(--color-bg); 100 | display: grid; 101 | place-content: center; 102 | padding: 1rem; 103 | } 104 | 105 | .content video{ 106 | justify-self: center; 107 | width: 300px; 108 | border-radius: 10px; 109 | } 110 | 111 | @media screen and (min-width: 720px) { 112 | .content{ 113 | width: 400px; 114 | } 115 | .content ol{ 116 | font-size: 12px; 117 | } 118 | 119 | .content video{ 120 | width: 200px; 121 | } 122 | } 123 | 124 | footer{ 125 | margin-top: 1rem; 126 | width: 100%; 127 | display: flex; 128 | justify-content: center; 129 | align-items: center; 130 | } 131 | 132 | footer h3{ 133 | color: var(--color-text); 134 | font-weight: 300; 135 | font-size: 14px; 136 | margin: 0; 137 | } 138 | footer b{ 139 | font-weight: 500; 140 | color: var(--color-primary); 141 | } 142 | 143 | footer p{ 144 | margin: 0; 145 | font-size: 12px; 146 | text-align: center; 147 | color: var(--color-text); 148 | } 149 | 150 | .btn-instagram{ 151 | text-decoration: none; 152 | } 153 | 154 | .messageError{ 155 | color: var(--color-danger); 156 | } --------------------------------------------------------------------------------