first commit

This commit is contained in:
2026-04-03 21:50:36 +08:00
commit 10843a5bc5
43 changed files with 3958 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
# db package
Binary file not shown.
Binary file not shown.
Binary file not shown.
+230
View File
@@ -0,0 +1,230 @@
import sqlite3
import os
import shutil
# 数据库放到 Windows 常见的 APPDATA 目录(避免写在项目目录)
APP_NAME = "CleanDesktopOrganizer"
_PROJECT_DB_PATH = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "data.db"
)
_BASE_DIR = os.environ.get("APPDATA") or os.environ.get("LOCALAPPDATA") or ""
DB_DIR = os.path.join(_BASE_DIR, APP_NAME) if _BASE_DIR else None
DB_PATH = os.path.join(DB_DIR, "data.db") if DB_DIR else _PROJECT_DB_PATH
def _ensure_db_dir():
if DB_DIR:
os.makedirs(DB_DIR, exist_ok=True)
def _migrate_old_db_if_needed():
"""
首次升级:把旧版项目目录下的 data.db 自动拷贝到 APPDATA
避免你之前分组/设置丢失。
"""
try:
if os.path.isfile(_PROJECT_DB_PATH) and not os.path.isfile(DB_PATH):
_ensure_db_dir()
shutil.copy2(_PROJECT_DB_PATH, DB_PATH)
except Exception:
# 迁移失败不影响程序运行(会在新目录重新创建库)
pass
def get_conn():
_ensure_db_dir()
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def init_db():
_migrate_old_db_if_needed()
conn = get_conn()
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
position INTEGER DEFAULT 0,
folder_path TEXT DEFAULT ''
)
""")
c.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL,
name TEXT NOT NULL,
path TEXT NOT NULL,
icon_path TEXT,
position INTEGER DEFAULT 0,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
)
""")
c.execute("""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
""")
# 迁移:旧库没有 folder_path 字段时自动添加
try:
c.execute("ALTER TABLE groups ADD COLUMN folder_path TEXT DEFAULT ''")
conn.commit()
except Exception:
pass # 字段已存在则忽略
# 默认分组
c.execute("SELECT COUNT(*) FROM groups")
if c.fetchone()[0] == 0:
c.execute("INSERT INTO groups (name, position) VALUES ('常用程序', 0)")
conn.commit()
conn.close()
_migrate_item_shortcut_paths_to_targets()
def _migrate_item_shortcut_paths_to_targets():
"""将旧数据中仍保存为 .lnk 的路径改存为快捷方式目标(若可解析)。仅执行一次。"""
conn = get_conn()
row = conn.execute(
"SELECT value FROM settings WHERE key='items_lnk_targets_migrated'"
).fetchone()
conn.close()
if row and row["value"] == "1":
return
from shortcut_target import path_for_storage
conn = get_conn()
rows = conn.execute("SELECT id, path FROM items").fetchall()
for r in rows:
iid, p = r["id"], (r["path"] or "")
pl = p.lower()
if not pl.endswith(".lnk"):
continue
try:
if not os.path.isfile(p):
continue
except OSError:
continue
new_p = path_for_storage(p)
if new_p != p:
conn.execute("UPDATE items SET path=? WHERE id=?", (new_p, iid))
conn.execute(
"INSERT INTO settings (key, value) VALUES (?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
("items_lnk_targets_migrated", "1"),
)
conn.commit()
conn.close()
# ── Settings ─────────────────────────────────────────────
def get_setting(key: str, default: str = "") -> str:
conn = get_conn()
row = conn.execute("SELECT value FROM settings WHERE key=?", (key,)).fetchone()
conn.close()
return row["value"] if row else default
def set_setting(key: str, value: str):
conn = get_conn()
conn.execute(
"INSERT INTO settings (key, value) VALUES (?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
(key, value)
)
conn.commit()
conn.close()
# ── Groups ──────────────────────────────────────────────
def get_groups():
conn = get_conn()
rows = conn.execute("SELECT * FROM groups ORDER BY position").fetchall()
conn.close()
return [dict(r) for r in rows]
def add_group(name, folder_path=""):
conn = get_conn()
conn.execute("INSERT INTO groups (name, folder_path) VALUES (?,?)", (name, folder_path))
conn.commit()
gid = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
conn.close()
return gid
def rename_group(gid, name):
conn = get_conn()
conn.execute("UPDATE groups SET name=? WHERE id=?", (name, gid))
conn.commit()
conn.close()
def delete_group(gid):
conn = get_conn()
conn.execute("DELETE FROM groups WHERE id=?", (gid,))
conn.commit()
conn.close()
def reorder_groups(id_list):
conn = get_conn()
for pos, gid in enumerate(id_list):
conn.execute("UPDATE groups SET position=? WHERE id=?", (pos, gid))
conn.commit()
conn.close()
# ── Items ────────────────────────────────────────────────
def get_items(group_id):
conn = get_conn()
rows = conn.execute(
"SELECT * FROM items WHERE group_id=? ORDER BY position", (group_id,)
).fetchall()
conn.close()
return [dict(r) for r in rows]
def add_item(group_id, name, path, icon_path=None):
from shortcut_target import path_for_storage
path = path_for_storage(path)
conn = get_conn()
conn.execute(
"INSERT INTO items (group_id, name, path, icon_path) VALUES (?,?,?,?)",
(group_id, name, path, icon_path),
)
conn.commit()
iid = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
conn.close()
return iid
def delete_item(item_id):
conn = get_conn()
conn.execute("DELETE FROM items WHERE id=?", (item_id,))
conn.commit()
conn.close()
def move_item(item_id, new_group_id, new_position):
conn = get_conn()
conn.execute(
"UPDATE items SET group_id=?, position=? WHERE id=?",
(new_group_id, new_position, item_id),
)
conn.commit()
conn.close()
def reorder_items(group_id, id_list):
conn = get_conn()
for pos, iid in enumerate(id_list):
conn.execute("UPDATE items SET position=? WHERE id=?", (pos, iid))
conn.commit()
conn.close()