From 08afc63d92aab5d413364425bcf4827dcc434bd0 Mon Sep 17 00:00:00 2001 From: Brian Evans Date: Fri, 21 Jan 2022 14:57:12 +0000 Subject: [PATCH] Add images and videos to instagram post list GH-36 Signed-off-by: Brian Evans --- client/src/components/FileUploader.svelte | 4 +- .../instagram/InstagramPostsList.svelte | 55 +++++++-- lib/common/ArrayUtils.ts | 2 + lib/common/PathProcessing.ts | 2 +- lib/package.json | 3 +- .../postProcessors/instagram.ts | 9 +- lib/vendors/instagram/Media.ts | 115 +++++++++++++++--- 7 files changed, 157 insertions(+), 33 deletions(-) diff --git a/client/src/components/FileUploader.svelte b/client/src/components/FileUploader.svelte index 4cafd11..3f8928c 100644 --- a/client/src/components/FileUploader.svelte +++ b/client/src/components/FileUploader.svelte @@ -21,13 +21,13 @@ const worker = new ProcessingWorker() worker.postMessage(fileItem.file) - console.dir(fileItem) + // console.dir(fileItem) const workerOutput: PostProcessedOutput = await new Promise(resolve => { worker.onmessage = message => { resolve(message.data) } }) - console.log('metadata', workerOutput.metadata) + // console.log('metadata', workerOutput.metadata) if(workerOutput.metadata.isMedia) sessionStorage.setItem(onlyFilename(fileItem.relativePath || fileItem.filename), workerOutput.data.url) else files = [...files, workerOutput] diff --git a/client/src/visualisations/specific/instagram/InstagramPostsList.svelte b/client/src/visualisations/specific/instagram/InstagramPostsList.svelte index b251f66..22d2ba5 100644 --- a/client/src/visualisations/specific/instagram/InstagramPostsList.svelte +++ b/client/src/visualisations/specific/instagram/InstagramPostsList.svelte @@ -1,21 +1,45 @@
- +

- {post.caption} -
Posted on {longDateTime(new Date(post.taken_at))} -
Path: {post.path} + {post.type} + {#if post.type === 'profile'} + + {post.is_active_profile ? 'active' : 'replaced'} + + {/if} + {#if post.location} + {post.location} + {/if} + {#if post.caption} +
{post.caption} + {/if} +
📆 {longDateTime(new Date(post.timestamp))}

+ {#if post.type === 'photo'} + generic image + {:else if post.type === 'video'} + + {:else if post.type === 'story'} + generic image + {:else if post.type === 'profile'} + {'instagram + {/if}
@@ -28,13 +52,18 @@ } .container div.post { - background-color: var(--lumo-contrast-10pct); - border-color: var(--lumo-primary-color-50pct); - border-width: medium; - border-style: solid; - border-radius: var(--lumo-border-radius-l); - padding: var(--lumo-space-m); - margin: 0.5rem 1rem; - width: 600px; + background-color: var(--lumo-contrast-10pct); + border-color: var(--lumo-primary-color-50pct); + border-width: medium; + border-style: solid; + border-radius: var(--lumo-border-radius-l); + padding: var(--lumo-space-m); + margin: 0.5rem 1rem; + width: 600px; + } + + div.post img, video { + width: 100%; + border-radius: var(--lumo-border-radius-m); } \ No newline at end of file diff --git a/lib/common/ArrayUtils.ts b/lib/common/ArrayUtils.ts index b18cbb5..ba01122 100644 --- a/lib/common/ArrayUtils.ts +++ b/lib/common/ArrayUtils.ts @@ -72,9 +72,11 @@ export const objectOrArrayDepth = (obj) => { * If start === finish, it starts at zero up to finish. * * @example + * ```ts range(10) // 0 - 10 range(1,5) // 1 - 5 range(0,10,2) // 0,2,4,6,8,10 +``` */ export const range = (start: number, finish = start, increment = 1) => { if (start === finish) start = 0 diff --git a/lib/common/PathProcessing.ts b/lib/common/PathProcessing.ts index bc84749..a56c843 100644 --- a/lib/common/PathProcessing.ts +++ b/lib/common/PathProcessing.ts @@ -8,4 +8,4 @@ export function normalisePath(path: string) { export function onlyFilename(path: string) { const normalPath = normalisePath(path) return normalPath.split('/').slice(-1)[0] // .at(-1) not yet available -} \ No newline at end of file +} diff --git a/lib/package.json b/lib/package.json index d0ca012..69dbf98 100644 --- a/lib/package.json +++ b/lib/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "scripts": { "build": "tsc --build", - "clean": "tsc --build --clean" + "clean": "tsc --build --clean", + "docs": "npx typedoc --entryPointStrategy expand ./ --out ../docs" }, "dependencies": { "camelcase": "^6.2.0", diff --git a/lib/postProcessing/postProcessors/instagram.ts b/lib/postProcessing/postProcessors/instagram.ts index 3e80a75..cdcd327 100644 --- a/lib/postProcessing/postProcessors/instagram.ts +++ b/lib/postProcessing/postProcessors/instagram.ts @@ -1,8 +1,12 @@ -import { PostProcess } from '../../typedefs/PostProcess' +import { PostProcess, PostProcessedFileInput } from '../../typedefs/PostProcess' import { instagramConnectionsPostProcessingFunction } from '../../vendors/instagram/Connections' import { instagramCommentsPostProcessingFunction } from '../../vendors/instagram/Comments' import { instagramLikesPostProcessFunction } from '../../vendors/instagram/Likes' import { instagramAccountHistoryPostProcessor } from '../../vendors/instagram/AccountHistory' +import { + instagramMediaPostProcessFunction, + Media +} from '../../vendors/instagram/Media' export const InstagramPostsPostProcess: PostProcess = { classifier: { @@ -15,7 +19,8 @@ export const InstagramPostsPostProcess: PostProcess = { component: 'InstagramPostsList', name: 'Instagram Posts', code: 'instagram-posts', - vendor: 'Instagram' + vendor: 'Instagram', + postProcessingFunction: instagramMediaPostProcessFunction } export const InstagramProfilePostProcess: PostProcess = { diff --git a/lib/vendors/instagram/Media.ts b/lib/vendors/instagram/Media.ts index 5317537..032edba 100644 --- a/lib/vendors/instagram/Media.ts +++ b/lib/vendors/instagram/Media.ts @@ -1,7 +1,10 @@ import { RandHex } from '../../common/RandomUtils/RandomNumberUtils' import { RandDate } from '../../common/RandomUtils/RandomDateUtils' import { generateCaption } from '../../common/RandomUtils/RandomContent/RandomSentence' -import { formatDateEurTimeWithTz } from '../../common/DateUtils' +import { formatDateEurTimeWithTz, longDateTime } from '../../common/DateUtils' +import { repeat } from '../../common/ArrayUtils' +import { PostProcessor } from '../../typedefs/PostProcess' +import { InstagramLikes, InstagramLikesPostProcess } from './Likes' type DateString = `${number}-${number}-${number}T${number}:${number}:${number}+${number}:${number}` @@ -45,6 +48,70 @@ export interface Media { stories: Story[] videos: Video[] } +interface MediaTimestamp { + timestamp: number +} +interface StoryProcessed extends Story { + type: 'story' +} +interface ProfileProcessed extends Profile { + type: 'profile' +} +interface VideoProcessed extends Video { + type: 'video' +} +interface PhotoProcessed extends Photo { + type: 'photo' +} + +export type InstagramMediaAfterProcessing = (( + | VideoProcessed + | StoryProcessed + | ProfileProcessed + | PhotoProcessed +) & + MediaTimestamp)[] + +export const instagramMediaPostProcessFunction: PostProcessor< + Media, + InstagramMediaAfterProcessing +> = (input) => { + const d = input.preProcessedOutput.data + const data: InstagramMediaAfterProcessing = [] + data.push( + ...d['profile'].map((p) => ({ + ...p, + type: 'profile' as const, + timestamp: new Date(p.taken_at).getTime() + })) + ) + data.push( + ...d['stories'].map((p) => ({ + ...p, + type: 'story' as const, + timestamp: new Date(p.taken_at).getTime() + })) + ) + data.push( + ...d['photos'].map((p) => ({ + ...p, + type: 'photo' as const, + timestamp: new Date(p.taken_at).getTime() + })) + ) + data.push( + ...d['videos'].map((p) => ({ + ...p, + type: 'video' as const, + timestamp: new Date(p.taken_at).getTime() + })) + ) + data.sort((a, b) => a.timestamp - b.timestamp) + return { + ...input.preProcessedOutput, + data + } +} const staticSampleData: Media = { photos: [ @@ -104,18 +171,38 @@ export const generateSampleMediaData = ({ profiles = 2 }): Media => { return { - profile: [], - stories: [], - videos: [], - photos: Array(photos) - .fill(null) - .map(() => { - const date = RandDate() - return { - taken_at: generateRandomDateString(date), - caption: generateCaption(), - path: generatePath('photos', 'jpg', date) - } - }) + profile: repeat(profiles, (i) => { + const date = RandDate() + return { + is_active_profile: i === 0, + taken_at: generateRandomDateString(date), + caption: '', + path: generatePath('profile', 'jpg', date) + } + }), + stories: repeat(stories, (i) => { + const date = RandDate() + return { + taken_at: generateRandomDateString(date), + caption: i % 2 == 0 ? generateCaption() : '', + path: generatePath('stories', 'jpg', date) + } + }), + videos: repeat(videos, () => { + const date = RandDate() + return { + taken_at: generateRandomDateString(date), + caption: generateCaption(), + path: generatePath('videos', 'mp4', date) + } + }), + photos: repeat(photos, () => { + const date = RandDate() + return { + taken_at: generateRandomDateString(date), + caption: generateCaption(), + path: generatePath('photos', 'jpg', date) + } + }) } }