diff --git a/README.md b/README.md index 7a4bdaf..b4f910a 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ or jump down to [example workflows](#example-workflows) for more examples. # Recent Changes +## New in 1.9 + +- [Custom audio](#audiofile) + ## New in 1.8 - Fix for mask image filter when using more than one in a workflow @@ -115,6 +119,16 @@ Set the FPS for playback in the global settings. This is a new, experimental feature, so please report any issues... +### audiofile + +The sound to play when the node is triggered. Can be one of the built-in options, +[`beep.mp3`](js/audio/beep.mp3), [`ding.mp3`](js/audio/ding.mp3), or [`honk.mp3`](js/audio/honk.mp3), +or the path to a local audiofile, or a URL of an audiofile. + +You can add files to `js/audio` and then just use their names. + +If a file can't be loaded, it will fallback to `ding.mp3` + --- # Mask Image Filter diff --git a/image_filter_nodes.py b/image_filter_nodes.py index 5df88e1..45d0047 100644 --- a/image_filter_nodes.py +++ b/image_filter_nodes.py @@ -73,6 +73,7 @@ class ImageFilter(io.ComfyNode, FilterNodeBase): io.Int.Input("pick_list_start", advanced=True, optional=True, default=0, tooltip="The index of the first image (normally 0 or 1)"), io.String.Input("pick_list", advanced=True, optional=True, default="", tooltip="If a comma separated list of integers is provided, the images with these indices will be selected automatically."), io.Int.Input("video_frames", advanced=True, optional=True, default=1, tooltip="Treat each block of n images as a video"), + io.String.Input("audiofile", advanced=True, optional=True, default="", tooltip="Path or URL for the audiofile to use, or name of the file in the default audio folder"), io.String.Input("graph_id", default="") ], outputs = [ @@ -107,6 +108,7 @@ class ImageFilter(io.ComfyNode, FilterNodeBase): graph_id:str="", tip:str="", extra1:str="", extra2:str="", extra3:str="", pick_list_start:int=0, pick_list:str="", video_frames:int=1, + audiofile:str|None="", **kwargs ) -> io.NodeOutput: assert images is not None, "Image Filter received None for images" @@ -124,7 +126,14 @@ class ImageFilter(io.ComfyNode, FilterNodeBase): if len(images_to_return) == 0: all_the_same = ( B and all( (images[i]==images[0]).all() for i in range(1,B) )) urls:list[dict[str,str]] = cls.save_images_return_urls(images=images, **kwargs) - payload = { "urls":urls, "allsame":all_the_same, "extras":[extra1, extra2, extra3], "tip":tip, "video_frames":video_frames } + payload = { + "urls":urls, + "allsame":all_the_same, + "extras":[extra1, extra2, extra3], + "tip":tip, + "video_frames":video_frames, + "audiopath": audiofile + } response:Response = send_and_wait(payload, timeout, graph_id) images_to_return:list[int] diff --git a/js/audio/beep.mp3 b/js/audio/beep.mp3 new file mode 100644 index 0000000..5f5c40e Binary files /dev/null and b/js/audio/beep.mp3 differ diff --git a/js/ding.mp3 b/js/audio/ding.mp3 similarity index 100% rename from js/ding.mp3 rename to js/audio/ding.mp3 diff --git a/js/audio/honk.mp3 b/js/audio/honk.mp3 new file mode 100644 index 0000000..3e808df Binary files /dev/null and b/js/audio/honk.mp3 differ diff --git a/js/popup.js b/js/popup.js index da88dc3..c1b4b90 100644 --- a/js/popup.js +++ b/js/popup.js @@ -29,11 +29,13 @@ const State = Object.freeze({ ZOOMED : 5, }) +const default_audio_folder = 'extensions/cg-image-filter/audio/' +const default_audio_file = 'ding.mp3'; + class Popup extends HTMLElement { constructor() { super() - this.audio = new Audio('extensions/cg-image-filter/ding.mp3'); - + this.classList.add('cg_popup') this.grid = create('span', 'grid', this) @@ -225,7 +227,26 @@ class Popup extends HTMLElement { this.render() } - maybe_play_sound() { if (app.ui.settings.getSettingValue("Image Filter.UI.Play Sound")) this.audio.play(); } + async maybe_play_sound() { + if (app.ui.settings.getSettingValue("Image Filter.UI.Play Sound")) { + if (this.audiopath) { + if (await this.play_sound(this.audiopath) || + await this.play_sound(default_audio_folder + this.audiopath)) return + } + this.play_sound(default_audio_folder + default_audio_file) + } + } + + async play_sound(path) { + if (!path) return false + try { + const audio = new Audio(path); + await audio.play() + return true + } catch (e) { + return false + } + } handle_message(message) { Log.message_in(message) @@ -284,6 +305,8 @@ class Popup extends HTMLElement { const the_node = this.find_node(uid) const graph_id = message.detail.graph_id + if (detail.audiopath) this.audiopath = detail.audiopath + if (graph_id != app.graph.id) { this._flash_tab(message.detail.graph_id) Log.detail(`Message for different tab`)