简体   繁体   中英

Python - add multiple files to folder but run event only once

I'm trying to make a watchdog to listen to a folder changes (adding/deleting) files.

My problem is, that every time I copy-create/delete several files from this folder (and its subfolders), the event chain starts one by one for each and every file.

How can I make the on_event() method to be invoked only once, after multiple files creation/deletion?

Let's say I'm copying to this folders two images.

I want the event handler to be invoked only once after file transfer finishes, and not twice - once for each image - as it currently works.

Thanks!

The code runs on a raspberry pi 3 with python 3.7.

Here's the code:

    import os
    import time
    import psutil
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
    
    i = 0
    
    
def show_stats():
    global i
    read = "read #" + str(i) + ":"
    mem = "\nmemory in use: " + str(psutil.virtual_memory().percent)+"%"
    cpu = "\ncpu load: " + str(psutil.cpu_percent())+"%"
    temp = "\ncurrent " + \
        os.popen("vcgencmd measure_temp").readline().replace(
            "=", ": ").replace("'C", " C°")
    end = "\n=================="
    i += 1
    stats = read + mem + cpu + temp + end
    return stats
    
    
    class Watcher:
        DIRECTORY_TO_WATCH = r'/home/pi/Desktop/jsSlider/images'
    
        def __init__(self):
            self.observer = Observer()
            print("watching ", self.DIRECTORY_TO_WATCH, "...")
    
        def run(self):
            event_handler = Handler()
            self.observer.schedule(
                event_handler, self.DIRECTORY_TO_WATCH, recursive=True)
            self.observer.start()
            try:
                while True:
                    time.sleep(5)
                    print(show_stats())
            except Exception as e:
                self.observer.stop()
                print(e)
            self.observer.join()
    
    
    class Handler(FileSystemEventHandler):
        @staticmethod
        def on_event(event):
            wait = 1
            elif event.event_type == 'created' or event.event_type == 'deleted':
                print("Received event - %s. " %event.src_path, str(event.event_type))
                time.sleep(wait) #i found that its best to give some timeout between commands because it overwhelmed the pi for some reason (one second seems to be enough)...
                os.system('python /home/pi/Desktop/Slider/scripts/arr_edit.py') #recreate the JS array
                time.sleep(wait)
                os.system('cp -r /home/pi/Desktop/jsSlider/scripts/imgArr.js /home/pi/Desktop/jsSlider/themes/1') #copy the newly created JS array to its place
                time.sleep(wait)
                os.system('sudo pkill chromium') #"refresh" the page -the kiosk mode reactivates the process...
                # os.system('cls')
                print('done!')
    
    
    if __name__ == '__main__':
        w = Watcher()
        w.run()

Edit I

There is a poor rpi3 connected to a tv in some clinic, working in kiosk mode to display images from a local html file (with some js code - the slide show run with an existing JS script - i can upload everything if requested | the images are also on the pi itself).

What I'm trying to achieve is to automatically:

  1. rebulid the JS array (with a working python script - code below (arr_edit.py)).
  2. copy the new array to its desired location. (shell command)
  3. and restart chromium with "pkill chromium". (shell command)

Now, I cannot allow that every time someone copies/deletes multiple images, the commands will run each time - which means:

whenever 2+ images are being added, i cannot "restart" the kiosk (sudo pkill chromium) each and every time a file is created.

Every time you copy multiple files (images in that case), for each individual image that was created in the folder, an entirely individual event.created is invoked, therefore for 5 images, there will be 5 different event.created events that will fire the on_event() method each on its own turn, making the kiosk restart 5 times in a row. (now think of what will happen if a 50 files transfer occurs - the pi will just crash)

Therefore, I need a method to invoke the command only 1 time after file transfer finishes, regardless of how many files has changed/created/deleted in the folder.

arr_edit.py (not entirely my code):

import os
dir_path = r'/home/pi/Desktop/jsSlider/images'
file_path = r'/home/pi/Desktop/jsSlider/scripts/imgArr.js'

directory = os.fsencode(dir_path)
arr_name = 'images=[\n'
start_str = '{"img":"./images/'
end_str = '"},\n'
images = ''


def writer(array, imagesList):
    str_to_write = array + imagesList + ']'
    f = open(file_path, 'w')
    f.write(str_to_write)
    f.close


file_list = os.listdir(directory)
for file in file_list:
    filename = os.fsdecode(file)
    if filename.endswith(".jpg") or filename.endswith(".jpeg") or filename.endswith(".webp") or filename.endswith(".webp"):
        if file == file_list[len(file_list)-1]:
            end_str = '"}\n'
        images += start_str + filename + end_str
        continue
    else:
        continue

writer(arr_name, images)

output JS array (sample from inside imgArr.js):

images=[
{"img":"./images/246.jpg"},
{"img":"./images/128.jpg"},
{"img":"./images/238.webp"},
{"img":"./images/198.jpg"},
{"img":"./images/247.webp"}
]

As Mark suggested in the comments,
i added a check to see if the js file has changed in the past 5 minutes.
if the file changed,
wait for another 5 minutes and re-initiate the cange (if more files have been added to the folder) so the new, larger files will also be shown in this run.
Works like a charm!
many thanks!!
here's the final watchdog.py

import os
import time
import psutil
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

i = 0


def show_stats():
    global i
    read = "read #" + str(i) + ":"
    mem = "\nmemory in use: " + str(psutil.virtual_memory().percent)+"%"
    cpu = "\ncpu load: " + str(psutil.cpu_percent())+"%"
    temp = "\ncurrent " + \
        os.popen("vcgencmd measure_temp").readline().replace(
            "=", ": ").replace("'C", " C°")
    end = "\n=================="
    i += 1
    stats = read + mem + cpu + temp + end
    return stats


def wait_for_file(file):
    time.sleep(300)
    if age(file) >= 5:
        modify()


def modify():
    os.system('python /home/pi/Desktop/jsSlider/scripts/arr_edit.py')
    os.system(
        'cp -r /home/pi/Desktop/jsSlider/scripts/imgArr.js /home/pi/Desktop/jsSlider/themes/1')
    time.sleep(1)
    os.system('sudo pkill chromium')
    # os.system('cls')
    print("done!\nwatching...")


def age(filename):
    return ((time.time() - os.path.getmtime(filename))//60)


class Watcher:
    DIRECTORY_TO_WATCH = r'/home/pi/Desktop/jsSlider/images'

    def __init__(self):
        self.observer = Observer()
        print("watching ", self.DIRECTORY_TO_WATCH, "...")

    def run(self):
        event_handler = Handler()
        self.observer.schedule(
            event_handler, self.DIRECTORY_TO_WATCH, recursive=True)
        self.observer.start()
        try:
            while True:
                time.sleep(5)
                print(show_stats())
        except Exception as e:
            self.observer.stop()
            print(e)
        self.observer.join()


class Handler(FileSystemEventHandler):
    @ staticmethod
    def on_any_event(event):
        file = r'/home/pi/Desktop/jsSlider/scripts/imgArr.js'
        if event.event_type == 'created' or event.event_type == 'deleted':
            print("Received event - %s. " %
                  event.src_path, str(event.event_type))
            time.sleep(5)
            if age(file) < 5:
                wait_for_file(file)
            else:
                modify()


if __name__ == '__main__':
    w = Watcher()
    w.run() 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM