|
from src.routes.trailer import trailerBP |
|
from src.routes.subtitledownload import subtitledownloadBP |
|
from src.routes.streammap import streammapBP |
|
from src.routes.signup import signupBP |
|
from src.routes.restart import restartBP |
|
from src.routes.redirectdownload import redirectdownloadBP |
|
|
|
from src.routes.ping import pingBP |
|
from src.routes.metadata import metadataBP |
|
from src.routes.image import imageBP |
|
from src.routes.environment import environmentBP |
|
from src.routes.download import downloadBP |
|
from src.routes.debug import debugBP |
|
|
|
from src.routes.auth import authBP |
|
import datetime |
|
import io |
|
import json |
|
import logging |
|
import os |
|
import sys |
|
import threading |
|
|
|
import apscheduler.schedulers.background |
|
import bs4 |
|
import colorama |
|
import flask |
|
import flask_cors |
|
import googleapiclient |
|
import requests |
|
|
|
import src.functions.config |
|
import src.functions.credentials |
|
import src.functions.metadata |
|
import src.functions.tests |
|
|
|
colorama.init() |
|
print( |
|
"====================================================\n\033[96m libDrive - v1.4.7\033[94m\n @eliasbenb\033[0m\n====================================================\n" |
|
) |
|
|
|
print("\033[32mREADING CONFIG...\033[0m") |
|
if os.getenv("LIBDRIVE_CONFIG"): |
|
config_str = os.getenv("LIBDRIVE_CONFIG") |
|
with open("config.json", "w+") as w: |
|
json.dump(obj=json.loads(config_str), fp=w, sort_keys=True, indent=4) |
|
config = src.functions.config.readConfig() |
|
print("DONE.\n") |
|
|
|
print("\033[32mREADING METADATA...\033[0m") |
|
metadata = src.functions.metadata.readMetadata(config) |
|
if os.getenv("LIBDRIVE_CLOUD") and config.get("refresh_token"): |
|
config, drive = src.functions.credentials.refreshCredentials(config) |
|
params = { |
|
"supportsAllDrives": True, |
|
"includeItemsFromAllDrives": True, |
|
"fields": "files(id,name)", |
|
"q": "'%s' in parents and trashed = false and mimeType = 'application/json'" |
|
% (os.getenv("LIBDRIVE_CLOUD")), |
|
} |
|
files = drive.files().list(**params).execute()["files"] |
|
config_file = next((i for i in files if i["name"] == "config.json"), None) |
|
metadata_file = next((i for i in files if i["name"] == "metadata.json"), None) |
|
if config_file: |
|
request = drive.files().get_media(fileId=config_file["id"]) |
|
fh = io.BytesIO() |
|
downloader = googleapiclient.http.MediaIoBaseDownload(fh, request) |
|
done = False |
|
while done is False: |
|
status, done = downloader.next_chunk() |
|
config = json.loads(fh.getvalue()) |
|
config, drive = src.functions.credentials.refreshCredentials(config) |
|
src.functions.config.updateConfig(config) |
|
if metadata_file: |
|
request = drive.files().get_media(fileId=metadata_file["id"]) |
|
fh = io.BytesIO() |
|
downloader = googleapiclient.http.MediaIoBaseDownload(fh, request) |
|
done = False |
|
while done is False: |
|
status, done = downloader.next_chunk() |
|
metadata = json.loads(fh.getvalue()) |
|
with open("metadata.json", "w+") as w: |
|
json.dump(metadata, w) |
|
print("DONE.\n") |
|
|
|
if not config.get("account_list"): |
|
config["account_list"] = [] |
|
if config.get("account_list") == [] and config.get("signup") == False: |
|
config["auth"] = False |
|
if not config.get("auth"): |
|
config["auth"] = False |
|
if not config.get("build_interval"): |
|
config["build_interval"] = 360 |
|
if not config.get("build_type"): |
|
config["build_type"] = "hybrid" |
|
if not config.get("category_list"): |
|
config["category_list"] = [] |
|
if not config.get("cloudflare"): |
|
config["cloudflare"] = "" |
|
if not config.get("prefer_mkv"): |
|
config["prefer_mkv"] = False |
|
if not config.get("prefer_mp4"): |
|
config["prefer_mp4"] = True |
|
if not config.get("service_accounts"): |
|
config["service_accounts"] = [] |
|
if not config.get("signup"): |
|
config["signup"] = False |
|
if not config.get("subtitles"): |
|
config["subtitles"] = False |
|
if not config.get("transcoded"): |
|
config["transcoded"] = False |
|
if not config.get("ui_config"): |
|
config["ui_config"] = {} |
|
|
|
|
|
|
|
|
|
print("\033[32mTESTING YOUR CONFIG...\033[0m") |
|
|
|
|
|
|
|
|
|
print("DONE.\n") |
|
|
|
|
|
def threaded_metadata(): |
|
for thread in threading.enumerate(): |
|
if thread.name == "metadata_thread": |
|
print("DONE.\n") |
|
return ( |
|
{ |
|
"code": 500, |
|
"content": None, |
|
"message": "libDrive is already building metadata, please wait.", |
|
"success": False, |
|
}, |
|
500, |
|
) |
|
config = src.functions.config.readConfig() |
|
if len(config.get("category_list")) > 0: |
|
metadata_thread = threading.Thread( |
|
target=src.functions.metadata.writeMetadata, |
|
args=(config,), |
|
daemon=True, |
|
name="metadata_thread", |
|
) |
|
metadata_thread.start() |
|
else: |
|
pass |
|
return ( |
|
{ |
|
"code": 200, |
|
"content": None, |
|
"message": "libDrive is building your new metadata.", |
|
"success": True, |
|
}, |
|
200, |
|
) |
|
|
|
|
|
def create_app(): |
|
if os.path.exists("./build"): |
|
LIBDRIVE_DEBUG = os.getenv("LIBDRIVE_DEBUG") |
|
if LIBDRIVE_DEBUG: |
|
if LIBDRIVE_DEBUG.lower() == "true": |
|
LIBDRIVE_DEBUG = True |
|
else: |
|
LIBDRIVE_DEBUG = False |
|
else: |
|
LIBDRIVE_DEBUG = False |
|
r = open("./build/index.html", "r") |
|
soup = bs4.BeautifulSoup(r.read(), features="html.parser") |
|
if config.get("ui_config", {}).get("icon"): |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-image"})["content"] = config.get( |
|
"ui_config", {} |
|
).get("icon") |
|
except: |
|
pass |
|
try: |
|
soup.find("link", {"id": "@ld-link-icon"})["href"] = config.get( |
|
"ui_config", {} |
|
).get("icon") |
|
except: |
|
pass |
|
else: |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-image"})[ |
|
"content" |
|
] = "/images/icons/icon-512x512.png" |
|
except: |
|
pass |
|
try: |
|
soup.find("link", {"id": "@ld-link-icon"})["href"] = "/favicon.ico" |
|
except: |
|
pass |
|
if config.get("ui_config", {}).get("title"): |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-title"})["content"] = config.get( |
|
"ui_config", {} |
|
).get("title") |
|
except: |
|
pass |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-site_name"})[ |
|
"content" |
|
] = config.get("ui_config", {}).get("title") |
|
except: |
|
pass |
|
try: |
|
soup.find("title", {"id": "@ld-title"}).string = config.get( |
|
"ui_config", {} |
|
).get("title") |
|
except: |
|
pass |
|
else: |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-title"})["content"] = "libDrive" |
|
except: |
|
pass |
|
try: |
|
soup.find("meta", {"id": "@ld-meta-og-site_name"})[ |
|
"content" |
|
] = "libDrive" |
|
except: |
|
pass |
|
try: |
|
soup.find("title", {"id": "@ld-title"}).string = "libDrive" |
|
except: |
|
pass |
|
if ( |
|
config.get("arcio") |
|
and config.get("arcio") != "" |
|
and LIBDRIVE_DEBUG == False |
|
): |
|
req = requests.get("https://arc.io/arc-sw.js") |
|
with open("./build/arc-sw.js", "wb") as wb: |
|
wb.write(req.content) |
|
code = config.get("arcio") |
|
if code == "dev": |
|
code = "tUUqUjhw" |
|
soup.find("script", {"id": "@ld-script-arcio"})[ |
|
"src" |
|
] = "//arc.io/widget.min.js#%s" % (code) |
|
else: |
|
if os.path.exists("./build/arc-sw.js"): |
|
os.remove("./build/arc-sw.js") |
|
soup.find("script", {"id": "@ld-script-arcio"})["src"] = "" |
|
|
|
|
|
r.close() |
|
|
|
app = flask.Flask(__name__, static_folder="build") |
|
|
|
build_interval = config.get("build_interval") |
|
if not build_interval: |
|
build_interval = 360 |
|
if build_interval != 0: |
|
print("\033[32mCREATING CRON JOB...\033[0m") |
|
sched = apscheduler.schedulers.background.BackgroundScheduler(daemon=True) |
|
sched.add_job( |
|
threaded_metadata, |
|
"interval", |
|
minutes=build_interval, |
|
) |
|
sched.start() |
|
print("DONE.\n") |
|
|
|
config_categories = [d["id"] for d in config["category_list"]] |
|
metadata_categories = [d["id"] for d in metadata] |
|
if len(metadata) > 0 and sorted(config_categories) == sorted(metadata_categories): |
|
if build_interval == 0: |
|
return app |
|
elif datetime.datetime.utcnow() <= datetime.datetime.strptime( |
|
metadata[-1]["buildTime"], "%Y-%m-%d %H:%M:%S.%f" |
|
) + datetime.timedelta(minutes=build_interval): |
|
return app |
|
else: |
|
threaded_metadata() |
|
else: |
|
threaded_metadata() |
|
|
|
return app |
|
|
|
|
|
app = create_app() |
|
flask_cors.CORS(app) |
|
app.secret_key = config.get("secret_key") |
|
|
|
|
|
app.register_blueprint(authBP) |
|
|
|
app.register_blueprint(debugBP) |
|
app.register_blueprint(downloadBP) |
|
app.register_blueprint(environmentBP) |
|
app.register_blueprint(imageBP) |
|
app.register_blueprint(metadataBP) |
|
app.register_blueprint(pingBP) |
|
|
|
app.register_blueprint(redirectdownloadBP) |
|
app.register_blueprint(restartBP) |
|
app.register_blueprint(signupBP) |
|
app.register_blueprint(streammapBP) |
|
app.register_blueprint(subtitledownloadBP) |
|
app.register_blueprint(trailerBP) |
|
|
|
|
|
@app.route("/", defaults={"path": ""}) |
|
@app.route("/<path:path>") |
|
async def serve(path): |
|
if (path != "") and os.path.exists("%s/%s" % (app.static_folder, path)): |
|
return flask.send_from_directory(app.static_folder, path) |
|
else: |
|
return flask.send_from_directory(app.static_folder, "index.html") |
|
|
|
|
|
if __name__ == "__main__": |
|
print("\033[32mSERVING SERVER...\033[0m") |
|
LIBDRIVE_DEBUG = os.getenv("LIBDRIVE_DEBUG") |
|
if LIBDRIVE_DEBUG: |
|
if LIBDRIVE_DEBUG.lower() == "true": |
|
LIBDRIVE_DEBUG = True |
|
else: |
|
LIBDRIVE_DEBUG = False |
|
else: |
|
LIBDRIVE_DEBUG = False |
|
print("DONE.\n") |
|
app.run( |
|
host="0.0.0.0", |
|
port=7860, |
|
threaded=True, |
|
debug=LIBDRIVE_DEBUG, |
|
) |
|
else: |
|
print("\033[32mINITIALIZING LOGGER...\033[0m") |
|
if not os.path.exists("./logs"): |
|
os.mkdir("./logs") |
|
logs_path = os.path.abspath("./logs") |
|
logs_max_files = 5 |
|
|
|
def sorted_ls(path): |
|
def mtime(f): return os.stat(os.path.join(path, f)).st_mtime |
|
return list(sorted(os.listdir(path), key=mtime)) |
|
|
|
del_list = sorted_ls(logs_path)[0: (len(sorted_ls(logs_path)) - logs_max_files)] |
|
for del_file in del_list: |
|
try: |
|
os.remove(os.path.join(logs_path, del_file)) |
|
except: |
|
pass |
|
logging.getLogger("googleapiclient").setLevel(logging.WARNING) |
|
logging.getLogger("oauth2client").setLevel(logging.WARNING) |
|
logging.getLogger("waitress").setLevel(logging.INFO) |
|
logging.basicConfig( |
|
filename="./logs/%s.log" |
|
% (datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S")), |
|
level=logging.INFO, |
|
) |
|
console_logger = logging.getLogger() |
|
console_logger.setLevel(logging.INFO) |
|
console_handler = logging.StreamHandler(sys.stdout) |
|
console_handler.setLevel(logging.INFO) |
|
console_logger.addHandler(console_handler) |
|
print("DONE.\n") |
|
|