diff --git a/tools/get_version.bat b/tools/get_version.bat
new file mode 100644
index 0000000..3d2737d
--- /dev/null
+++ b/tools/get_version.bat
@@ -0,0 +1,4 @@
+@echo off
+(
+git log -1 --pretty="format:{\"commit\": \"%%H\", \"commit_short\": \"%%h\", \"version\": \"%%ad\", \"url\": \"https://github.com/bui/taiko-web/\"}" --date="format:%%y.%%m.%%d"
+) > ../version.json
diff --git a/tools/get_version.sh b/tools/get_version.sh
new file mode 100644
index 0000000..8d46c64
--- /dev/null
+++ b/tools/get_version.sh
@@ -0,0 +1 @@
+git log -1 --pretty="format:{\"commit\": \"%H\", \"commit_short\": \"%h\", \"version\": \"%ad\", \"url\": \"https://github.com/bui/taiko-web/\"}" --date="format:%y.%m.%d" > ../version.json
diff --git a/tools/merge_image.htm b/tools/merge_image.htm
new file mode 100644
index 0000000..fd4726f
--- /dev/null
+++ b/tools/merge_image.htm
@@ -0,0 +1,196 @@
+
+
+Merge Image
+
+
+
+
+
+
+
+
+Drag and drop your images here...
+
+
+
+
diff --git a/tools/set_previews.py b/tools/set_previews.py
new file mode 100644
index 0000000..835884e
--- /dev/null
+++ b/tools/set_previews.py
@@ -0,0 +1,86 @@
+from __future__ import division
+import os
+import sqlite3
+import re
+DATABASE = 'taiko.db'
+
+conn = sqlite3.connect(DATABASE)
+curs = conn.cursor()
+
+def parse_osu(osu):
+ osu_lines = open(osu, 'r').read().replace('\x00', '').split('\n')
+ sections = {}
+ current_section = (None, [])
+
+ for line in osu_lines:
+ line = line.strip()
+ secm = re.match('^\[(\w+)\]$', line)
+ if secm:
+ if current_section:
+ sections[current_section[0]] = current_section[1]
+ current_section = (secm.group(1), [])
+ else:
+ if current_section:
+ current_section[1].append(line)
+ else:
+ current_section = ('Default', [line])
+
+ if current_section:
+ sections[current_section[0]] = current_section[1]
+
+ return sections
+
+
+def get_osu_key(osu, section, key, default=None):
+ sec = osu[section]
+ for line in sec:
+ ok = line.split(':', 1)[0].strip()
+ ov = line.split(':', 1)[1].strip()
+
+ if ok.lower() == key.lower():
+ return ov
+
+ return default
+
+
+def get_preview(song_id, song_type):
+ preview = 0
+
+ if song_type == "tja":
+ if os.path.isfile('public/songs/%s/main.tja' % song_id):
+ preview = get_tja_preview('public/songs/%s/main.tja' % song_id)
+ else:
+ osus = [osu for osu in os.listdir('public/songs/%s' % song_id) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
+ if osus:
+ osud = parse_osu('public/songs/%s/%s' % (song_id, osus[0]))
+ preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
+
+ return preview
+
+
+def get_tja_preview(tja):
+ tja_lines = open(tja, 'r').read().replace('\x00', '').split('\n')
+
+ for line in tja_lines:
+ line = line.strip()
+ if ':' in line:
+ name, value = line.split(':', 1)
+ if name.lower() == 'demostart':
+ value = value.strip()
+ try:
+ value = float(value)
+ except ValueError:
+ pass
+ else:
+ return int(value * 1000)
+ elif line.lower() == '#start':
+ break
+ return 0
+
+
+if __name__ == '__main__':
+ songs = curs.execute('select id, type from songs').fetchall()
+ for song in songs:
+ preview = get_preview(song[0], song[1]) / 1000
+ curs.execute('update songs set preview = ? where id = ?', (preview, song[0]))
+ conn.commit()
diff --git a/tools/taikodb_hash.py b/tools/taikodb_hash.py
new file mode 100644
index 0000000..7c6955f
--- /dev/null
+++ b/tools/taikodb_hash.py
@@ -0,0 +1,49 @@
+import os
+import sys
+import hashlib
+import base64
+import sqlite3
+
+def md5(md5hash, filename):
+ with open(filename, "rb") as file:
+ for chunk in iter(lambda: file.read(64 * 1024), b""):
+ md5hash.update(chunk)
+
+def get_hashes(root):
+ hashes = {}
+ diffs = ["easy", "normal", "hard", "oni", "ura"]
+ dirs = os.listdir(root)
+ for dir in dirs:
+ dir_path = os.path.join(root, dir)
+ if dir.isdigit() and os.path.isdir(dir_path):
+ files = os.listdir(dir_path)
+ md5hash = hashlib.md5()
+ if "main.tja" in files:
+ md5(md5hash, os.path.join(dir_path, "main.tja"))
+ else:
+ for diff in diffs:
+ if diff + ".osu" in files:
+ md5(md5hash, os.path.join(dir_path, diff + ".osu"))
+ hashes[dir] = base64.b64encode(md5hash.digest())[:-2]
+ return hashes
+
+def write_db(database, songs):
+ db = sqlite3.connect(database)
+ hashes = get_hashes(songs)
+ added = 0
+ for id in hashes:
+ added += 1
+ cur = db.cursor()
+ cur.execute("update songs set hash = ? where id = ?", (hashes[id].decode(), int(id)))
+ cur.close()
+ db.commit()
+ db.close()
+ if added:
+ print("{0} hashes have been added to the database.".format(added))
+ else:
+ print("Error: No songs were found in the given directory.")
+
+if len(sys.argv) >= 3:
+ write_db(sys.argv[1], sys.argv[2])
+else:
+ print("Usage: taikodb_hash.py ../taiko.db ../public/songs")