Skip to content

Commit f96b5c3

Browse files
committed
Merge branch 'main' into feature/unselect-all-different
2 parents f308e1d + 37aed00 commit f96b5c3

File tree

106 files changed

+4297
-4936
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+4297
-4936
lines changed

.env.sample

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,12 @@ DB_PORT="" # Postgres Port number (Default: 5432)
77
DB_DATABASE_NAME="" # Name of the database
88

99
# Additional configuration
10-
SECURE_COOKIE=false # Set to true to enable secure cookies
10+
SECURE_COOKIE=false # Set to true to enable secure cookies
11+
12+
# Optional
13+
GOOGLE_MAPS_API_KEY="" # Google Maps API Key for heatmap
14+
GEMINI_API_KEY="" # Gemini API Key for parsing search query in "Find"
15+
16+
# Immich Share Link
17+
IMMICH_SHARE_LINK_KEY="" # Share link key for Immich
18+
POWER_TOOLS_ENDPOINT_URL="" # URL of the Power Tools endpoint (Used for share links)

.eslintrc.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
{
2-
"extends": "next/core-web-vitals"
2+
"extends": "next/core-web-vitals",
3+
"plugins": ["@remotion"],
4+
"overrides": [
5+
{
6+
"files": ["remotion/*.{ts,tsx}"],
7+
"extends": ["plugin:@remotion/recommended"]
8+
}
9+
]
310
}

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: ci
33
on:
44
push:
55
branches:
6-
- release
6+
- main
77

88
jobs:
99
release:

README.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ A unofficial immich client to provide better tools to organize and manage your i
66

77
[![Immich Power Tools](./screenshots/screenshot-1.png)](https://www.loom.com/embed/13aa90d8ab2e4acab0993bdc8703a750?sid=71498690-b745-473f-b239-a7bdbe6efc21)
88

9+
### 🎒Features
10+
- **Manage people data in bulk 👫**: Options to update people data in bulk, and with advance filters
11+
- **People Merge Suggestion 🎭**: Option to bulk merge people with suggested faces based on similarity.
12+
- **Update Missing Locations 📍**: Find assets in your library those are without location and update them with the location of the asset.
13+
- **Potential Albums 🖼️**: Find albums that are potential to be created based on the assets and people in your library.
14+
- **Analytics 📈**: Get analytics on your library like assets over time, exif data, etc.
15+
- **Smart Search 🔎**: Search your library with natural language, supports queries like "show me all my photos from 2024 of <person name>"
16+
- **Bulk Date Offset 📅**: Offset the date of selected assets by a given amount of time. Majorly used to fix the date of assets that are out of sync with the actual date.
17+
18+
### Support me 🙏
19+
20+
If you find this tool useful, please consider supporting me by buying me a coffee.
21+
22+
[![Buy me a coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/varunraj)
23+
924
## 💭 Back story
1025

1126
Recently I've migrated my entire Google photos library to Immich, I was able to successfully migrate all my assets along with its albums to immich. But there were few things like people match that was lacking. I loved Immich UI on the whole but for organizing content I felt its quite restricted and I had to do a lot of things in bulk instead of opening each asset and doing it. Hence I built this tool (continuing to itereate) to make my life and any other Immich user's life easier.
@@ -39,6 +54,10 @@ Add the Immich API Key and immich url's to the env file (which you already have
3954
IMMICH_API_KEY= # your_immich_api_key
4055
IMMICH_URL = "http://local-ip-of-immich:port" # Your immich instace ip address and port
4156
EXTERNAL_IMMICH_URL = "https://external-address" # External address of immich
57+
58+
# Optional
59+
GOOGLE_MAPS_API_KEY= # Google Maps API Key
60+
GEMINI_API_KEY= # Gemini API Key
4261
```
4362
Refer here for obtaining Immich API Key: https://immich.app/docs/features/command-line-interface#obtain-the-api-key
4463

@@ -47,7 +66,11 @@ Refer here for obtaining Immich API Key: https://immich.app/docs/features/comman
4766
If you're using portainer, run the docker using `docker run` and add the power tools to the same network as immich.
4867

4968
```bash
69+
# Run the power tools from docker
5070
docker run -d --name immich_power_tools -p 8001:3000 --env-file .env ghcr.io/varun-raj/immich-power-tools:latest
71+
72+
# Add Power tools to the same network as immich
73+
docker network connect immich_default immich_power_tools
5174
```
5275

5376

@@ -86,7 +109,8 @@ bun run dev
86109
- [x] Manage People
87110
- [x] Smart Merge
88111
- [x] Manage Albums
89-
- [ ] Bulk Delete
112+
- [x] Bulk Delete
113+
- [x] Bulk Share
90114
- [ ] Bulk Edit
91115
- [ ] Filters
92116
- [x] Potential Albums
@@ -100,7 +124,7 @@ bun run dev
100124

101125
- [x] Dark Mode
102126
- [x] Dockerize
103-
- [ ] Authentication
127+
- [x] Authentication
104128
- [x] Push to github packages
105129

106130
## Tech Stack
@@ -110,6 +134,19 @@ bun run dev
110134
- [Shadcn](https://shadcn.com/) for UI Components
111135
- [Axios](https://axios-http.com/) for API calls
112136

137+
## External Services
138+
These services are completely optional and you can use the tool without them. Just that they are used for some of the features. But we dont send any personal data to these services.
139+
140+
- [Google Maps](https://maps.google.com/) for heatmap
141+
Google Maps Javascript API Key is used to render the maps layer for heatmap. When rendering the heatmap, we only send the location data to Google Maps and not any other data.
142+
143+
> Code where heatmap data is plotted: [src/pages/assets/geo-heatmap.tsx:32](./src/pages/assets/geo-heatmap.tsx#L32-L35)
144+
145+
- [Gemini](https://gemini.google.com/) for rewind video generation
146+
Google Gemini 1.5 Flash model is used for parsing your search query in "Find" page. We do not send any personal data to Gemini, only data that is sent to Gemini is your search query and rest of the querying happes using [Immich's Smart Search API](https://immich.app/docs/api/search-smart)
147+
148+
> Code where Gemini is used: [src/helpers/gemini.helper.ts](./src/helpers/gemini.helper.ts)
149+
113150
## Contributing
114151

115-
Feel free to contribute to this project, I'm open to any suggestions and improvements. Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
152+
Feel free to contribute to this project, I'm open to any suggestions and improvements. Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.

bun.lockb

77.6 KB
Binary file not shown.

package.json

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "immich-power-tools",
3-
"version": "0.10.1",
3+
"version": "0.13.0",
44
"private": true,
55
"scripts": {
66
"dev": "next dev",
@@ -14,7 +14,9 @@
1414
"url": "https://varunraj.in"
1515
},
1616
"dependencies": {
17+
"@google/generative-ai": "^0.21.0",
1718
"@radix-ui/react-accordion": "^1.2.1",
19+
"@radix-ui/react-alert-dialog": "^1.1.4",
1820
"@radix-ui/react-avatar": "^1.1.0",
1921
"@radix-ui/react-checkbox": "^1.1.2",
2022
"@radix-ui/react-dialog": "^1.1.1",
@@ -30,10 +32,13 @@
3032
"@radix-ui/react-tabs": "^1.1.0",
3133
"@radix-ui/react-toast": "^1.2.1",
3234
"@radix-ui/react-tooltip": "^1.1.2",
35+
"@remotion/cli": "4.0.232",
36+
"@remotion/eslint-plugin": "^4.0.232",
3337
"@tanstack/react-table": "^8.20.1",
3438
"@types/cookie": "^0.6.0",
3539
"@types/qs": "^6.9.15",
3640
"@types/react-calendar-heatmap": "^1.6.7",
41+
"@vis.gl/react-google-maps": "^1.4.2",
3742
"axios": "^1.7.4",
3843
"chrono-node": "^1.4.9",
3944
"class-variance-authority": "^0.7.0",
@@ -43,25 +48,29 @@
4348
"cookie": "^0.6.0",
4449
"date-fns": "^3.6.0",
4550
"drizzle-orm": "^0.33.0",
51+
"jsonwebtoken": "^9.0.2",
4652
"leaflet": "^1.9.4",
47-
"leaflet-defaulticon-compatibility":"0.1.2",
53+
"leaflet-defaulticon-compatibility": "0.1.2",
4854
"lucide-react": "^0.428.0",
4955
"next": "14.2.5",
5056
"next-themes": "^0.3.0",
5157
"pg": "^8.12.0",
5258
"qs": "^6.13.0",
5359
"react": "^18",
54-
"react-calendar-heatmap": "^1.9.0",
5560
"react-day-picker": "9.0.8",
5661
"react-dom": "^18",
5762
"react-grid-gallery": "^1.0.1",
63+
"react-hot-toast": "^2.5.1",
5864
"react-leaflet": "^4.2.1",
65+
"react-mentions": "^4.4.10",
5966
"react-query": "^3.39.3",
6067
"recharts": "^2.12.7",
68+
"remotion": "4.0.232",
6169
"sass": "^1.77.8",
6270
"tailwind-merge": "^2.5.2",
6371
"tailwindcss-animate": "^1.0.7",
64-
"yet-another-react-lightbox": "^3.21.4"
72+
"yet-another-react-lightbox": "^3.21.4",
73+
"zod": "^3.24.1"
6574
},
6675
"devDependencies": {
6776
"@semantic-release/commit-analyzer": "^13.0.0",
@@ -70,11 +79,12 @@
7079
"@semantic-release/npm": "^12.0.1",
7180
"@semantic-release/release-notes-generator": "^14.0.1",
7281
"@types/jsonwebtoken": "^9.0.6",
73-
"@types/leaflet":"^1.9.15",
82+
"@types/leaflet": "^1.9.15",
7483
"@types/node": "^20",
7584
"@types/pg": "^8.11.6",
7685
"@types/react": "^18",
7786
"@types/react-dom": "^18",
87+
"@types/react-mentions": "^4.4.1",
7888
"autoprefixer": "^10.4.20",
7989
"drizzle-kit": "^0.24.0",
8090
"eslint": "^8",

postcss.config.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

postcss.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const config = {
33
plugins: {
44
tailwindcss: {},
5+
autoprefixer: {},
56
},
67
};
78

public/audio/rewind.mp3

3.55 MB
Binary file not shown.

remotion/Composition.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { AbsoluteFill, useCurrentFrame, interpolate, staticFile, Audio, Sequence } from "remotion";
2+
import WelcomeScene from "./rewind/WelcomeScene";
3+
import CountryScene from "./rewind/CountryScene";
4+
import MemoriesScene from "./rewind/MemoriesScene";
5+
import AlbumsScene from "./rewind/AlbumScene";
6+
import FriendsScene from "./rewind/FriendsScene";
7+
import PowertoolsLogo from "./rewind/Powertoolslogo";
8+
9+
export interface Scene {
10+
message: string;
11+
type: string;
12+
emoji: string;
13+
data: any;
14+
}
15+
export const IntroComposition = ({ scenes }: { scenes: Scene[] }) => {
16+
const frame = useCurrentFrame();
17+
const screenDuration = 120;
18+
19+
const renderScene = (scene: Scene) => {
20+
switch (scene.type) {
21+
case "WELCOME":
22+
return <WelcomeScene message={scene.message} emoji={scene.emoji} />;
23+
case "COUNTRY":
24+
return <CountryScene message={scene.message} emoji={scene.emoji} data={scene.data} />;
25+
case "MEMORY":
26+
return <MemoriesScene message={scene.message} emoji={scene.emoji} data={scene.data} />;
27+
case "ALBUM":
28+
return <AlbumsScene message={scene.message} emoji={scene.emoji} data={scene.data} />;
29+
case "FRIEND":
30+
return <FriendsScene message={scene.message} emoji={scene.emoji} data={scene.data} />;
31+
default:
32+
return <WelcomeScene message={scene.message} emoji={scene.emoji} />;
33+
}
34+
};
35+
36+
return (
37+
<AbsoluteFill
38+
style={{
39+
justifyContent: "center",
40+
alignItems: "center",
41+
backgroundColor: "black",
42+
transition: "background-color 1s ease",
43+
fontFamily: "sans-serif",
44+
}}
45+
>
46+
<Sequence name="Logo Intro" durationInFrames={screenDuration}>
47+
<div style={{
48+
width: "100%",
49+
height: "100%",
50+
display: "flex",
51+
justifyContent: "center",
52+
alignItems: "center"
53+
}}>
54+
<PowertoolsLogo size={200} />
55+
</div>
56+
</Sequence>
57+
58+
{scenes.map((scene, index) => (
59+
<Sequence
60+
key={index}
61+
name={`Scene ${index + 1} - ${scene.type}`}
62+
from={screenDuration * (index + 1)}
63+
durationInFrames={screenDuration}
64+
>
65+
{renderScene(scene)}
66+
</Sequence>
67+
))}
68+
69+
<Audio src={staticFile("audio/rewind.mp3")} />
70+
</AbsoluteFill>
71+
);
72+
};

0 commit comments

Comments
 (0)