Files
mini-flees/code/utils/files.py
2023-08-20 22:23:42 +03:00

202 lines
5.4 KiB
Python

import os
from datetime import datetime
from flask import current_app as app
import time
import sqlite3
import shutil
from .misc import file_size_human, file_date_human, file_time_human
def get_db():
db = sqlite3.connect(app.config["DB"], timeout=5)
c = db.cursor()
return db, c
def db_store_file(token, name, expires, max_dl, password):
db, c = get_db()
c.execute(
"""
insert into files(token,name,added,expires,downloads,max_downloads,passhash)
values (?,?,?,?,?,?,?)
""",
(token, name, int(time.time()), expires, 0, max_dl, password),
)
if c.rowcount > 0:
db.commit()
return
def db_get_file(token, name):
db, c = get_db()
return db.execute(
"""
SELECT added,expires,downloads,max_downloads,passhash
FROM files WHERE token = ? AND name = ?
""",
(token, name),
).fetchone()
def db_get_files():
db, c = get_db()
return db.execute(
"""
SELECT token,name,added,expires,downloads,max_downloads,passhash
FROM files
WHERE expires > ? and (downloads < max_downloads or max_downloads = -1)
ORDER BY added
""",
(time.time(),),
)
def db_delete_file(token, name):
db, c = get_db()
c.execute(
"""
DELETE FROM files WHERE token = ? and name = ?
""",
(token, name),
)
if c.rowcount > 0:
db.commit()
def db_add_download(token, name):
db, c = get_db()
c.execute(
"""
UPDATE files SET downloads = downloads + 1 WHERE token = ? AND name = ?
""",
(token, name),
)
if c.rowcount > 0:
db.commit()
return
def db_maintenance():
messages = []
# === Delete DB entries where expiry or max DL is used up ===
db, c = get_db()
rows = db.execute(
"""
select
token, name
from files
where expires < ? or (downloads >= max_downloads and max_downloads != -1)
""",
(int(time.time()),),
)
deleted_tokens = []
for row in rows:
deleted_tokens.append((row[0],))
messages.append(f"Deleting DB {row[0]}/{row[1]}")
if len(deleted_tokens) > 0:
db, c = get_db()
c.executemany("DELETE FROM files WHERE token = ?", deleted_tokens)
if c.rowcount > 0:
db.commit()
# Delete files, if DB entry is gone
subdirs = next(os.walk(app.config["DATAFOLDER"]))[1]
db, c = get_db()
for d in subdirs:
keep = db.execute(
"SELECT 1 FROM files WHERE token = ?",
(d,),
).fetchone()
if not keep:
try:
for fname in os.listdir(os.path.join(app.config["DATAFOLDER"], d)):
os.remove(os.path.join(app.config["DATAFOLDER"], d, fname))
messages.append(f"Deleting file {d}/{fname}")
except Exception:
pass
shutil.rmtree(os.path.join(app.config["DATAFOLDER"], d), ignore_errors=True)
messages.append(f"Deleting folder {d}")
# Delete DB entries, if files have been deleted (probably manually)
db, c = get_db()
rows = db.execute(
"""
select
token, name
from files
"""
)
deleted_tokens = []
for row in rows:
full_path = file_full_path(row[0], row[1])
if not os.path.exists(full_path):
deleted_tokens.append((row[0],))
messages.append(f"Deleting DB {row[0]}/{row[1]} - files missing")
if len(deleted_tokens) > 0:
db, c = get_db()
c.executemany("DELETE FROM files WHERE token = ?", deleted_tokens)
if c.rowcount > 0:
db.commit()
messages.append("Maintenance done.")
return "\n".join(messages)
def file_age(path):
now = datetime.now()
then = datetime.fromtimestamp(os.stat(path).st_mtime)
diff = now - then
return (
diff,
"%03d d %s"
% (diff.days, datetime.utcfromtimestamp(diff.seconds).strftime("%H:%M:%S")),
)
def file_details(token, name):
full_path = file_full_path(token, name)
try:
s = os.stat(full_path)
db_stat = db_get_file(token, name)
if db_stat:
added, expires, downloads, max_dl, password = db_stat
else:
return {}
return {
"size": s.st_size,
"hsize": file_size_human(s.st_size, HTML=False),
"added": file_time_human(added),
"name": name,
"url": file_full_url(token, name),
"expires": file_time_human(expires),
"downloaded": downloads,
"max-dl": max_dl,
"protected": password is not None,
}
except FileNotFoundError:
return {}
def file_full_path(token, name):
return os.path.join(app.config["DATAFOLDER"], token, name)
def file_full_url(token, name):
return f"{app.config['PUBLIC_URL']}/d/{token}/{name}"
def file_list():
details = []
details.append(" Added/Expiry DL/MaxDL URL")
details.append("=" * 75)
for file in db_get_files():
url = file_full_url(file[0], file[1])
added = file_date_human(file[2])
expiry = file_date_human(file[3])
pw = " (PW)" if file[6] else ""
details.append(f"{added}/{expiry} {file[4]:4d}/{file[5]:4d} {url}{pw}")
return details
def file_list_simple():
return [f"{r[0]}/{r[1]}" for r in db_get_files()]