202 lines
5.4 KiB
Python
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()]
|