Leng Social blends a full news feed & stories, a Watch video hub and a TikTok-style Reels engine driven by an FFmpeg → adaptive-HLS pipeline, a marketplace with cart & checkout, a seller store back-office & POS, messaging & push — and a complete Admin control center, on web, PWA, iOS & Android.
A vertically-integrated social + video + commerce platform — from a raw video upload to a fulfilled order, tracked end to end.
Infinite-scroll feed with a text/photo/video composer, 7 reactions, polls, feelings, colored backgrounds, threaded comments, share, save — plus stories with viewer lists & reaction taps.
Vertical scroll-snap short-video feed on adaptive HLS: double-tap like, soundtracks, categories, drama seasons & episodes, comments, saves — and sponsored slides interleaved in the feed.
A landscape video hub with per-category browse rows and a custom player — draggable seek with buffer, volume, 0.5–2× speed, Picture-in-Picture, fullscreen and keyboard shortcuts.
Listings with galleries, categories & live search, cart and checkout, orders, saves, seller inquiries — and a dynamic QR code on every product page.
A per-seller back-office: sales dashboard, products with variants & stock, an in-store POS, order fulfilment with delivery service & tracking, and an inquiry inbox.
1-to-1 chat with a conversation list, unread badges and image attachments; a notification center; native push (APNs/FCM) and web push with tap-to-open deep links.
A shared CMS engine — Pages, Groups, Events, Blogs and Offers — each with categories, covers, likes, invites and its own posting timeline.
Profiles with covers & follows, friend requests, people-you-may-know, verified badges, user groups, block & report — and 16 per-user privacy visibility controls.
A full back-office: users & permission groups, approvals, content moderation, reels ads, the music library, the Money modules, customization and 15 groups of system settings.
What shipped most recently on Leng Social.
Stories now show exactly who watched, with an animated viewer ticker and a per-reaction tap counter. Posts gained a “who reacted” modal, and long captions fold behind a “See more”.
The video composer got a type-ahead category picker with an inline “+ New” option, so a category can be created without leaving the upload panel — and the music library is searchable too.
16 “who can see X” privacy settings are now enforced across the API — profile fields, messaging, chat and suggestions. The admin Edit-user panel gained Security & Membership tabs with live sessions.
Sign in with Apple landed in the iOS app alongside Google, Facebook and Telegram OTP. Telegram signups now take the local phone number as their username (+855 12 890 323 → 012890323).
Large videos now upload in chunks (past the 100 MB edge limit) and reassemble server-side, while a pasted YouTube link imports straight through yt-dlp → FFmpeg → HLS, with 1080p H.264 enforced and proxy-session rotation on blocks.
Pages, Groups, Events, Blogs and Offers arrived as first-class modules, along with 7-way reactions, share-to, verified badges, invite codes, discovery search and server-rendered OpenGraph previews for shared links.
Native iOS & Android apps (a Capacitor shell over the web app) shipped with 1-to-1 messaging, APNs/FCM + web push, password reset by email, saved posts, and the Privacy Policy & data-deletion pages.
Real screens captured from the live iOS & Android app.








Every reel and Watch video is transcoded into a multi-rendition HLS ladder in a single FFmpeg pass and delivered from a global CDN — including one-tap import from a YouTube link.
Direct upload, or <96 MB chunks reassembled server-side (2 GB cap).
FFprobe reads duration; 5 candidates at 10/25/50/75/90% — the creator picks the cover.
Optional soundtrack, trimmed with -ss and muxed to H.264 + AAC.
One FFmpeg pass → up to 3 renditions + a master.m3u8.
Pushed to Cloudflare R2 over the S3 API with 6 MB multipart.
HLS.js over the CDN, or the same-origin proxy.
// videoProcessor.js — processMedia() raw.mp4 ├─ ffprobe → duration, width/height, has-audio, codecs ├─ ffmpeg thumb ×5 → scale=720:-2 -q:v 3 → R2 <prefix>/thumbs/*.jpg ├─ ffmpeg music mix → -map 0:v:0 -map 1:a:0 -shortest -movflags +faststart ├─ ffmpeg ABR ladder → split=N → scale short-side 1080/720/480/360 (max 3) │ -hls_time 4 -hls_playlist_type vod -hls_flags independent_segments │ master.m3u8 + v0/ v1/ v2/ playlist.m3u8 + seg###.ts ├─ upload tree ×8 → Cloudflare R2 (S3 API), 6 MB multipart over 6 MB └─ cleanup → every temp file removed in finally{} fallbacks: ABR ladder ─✗→ single-rendition HLS ─✗→ raw .mp4 upload delivery: https://<cdn>/<prefix>/<uuid>/master.m3u8 GET /api/reels/hls/:uuid/* ← same-origin proxy, whitelisted filenames
Paste a YouTube link → yt-dlp downloads it → FFmpeg → HLS → a native reel or Watch video. The height is verified with FFprobe, and an SD or blocked attempt rotates to a fresh proxy session until HD lands.
Heavy transcodes run outside the HTTP request: finalize returns a jobId instantly and the client polls GET /api/jobs/:id — so a long encode never trips the 100-second edge timeout. Jobs expire 15 minutes after creation.
If the ladder fails the pipeline falls back to single-rendition HLS, then to a raw MP4 upload — a reel is never lost to an encoder error. The HLS proxy also retries legacy key prefixes so older posts keep playing.
Two video surfaces — a full-screen vertical feed for short video, and a landscape hub for long-form — both riding the same HLS pipeline.
A complete selling loop — from product discovery to a delivered order — plus a back-office for every seller.
Discovery and checkout that feel like part of the social app, not a bolted-on shop.
A fixed-sidebar back-office covering users, content, modules, money, customization and system settings.
A multi-tab Edit-user panel (Account · Profile · Privacy · Security · Membership), user & permission groups, login-as, live session control, CSV export, and filtered lists for moderators, admins, online, banned and not-activated accounts.
Approval queues for posts and new users, deletion across posts / reels / comments / listings / stories, and a report queue covering posts, reels, comments, messages and users — plus blocking and bans with a custom message.
Custom profile fields, static pages, colored post patterns, placement-aware HTML widgets, reactions, emojis, stickers and gifts — all editable from the admin without a code deploy.
iOS & Android apps built with Capacitor around the same web bundle — shipping on the App Store worldwide, with push, sharing and Sign in with Apple.
Installable, with a manifest, maskable icons, a network-first service worker with an offline shell, and VAPID web push.
Email & password (bcrypt + JWT), Google, Facebook, Sign in with Apple, and Telegram Gateway OTP with phone-number normalization.
Server-rendered OpenGraph pages for /post/:id and /reels/:id, so links shared elsewhere unfurl with the right image, title and video.
A zero-tolerance EULA accepted before account creation, Report on every UGC surface, user blocking, and self-serve account deletion.
16 “who can see X” settings ranging over everyone / people I follow / people who follow me / only me — enforced server-side across profiles, messaging, chat and suggestions.
Images, thumbnails and HLS segments live on Cloudflare R2 and stream from the CDN, with a same-origin proxy for playback that must avoid cross-origin fetches.
Watch, Reels, Marketplace, Stories, Messenger and People each toggle from the admin — switching one off hides it from the nav and bounces direct URLs back to the feed.
A single Express API and SQLite core, fronted by a no-build-step SPA and backed by a media-processing pipeline and a global CDN.
A cohesive, role-guarded API — a representative slice of the 240-plus endpoints.
Expand any module for how it actually works under the hood.
/api/upload/chunk and appended into one assembly file, capped at 2 GB. Assemblies are namespaced per user id so two uploads can never collide, and abandoned parts are swept after an hour.scale=720:-2, -q:v 3) and uploaded so the creator can choose the cover.-ss, mapped over the original audio (-map 0:v:0 -map 1:a:0), cut to -shortest, and re-encoded to H.264 baseline + AAC with +faststart.splits the video into up to three renditions chosen from the short side — 1080 / 720 / 480 / 360 — so portrait and landscape sources both ladder correctly. Output is master.m3u8 plus v0/ v1/ v2/ variant playlists with 4-second, independent segments.application/vnd.apple.mpegurl, video/mp2t).GET /api/reels/hls/:uuid/* proxies the same bytes same-origin behind a strict filename whitelist — playlists no-cache, segments cached a day — and falls back to legacy key prefixes so older posts still resolve.finally block, whichever path ran.POST /api/reels/from-url and /api/videos/from-url take a YouTube URL, validate it, then hand it to yt-dlp. The downloaded file's height is checked with FFprobe; anything below the HD threshold rotates to a fresh proxy session and retries, so a throttled or SD-only session doesn't become a low-quality reel.startJob() hands back a jobId immediately and runs the encode off the request. The client polls GET /api/jobs/:id for processing / done / error; entries self-expire 15 minutes after creation. This is what keeps a five-minute encode from hitting the 100-second edge timeout.#/store-management: a sales dashboard by period, a product catalog with variants and stock, a POS for walk-in sales, order fulfilment with delivery service and tracking number, and an inbox of buyer inquiries.+855 12 890 323 becomes 012890323 — with a longest-prefix dial-code table and a collision suffix.public/ build and points its API at the live server. Universal on iPad and iPhone, full-screen, with FCM/APNs push and Sign in with Apple.?v= cache busting./post/:id, /reels/:id and /reel/:id are server-rendered OpenGraph pages so a shared link unfurls with the right title, description, poster and video — even though the app itself is a hash-routed SPA.
Feed, stories & conversation
A complete social layer — post, react, comment, share, follow and chat.
The composer
Reactions & engagement
Stories
People & graph
Messaging
Notifications