refactor: new database format

This commit is contained in:
Terry Geng 2020-03-21 00:10:30 +08:00
parent bfa64547e8
commit 575d363de3
3 changed files with 86 additions and 26 deletions

View File

@ -112,10 +112,10 @@ class Condition:
return self return self
SETTING_DB_VERSION = 1
MUSIC_DB_VERSION = 1
class SettingsDatabase: class SettingsDatabase:
version = 1
def __init__(self, db_path): def __init__(self, db_path):
self.db_path = db_path self.db_path = db_path
@ -127,10 +127,10 @@ class SettingsDatabase:
conn.commit() conn.commit()
conn.close() conn.close()
def has_table(self): def has_table(self, table):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
tables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='botamusique';").fetchall() tables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", (table,)).fetchall()
conn.close() conn.close()
if len(tables) == 0: if len(tables) == 0:
return False return False
@ -140,17 +140,16 @@ class SettingsDatabase:
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
if self.has_table(): if self.has_table('botamusique'):
# check version # check version
result = cursor.execute("SELECT value FROM botamusique WHERE section=? AND option=?", ver = self.getint("bot", "db_version", fallback=None)
("bot", "db_version")).fetchall()
if len(result) == 0 or int(result[0][0]) != self.version: if ver is None or ver != SETTING_DB_VERSION:
old_name = "botamusique_old_%s" % datetime.datetime.now().strftime("%Y%m%d") # old_name = "botamusique_old_%s" % datetime.datetime.now().strftime("%Y%m%d")
cursor.execute("ALTER TABLE botamusique RENAME TO %s" % old_name) # cursor.execute("ALTER TABLE botamusique RENAME TO %s" % old_name)
cursor.execute("DROP TABLE botamusique")
conn.commit() conn.commit()
self.create_table() self.create_table()
self.set("bot", "old_db_name", old_name)
else: else:
self.create_table() self.create_table()
@ -165,9 +164,7 @@ class SettingsDatabase:
"value TEXT, " "value TEXT, "
"UNIQUE(section, option))") "UNIQUE(section, option))")
cursor.execute("INSERT INTO botamusique (section, option, value) " cursor.execute("INSERT INTO botamusique (section, option, value) "
"VALUES (?, ?, ?)", ("bot", "db_version", "1")) "VALUES (?, ?, ?)", ("bot", "db_version", SETTING_DB_VERSION))
cursor.execute("INSERT INTO botamusique (section, option, value) "
"VALUES (?, ?, ?)", ("bot", "music_db_version", "0"))
conn.commit() conn.commit()
conn.close() conn.close()
@ -248,20 +245,61 @@ class MusicDatabase:
def __init__(self, db_path): def __init__(self, db_path):
self.db_path = db_path self.db_path = db_path
# connect self.db_version_check_and_create()
def has_table(self, table):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
tables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", (table,)).fetchall()
conn.close()
if len(tables) == 0:
return False
return True
def create_table(self):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
# check if table exists, or create one cursor.execute("CREATE TABLE music ("
cursor.execute("CREATE TABLE IF NOT EXISTS music ("
"id TEXT PRIMARY KEY, " "id TEXT PRIMARY KEY, "
"type TEXT, " "type TEXT, "
"title TEXT, " "title TEXT, "
"keywords TEXT, "
"metadata TEXT, " "metadata TEXT, "
"tags TEXT)") "tags TEXT, "
"path TEXT, "
"create_at DATETIME DEFAULT CURRENT_TIMESTAMP"
")")
cursor.execute("INSERT INTO music (id, title) "
"VALUES ('info', ?)", (MUSIC_DB_VERSION,))
conn.commit() conn.commit()
conn.close() conn.close()
def db_version_check_and_create(self):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
if self.has_table('music'):
ver = cursor.execute("SELECT title FROM music WHERE id='info'").fetchone()
if ver and int(ver[0]) == MUSIC_DB_VERSION:
conn.close()
return True
else:
cursor.execute("ALTER TABLE music RENAME TO music_old")
conn.commit()
self.create_table()
cursor.execute("INSERT INTO music (id, type, title, metadata, tags)"
"SELECT id, type, title, metadata, tags FROM music_old")
cursor.execute("DROP TABLE music_old")
conn.commit()
conn.close()
else:
self.create_table()
def insert_music(self, music_dict): def insert_music(self, music_dict):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
@ -269,19 +307,25 @@ class MusicDatabase:
id = music_dict['id'] id = music_dict['id']
title = music_dict['title'] title = music_dict['title']
type = music_dict['type'] type = music_dict['type']
path = music_dict['path']
keywords = music_dict['keywords']
tags = ",".join(music_dict['tags']) + "," tags = ",".join(music_dict['tags']) + ","
del music_dict['id'] del music_dict['id']
del music_dict['title'] del music_dict['title']
del music_dict['type'] del music_dict['type']
del music_dict['tags'] del music_dict['tags']
del music_dict['path']
del music_dict['keywords']
cursor.execute("INSERT OR REPLACE INTO music (id, type, title, metadata, tags) VALUES (?, ?, ?, ?, ?)", cursor.execute("INSERT OR REPLACE INTO music (id, type, title, metadata, tags, path, keywords) VALUES (?, ?, ?, ?, ?, ?, ?)",
(id, (id,
type, type,
title, title,
json.dumps(music_dict), json.dumps(music_dict),
tags)) tags,
path,
keywords))
conn.commit() conn.commit()
conn.close() conn.close()
@ -323,7 +367,7 @@ class MusicDatabase:
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
results = cursor.execute("SELECT id, type, title, metadata, tags FROM music " results = cursor.execute("SELECT id, type, title, metadata, tags, path, keywords FROM music "
"WHERE %s" % condition_str, filler).fetchall() "WHERE %s" % condition_str, filler).fetchall()
conn.close() conn.close()
@ -373,8 +417,8 @@ class MusicDatabase:
def query_random_music(self, count): def query_random_music(self, count):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
results = cursor.execute("SELECT id, type, title, metadata, tags FROM music " results = cursor.execute("SELECT id, type, title, metadata, tags, path, keywords FROM music "
"WHERE id IN (SELECT id FROM music ORDER BY RANDOM() LIMIT ?)", (count,)).fetchall() "WHERE id != 'info' AND id IN (SELECT id FROM music ORDER BY RANDOM() LIMIT ?)", (count,)).fetchall()
conn.close() conn.close()
return self._result_to_dict(results) return self._result_to_dict(results)
@ -388,6 +432,9 @@ class MusicDatabase:
music_dict['title'] = result[2] music_dict['title'] = result[2]
music_dict['id'] = result[0] music_dict['id'] = result[0]
music_dict['tags'] = result[4].strip(",").split(",") music_dict['tags'] = result[4].strip(",").split(",")
if result[5]:
music_dict['path'] = result[5]
music_dict['keywords'] = result[6]
if not music_dict['tags'][0]: if not music_dict['tags'][0]:
music_dict['tags'] = [] music_dict['tags'] = []

View File

@ -51,10 +51,9 @@ class FileItem(BaseItem):
if os.path.exists(self.uri()): if os.path.exists(self.uri()):
self._get_info_from_tag() self._get_info_from_tag()
self.ready = "yes" self.ready = "yes"
self.keywords = self.title + " " + self.artist
else: else:
super().__init__(bot, from_dict) super().__init__(bot, from_dict)
self.path = from_dict['path']
self.title = from_dict['title']
self.artist = from_dict['artist'] self.artist = from_dict['artist']
self.thumbnail = from_dict['thumbnail'] self.thumbnail = from_dict['thumbnail']
if not self.validate(): if not self.validate():
@ -75,6 +74,10 @@ class FileItem(BaseItem):
self.send_client_message(constants.strings('file_missed', file=self.path)) self.send_client_message(constants.strings('file_missed', file=self.path))
return False return False
if not self.keywords:
self.keywords = self.title + " " + self.artist # migrate from previous version
self.version += 1
# self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time # self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time
self.ready = "yes" self.ready = "yes"
return True return True

View File

@ -43,6 +43,7 @@ class BaseItem:
self.title = "" self.title = ""
self.path = "" self.path = ""
self.tags = [] self.tags = []
self.keywords = ""
self.version = 0 # if version increase, wrapper will re-save this item self.version = 0 # if version increase, wrapper will re-save this item
if from_dict is None: if from_dict is None:
@ -52,6 +53,9 @@ class BaseItem:
self.id = from_dict['id'] self.id = from_dict['id']
self.ready = from_dict['ready'] self.ready = from_dict['ready']
self.tags = from_dict['tags'] self.tags = from_dict['tags']
self.title = from_dict['title']
self.path = from_dict['path']
self.keywords = from_dict['keywords']
def is_ready(self): def is_ready(self):
return True if self.ready == "yes" else False return True if self.ready == "yes" else False
@ -105,4 +109,10 @@ class BaseItem:
self.bot.send_msg(msg) self.bot.send_msg(msg)
def to_dict(self): def to_dict(self):
return {"type": self.type, "id": self.id, "ready": self.ready, "path": self.path, "tags": self.tags} return {"type": self.type,
"id": self.id,
"ready": self.ready,
"title": self.title,
"path": self.path,
"tags": self.tags,
"keywords": self.keywords}