A sample Node.js project, built on browser automation (Puppeteer), that downloads video episodes from a source site and posts them to TikTok automatically.
This project is shared for educational and research purposes only. It was written to demonstrate how the concepts of browser automation, web scraping, session management, and job scheduling come together.
By using this software, you are deemed to have accepted the following:
- All responsibility lies with the user. The person who runs this code is solely responsible for any legal, financial, and technical consequences that arise from running it. The author(s) accept no liability and provide no warranty.
- Copyright and content rights. Downloading, re-uploading, or distributing content that does not belong to you, or for which you do not have publishing or distribution rights, may constitute copyright infringement. Make sure you own the rights to the content or have the necessary permissions.
- Platform rules. Complying with the terms of service (ToS), community guidelines, and automation policies of the relevant sites and of TikTok is your responsibility. Automated uploading may result in your account being suspended, restricted, or permanently banned.
- Legal compliance. It is your duty to comply with the laws of your country/region. Do not use this tool for any unlawful purpose.
- No warranty. The software is provided "AS IS", without any express or implied warranty, including fitness for a particular purpose.
If you do not accept these terms, do not use this software.
It runs as a single Node.js process and automates the following loop:
- Fetches show titles from the source site (via its catalog API).
- Picks a title and an episode that has not been processed before.
- Downloads the episode video to local disk.
- Uploads the downloaded video to TikTok, adds a caption, and publishes it.
- Records the processed episode in a local database so it is not uploaded again.
- Repeats this loop at fixed intervals (20 minutes by default).
The application is split into modules: the entry point is
src/index.js, the settings live in
src/config.js, and the business logic sits under
src/modules/. Step by step:
- A real Chrome instance is launched with
puppeteer-real-browser(modules/runner.js). This library ships with settings designed to bypass standard automation (bot) detection. - Session data is kept in a persistent Chrome profile (the
data/folder). This way, once you log in to TikTok, the session stays signed in.
2. Content selection Β· modules/source.js
- The list of titles is fetched page by page from the catalog API
(
fetchCatalogTitles). - The list is shuffled (
shuffleInPlace) and queued so that previously unvisited titles are prioritized (createCatalogTitleSelector). - The selected title page is opened, and the description text in the "About"
section is read (
openAboutAndReadData). This text is later used as the TikTok caption.
3. Finding and downloading an episode Β· modules/source.js + modules/downloads.js
- The "Episodes" tab is opened and the visible episodes are listed
(
getVisibleEpisodes). - The first episode that has not yet been published is selected from the
local database (
openEpisodeOrExitIfDownloaded). If it has already been published, the process moves on to the next title. - Download preferences are written to the Chrome profile
(
configureDownloadPreferences), and via CDPBrowser.setDownloadBehaviorthe download folder is set todownloads/; the native "Save As" dialog is disabled. - The download button is found and clicked, and the process waits until the
download is complete (until the file size is stable)
(
downloadCurrentEpisode,waitForDownloadedFile).
4. Uploading to TikTok Β· modules/tiktok.js
https://www.tiktok.com/uploadis opened in a separate browser session (uploadVideoToTikTok).- The
<input type="file">element is located and the downloaded file is uploaded. - The caption field is built from the source description and filled in
(
buildTikTokCaption,modules/caption.js, up to 2200 characters). - Once the upload is ready, the "Share / Post" button is found and clicked;
success is verified by scanning the status text across pages/iframes
(
publishTikTokVideo,waitForTikTokPublishSuccess).
5. Persistence and scheduling Β· modules/database.js + modules/scheduler.js
- After a successful publish, the episode is saved to a local file database
using
kilic.db(markEpisodeDownloaded). Only records whose publish has been confirmed are counted as "processed". - The scheduler (
startScheduler) reschedules the job after 20 minutes on success, or after 30 seconds on failure. State is written todata/scheduler-state.json, so the process resumes where it left off even if it is restarted.
Debugging Β· modules/debug.js
- If a step fails, a screenshot and an HTML dump are saved to the
debug/folder (saveDebugSnapshot,saveTikTokDebugSnapshot).
Requirements: Node.js 18+ (for the built-in fetch) and pnpm.
pnpm installOn the first run, Puppeteer may need to download Chrome.
Single run (scheduler off; recommended for development/testing):
node src/index.js --onceContinuous run (scheduler on, 20-minute interval by default):
pnpm start
# or
node src/index.jsOn the first run, you must log in to TikTok. When the browser opens, sign in to your TikTok session manually; because the session is stored in the
data/profile, you will not be asked to log in again on subsequent runs.
To stop, press Ctrl+C (the scheduler shuts down cleanly on SIGINT/SIGTERM).
All settings are collected in src/config.js. Some can be
overridden with environment variables (env); if not set, the default value is
used:
| Environment variable | Description | Default |
|---|---|---|
SOURCE_ROOT_URL |
Source site root address | https://dramalar.com |
SOURCE_CATALOG_API_URL |
Catalog API address | β¦/catalog/titles?β¦ |
SOURCE_CATALOG_USER_AGENT |
User-Agent used for the catalog request | Chrome UA |
TIKTOK_UPLOAD_URL |
TikTok upload page | https://www.tiktok.com/upload |
SCHEDULE_INTERVAL_MINUTES |
Wait between successful jobs | 20 |
FAILED_JOB_RETRY_SECONDS |
Retry delay after a failed job | 30 |
In addition, constants such as TIKTOK_CAPTION_MAX_LENGTH (2200) and TIMEOUTS
(per-step timeout durations) are also defined in the same file.
src/
βββ index.js Entry point (--once for a single job / no args for the scheduler)
βββ config.js All constants, paths, timeouts, Chrome arguments
βββ modules/
βββ utils.js Helpers: sleep, retry, log, formatters
βββ database.js kilic.db model and record operations
βββ downloads.js Download monitoring + Chrome download preferences
βββ browser.js Generic DOM helpers (click, wait, frame)
βββ caption.js TikTok caption generation/comparison
βββ debug.js Debugging snapshots
βββ source.js Source-site navigation + episode download
βββ tiktok.js TikTok upload/publish flow
βββ runner.js End-to-end orchestration of a single job (run)
βββ scheduler.js Scheduler + runJob
data/ Persistent Chrome profile, database, scheduler state (not tracked in git)
downloads/ Downloaded videos (not tracked in git)
debug/ Debugging screenshots / HTML (not tracked in git)
The data/, downloads/, and debug/ folders are generated at runtime and are
kept out of version control via .gitignore. These folders may contain
sensitive data such as session cookies; do not share them.
MIT. The disclaimer above applies as part of this license.