implemented image cache, fixes #1
This commit is contained in:
parent
9cc6180845
commit
2ac21a4ca3
@ -23,11 +23,21 @@ signal cmd_invalid_argcount(cmd_name, sender_data, cmd_data, arg_ary)
|
||||
signal cmd_no_permission(cmd_name, sender_data, cmd_data, arg_ary)
|
||||
# Twitch's ping is about to be answered with a pong.
|
||||
signal pong
|
||||
# Emote has been downloaded
|
||||
signal emote_downloaded(emote_id)
|
||||
# Badge has been downloaded
|
||||
signal badge_downloaded(badge_name)
|
||||
|
||||
# Messages starting with one of these symbols are handled. '/' will be ignored, reserved by Twitch.
|
||||
export(PoolStringArray) var command_prefixes : Array = ["!"]
|
||||
# Time to wait after each sent chat message. Values below ~0.31 will lead to a disconnect after 100 messages.
|
||||
export(Array, String) var command_prefixes : Array = ["!"]
|
||||
# Time to wait after each sent chat message. Values below ~0.31 might lead to a disconnect after 100 messages.
|
||||
export(float) var chat_timeout = 0.32
|
||||
export(bool) var get_images : bool = false
|
||||
# If true, caches emotes/badges to disk, so that they don't have to be redownloaded on every restart.
|
||||
# This however means that they might not be updated if they change until you clear the cache.
|
||||
export(bool) var disk_cache : bool = false
|
||||
# Disk Cache has to be enbaled for this to work
|
||||
export(String, FILE) var disk_cache_path = "user://gift/cache"
|
||||
|
||||
var websocket : WebSocketClient = WebSocketClient.new()
|
||||
var user_regex = RegEx.new()
|
||||
@ -38,6 +48,7 @@ onready var chat_accu = chat_timeout
|
||||
# Mapping of channels to their channel info, like available badges.
|
||||
var channels : Dictionary = {}
|
||||
var commands : Dictionary = {}
|
||||
var image_cache : ImageCache
|
||||
|
||||
# Required permission to execute the command
|
||||
enum PermissionFlag {
|
||||
@ -68,6 +79,9 @@ func _ready() -> void:
|
||||
websocket.connect("connection_closed", self, "connection_closed")
|
||||
websocket.connect("server_close_request", self, "sever_close_request")
|
||||
websocket.connect("connection_error", self, "connection_error")
|
||||
if(get_images):
|
||||
image_cache = ImageCache.new(disk_cache, disk_cache_path)
|
||||
add_child(image_cache)
|
||||
|
||||
func connect_to_twitch() -> void:
|
||||
if(websocket.connect_to_url("wss://irc-ws.chat.twitch.tv:443") != OK):
|
||||
@ -180,7 +194,13 @@ func handle_message(message : String, tags : Dictionary) -> void:
|
||||
var sender_data : SenderData = SenderData.new(user_regex.search(msg[0]).get_string(), msg[2], tags)
|
||||
handle_command(sender_data, msg)
|
||||
emit_signal("chat_message", sender_data, msg[3].right(1))
|
||||
print("TAGS: " + str(tags))
|
||||
if(get_images):
|
||||
if(!image_cache.badge_map.has(tags["room-id"])):
|
||||
image_cache.get_badge_mappings(tags["room-id"])
|
||||
for emote in tags["emotes"].split("/", false):
|
||||
image_cache.get_emote(emote.split(":")[0])
|
||||
for badge in tags["badges"].split(",", false):
|
||||
image_cache.get_badge(badge, tags["room-id"])
|
||||
"WHISPER":
|
||||
var sender_data : SenderData = SenderData.new(user_regex.search(msg[0]).get_string(), msg[2], tags)
|
||||
handle_command(sender_data, msg, true)
|
||||
@ -195,6 +215,10 @@ func handle_command(sender_data : SenderData, msg : PoolStringArray, whisper : b
|
||||
var command : String = msg[3].right(2)
|
||||
var cmd_data : CommandData = commands.get(command)
|
||||
if(cmd_data):
|
||||
if(whisper == true && cmd_data.where & WhereFlag.WHISPER != WhereFlag.WHISPER):
|
||||
return
|
||||
elif(whisper == false && cmd_data.where & WhereFlag.CHAT != WhereFlag.CHAT):
|
||||
return
|
||||
var args = "" if msg.size() < 5 else msg[4]
|
||||
var arg_ary : PoolStringArray = PoolStringArray() if args == "" else args.split(" ")
|
||||
if(arg_ary.size() > cmd_data.max_args && cmd_data.max_args != -1 || arg_ary.size() < cmd_data.min_args):
|
||||
@ -264,9 +288,3 @@ func connection_error() -> void:
|
||||
|
||||
func server_close_request(code : int, reason : String) -> void:
|
||||
pass
|
||||
|
||||
func _enter_tree() -> void:
|
||||
pass
|
||||
|
||||
func _exit_tree() -> void:
|
||||
pass
|
@ -3,5 +3,5 @@
|
||||
name="Godot IRC For Twitch"
|
||||
description="Godot websocket implementation for Twitch IRC."
|
||||
author="MennoMax"
|
||||
version="0.1.0"
|
||||
version="0.1.1"
|
||||
script="gift.gd"
|
||||
|
111
addons/gift/util/image_cache.gd
Normal file
111
addons/gift/util/image_cache.gd
Normal file
@ -0,0 +1,111 @@
|
||||
extends Node
|
||||
class_name ImageCache
|
||||
|
||||
signal badge_mapping_available
|
||||
|
||||
var cached_images : Dictionary = {"emotes": {}, "badges": {}}
|
||||
var cache_mutex = Mutex.new()
|
||||
var badge_map : Dictionary = {}
|
||||
var badge_mutex = Mutex.new()
|
||||
var dl_queue : PoolStringArray = []
|
||||
var disk_cache : bool
|
||||
var disk_cache_path : String
|
||||
|
||||
var file : File = File.new()
|
||||
var dir : Directory = Directory.new()
|
||||
|
||||
func _init(do_disk_cache : bool, cache_path : String) -> void:
|
||||
disk_cache = do_disk_cache
|
||||
disk_cache_path = cache_path
|
||||
|
||||
func _ready() -> void:
|
||||
if(disk_cache):
|
||||
for cache_dir in cached_images.keys():
|
||||
cached_images[cache_dir] = {}
|
||||
dir.make_dir_recursive(disk_cache_path + "/" + cache_dir)
|
||||
dir.open(disk_cache_path + "/" + cache_dir)
|
||||
dir.list_dir_begin(true)
|
||||
var current = dir.get_next()
|
||||
while current != "":
|
||||
if(!dir.current_is_dir()):
|
||||
file.open(dir.get_current_dir() + "/" + current, File.READ)
|
||||
var img : Image = Image.new()
|
||||
img.load_png_from_buffer(file.get_buffer(file.get_len()))
|
||||
file.close()
|
||||
var img_texture : ImageTexture = ImageTexture.new()
|
||||
img_texture.create_from_image(img, 0)
|
||||
cache_mutex.lock()
|
||||
cached_images[cache_dir][current.get_basename()] = img_texture
|
||||
cache_mutex.unlock()
|
||||
current = dir.get_next()
|
||||
dir.open(disk_cache_path)
|
||||
dir.list_dir_begin(true)
|
||||
var current = dir.get_next()
|
||||
while current != "":
|
||||
if(!dir.current_is_dir()):
|
||||
file.open(disk_cache_path + "/" + current, File.READ)
|
||||
badge_map[current.get_basename()] = parse_json(file.get_as_text())["badge_sets"]
|
||||
file.close()
|
||||
current = dir.get_next()
|
||||
get_badge_mappings()
|
||||
yield(self, "badge_mapping_available")
|
||||
|
||||
func create_request(url : String, resource : String, res_type : String) -> void:
|
||||
var http_request = HTTPRequest.new()
|
||||
http_request.connect("request_completed", self, "downloaded", [http_request, resource, res_type], CONNECT_ONESHOT)
|
||||
add_child(http_request)
|
||||
http_request.download_file = disk_cache_path + "/" + res_type + "/" + resource + ".png"
|
||||
http_request.request(url, [], false, HTTPClient.METHOD_GET)
|
||||
|
||||
# Gets badge mappings for the specified channel. Empty String will get the mappings for global badges instead.
|
||||
func get_badge_mappings(channel_id : String = "") -> void:
|
||||
var url : String
|
||||
if(channel_id == ""):
|
||||
channel_id = "_global"
|
||||
url = "https://badges.twitch.tv/v1/badges/global/display"
|
||||
else:
|
||||
url = "https://badges.twitch.tv/v1/badges/channels/" + channel_id + "/display"
|
||||
if(!badge_map.has(channel_id)):
|
||||
var http_request = HTTPRequest.new()
|
||||
add_child(http_request)
|
||||
http_request.request(url, [], false, HTTPClient.METHOD_GET)
|
||||
http_request.connect("request_completed", self, "badge_mapping_received", [http_request, channel_id], CONNECT_ONESHOT)
|
||||
else:
|
||||
emit_signal("badge_mapping_available")
|
||||
|
||||
func get_emote(id : String) -> ImageTexture:
|
||||
cache_mutex.lock()
|
||||
if(cached_images["emotes"].has(id)):
|
||||
return cached_images["emotes"][id]
|
||||
else:
|
||||
create_request("http://static-cdn.jtvnw.net/emoticons/v1/" + id + "/1.0", id, "emotes")
|
||||
cache_mutex.unlock()
|
||||
return null
|
||||
|
||||
func get_badge(badge_name : String, channel_id : String = "") -> ImageTexture:
|
||||
cache_mutex.lock()
|
||||
var badge_data : PoolStringArray = badge_name.split("/")
|
||||
if(cached_images["badges"].has(badge_data[0])):
|
||||
return cached_images["badges"][badge_data[0]]
|
||||
var channel : String
|
||||
if(!badge_map[channel_id].has(badge_data[0])):
|
||||
channel_id = "_global"
|
||||
create_request(badge_map[channel_id][badge_data[0]]["versions"][badge_data[1]]["image_url_1x"], badge_data[0], "badges")
|
||||
cache_mutex.unlock()
|
||||
return null
|
||||
|
||||
func downloaded(result : int, response_code : int, headers : PoolStringArray, body : PoolByteArray, request : HTTPRequest, id : String, type : String) -> void:
|
||||
if(type == "emotes"):
|
||||
get_parent().emit_signal("emote_downloaded", id)
|
||||
elif(type == "badges"):
|
||||
get_parent().emit_signal("badge_downloaded", id)
|
||||
request.queue_free()
|
||||
|
||||
func badge_mapping_received(result : int, response_copde : int, headers : PoolStringArray, body : PoolByteArray, request : HTTPRequest, id : String) -> void:
|
||||
badge_map[id] = parse_json(body.get_string_from_utf8())["badge_sets"]
|
||||
if(disk_cache):
|
||||
file.open(disk_cache_path + "/" + id + ".json", File.WRITE)
|
||||
file.store_buffer(body)
|
||||
file.close()
|
||||
emit_signal("badge_mapping_available")
|
||||
request.queue_free()
|
Loading…
x
Reference in New Issue
Block a user