Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to authenticate to user #2

Closed
feerlessleadr opened this issue Sep 12, 2023 · 36 comments
Closed

Add ability to authenticate to user #2

feerlessleadr opened this issue Sep 12, 2023 · 36 comments

Comments

@feerlessleadr
Copy link

feerlessleadr commented Sep 12, 2023

Hi - I have ntfy setup in a separate docker container, however I have authentication setup. I mapped the main.py file outside of the container and tried to add in the basic auth to the main.py file:

def ntfy_notification(ntfyurl, ntfytitle, ntfymessage, ntfylink):
    requests.post(ntfyurl,
                  data=ntfymessage.encode('utf-8'),
                  headers={
                      "Title": ntfytitle,
                      "Click": ntfylink,
                      "Icon": NTFY_ICON
                      "Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
                  })

However when I run the above, I get an error in the container that says:

immich_notify  | 09/12/2023 22:15:01 - Immich Notification Check Triggered
immich_notify  |   File "//./main.py", line 77
immich_notify  |     "Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "
immich_notify  |     ^
immich_notify  | SyntaxError: invalid syntax

Any idea how I can add in the auth to your script? Thanks

@feerlessleadr
Copy link
Author

So turns out, I was just missing a comma, however I'm still getting an error:

immich_notify  | 09/15/2023 15:30:02 - Immich Notification Check Triggered
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 971, in json
immich_notify  |     return complexjson.loads(self.text, **kwargs)
immich_notify  |   File "/usr/local/lib/python3.9/json/__init__.py", line 346, in loads
immich_notify  |     return _default_decoder.decode(s)
immich_notify  |   File "/usr/local/lib/python3.9/json/decoder.py", line 337, in decode
immich_notify  |     obj, end = self.raw_decode(s, idx=_w(s, 0).end())
immich_notify  |   File "/usr/local/lib/python3.9/json/decoder.py", line 355, in raw_decode
immich_notify  |     raise JSONDecodeError("Expecting value", s, err.value) from None
immich_notify  | json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
immich_notify  |
immich_notify  | During handling of the above exception, another exception occurred:
immich_notify  |
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "//./main.py", line 141, in <module>
immich_notify  |     tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
immich_notify  |   File "//./main.py", line 62, in get_album_contents
immich_notify  |     a = response.json()
immich_notify  |   File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 975, in json
immich_notify  |     raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
immich_notify  | requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

@pman07
Copy link
Owner

pman07 commented Sep 15, 2023

So turns out, I was just missing a comma, however I'm still getting an error:

immich_notify  | 09/15/2023 15:30:02 - Immich Notification Check Triggered
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 971, in json
immich_notify  |     return complexjson.loads(self.text, **kwargs)
immich_notify  |   File "/usr/local/lib/python3.9/json/__init__.py", line 346, in loads
immich_notify  |     return _default_decoder.decode(s)
immich_notify  |   File "/usr/local/lib/python3.9/json/decoder.py", line 337, in decode
immich_notify  |     obj, end = self.raw_decode(s, idx=_w(s, 0).end())
immich_notify  |   File "/usr/local/lib/python3.9/json/decoder.py", line 355, in raw_decode
immich_notify  |     raise JSONDecodeError("Expecting value", s, err.value) from None
immich_notify  | json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
immich_notify  |
immich_notify  | During handling of the above exception, another exception occurred:
immich_notify  |
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "//./main.py", line 141, in <module>
immich_notify  |     tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
immich_notify  |   File "//./main.py", line 62, in get_album_contents
immich_notify  |     a = response.json()
immich_notify  |   File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 975, in json
immich_notify  |     raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
immich_notify  | requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Could you post your docker ENV variables setup?

@feerlessleadr
Copy link
Author

sure

# Base url to access API
# example: http://192.168.1.100:
BASEURL=http://192.168.1.18:

# External url to access albums via notification link
# example: https://immich.fakeurl.com
EXTERNALURL=https://pics.mydomain.com

# Immich API Key
IMMICHKEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX

# File to store album item counts
FILEPATH=./data/data.txt

# Dictionary with album id(s) and desired notification topic(s)
# Can all be the same topic or divide up as desired
ALBUMS={'79bed5d2-2c71-4dd8-91f7-d06afe496569': 'My-Topic'}

# ntfy URL to send notifications to
# ntfy can be self hosted or use free or paid teirs of https://ntfy.sh
NTFYURL=https://ntfy.mydomain.com

# Icon to use for ntfy notification
NTFYICON=https://raw.githubusercontent.com/immich-app/immich/main/design/immich-logo-no-outline.png

@pman07
Copy link
Owner

pman07 commented Sep 15, 2023

Does your album have pictures in it? Are you sure it's the right album ID?

It looks like it's not getting any album contents back.

@feerlessleadr
Copy link
Author

feerlessleadr commented Sep 15, 2023

The album definitely has pictures in it (1k+ pictures). I'm not 100% sure I have the right ID though. I grabbed the ID by navigating to the album and then copying the numbers at the end of the address bar in my browser:

https://pics.mydomain.com/albums/79bed5d2-2c71-4dd8-91f7-d06afe496569

Is that the right way to do it?

@feerlessleadr
Copy link
Author

Any thoughts on whether I'm grabbing the right album ID? @pman07

@pman07
Copy link
Owner

pman07 commented Sep 18, 2023

Well, that should be it. Where did you get your Immich API Key? Is it still active?

@feerlessleadr
Copy link
Author

I created 2 new keys (tested both, both give the same error as above) by going to my username on the top right, then 'Account Settings', then 'API Keys', then 'New API Key'.

I even created a test album with only a few pictures in it (vs my main album with has a few thousand and is shared with a few people just in case).

Here is my compose file in case something is wonky there:

version: "3.8"

services:
  immich_notify:
    image: pierson07/immich_notify:latest
    container_name: immich_notify
    env_file:
      - stack.env
    volumes:
      - ./data:/data # optional, use to retain data through redeployment
      - ${PWD}/data/main.py:/main.py # to persist the main.py file to add authentication
    restart: unless-stopped

And here is the main.py file, which I have mapped outside the container to allow me to add auth to my ntfy instance. I only made 2 changes to this file, which I bolded below:

import os
import ast
import socket
import requests


IMMICH_KEY = os.environ.get('IMMICHKEY')
BASE_URL = os.environ.get('BASEURL')
EXT_URL = os.environ.get('EXTERNALURL')
FILE_PATH = os.environ.get('FILEPATH')
ALBUMS = ast.literal_eval(os.environ['ALBUMS'])
NTFY_URL = os.environ.get('NTFYURL')
NTFY_ICON = os.environ.get('NTFYICON')
DEBUG = (os.getenv('DEBUG', 'False') == 'True')


def check(host, port, timeout=1):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    try:
        sock.connect((host, port))
    except:
        return False
    else:
        sock.close()
        return True


def save_data(file_path, dictionary):
    try:
        with open(file_path, 'w') as file:
            for key in dictionary:
                file.write(str(dictionary[key]['total items']) + '\n')
        if DEBUG:
            print("Data stored successfully!")
    except IOError:
        print("An error occurred while saving the file.")


def read_data(file_path):
    tmp = []
    try:
        with open(file_path, 'r') as file:
            for string in file:
                tmp.append(int(string.strip()))
        return tmp
    except IOError:
        print("An error occurred while loading the file.")


def get_album_contents(uuid, imkey):
    url = BASE_URL + "/api/album/" + uuid

    payload = {}
    headers = {
        'Accept': 'application/json',
        'x-api-key': imkey
    }

    response = requests.request("GET", url, headers=headers, data=payload)

    a = response.json()

    album_name = a['albumName']
    count = a['assetCount']

    return album_name, count


def ntfy_notification(ntfyurl, ntfytitle, ntfymessage, ntfylink):
    requests.post(ntfyurl,
                  data=ntfymessage.encode('utf-8'),
                  headers={
                      "Title": ntfytitle,
                      "Click": ntfylink,
                      "Icon": NTFY_ICON,
                      "Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
                  })


if __name__ == '__main__':

    total_items_stored = []
    albums = {}

    if check('192.168.1.18', 2283):
        if os.path.exists(FILE_PATH):
            if DEBUG:
                print('File Exists')
            total_items_stored = read_data(FILE_PATH)
            if DEBUG:
                for item in total_items_stored:
                    print('Items:', item)

            index = 0
            for key in ALBUMS:
                album = key
                topic = ALBUMS[key]
                if DEBUG:
                    print("Topic: ", topic)
                    print("Album ID: ", album)
                tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
                albums[album] = {'topic': topic, 'title': tmp_title, 'total items': tmp_total,
                                 'stored items': total_items_stored[index]}
                index += 1

            if DEBUG:
                for album in albums:
                    print('Album Name: ', albums[album]['title'])
                    print('Total Items Stored: ', albums[album]['stored items'])
                    print('Total Items Now: ', albums[album]['total items'])

            index = 0
            for album in albums:
                albums[album]['new items'] = albums[album]['total items'] - albums[album]['stored items']
                index += 1

            if DEBUG:
                for album in albums:
                    print('Album Name:', albums[album]['title'])
                    print("Items Added:", albums[album]['new items'])

            for album in albums:
                if albums[album]['new items'] > 0:
                    topic = albums[album]['topic']
                    url = NTFY_URL + '/' + topic
                    title = 'Immich'
                    link = EXT_URL + '/albums/' + album

                    if albums[album]['new items'] > 1:
                        message = str(albums[album]['new items']) + ' photos added to ' + albums[album]['title'] + '!'
                    else:
                        message = 'Photo added to ' + albums[album]['title'] + '!'

                    ntfy_notification(url, title, message, link)

        else:
            for key in ALBUMS:
                album = key
                topic = ALBUMS[key]
                tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
                albums[album] = {'topic': topic, 'title': tmp_title, 'total items': tmp_total}

            if DEBUG:
                for album in albums:
                    print('Album Name:', albums[album]['title'])
                    print('Total Items Now: ', albums[album]['total items'])

        save_data(FILE_PATH, albums)

I made 2 changes to the above file:

I added in the authorization for my ntfy instance:

def ntfy_notification(ntfyurl, ntfytitle, ntfymessage, ntfylink):
    requests.post(ntfyurl,
                  data=ntfymessage.encode('utf-8'),
                  headers={
                      "Title": ntfytitle,
                      "Click": ntfylink,
                      "Icon": NTFY_ICON,
                      "Authorization": "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
                  })

And I changed a hard coded local IP from 192.168.1.80 to 192.168.1.18, which I assumed was a mistake?

if __name__ == '__main__':

    total_items_stored = []
    albums = {}

    if check('192.168.1.18', 2283):
        if os.path.exists(FILE_PATH):
            if DEBUG:
                print('File Exists')
            total_items_stored = read_data(FILE_PATH)
            if DEBUG:
                for item in total_items_stored:
                    print('Items:', item)

If I leave the above portion of main.py as it is in the repo:

if __name__ == '__main__':

    total_items_stored = []
    albums = {}

    if check('192.168.1.80', 2283):
        if os.path.exists(FILE_PATH):
            if DEBUG:
                print('File Exists')
            total_items_stored = read_data(FILE_PATH)
            if DEBUG:
                for item in total_items_stored:
                    print('Items:', item)

the following shows up, but nothing happens (no notification, etc.):

immich_notify | 09/18/2023 22:00:01 - Immich Notification Check Triggered

@pman07
Copy link
Owner

pman07 commented Sep 19, 2023

I don't see anything glaring that's wrong. If I make the same changes to my copy it still works, but I don't have NTFY authentication setup currently.

Good catch on the hardcoded local IP, that's embarrassing. I'm working on a fix for that as well as adding optional authentication. Would you be able to test the following out and see if it works for you?

Add AUTHORIZATION_KEY to your Docker stack.env variables

import os
import ast
import socket
import requests
from urllib.parse import urlparse

IMMICH_KEY = os.environ.get('IMMICHKEY')
BASE_URL = os.environ.get('BASEURL')
EXT_URL = os.environ.get('EXTERNALURL')
FILE_PATH = os.environ.get('FILEPATH')
ALBUMS = ast.literal_eval(os.environ['ALBUMS'])
NTFY_URL = os.environ.get('NTFYURL')
NTFY_ICON = os.environ.get('NTFYICON')
DEBUG = (os.getenv('DEBUG', 'False') == 'True')

if 'AUTHORIZATION_KEY' in os.environ:
    AUTHORIZATION_KEY = os.environ.get('AUTHORIZATION_KEY')
else:
    AUTHORIZATION_KEY = ''


def check(host, port, timeout=1):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    try:
        sock.connect((host, port))
    except:
        return False
    else:
        sock.close()
        return True


def save_data(file_path, dictionary):
    try:
        with open(file_path, 'w') as file:
            for key in dictionary:
                file.write(str(dictionary[key]['total items']) + '\n')
        if DEBUG:
            print("Data stored successfully!")
    except IOError:
        print("An error occurred while saving the file.")


def read_data(file_path):
    tmp = []
    try:
        with open(file_path, 'r') as file:
            for string in file:
                tmp.append(int(string.strip()))
        return tmp
    except IOError:
        print("An error occurred while loading the file.")


def get_album_contents(uuid, imkey):
    url = BASE_URL + "/api/album/" + uuid

    payload = {}
    headers = {
        'Accept': 'application/json',
        'x-api-key': imkey
    }

    response = requests.request("GET", url, headers=headers, data=payload)

    a = response.json()

    album_name = a['albumName']
    count = a['assetCount']

    return album_name, count


def ntfy_notification(ntfyurl, ntfytitle, ntfymessage, ntfylink, authorization=''):
    if authorization != '':
        requests.post(ntfyurl,
                  data=ntfymessage.encode('utf-8'),
                  headers={
                      "Title": ntfytitle,
                      "Click": ntfylink,
                      "Icon": NTFY_ICON,
                      "Authorization": "Basic " + authorization
                  })
    else:
        requests.post(ntfyurl,
                  data=ntfymessage.encode('utf-8'),
                  headers={
                      "Title": ntfytitle,
                      "Click": ntfylink,
                      "Icon": NTFY_ICON
                  })


if __name__ == '__main__':

    total_items_stored = []
    albums = {}

    url = urlparse(BASE_URL)

    if check(url.hostname, url.port):
        if os.path.exists(FILE_PATH):
            if DEBUG:
                print('File Exists')
            total_items_stored = read_data(FILE_PATH)
            if DEBUG:
                for item in total_items_stored:
                    print('Items:', item)

            index = 0
            for key in ALBUMS:
                album = key
                topic = ALBUMS[key]
                if DEBUG:
                    print("Topic: ", topic)
                    print("Album ID: ", album)
                tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
                albums[album] = {'topic': topic, 'title': tmp_title, 'total items': tmp_total,
                                 'stored items': total_items_stored[index]}
                index += 1

            if DEBUG:
                for album in albums:
                    print('Album Name: ', albums[album]['title'])
                    print('Total Items Stored: ', albums[album]['stored items'])
                    print('Total Items Now: ', albums[album]['total items'])

            index = 0
            for album in albums:
                albums[album]['new items'] = albums[album]['total items'] - albums[album]['stored items']
                index += 1

            if DEBUG:
                for album in albums:
                    print('Album Name:', albums[album]['title'])
                    print("Items Added:", albums[album]['new items'])

            for album in albums:
                if albums[album]['new items'] > 0:
                    topic = albums[album]['topic']
                    url = NTFY_URL + '/' + topic
                    title = 'Immich'
                    link = EXT_URL + '/albums/' + album

                    if albums[album]['new items'] > 1:
                        message = str(albums[album]['new items']) + ' photos added to ' + albums[album]['title'] + '!'
                    else:
                        message = 'Photo added to ' + albums[album]['title'] + '!'

                    ntfy_notification(url, title, message, link, AUTHORIZATION_KEY)

        else:
            for key in ALBUMS:
                album = key
                topic = ALBUMS[key]
                tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
                albums[album] = {'topic': topic, 'title': tmp_title, 'total items': tmp_total}

            if DEBUG:
                for album in albums:
                    print('Album Name:', albums[album]['title'])
                    print('Total Items Now: ', albums[album]['total items'])

        save_data(FILE_PATH, albums)
        

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

@feerlessleadr I've updated the container to fix the hardcoded IP and hopefully add support for Basic Auth.

If you get a chance to try it out, let me know how it goes!

@feerlessleadr
Copy link
Author

feerlessleadr commented Sep 20, 2023

Thanks - I updated my compose to remove mapping the main.py outside of the container:

version: "3.8"

services:
  immich_notify:
    image: pierson07/immich_notify:latest
    container_name: immich_notify
    env_file:
      - stack.env
    volumes:
      - ./data:/data # optional, use to retain data through redeployment
#      - ${PWD}/data/main.py:/main.py # to persist the main.py file to add authentication
    restart: unless-stopped

I also updated my stack.env for the auth:

# Base url to access API
# example: http://192.168.1.100:
BASEURL=http://192.168.1.18:

# External url to access albums via notification link
# example: https://immich.fakeurl.com
EXTERNALURL=https://pics.mydomain.com

# Immich API Key
IMMICHKEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

# File to store album item counts
FILEPATH=./data.txt

# Dictionary with album id(s) and desired notification topic(s)
# Can all be the same topic or divide up as desired
ALBUMS={'1009fc79-72ea-4875-b6a4-a493ad205632': 'immich'}

# ntfy URL to send notifications to
# ntfy can be self hosted or use free or paid teirs of https://ntfy.sh
NTFYURL=https://ntfy.mydomain.com

# Icon to use for ntfy notification
NTFYICON=https://raw.githubusercontent.com/immich-app/immich/main/design/immich-logo-no-outline.png

# OPTIONAL Basic Authorization Token
AUTHORIZATION_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

I re-pulled the contaner and let this run and all I get in the docker log is:

immich_notify  | 09/20/2023 17:22:01 - Immich Notification Check Triggered
immich_notify  | 09/20/2023 17:23:01 - Immich Notification Check Triggered
immich_notify  | 09/20/2023 17:24:01 - Immich Notification Check Triggered

It seems like the script is running every minute now? However I do not get a notification nor is the data.txt created.

I know that my ntfy instance is working, as I'm using it for other scripts/services, so not sure where I'm going wrong.

@pman07

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

@feerlessleadr Ahh I see a documentation error. There needs to be your Immich port number in the stack.env variable BASEURL=http://192.168.1.18:2283

I'll fix that in the ReadMe. Apologies.

@feerlessleadr
Copy link
Author

No worries. I'm definitely getting somewhere. I have a new error:

immich_notify  | 09/20/2023 18:31:01 - Immich Notification Check Triggered
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "//./main.py", line 158, in <module>
immich_notify  |     tmp_title, tmp_total = get_album_contents(album, IMMICH_KEY)
immich_notify  |   File "//./main.py", line 70, in get_album_contents
immich_notify  |     album_name = a['albumName']
immich_notify  | KeyError: 'albumName'

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

Hmm. Are you familiar with the program Postman?

If so, could you try sending a "GET" to https://pics.mydomain.com/api/album/1009fc79-72ea-4875-b6a4-a493ad205632

with Authorization set to Bearer Token and paste your Immich API token XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

I'm curious if your API access isn't working with your key. What the error means is that when calling the album API to check the album contents it's not seeing the albumName in the response.

@feerlessleadr
Copy link
Author

feerlessleadr commented Sep 20, 2023

I'm not familiar, but I was able to sign up and download the program. It looks like the issue is an invalid key. I'm not sure how that's possible though, as I just created a new key, copied it into the postman and re-ran the request, and I'm still getting the below error in postman:

{
    "message": "Invalid user token",
    "error": "Unauthorized",
    "statusCode": 401
}

Am I creating the key correctly? I'm going to my username on the top right, then 'Account Settings', then 'API Keys', then 'New API Key', then copying the key, then clicking done.

::EDIT:: Ok, so things are getting stranger and stranger. I ran across this issue, thinking I was having the same problem.

I created another new api key and ran the following:

curl -L -X GET 'pics.mydomain.com/api/server-info' -H 'Accept: application/json' -H 'x-api-key: XXXXXXXXXXXXXXXXXX'

and the api key works:

{"diskAvailable":"26.2 TiB","diskSize":"117.6 TiB","diskUse":"91.3 TiB","diskAvailableRaw":28833714106368,"diskSizeRaw":129270715641856,"diskUseRaw":100424953786368,"diskUsagePercentage":77.69}

However, when I use the exact same API key in postman (which I know works), I get the invalid user token message from above.

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

Hmmm. Do you have '' around your API Key in the stack.env?

Kinda grasping at straws, that's very odd.

@feerlessleadr
Copy link
Author

I tried it both ways (with and without ") and get the same error.

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

Where are you running the curl command vs postman? Same computer?

@feerlessleadr
Copy link
Author

feerlessleadr commented Sep 20, 2023

So turns out I'm a little dumb and forgot to update my env with the new API key I used in the curl command. Now that I did that and encased the key inside double quotes, the error goes away and it just says that a notification check was triggered. Unfortunately I still don't get a notification and a data.txt file isn't created still. No other errors are thrown though, so I'm not sure what exactly is failing.

I did run the curl command from the same machine that immich and immich-notify docker containers are located. Postman is located on my windows machine though. Despite me not updating the env, postman still comes back with invalid token, but that could be a Windows firewall issue.

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

I'm assuming it still didn't create the data.txt file? The first time it runs successfully it won't send a notification.

@feerlessleadr
Copy link
Author

Yeah, no data.txt file. I'm not sure I have the env and the compose file setup correctly for the data.txt file though (I posted both above).

In my /immich-notify/ folder, I have a data folder and that is where I'd like the data.txt file to be created.

In the compose file, should I just map the ./data/ folder to inside the container (as I have now), or should I include the specific data.txt file as well?

Also in the .env, is that path for inside the container or outside? And should I have it as a relative path or full path, and should I include data.txt in that path or no?

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

The volume should just be the folder, the env file should include the path and the file name.

Here is how I have my Docker Compose setup

services:
  immich_notify:
    image: pierson07/immich_notify:latest
    container_name: immich_notify
    env_file:
      - stack.env
    volumes:
      - /mnt/data/appdata/immich_notification:/mnt/data/appdata/immich_notification
    restart: unless-stopped

And my stack.env FILEPATH

BASEURL=http://192.168.1.80:2283
EXTERNALURL=https://pics.url
IMMICHKEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
FILEPATH=/mnt/data/appdata/immich_notification/data.txt
ALBUMS={'18e2df3e-e44d-48a4-ac78-7d08dc826a7e': 'immich','3a5ef3de-e0f1-4759-be59-bcc56c2f2104': 'immich'}
NTFYURL=http://192.168.1.80:8080
NTFYICON=https://raw.githubusercontent.com/immich-app/immich/main/design/immich-logo-no-outline.png

In my case, the /mnt/data/appdata/immich_notification is a folder on my TrueNas server. You could probably simplify the internal folder structure but I keep it the same because I'm lazy and it works.

@feerlessleadr
Copy link
Author

well im thoroughly confused now. all i did was change the file path in the env and im back to the same error with the album:

immich_notify  | 09/20/2023 22:20:01 - Immich Notification Check Triggered
immich_notify  | Traceback (most recent call last):
immich_notify  |   File "/main.py", line 11, in <module>
immich_notify  |     ALBUMS = ast.literal_eval(os.environ['ALBUMS'])
immich_notify  |   File "/usr/local/lib/python3.9/os.py", line 679, in __getitem__
immich_notify  |     raise KeyError(key) from None
immich_notify  | KeyError: 'ALBUMS'

one more time in case i messed up, heres my compose:

version: "3.8"

services:
  immich_notify:
    image: pierson07/immich_notify:latest
    container_name: immich_notify
    env_file:
      - stack.env
    volumes:
      - /home/kevin/docker-apps/immich-notify/data:/data # optional, use to retain data through redeployment
#      - ${PWD}/data/main.py:/main.py # to persist the main.py file to add authentication
    restart: unless-stopped

here is my env:

# Base url to access API
# example: http://192.168.1.100:
BASEURL=http://192.168.1.18:2283

# External url to access albums via notification link
# example: https://immich.fakeurl.com
EXTERNALURL=https://pics.mydomain.com

# Immich API Key
IMMICHKEY=XXXX

# File to store album item counts
FILEPATH=/home/kevin/docker-apps/immich-notify/data/data.txt

# Dictionary with album id(s) and desired notification topic(s)
# Can all be the same topic or divide up as desired
ALBUMS={'1009fc79-72ea-4875-b6a4-a493ad205632': 'immich'}

# ntfy URL to send notifications to
# ntfy can be self hosted or use free or paid teirs of https://ntfy.sh
NTFYURL=https://ntfy.mydomain.com

# Icon to use for ntfy notification
NTFYICON=https://raw.githubusercontent.com/immich-app/immich/main/design/immich-logo-no-outline.png

# OPTIONAL Basic Authorization Token
AUTHORIZATION_KEY=XXXXX

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

Well, in this case we're in the same boat. I updated it to run every 15 minutes and the docker container broke. I'm trying to figure out why its 50/50 when I build the docker container. I'll message when I get it fixed. Sorry for the inconvenience.

EDIT
This is why I shouldn't try using my desktop. Back on my laptop and testing before I push the fixes.

@feerlessleadr
Copy link
Author

All good, hopefully I can help you fix!

@pman07
Copy link
Owner

pman07 commented Sep 20, 2023

Ok, latest container works for me. Should be back on track.

-EDIT-
Also, you can add

DEBUG=True

to stack.env to see more information in logs.

@feerlessleadr
Copy link
Author

Ok - making more progress. The container can see the album and can see the number of assets, but I'm getting an error about writing the file:

immich_notify  | 09/21/2023 14:00:01 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  3
immich_notify  | An error occurred while saving the file.

I then added another asset to the 'Test' album, and received the same error, and did not get a notification through ntfy. I'm assuming that's because of the file error.

immich_notify  | 09/21/2023 14:30:01 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  4
immich_notify  | An error occurred while saving the file.

When I log into the container, I can access the /data/ folder (mapped to /home/kevin/docker-apps/immich-notify/data/ on my docker host), where I have the data.txt file set to save. I can also create/edit/delete a test file within the container in the mapped directory above.

@pman07
Copy link
Owner

pman07 commented Sep 21, 2023

That's interesting, I'll add some logging for the actual error with saving the file later today.

In the meantime, can you try running

chmod 777 /home/kevin/docker-apps/immich-notify/data/

and see if that changes anything?

@feerlessleadr
Copy link
Author

thanks, happy to keep testing.

i ran the chmod command and same issue:

kevin@ubuntu-server:~/docker-apps/immich-notify$ sudo chmod 777 /home/kevin/docker-apps/immich-notify/data/
[sudo] password for kevin:
kevin@ubuntu-server:~/docker-apps/immich-notify$ ls -la
total 32
drwxrwxr-x  3 kevin kevin 4096 Sep 21 10:41 .
drwxrwxr-x 30 kevin kevin 4096 Sep 11 15:15 ..
drwxrwxrwx  2 root  root  4096 Sep 21 10:56 data
-rw-rw-r--  1 kevin kevin  391 Sep 21 10:40 docker-compose.yml
-rw-r--r--  1 root  root  4744 Sep 18 17:15 main.py.bak
-rw-rw-r--  1 kevin kevin 1027 Sep 21 10:41 stack.env
-rwxrwxr-x  1 kevin kevin  232 Sep 12 18:25 test.py
immich_notify  | 09/21/2023 23:00:02 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  4
immich_notify  | An error occurred while saving the file.

@pman07
Copy link
Owner

pman07 commented Sep 22, 2023

@feerlessleadr dang, hoped that'd get it. Ok I added some logging for the IO errors. Let me know if that helps at all.

@feerlessleadr
Copy link
Author

Thanks - here is the error with the updated logging:

immich_notify  | 09/22/2023 05:00:01 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  4
immich_notify  | <class 'OSError'>
immich_notify  | An error occurred while saving the file.

@pman07
Copy link
Owner

pman07 commented Sep 22, 2023

Hmm ok that didn't work like I thought it would. Updated again, please try again when you get a chance.

@feerlessleadr
Copy link
Author

thanks - just updated and got the following:

immich_notify  | 09/22/2023 15:00:01 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  4
immich_notify  | [Errno 2] No such file or directory: '/home/kevin/docker-apps/immich-notify/data/data.txt'
immich_notify  | An error occurred while saving the file.

I then created the 'data.txt' file in the folder just in case the script doesn't create that file automatically:

kevin@ubuntu-server:~/docker-apps/immich-notify/data$ nano data.txt
kevin@ubuntu-server:~/docker-apps/immich-notify/data$ ls
data.txt
kevin@ubuntu-server:~/docker-apps/immich-notify/data$ readlink -f data.txt
/home/kevin/docker-apps/immich-notify/data/data.txt

I think made sure it is world writable:

kevin@ubuntu-server:~/docker-apps/immich-notify/data$ chmod 777 /home/kevin/docker-apps/immich-notify/data/data.txt
kevin@ubuntu-server:~/docker-apps/immich-notify/data$ ls -la
total 12
drwxrwxrwx 2 root  root  4096 Sep 22 10:32 .
drwxrwxr-x 3 kevin kevin 4096 Sep 22 09:20 ..
-rwxrwxrwx 1 kevin kevin   13 Sep 22 10:32 data.txt

However I'm still getting the same error that there is no such file or directory:

immich_notify  | 09/22/2023 15:15:01 - Immich Notification Check Triggered
immich_notify  | Album Name: Test
immich_notify  | Total Items Now:  4
immich_notify  | [Errno 2] No such file or directory: '/home/kevin/docker-apps/immich-notify/data/data.txt'
immich_notify  | An error occurred while saving the file.

@pman07
Copy link
Owner

pman07 commented Sep 23, 2023

Could you try using the following as your docker-compose file? I think either the volume mapping order needs swapped or the FILEPATH variable needs to be /data/data.txt for your current setup, but the below should work either way.

version: "3.8"

services:
  immich_notify:
    image: pierson07/immich_notify:latest
    container_name: immich_notify
    env_file:
      - stack.env
    volumes:
      - /home/kevin/docker-apps/immich-notify/data:/home/kevin/docker-apps/immich-notify/data # optional, use to retain data through redeployment
#      - ${PWD}/data/main.py:/main.py # to persist the main.py file to add authentication
    restart: unless-stopped

@feerlessleadr
Copy link
Author

I'm extremely happy to say that it's finally working for me. Thank you for your help and patience getting this to work, it's awesome that it opens up the website too when you click on the notification!

@pman07
Copy link
Owner

pman07 commented Sep 23, 2023

Phew! Man I'm glad it's working. Thanks for your patience, obviously you're the first one to use it other than myself lol. Sorry for how long it took to get here. Hopefully made it more usable for anyone else now! Please let me know if you have any other issues or requests!

Enjoy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants