{"id":50849323,"url":"https://github.com/ibrahimjspy/insta-like-player","last_synced_at":"2026-06-14T12:04:46.581Z","repository":{"id":363352415,"uuid":"1255272035","full_name":"ibrahimjspy/insta-like-player","owner":"ibrahimjspy","description":"Turn your liked Instagram, TikTok \u0026 Facebook videos into a private, searchable, self-hosted video library — official exports + yt-dlp, no scraping.","archived":false,"fork":false,"pushed_at":"2026-06-08T13:49:54.000Z","size":5963,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T15:29:10.097Z","etag":null,"topics":["data-hoarding","facebook","instagram","media-server","nextjs","personal-archive","postgresql","prisma","reels","self-hosted","self-hosting","tiktok","typescript","video-library","yt-dlp"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ibrahimjspy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-31T16:14:55.000Z","updated_at":"2026-06-08T14:03:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ibrahimjspy/insta-like-player","commit_stats":null,"previous_names":["ibrahimjspy/insta-like-player"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ibrahimjspy/insta-like-player","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibrahimjspy%2Finsta-like-player","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibrahimjspy%2Finsta-like-player/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibrahimjspy%2Finsta-like-player/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibrahimjspy%2Finsta-like-player/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ibrahimjspy","download_url":"https://codeload.github.com/ibrahimjspy/insta-like-player/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibrahimjspy%2Finsta-like-player/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34320284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-hoarding","facebook","instagram","media-server","nextjs","personal-archive","postgresql","prisma","reels","self-hosted","self-hosting","tiktok","typescript","video-library","yt-dlp"],"created_at":"2026-06-14T12:04:45.683Z","updated_at":"2026-06-14T12:04:46.575Z","avatar_url":"https://github.com/ibrahimjspy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Like Player\n\n**Turn your liked videos into a private, searchable, TikTok-style library.**\n\nImport likes from Instagram, TikTok, and Facebook using each platform's official\ndata export. Download the media locally with `yt-dlp`. Browse everything in a\nfast web app — vertical feed, full-text search, favorites, and custom collections.\n\nNot affiliated with Meta, ByteDance, or any social platform. Use only with **your\nown** exported data.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![CI](https://github.com/ibrahimjspy/insta-like-player/actions/workflows/ci.yml/badge.svg)](https://github.com/ibrahimjspy/insta-like-player/actions/workflows/ci.yml)\n[![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](package.json)\n[![Next.js](https://img.shields.io/badge/Next.js-16-black)](https://nextjs.org)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/media/demo.gif\" alt=\"Like Player — vertical For you feed\" width=\"300\"\u003e\u003cbr\u003e\n  \u003csub\u003e\u003cb\u003eFor you feed\u003c/b\u003e — vertical, snap-scrolling, ranked by your watch behavior\u003c/sub\u003e\n\u003c/p\u003e\n\n---\n\n## Screenshots\n\n\u003cp align=\"center\"\u003e\u003cb\u003eSearch\u003c/b\u003e — caption, creator, or hashtag, filtered by platform\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/media/search.png\" alt=\"Search with platform pills and creator chips\" width=\"100%\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cb\u003eAdmin dashboard\u003c/b\u003e — library stats, per-platform import, and live sync\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/media/admin.png\" alt=\"Admin dashboard\" width=\"100%\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cb\u003eCollections\u003c/b\u003e — curate subsets without touching the original platforms\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/media/collections.png\" alt=\"Collections\" width=\"100%\"\u003e\u003c/p\u003e\n\n---\n\n## Contents\n\n[Why this exists](#why-this-exists) ·\n[How it works](#how-it-works) ·\n[Features](#features) ·\n[Supported platforms](#supported-platforms) ·\n[Quick start](#quick-start) ·\n[Configuration](#configuration) ·\n[FAQ](#faq) ·\n[Roadmap](#roadmap) ·\n[Self-hosting](#self-hosting) ·\n[Legal \u0026 privacy](#legal--privacy)\n\n---\n\n## Why this exists\n\nSocial platforms bury your likes in export ZIPs and expired CDN links. Like Player\ngives you:\n\n- **One library** for Instagram Reels, TikTok videos, and Facebook saved/reacted videos\n- **Local files** — no streaming from expired URLs; seekable playback from disk\n- **A real feed** — Recent, Oldest, or a **For you** ranker that learns from watch time\n- **Search** — caption, creator, hashtag, and platform filters\n- **Collections \u0026 favorites** — curate subsets without touching the original platforms\n- **Self-hosted** — single-user, runs on your machine; optional Tailscale access from your phone\n\nNo scraping. No login automation. Discovery comes from official exports; downloads\nuse `yt-dlp` with optional session cookies you provide.\n\n### Why not just keep the export?\n\n| Instead of… | …you get with Like Player |\n|-------------|---------------------------|\n| A `liked_posts.json` you'll never open again | A scrollable, watchable feed of the actual videos |\n| Saves \u0026 bookmarks that vanish when posts are deleted | Local copies that survive takedowns and expired CDN links |\n| A folder of `yt-dlp` files named by ID | Captions, creators, hashtags, search, and collections |\n| Re-finding things at the algorithm's whim | A **For you** feed ranked by *your* watch behavior |\n\n---\n\n## How it works\n\n```\nPlatform export (JSON)  ──►  ingest  ──►  PostgreSQL  ◄──  sync (yt-dlp)  ──►  data/media\n                                              │\n                                              ▼\n                                         Next.js web app\n                               Reader (/)  ·  Admin (/admin)\n```\n\n| Step | What happens |\n|------|----------------|\n| **Import** | Parse `liked_posts.json`, `user_data_tiktok.json`, or Facebook `posts_and_comments.json` / saved collections into the DB |\n| **Sync** | Download video + thumbnail + metadata for each pending item |\n| **Browse** | Stream from `/api/media/...` with HTTP range support (scrubbing works) |\n\n---\n\n## Features\n\n### Reader (`/`)\n\n- Infinite vertical feed with tap-to-pause chrome\n- Sort: **Recent** · **Oldest** · **For you** (personalized from watch behavior)\n- Auto-scroll and video-only modes while paused\n- Search by text, creator, or platform\n- Favorites and user-defined collections\n\n### Admin (`/admin`)\n\n- Upload exports per platform\n- Run and monitor background sync\n- Inspect reel status (pending, downloaded, failed, unavailable)\n\n### For you feed\n\nNot random — ranks reels from engagement signals (watch time, loops, deep watches\nvs quick skips, creator/hashtag/collection affinity). Tune weights in\n`src/lib/feed/config.ts`. Design doc: [docs/FEED_RECOMMENDATIONS.md](docs/FEED_RECOMMENDATIONS.md).\n\n---\n\n## Supported platforms\n\n| Platform | Export file | CLI flag |\n|----------|-------------|----------|\n| Instagram | `liked_posts.json` (Likes, JSON, all time) | `--platform instagram` (default) |\n| TikTok | `user_data_tiktok.json` (include **Likes**) | `--platform tiktok` |\n| Facebook | `likes_and_reactions/posts_and_comments.json`, saved collections, or `your_saved_items.json` | `--platform facebook` |\n\nEach platform uses the same pipeline; media is stored as\n`\u003cplatform\u003e_\u003cid\u003e.mp4` (Instagram keeps bare shortcodes for backward compatibility).\n\n---\n\n## Quick start\n\n**Prerequisites:** Node.js 20+, Docker (for Postgres), [`yt-dlp`](https://github.com/yt-dlp/yt-dlp)\n\n```bash\ngit clone https://github.com/ibrahimjspy/insta-like-player.git\ncd insta-like-player\nnpm install\n\ncp .env.example .env          # edit DATABASE_URL if port 5432 is taken\nnpm run db:up \u0026\u0026 npm run db:push\nnpm run dev                   # http://localhost:3000\n```\n\n### Import your likes\n\n**Admin UI:** open `/admin` → pick platform → upload JSON → Sync.\n\n**CLI:**\n\n```bash\n# Instagram (default)\nnpm run ingest -- path/to/liked_posts.json\n\n# TikTok\nnpm run ingest -- --platform tiktok path/to/user_data_tiktok.json\n\n# Facebook\nnpm run ingest -- --platform facebook path/to/posts_and_comments.json\n\nnpm run sync                  # download pending media\nnpm run sync -- --limit 50    # batch of 50\nnpm run sync -- --retry       # include previously failed reels\n```\n\n### Cookies (the key to reliable downloads)\n\nDiscovery (the list of your likes) comes from the export and needs no login. But\nthe **download** step does: platforms gate reel/video media behind a session, so\n`yt-dlp` needs your browser cookies to fetch it. Without cookies most downloads\nfail or get rate-limited fast — this is the single most important setup step.\n\n**1. Export a `cookies.txt` (Netscape format).** While logged into the platform in\nyour browser, use a cookie-export extension such as\n**\"Get cookies.txt LOCALLY\"** (open source, runs locally). Export **as\n`cookies.txt` (Netscape format, _not_ JSON)** while the platform's site is open.\n\nA valid file starts with `# Netscape HTTP Cookie File` and, for Instagram,\ncontains `sessionid`, `ds_user_id`, and `csrftoken`.\n\n**2. Save it and point `.env` at it** (per platform you'll download from):\n\n```bash\nYTDLP_COOKIES_INSTAGRAM=\"./data/cookies-instagram.txt\"\nYTDLP_COOKIES_TIKTOK=\"./data/cookies-tiktok.txt\"\nYTDLP_COOKIES_FACEBOOK=\"./data/cookies-facebook.txt\"\n```\n\n**3. Verify it works** before a big sync:\n\n```bash\nyt-dlp --cookies data/cookies-instagram.txt -o \"data/_test.%(ext)s\" \\\n  \"https://www.instagram.com/reel/SHORTCODE/\"   # any reel you can view\n# success = an .mp4 appears, then: rm data/_test.*\n```\n\n\u003e **`cookies.txt` is a live session credential — treat it like a password.** It's\n\u003e gitignored (everything under `data/` is). Never commit or share it. Logging out\n\u003e or changing your password invalidates it. To minimize account risk, you can use\n\u003e a throwaway/secondary session and keep `SYNC_RATE_LIMIT_MS` polite (≥ 4000).\n\nTikTok also often needs browser impersonation (a `curl_cffi`-enabled yt-dlp\nbuild) — see the commented setup in `.env.example`.\n\n---\n\n## Configuration\n\nAll settings flow through `.env` → `src/lib/config.ts`:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `DATABASE_URL` | local Docker Postgres | PostgreSQL connection string |\n| `MEDIA_DIR` | `./data/media` | Downloaded videos and thumbnails |\n| `FEED_PAGE_SIZE` | `10` | Reels per infinite-scroll page |\n| `YTDLP_PATH` | `yt-dlp` | Path to yt-dlp binary |\n| `YTDLP_COOKIES_*` | _(unset)_ | Per-platform Netscape cookies |\n| `YTDLP_IMPERSONATE_TIKTOK` | `chrome` | TLS fingerprint for TikTok 403s |\n| `SYNC_RATE_LIMIT_MS` | `4000` | Delay between sequential downloads |\n| `SYNC_MAX_RETRIES` | `3` | Retries before marking FAILED |\n| `SYNC_REELS_ONLY` | `true` | Skip non-video likes (e.g. Instagram `/p/` photos) |\n\n---\n\n## Scripts\n\n| Command | Description |\n|---------|-------------|\n| `npm run dev` | Development server |\n| `npm run build` | Production build + typecheck |\n| `npm test` | Vitest unit tests |\n| `npm run lint` | ESLint |\n| `npm run ingest` | Import a platform export |\n| `npm run sync` | Download pending reels |\n| `npm run db:up` / `db:down` | Start/stop Postgres container |\n| `npm run db:push` | Apply Prisma schema |\n| `npm run serve` | Production server on port 7319 |\n\n---\n\n## Project structure\n\n```\nprisma/schema.prisma       Reels, creators, hashtags, collections, engagement\nsrc/lib/platforms/         Instagram, TikTok, Facebook export parsers\nsrc/lib/feed/              For you scoring, taste classification, SQL ranker\nsrc/lib/queries.ts         Feed, search, collections, favorites\nsrc/app/(reader)/          Feed, search, collections, favorites\nsrc/app/admin/             Import, sync, reel management\nsrc/app/api/media/         Local media streaming with range requests\ndocs/                      FEED_RECOMMENDATIONS.md, DEPLOYMENT.md\n```\n\n---\n\n## Self-hosting\n\nRun as an always-on personal server and reach it from your phone over\n[Tailscale](https://tailscale.com) — no cloud, no public exposure. See\n**[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)**.\n\n```bash\nnpm run build\nbash scripts/install-service.sh   # macOS launchd agent on port 7319\ntailscale serve --bg 7319         # private HTTPS on your tailnet\n```\n\n---\n\n## Testing\n\n```bash\nnpm test            # full suite\nnpm test -- src/lib/feed   # after feed algorithm changes\n```\n\nTests cover export parsers (all three platforms), feed pagination and scoring,\nsearch filters, media path safety, and yt-dlp helpers. Prisma is mocked — no DB\nrequired.\n\n---\n\n## Tech stack\n\nNext.js 16 (App Router) · TypeScript · Tailwind CSS v4 · PostgreSQL · Prisma 7 ·\n`yt-dlp` · Docker Compose · Vitest\n\n---\n\n## FAQ\n\n**Will my account get banned?**\nDownloads are read-only and rate-limited — sequential, one at a time, with\n`SYNC_RATE_LIMIT_MS` ≥ 4000 by default. The app never likes, follows, comments,\nor posts. As with any `yt-dlp` use there's mild risk on a main account; go slow,\nor use a throwaway session for the cookies.\n\n**Is this legal?**\nYou only process **your own** exported data and download content you already\nliked. The app doesn't bypass access controls or scrape. Automated downloading\nmay still conflict with a platform's Terms of Service — use at your own risk.\n\n**Do I need cookies?**\nFor discovery, no — the official export already lists your likes. For\n*downloading*, most platforms gate media behind login, so a Netscape\n`cookies.txt` makes sync far more reliable. TikTok also often needs browser\nimpersonation (see `.env.example`).\n\n**Does it run on Windows / Linux?**\nYes — it's Node + Docker + `yt-dlp`. Only the always-on service scripts\n(`launchd`) are macOS-specific; on Linux run `npm run serve` under systemd.\nEverything else is cross-platform.\n\n**Why Postgres instead of SQLite?**\nThe **For you** ranker runs a single scoring SQL query per page over engagement\nrollups; Postgres keeps that fast with a clean schema, and Docker Compose makes\nit one command to start.\n\n**Does it download photos too?**\nBy default it fetches videos only (`SYNC_REELS_ONLY=true`) and skips photo posts.\nSet it to `false` to attempt everything.\n\n**Can it auto-sync new likes?**\nNot by default — discovery is export-based to stay scraping-free. An opt-in,\nflagged Playwright auto-sync is on the roadmap.\n\n---\n\n## Legal \u0026 privacy\n\n- Only use with **your own** exported data. The app does not bypass platform access controls.\n- Media and exports live in `data/` (gitignored). Nothing personal belongs in git.\n- Automated downloading may conflict with platform Terms of Service. Discovery uses\n  official exports; downloads are read-only fetches of content you already liked.\n  **Use at your own risk.**\n\n---\n\n## Roadmap\n\n- [ ] Resume-from-last-position in the feed\n- [ ] Auto-tagging and smart collections\n- [ ] Opt-in, flagged Playwright auto-sync of new likes\n- [ ] `gallery-dl` fallback engine for stubborn downloads\n- [ ] One-click \"reset library\" in Admin\n\nHave an idea? [Open an issue](https://github.com/ibrahimjspy/insta-like-player/issues)\nor send a PR — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n---\n\n## Contributing\n\nIssues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). For AI-assisted\ndevelopment, see [CLAUDE.md](CLAUDE.md). Found a security issue? See\n[SECURITY.md](SECURITY.md). Notable changes are tracked in\n[CHANGELOG.md](CHANGELOG.md).\n\nIf this project saves you from losing liked videos to the algorithm, consider\n**starring the repo** — it helps others find it.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibrahimjspy%2Finsta-like-player","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fibrahimjspy%2Finsta-like-player","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibrahimjspy%2Finsta-like-player/lists"}