aboutsummaryrefslogtreecommitdiffstats
path: root/gallery_dl/extractor/gofile.py
blob: 7c9755ad2bdfcc4897a59955c9b9a9c0f969a31c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# -*- coding: utf-8 -*-

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.

"""Extractors for https://gofile.io/"""

from .common import Extractor, Message
from .. import text, exception
from ..cache import cache, memcache
import hashlib


class GofileFolderExtractor(Extractor):
    category = "gofile"
    subcategory = "folder"
    root = "https://gofile.io"
    directory_fmt = ("{category}", "{name} ({code})")
    archive_fmt = "{id}"
    pattern = r"(?:https?://)?(?:www\.)?gofile\.io/d/([^/?#]+)"
    example = "https://gofile.io/d/ID"

    def __init__(self, match):
        Extractor.__init__(self, match)
        self.content_id = match[1]

    def items(self):
        recursive = self.config("recursive")
        password = self.config("password")

        token = self.config("api-token")
        if not token:
            token = self._create_account()
        self.cookies.set("accountToken", token, domain=".gofile.io")
        self.api_token = token

        self.website_token = (self.config("website-token") or
                              self._get_website_token())

        folder = self._get_content(self.content_id, password)
        yield Message.Directory, "", folder

        try:
            contents = folder.pop("children")
        except KeyError:
            raise exception.AuthorizationError("Password required")

        num = 0
        for content in contents.values():
            content["folder"] = folder

            if content["type"] == "file":
                num += 1
                content["num"] = num
                content["filename"], _, content["extension"] = \
                    content["name"].rpartition(".")
                yield Message.Url, content["link"], content

            elif content["type"] == "folder":
                if recursive:
                    url = "https://gofile.io/d/" + content["id"]
                    content["_extractor"] = GofileFolderExtractor
                    yield Message.Queue, url, content

            else:
                self.log.debug("'%s' is of unknown type (%s)",
                               content.get("name"), content["type"])

    @memcache()
    def _create_account(self):
        self.log.debug("Creating temporary account")
        return self._api_request("accounts", method="POST")["token"]

    @cache(maxage=86400)
    def _get_website_token(self):
        self.log.debug("Fetching website token")
        page = self.request(self.root + "/dist/js/config.js").text
        return text.extr(page, '.wt = "', '"')

    def _get_content(self, content_id, password=None):
        headers = {
            "Authorization"  : "Bearer " + self.api_token,
            "X-Website-Token": self.website_token,
        }
        params = None if password is None else {"password": hashlib.sha256(
            password.encode()).hexdigest()}
        return self._api_request("contents/" + content_id, params, headers)

    def _api_request(self, endpoint, params=None, headers=None, method="GET"):
        response = self.request_json(
            "https://api.gofile.io/" + endpoint,
            method=method, params=params, headers=headers)

        if response["status"] != "ok":
            if response["status"] == "error-notFound":
                raise exception.NotFoundError("content")
            if response["status"] == "error-passwordRequired":
                raise exception.AuthorizationError("Password required")
            raise exception.AbortExtraction(
                f"{endpoint} failed (Status: {response['status']})")

        return response["data"]