shorts-maker 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -0
- package/bunfig.toml +3 -0
- package/dist/chunk-27wzf6kd.js +240 -0
- package/dist/chunk-wt9saz7q.css +1 -0
- package/dist/index.html +18 -0
- package/hashtags.txt +40 -0
- package/package.json +59 -0
- package/src/build.ts +30 -0
- package/src/cli.ts +70 -0
- package/src/files.ts +24 -0
- package/src/jobs/store.ts +390 -0
- package/src/paths.ts +23 -0
- package/src/pipeline/download.ts +201 -0
- package/src/pipeline/media.ts +312 -0
- package/src/pipeline/overlay.ts +138 -0
- package/src/pipeline/parts.ts +78 -0
- package/src/pipeline/pipeline.ts +217 -0
- package/src/server.ts +645 -0
- package/src/social/config.ts +72 -0
- package/src/social/facebook.ts +232 -0
- package/tsconfig.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# shorts-maker
|
|
2
|
+
|
|
3
|
+
Split a long video into **consecutive parts** — the whole thing, in order, cut on natural
|
|
4
|
+
pauses — each titled `Main Title part-N #hashtags`, ready to post as a series to YouTube /
|
|
5
|
+
Instagram / TikTok.
|
|
6
|
+
|
|
7
|
+
TypeScript on [Bun](https://bun.sh) with a **React + Tailwind v4** frontend that Bun
|
|
8
|
+
bundles and hot-reloads itself — no Vite, no webpack, no PostCSS. No AI, no accounts. The
|
|
9
|
+
only runtime binary it shells out to is **ffmpeg**; a 90-minute video processes in seconds.
|
|
10
|
+
|
|
11
|
+
## How it works
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
video ──► find pauses (ffmpeg silencedetect) ──► split into parts ──► cut (stream-copy) ──► parts/ + captions
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- **Every second is covered** — parts are contiguous from 0:00 to the end. No highlight-picking.
|
|
18
|
+
- **Cuts land on a pause**, so parts don't end mid-sentence. (Stream-copy snaps to the
|
|
19
|
+
nearest keyframe, so a cut may shift a second or two.)
|
|
20
|
+
- **Part length is a cap, not a quota** — a 15-min target splits a 96-min video into 7
|
|
21
|
+
parts of ~14 min each (evenly), not 6 full 15-min parts plus a 6-min stub. If even parts
|
|
22
|
+
would come out under ~12 min, one part is dropped and the rest stretch a little to
|
|
23
|
+
absorb it.
|
|
24
|
+
- **Titles** = the video name (auto-derived from the file, editable in the form) + `part-N`
|
|
25
|
+
+ a random set of hashtags from [`hashtags.txt`](hashtags.txt) (edit to taste).
|
|
26
|
+
- Your source is already **1080×1920 (9:16 vertical)**, so no cropping is needed.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
You need two things on your machine: [**Bun**](https://bun.sh) and **ffmpeg**.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -fsSL https://bun.sh/install | bash # Bun (skip if installed)
|
|
34
|
+
brew install ffmpeg # ffmpeg — macOS; use your package manager elsewhere
|
|
35
|
+
brew install yt-dlp # optional — only to import from a video link
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`yt-dlp` is only needed if you paste a **link** (YouTube, Dailymotion, or a direct video
|
|
39
|
+
URL) instead of uploading a file.
|
|
40
|
+
|
|
41
|
+
> **YouTube “Sign in to confirm you’re not a bot”?** YouTube blocks some anonymous
|
|
42
|
+
> downloads. Point the app at your browser’s login:
|
|
43
|
+
> `bunx shorts-maker --serve --cookies-from-browser chrome` (or `safari` / `firefox` /
|
|
44
|
+
> `edge` / `brave`), or set `SHORTS_MAKER_COOKIES_FROM_BROWSER=chrome`. Failed link jobs
|
|
45
|
+
> also retry automatically through alternate players before giving up.
|
|
46
|
+
|
|
47
|
+
Then run it straight from npm — no clone, no install step:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd ~/videos # any folder — this is where output/ and config/ will be written
|
|
51
|
+
bunx shorts-maker --serve # → http://localhost:4321 (bare `bunx shorts-maker` prints help)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`--serve` starts the app from your **current folder**: generated clips land in `./output/`,
|
|
55
|
+
staged uploads in `./uploads/`, and your saved credentials in `./config/`. Run it wherever
|
|
56
|
+
you want that data to live.
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
shorts-maker --serve [options]
|
|
60
|
+
|
|
61
|
+
-s, --serve Start the web app (required — nothing runs without it)
|
|
62
|
+
-p, --port <n> Port to listen on (default 4321, or $PORT)
|
|
63
|
+
-d, --dir <path> Folder to read/write data in (default: current folder,
|
|
64
|
+
or $SHORTS_MAKER_DIR)
|
|
65
|
+
-v, --version Print the version and exit
|
|
66
|
+
-h, --help Show this help and exit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## From source
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/subasshrestha/ShortsMaker && cd ShortsMaker
|
|
73
|
+
bun install
|
|
74
|
+
bun dev # development → http://localhost:4321 (hot reload / React Fast Refresh)
|
|
75
|
+
bun start # production → builds dist/ then serves the optimized bundle
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
At runtime it needs Bun + ffmpeg; everything else is bundled.
|
|
79
|
+
|
|
80
|
+
## Using the app
|
|
81
|
+
|
|
82
|
+
The same server process serves both the React app and the API — one port, no second dev
|
|
83
|
+
server.
|
|
84
|
+
|
|
85
|
+
- **Pick a source three ways**: upload a video (click or drag-and-drop, with a live
|
|
86
|
+
progress bar), paste a **link**, or choose one you already have under **From uploads**.
|
|
87
|
+
- **Sources are kept**, not thrown away. Everything you upload — and every video fetched
|
|
88
|
+
from a link — lands in `uploads/` and stays there, so you can re-split it without
|
|
89
|
+
re-uploading or re-downloading. Manage them right in the **From uploads** tab: each
|
|
90
|
+
entry shows its size and date, with a trash icon to delete it and a **Clear all** to
|
|
91
|
+
empty the folder. Deleting a *job* never deletes its source video.
|
|
92
|
+
- The **title** auto-fills from the filename; adjust it, plus **part length**,
|
|
93
|
+
**hashtags-per-part**, and the **hashtag pool** (pre-filled from `hashtags.txt`) — all
|
|
94
|
+
from the form.
|
|
95
|
+
- Hit **Split** and watch the logs stream live.
|
|
96
|
+
- Every run is saved in the **History** sidebar — it survives refreshes and restarts.
|
|
97
|
+
Click a job to replay its logs, preview each part inline, copy captions, download
|
|
98
|
+
clips, **reveal a clip in Finder** (when running locally), or delete the whole run
|
|
99
|
+
(files included).
|
|
100
|
+
|
|
101
|
+
## Output
|
|
102
|
+
|
|
103
|
+
Each run lands in its own folder under `output/`:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
output/<name>__<timestamp>/
|
|
107
|
+
parts/
|
|
108
|
+
01_hacker-vs-coder.mp4
|
|
109
|
+
01_hacker-vs-coder.txt # "Hacker VS Coder part-1 #tags" — paste-ready caption
|
|
110
|
+
02_...
|
|
111
|
+
manifest.json # every part with timestamps + caption
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Hashtags are drawn from [`hashtags.txt`](hashtags.txt) — one per line, `#` lines are
|
|
115
|
+
comments. Edit that file to fit your niche.
|
|
116
|
+
|
|
117
|
+
## Publish to social media
|
|
118
|
+
|
|
119
|
+
Each finished part card has a **one-click Publish** button. Facebook Pages are supported
|
|
120
|
+
today (more platforms are planned — the code is structured to drop them in). Uploads use
|
|
121
|
+
Facebook's [chunked video upload](https://developers.facebook.com/docs/graph-api/reference/page/videos/)
|
|
122
|
+
(`upload_phase` start → transfer → finish), with resume + retry and a live progress bar
|
|
123
|
+
on the card.
|
|
124
|
+
|
|
125
|
+
1. Open **Settings** (gear in the sidebar) → **Facebook Page**, and follow the built-in
|
|
126
|
+
**Setup guide** to get a **Page ID** and a long-lived **Page Access Token**.
|
|
127
|
+
2. Paste them in and **Save** — it verifies with Facebook first and only stores if it works.
|
|
128
|
+
(**Test connection** also checks that the token has the `pages_manage_posts` permission.)
|
|
129
|
+
3. On any part card, hit **Publish to Facebook**. The clip is uploaded to your Page with
|
|
130
|
+
its caption; the card then shows **Posted ✓** with a link, and remembers it.
|
|
131
|
+
|
|
132
|
+
Credentials are stored **locally** in `config/social.json` (gitignored) and are never
|
|
133
|
+
returned to the browser or sent anywhere except Facebook's Graph API.
|
|
134
|
+
|
|
135
|
+
## Project layout
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
src/
|
|
139
|
+
cli.ts # `shorts-maker` command: --help/--version/--port/--dir, then serves
|
|
140
|
+
server.ts # Bun.serve: React app (dev bundler / prod dist) + REST/SSE API
|
|
141
|
+
build.ts # pre-builds frontend → dist/ (Bun.build + Tailwind plugin)
|
|
142
|
+
paths.ts # package-asset dirs vs. the user's data dir (cwd)
|
|
143
|
+
files.ts # shared fs helpers (safeJoin, uniqueName, video extensions)
|
|
144
|
+
jobs/
|
|
145
|
+
store.ts # job registry — SQLite (bun:sqlite, output/jobs.db) + SSE subscribers
|
|
146
|
+
pipeline/
|
|
147
|
+
pipeline.ts # orchestration (probe → pauses → split → cut → titles)
|
|
148
|
+
media.ts # ffprobe/ffmpeg wrappers (probe, silence detect, cut)
|
|
149
|
+
parts.ts # part model + splitter
|
|
150
|
+
social/
|
|
151
|
+
config.ts # credential store (config/social.json)
|
|
152
|
+
facebook.ts # Graph API verify + video upload
|
|
153
|
+
frontend/
|
|
154
|
+
index.html # entry — Bun bundles main.tsx from here
|
|
155
|
+
main.tsx # React mount + BrowserRouter
|
|
156
|
+
App.tsx # routes + app-shell layout
|
|
157
|
+
styles.css # Tailwind v4 entry: @import + @theme design tokens
|
|
158
|
+
pages/ # routes: NewSplitForm, JobDetail, Settings, Guide
|
|
159
|
+
components/ # shared: Sidebar, Brand, Dot, Icons, ConfirmDialog
|
|
160
|
+
lib/
|
|
161
|
+
api.ts # typed fetch helpers (+ streaming upload)
|
|
162
|
+
util.ts # formatting helpers
|
|
163
|
+
types.ts # shared Job/Part types
|
|
164
|
+
bunfig.toml # registers bun-plugin-tailwind for the dev bundler
|
|
165
|
+
hashtags.txt # default hashtag pool (a hashtags.txt in your run folder overrides it)
|
|
166
|
+
```
|
package/bunfig.toml
ADDED