diff --git a/miku/plugins/tumblr.lua b/miku/plugins/tumblr.lua
new file mode 100644
index 0000000..8eb6d21
--- /dev/null
+++ b/miku/plugins/tumblr.lua
@@ -0,0 +1,119 @@
+local tumblr = {}
+
+tumblr.triggers = {
+ "^https?://(.*).tumblr.com/post/(%d+)",
+ "^https?://(.*).tumblr.com/image/(%d+)",
+ "^https?://(.*).tumblr.com/?$"
+}
+
+local api_key = cred_data.tumblr_api_key
+
+local makeOurDate = function(dateString)
+ local pattern = "(%d+)%-(%d+)%-(%d+)"
+ local year, month, day = dateString:match(pattern)
+ if month == "00" then
+ return year
+ elseif day == "00" then
+ return month..'.'..year
+ else
+ return day..'.'..month..'.'..year
+ end
+end
+
+function tumblr:get_tumblr_text(data)
+ local title = data.posts[1].title
+ local post = unescape(data.posts[1].body)
+ return title, post
+end
+
+function tumblr:get_tumblr_photo(data)
+ local caption = data.posts[1].summary
+ local image_url = data.posts[1].photos[1].original_size.url
+ return caption, image_url
+end
+
+function tumblr:get_tumblr_video(data)
+ local caption = data.posts[1].caption
+ local video_url = data.posts[1].permalink_url
+ return caption, video_url
+end
+
+function tumblr:get_tumblr_info(blog, post, msg)
+ local url = 'https://api.tumblr.com/v2/blog/'..blog..'.tumblr.com/posts?id='..post..'&api_key='..api_key..'&filter=text'
+ local res, code = https.request(url)
+ if code ~= 200 then return "HTTP-Fehler" end
+ local data = json.decode(res).response
+ if not data.posts then return nil end
+
+ -- General blog info, present on every type
+ local blog_name = data.blog.title
+ local created_at = makeOurDate(data.posts[1].date)
+ local short_url = data.posts[1].short_url
+ local typ = data.posts[1].type
+ local text = ''..blog_name..' am '..created_at..':\n'
+
+ -- type-specific
+ if typ == 'text' then
+ local title, post = tumblr:get_tumblr_text(data)
+ text = text..''..title..'\n'..post..'\n'..short_url
+ elseif typ == 'photo' then
+ local caption, image_url = tumblr:get_tumblr_photo(data)
+ text = text..caption..'\n'..short_url
+ local file = download_to_file(image_url)
+ utilities.send_typing(msg.chat.id, 'upload_photo')
+ if string.ends(image_url, '.gif') then
+ utilities.send_document(msg.chat.id, file, nil, msg.message_id)
+ else
+ utilities.send_photo(msg.chat.id, file, nil, msg.message_id)
+ end
+ elseif typ == 'video' then
+ local caption, video_url = tumblr:get_tumblr_video(data)
+ text = text..caption..'\n'..video_url..'\n'..short_url
+ else
+ text = text..'Konnte Format nicht bestimmen (ist: '..typ..')'
+ end
+ return text
+end
+
+function tumblr:get_blog(blog)
+ local url = 'https://api.tumblr.com/v2/blog/'..blog..'.tumblr.com/info?api_key='..api_key
+ local res, code = https.request(url)
+ if code ~= 200 then return "HTTP-Fehler" end
+ local data = json.decode(res).response.blog
+ if not data then return nil end
+
+ local title = data.title
+ if data.description == "" then
+ description = ''
+ else
+ description = '\n'..data.description
+ end
+
+ if data.posts == 1 then
+ posts = data.posts..' Post'
+ else
+ posts = data.posts..' Posts'
+ end
+
+ if data.likes then
+ likes = ', '..data.likes..' Likes'
+ else
+ likes = ''
+ end
+
+ local text = ''..title..''..''..description..'\n'..posts..likes..'\n'
+ return text
+end
+
+function tumblr:action(msg, config, matches)
+ local blog = matches[1]
+ local post = matches[2]
+ if not post then
+ text = tumblr:get_blog(blog)
+ else
+ text = tumblr:get_tumblr_info(blog, post, msg)
+ end
+ utilities.send_reply(msg, text, 'HTML')
+end
+
+return tumblr
\ No newline at end of file