2020-08-13 23:14:14 +00:00
|
|
|
import json
|
2020-04-02 20:17:26 +00:00
|
|
|
import logging
|
2021-01-05 20:18:34 +00:00
|
|
|
import subprocess
|
2020-08-13 23:14:14 +00:00
|
|
|
import urllib.error
|
2020-06-05 22:03:37 +00:00
|
|
|
import urllib.request
|
2020-10-06 15:55:09 +00:00
|
|
|
from threading import Thread
|
2020-08-13 23:14:14 +00:00
|
|
|
from typing import Any, Dict, List
|
2020-06-05 22:03:37 +00:00
|
|
|
|
|
|
|
from szurubooru import config, errors
|
2021-01-07 13:28:22 +00:00
|
|
|
from szurubooru.func import mime
|
2016-08-14 12:22:53 +00:00
|
|
|
|
2020-04-02 20:17:26 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2021-01-05 20:18:34 +00:00
|
|
|
_dl_chunk_size = 2 ** 15
|
|
|
|
|
|
|
|
|
|
|
|
class DownloadError(errors.ProcessingError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class DownloadTooLargeError(DownloadError):
|
|
|
|
pass
|
2020-04-02 20:17:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
def download(url: str, use_video_downloader: bool = False) -> bytes:
|
2016-08-14 08:45:00 +00:00
|
|
|
assert url
|
2021-01-07 13:28:22 +00:00
|
|
|
youtube_dl_error = None
|
2021-01-05 20:18:34 +00:00
|
|
|
if use_video_downloader:
|
2021-01-07 13:28:22 +00:00
|
|
|
try:
|
|
|
|
url = _get_youtube_dl_content_url(url) or url
|
|
|
|
except errors.ThirdPartyError as ex:
|
|
|
|
youtube_dl_error = ex
|
2021-01-05 20:18:34 +00:00
|
|
|
|
2016-05-05 11:23:15 +00:00
|
|
|
request = urllib.request.Request(url)
|
2020-06-05 22:03:37 +00:00
|
|
|
if config.config["user_agent"]:
|
|
|
|
request.add_header("User-Agent", config.config["user_agent"])
|
|
|
|
request.add_header("Referer", url)
|
2021-01-05 20:18:34 +00:00
|
|
|
|
|
|
|
content_buffer = b""
|
|
|
|
length_tally = 0
|
2021-01-06 15:37:59 +00:00
|
|
|
try:
|
|
|
|
with urllib.request.urlopen(request) as handle:
|
|
|
|
while (chunk := handle.read(_dl_chunk_size)) :
|
|
|
|
length_tally += len(chunk)
|
|
|
|
if length_tally > config.config["max_dl_filesize"]:
|
|
|
|
raise DownloadTooLargeError(url)
|
|
|
|
content_buffer += chunk
|
|
|
|
except urllib.error.HTTPError as ex:
|
|
|
|
raise DownloadError(url) from ex
|
2021-01-07 13:28:22 +00:00
|
|
|
|
|
|
|
if (
|
|
|
|
youtube_dl_error
|
|
|
|
and mime.get_mime_type(content_buffer) == "application/octet-stream"
|
|
|
|
):
|
|
|
|
raise youtube_dl_error
|
|
|
|
|
2021-01-05 20:18:34 +00:00
|
|
|
return content_buffer
|
|
|
|
|
|
|
|
|
|
|
|
def _get_youtube_dl_content_url(url: str) -> str:
|
2021-01-07 13:28:22 +00:00
|
|
|
cmd = ["youtube-dl", "--format", "best", "--no-playlist"]
|
2021-01-05 20:18:34 +00:00
|
|
|
if config.config["user_agent"]:
|
|
|
|
cmd.extend(["--user-agent", config.config["user_agent"]])
|
|
|
|
cmd.extend(["--get-url", url])
|
2016-09-25 12:52:47 +00:00
|
|
|
try:
|
2021-01-05 20:18:34 +00:00
|
|
|
return (
|
|
|
|
subprocess.run(cmd, text=True, capture_output=True, check=True)
|
|
|
|
.stdout.split("\n")[0]
|
|
|
|
.strip()
|
2020-06-05 22:03:37 +00:00
|
|
|
)
|
2021-01-05 20:18:34 +00:00
|
|
|
except subprocess.CalledProcessError:
|
2020-04-03 19:32:25 +00:00
|
|
|
raise errors.ThirdPartyError(
|
2021-01-05 20:18:34 +00:00
|
|
|
"Could not extract content location from %s" % (url)
|
|
|
|
) from None
|
2020-08-13 23:14:14 +00:00
|
|
|
|
|
|
|
|
2020-10-06 15:55:09 +00:00
|
|
|
def post_to_webhooks(payload: Dict[str, Any]) -> List[Thread]:
|
|
|
|
threads = [
|
2021-01-05 20:18:34 +00:00
|
|
|
Thread(target=_post_to_webhook, args=(webhook, payload), daemon=False)
|
2020-10-06 15:55:09 +00:00
|
|
|
for webhook in (config.config["webhooks"] or [])
|
|
|
|
]
|
|
|
|
for thread in threads:
|
|
|
|
thread.start()
|
|
|
|
return threads
|
|
|
|
|
|
|
|
|
2021-01-06 15:37:59 +00:00
|
|
|
def _post_to_webhook(webhook: str, payload: Dict[str, Any]) -> int:
|
2020-10-06 15:55:09 +00:00
|
|
|
req = urllib.request.Request(webhook)
|
|
|
|
req.data = json.dumps(
|
|
|
|
payload,
|
|
|
|
default=lambda x: x.isoformat("T") + "Z",
|
|
|
|
).encode("utf-8")
|
|
|
|
req.add_header("Content-Type", "application/json")
|
|
|
|
try:
|
|
|
|
res = urllib.request.urlopen(req)
|
|
|
|
if not 200 <= res.status <= 299:
|
|
|
|
logger.warning(
|
|
|
|
f"Webhook {webhook} returned {res.status} {res.reason}"
|
|
|
|
)
|
|
|
|
return res.status
|
2021-01-07 13:28:22 +00:00
|
|
|
except urllib.error.URLError as ex:
|
|
|
|
logger.warning(f"Unable to call webhook {webhook}: {ex}")
|
2020-10-06 15:55:09 +00:00
|
|
|
return 400
|