feat: show reels in the profile grid, as Instagram does
Docker Build and Publish / build-and-push (push) Failing after 9s
Docker Build and Publish / build-and-push (push) Failing after 9s
The Posts tab filtered reels out, so the grid was not the archive — it
was the archive minus its videos. For `for.heejin` that hid 533 of 1225
posts; for `loonatheworld`, 1100 of 3813. On Instagram the grid holds
everything and the Reels tab is a filtered view of that same set.
Extract the tab logic to src/lib/post-tabs.ts so the reel heuristic is
testable outside the component, and add dedupePostCopies: the jd2 flow
crawls the profile URL and the /reels URL separately because the profile
page misses some reels, so the two overlap and a reel can land on disk
twice. Those are two posts with distinct directory-scoped ids, which the
grid would now render side by side; the reels-source copy wins so the
survivor is still recognised as a reel.
Deciding what *is* a reel stays a guess for most archives. Instagram
marks it with product_type ("clips" vs "feed" vs "igtv" — all three are
GraphVideo, and aspect ratio does not separate them), but only newer
Instaloader captures carry it: 1101 of gibiofficial's 5919 sidecars, and
only 2 marked clips. JDownloader archives carry none, so those still
fall back to treating a lone video as a reel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+5
-13
@@ -19,6 +19,7 @@ import { motion, AnimatePresence } from 'motion/react';
|
||||
import { cn } from './lib/utils';
|
||||
import { PRESS, prefersReducedMotion } from './lib/motion';
|
||||
import { buildPath, findPostBySlug, parseRoute, postSlug, tabForSource } from './lib/routing';
|
||||
import { postsForTab } from './lib/post-tabs';
|
||||
import { LocalArchiveFile, RemoteArchiveFile } from './lib/archive-files';
|
||||
import {
|
||||
deleteCachedArchive,
|
||||
@@ -172,20 +173,11 @@ export default function App() {
|
||||
const clearCache = async (name: string) => { await deleteCachedArchive(name); await refreshCachedArchives(); };
|
||||
|
||||
/**
|
||||
* Archives with a `- reels` sidecar directory say outright which posts are
|
||||
* reels; only fall back to the "lone video" heuristic for archives that have
|
||||
* no such directory.
|
||||
* The grid shows everything, reels included, and the Reels tab is a filtered
|
||||
* view of the same set — see src/lib/post-tabs.ts for the reel test and for
|
||||
* why a reel can arrive on disk twice.
|
||||
*/
|
||||
const hasReelSource = useMemo(() => allPosts.some(p => p.source === 'reels'), [allPosts]);
|
||||
const isReel = useCallback((p: Post) => (
|
||||
hasReelSource ? p.source === 'reels' : p.media.length === 1 && p.media[0].type === 'video'
|
||||
), [hasReelSource]);
|
||||
|
||||
const filteredPosts = useMemo(() => {
|
||||
if (activeTab === 'reels') return allPosts.filter(isReel);
|
||||
if (activeTab === 'posts') return allPosts.filter(p => !isReel(p));
|
||||
return [];
|
||||
}, [allPosts, activeTab, isReel]);
|
||||
const filteredPosts = useMemo(() => postsForTab(allPosts, activeTab), [allPosts, activeTab]);
|
||||
|
||||
/** Story highlights, grouped into the circles shown under the bio. */
|
||||
const highlightGroups = useMemo(() => {
|
||||
|
||||
Reference in New Issue
Block a user