1- """
2- Simplest example.
3- """
1+ """Simplest example of files_dropdown_menu + notification."""
42
5- from os import path , environ
3+ import tempfile
4+ from os import environ , path
65from typing import Annotated
76
8- import uvicorn
9- from fastapi import FastAPI , Depends
10- from requests import Response
11- import urllib3
12-
13- import tempfile
14- from pygifsicle import optimize
15- import imageio
167import cv2
8+ import imageio
179import numpy
10+ import urllib3
11+ import uvicorn
12+ from fastapi import BackgroundTasks , Depends , FastAPI
13+ from pygifsicle import optimize
14+ from requests import Response
1815
19- from nc_py_api import UiFileActionHandlerInfo , LogLvl , NextcloudApp , nc_app , set_enabled_handler , ApiScope , set_scopes
16+ from nc_py_api import (
17+ ApiScope ,
18+ GuiActionFileInfo ,
19+ GuiFileActionHandlerInfo ,
20+ LogLvl ,
21+ NextcloudApp ,
22+ enable_heartbeat ,
23+ nc_app ,
24+ set_enabled_handler ,
25+ set_scopes ,
26+ )
2027
2128APP = FastAPI ()
2229
2330
24- @APP .post ("/video_to_gif" )
25- async def video_to_gif (
26- file : UiFileActionHandlerInfo ,
27- nc : Annotated [NextcloudApp , Depends (nc_app )],
28- ):
29- source_path = path .join (file .actionFile .dir , file .actionFile .name )
31+ def convert_video_to_gif (input_params : GuiActionFileInfo , nc : NextcloudApp ):
32+ source_path = path .join (input_params .directory , input_params .name )
3033 save_path = path .splitext (source_path )[0 ] + ".gif"
3134 nc .log (LogLvl .WARNING , f"Processing:{ source_path } -> { save_path } " )
32- source_file = nc .files .download (source_path )
33- nc .log (LogLvl .WARNING , "File downloaded" )
3435 try :
3536 with tempfile .NamedTemporaryFile (mode = "w+b" ) as tmp_in :
36- tmp_in .write (source_file )
37+ nc .files .download2stream (source_path , tmp_in )
38+ nc .log (LogLvl .WARNING , "File downloaded" )
3739 tmp_in .flush ()
3840 cap = cv2 .VideoCapture (tmp_in .name )
3941 with tempfile .NamedTemporaryFile (mode = "w+b" , suffix = ".gif" ) as tmp_out :
4042 image_lst = []
4143 previous_frame = None
44+ skip = 0
4245 while True :
46+ skip += 1
4347 ret , frame = cap .read ()
48+ if frame is None :
49+ break
50+ if skip == 2 :
51+ skip = 0
52+ continue
4453 if previous_frame is not None :
4554 diff = numpy .mean (previous_frame != frame )
4655 if diff < 0.91 :
4756 continue
48- if frame is None :
49- break
5057 frame_rgb = cv2 .cvtColor (frame , cv2 .COLOR_BGR2RGB )
5158 image_lst .append (frame_rgb )
5259 previous_frame = frame
60+ if len (image_lst ) > 60 :
61+ break
5362 cap .release ()
5463 imageio .mimsave (tmp_out .name , image_lst )
5564 optimize (tmp_out .name )
5665 nc .log (LogLvl .WARNING , "GIF is ready" )
57- nc .files .upload (save_path , content = tmp_out . read () )
66+ nc .files .upload_stream (save_path , tmp_out )
5867 nc .log (LogLvl .WARNING , "Result uploaded" )
68+ nc .users .notifications .create (f"{ input_params .name } finished!" , f"{ save_path } is waiting for you!" )
5969 except Exception as e :
6070 nc .log (LogLvl .ERROR , str (e ))
71+ nc .users .notifications .create ("Error occurred" , "Error information was written to log file" )
72+
73+
74+ @APP .post ("/video_to_gif" )
75+ async def video_to_gif (
76+ file : GuiFileActionHandlerInfo ,
77+ nc : Annotated [NextcloudApp , Depends (nc_app )],
78+ background_tasks : BackgroundTasks ,
79+ ):
80+ background_tasks .add_task (convert_video_to_gif , file .actionFile , nc )
6181 return Response ()
6282
6383
6484def enabled_handler (enabled : bool , nc : NextcloudApp ) -> str :
6585 print (f"enabled={ enabled } " )
6686 try :
6787 if enabled :
68- nc .ui_files_actions .register ("to_gif" , "TO GIF" , "/video_to_gif" , mime = "video" )
88+ nc .gui . files_dropdown_menu .register ("to_gif" , "TO GIF" , "/video_to_gif" , mime = "video" )
6989 else :
70- nc .ui_files_actions .unregister ("to_gif" )
90+ nc .gui . files_dropdown_menu .unregister ("to_gif" )
7191 except Exception as e :
7292 return str (e )
7393 return ""
@@ -76,25 +96,10 @@ def enabled_handler(enabled: bool, nc: NextcloudApp) -> str:
7696@APP .on_event ("startup" )
7797def initialization ():
7898 set_enabled_handler (APP , enabled_handler )
79- set_scopes (APP , {
80- "required" : [ApiScope .DAV ],
81- "optional" : [ApiScope .NOTIFICATIONS ]
82- })
99+ set_scopes (APP , {"required" : [ApiScope .DAV ], "optional" : [ApiScope .NOTIFICATIONS ]})
100+ enable_heartbeat (APP )
83101
84102
85103if __name__ == "__main__" :
86- # This should be set by packaging step
87- secret = "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E" \
88- "X1T8Pi+T5papEolTLxz3fJSPS8ffC4204YmggxPsbJdCkXHWNPHKWS9B+vTj2SIV"
89- if "app_name" not in environ :
90- environ ["app_name" ] = "nc_py_api"
91- if "app_version" not in environ :
92- environ ["app_version" ] = "1.0.0"
93- if "app_secret" not in environ :
94- environ ["app_secret" ] = secret
95- if "nextcloud_url" not in environ :
96- environ ["nextcloud_url" ] = "http://nextcloud.local/index.php"
97- # environ["app_name"] = "test_app"
98- # ---------
99104 urllib3 .disable_warnings ()
100- uvicorn .run ("main:APP" , host = "0 .0.0.0" , port = 9001 , log_level = "trace" , reload = True )
105+ uvicorn .run ("main:APP" , host = environ . get ( "APP_HOST" , "127 .0.0.1" ) , port = int ( environ [ "APP_PORT" ]) , log_level = "trace" )
0 commit comments