Compare commits

..

No commits in common. "main" and "v1.1" have entirely different histories.
main ... v1.1

6 changed files with 56 additions and 222 deletions

View File

@ -41,18 +41,20 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
pip install -r requirements.txt pip install -r requirements.txt
pip install nuitka
- name: Build Executable with Nuitka - name: Build Executable with Nuitka
run: | uses: Nuitka/Nuitka-Action@main
python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist gofilecli.py --include-data-files=./assets/sounds/Blow_edited.wav=assets/sounds/Blow_edited.wav with:
nuitka-version: main
script-name: gofilecli.py
onefile: true
- name: Upload Artifact[win-x64] - name: Upload Artifact[win-x64]
uses: actions/upload-artifact@v3.1.3 uses: actions/upload-artifact@v3.1.3
with: with:
name: GoFileCLI_win-x64 name: GoFileCLI_win-x64
path: | path: |
dist/gofilecli.exe build/gofilecli.exe
build-linux-x64: build-linux-x64:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -72,23 +74,24 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
sudo apt-get install -y libasound2-dev
pip install -r requirements.txt pip install -r requirements.txt
pip install nuitka
- name: Build Executable with Nuitka - name: Build Executable with Nuitka
run: | uses: Nuitka/Nuitka-Action@main
python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist gofilecli.py --include-data-files=./assets/sounds/Blow_edited.wav=assets/sounds/Blow_edited.wav with:
nuitka-version: main
script-name: gofilecli.py
onefile: true
- name: Rename Executable - name: Rename Executable
run: mv dist/gofilecli.bin dist/gofilecli run: mv build/gofilecli.bin build/gofilecli
- name: Upload Artifact[linux-x64] - name: Upload Artifact[linux-x64]
uses: actions/upload-artifact@v3.1.3 uses: actions/upload-artifact@v3.1.3
with: with:
name: GoFileCLI_linux-x64 name: GoFileCLI_linux-x64
path: | path: |
dist/gofilecli build/gofilecli
build-macos: build-macos:
runs-on: macos-latest runs-on: macos-latest
@ -113,8 +116,8 @@ jobs:
- name: Build Executable with Nuitka - name: Build Executable with Nuitka
run: | run: |
python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist --macos-target-arch=arm64 gofilecli.py --include-data-files=./assets/sounds/Blow_edited.wav=assets/sounds/Blow_edited.wav python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist --macos-target-arch=arm64 gofilecli.py
python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist_x86_64 --macos-target-arch=x86_64 gofilecli.py --include-data-files=./assets/sounds/Blow_edited.wav=assets/sounds/Blow_edited.wav python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist_x86_64 --macos-target-arch=x86_64 gofilecli.py
- name: Rename Executable - name: Rename Executable
run: | run: |

1
.gitignore vendored
View File

@ -136,4 +136,3 @@ encrypt.py
assets/sounds/Blow.aiff assets/sounds/Blow.aiff
assets/sounds/Blow.mp3 assets/sounds/Blow.mp3
assets/sounds/Blow.wav assets/sounds/Blow.wav
/VP8SWj

View File

@ -53,7 +53,6 @@ gofilecli -d https://gofile.io/d/XXXXX # to download a folder
``` ```
# To do : # To do :
- KeyboardInterrupt + Lost connexion
- error-rateLimit - error-rateLimit
- env via CLI - env via CLI
- finish README.md - finish README.md

218
gofilecli.py Normal file → Executable file
View File

@ -6,69 +6,17 @@ import argparse
import os import os
import logging import logging
import sys import sys
from dotenv import load_dotenv, set_key
import platform import platform
import subprocess import subprocess
import sys import sys
import simpleaudio as sa import simpleaudio as sa
from tqdm import tqdm
import json
from dotenv import load_dotenv
# Suppress ALSA warnings
os.environ['SDL_AUDIODRIVER'] = 'dummy'
os.environ['AUDIODEV'] = 'null'
def reqst(url, method ,headers=None, data=None, files=None, params=None, json=None, logger=None): def play_sound():
try: wave_obj = sa.WaveObject.from_wave_file("assets/sounds/Blow_edited.wav")
if method == "get":
response = requests.get(url, headers=headers, data=data, params=params, json=json)
elif method == "post":
response = requests.post(url, headers=headers, data=data, files=files, params=params, json=json)
elif method == "put":
response = requests.put(url, headers=headers, data=data, files=files, params=params, json=json)
elif method == "delete":
response = requests.delete(url, headers=headers, data=data, files=files, params=params, json=json)
logger.debug(f"Request to {url} with method {method} returned status code {response.status_code}")
json_response = response.json() # If response content is not JSON, this will raise a ValueError
return json_response
except requests.exceptions.HTTPError as http_err:
logger.debug(f"Response: {response.text}")
logger.error(f"HTTP error occurred: {http_err}") # Handles HTTP errors (e.g., 404, 500)
sys.exit()
except requests.exceptions.ConnectionError as conn_err:
logger.debug(f"Response: {response.text}")
logger.error(f"Connection error occurred: {conn_err}") # Handles network-related errors
sys.exit()
except requests.exceptions.Timeout as timeout_err:
logger.debug(f"Response: {response.text}")
logger.error(f"Timeout error occurred: {timeout_err}") # Handles request timeouts
sys.exit()
except requests.exceptions.RequestException as req_err:
logger.debug(f"Response: {response.text}")
logger.error(f"An error occurred: {req_err}") # Catches any other requests-related errors
sys.exit()
except ValueError as json_err:
logger.debug(f"Response: {response.text}")
logger.error(f"JSON decode error: {json_err}") # Handles issues with JSON decoding
sys.exit()
def load_file(file_name: str) -> str:
"""
Get the correct path to a file, regardless of development or compiled mode.
"""
return os.path.join(os.path.dirname(__file__), file_name)
def play_sound(logger):
try:
sound_path = load_file("assets/sounds/Blow_edited.wav")
wave_obj = sa.WaveObject.from_wave_file(sound_path)
play_obj = wave_obj.play() play_obj = wave_obj.play()
play_obj.wait_done() play_obj.wait_done()
except Exception as e:
logger.debug(f"An error occurred while playing sound: {e}")
def set_env_var_unix(name, value, shell="bash"): def set_env_var_unix(name, value, shell="bash"):
@ -151,8 +99,7 @@ def check_folderPath(path):
def getservers(logger): def getservers(logger):
servers = [] servers = []
# response = requests.get("https://api.gofile.io/servers").json() response = requests.get("https://api.gofile.io/servers").json()
response = reqst("https://api.gofile.io/servers", logger=logger, method="get")
if response["status"] == "ok": if response["status"] == "ok":
for server in response["data"]["servers"]: for server in response["data"]["servers"]:
servers.append(server["name"]) servers.append(server["name"])
@ -163,48 +110,9 @@ def getservers(logger):
return None return None
def ping_server(url, logger, num_requests=4, delay=0.1):
response_times = []
for _ in range(num_requests):
try:
start_time = time.time()
response = requests.head(url)
response_time = time.time() - start_time
if response.status_code == 200:
response_times.append(response_time)
except requests.exceptions.RequestException as e:
logger.error(f"Error: {e}")
time.sleep(delay)
if response_times:
avg_response = sum(response_times) / len(response_times)
return avg_response
else:
return float('inf')
def test_servers(servers, logger):
best_server = None
best_time = float('inf')
for server in servers:
logger.debug(f"Pinging {server}...")
url = f"https://{server}.gofile.io"
avg_time = ping_server(url, logger)
logger.debug(f"Average response time for {server}: {avg_time:.2f} ms")
if avg_time < best_time:
best_time = avg_time
best_server = server
if best_server:
logger.debug(f"\nThe best server is {best_server} with an average response time of {best_time:.2f} ms.")
else:
logger.error("All pings failed.")
return best_server
def get_stats(logger): def get_stats(logger):
headers = {'authorization': f'Bearer {TOKEN}',} headers = {'authorization': f'Bearer {TOKEN}',}
# data = requests.get(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers).json() data = requests.get(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers).json()
data = reqst(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers, logger=logger, method="get")
if data["status"] == "ok":
stats = data["data"]["statsCurrent"] stats = data["data"]["statsCurrent"]
logger.info("Account stats:") logger.info("Account stats:")
logger.info(f"Total files: {stats['fileCount']}") logger.info(f"Total files: {stats['fileCount']}")
@ -213,15 +121,11 @@ def get_stats(logger):
logger.info(f"Total size: {size}") logger.info(f"Total size: {size}")
traffic = file_size(num_bytes=stats['trafficWebDownloaded']) traffic = file_size(num_bytes=stats['trafficWebDownloaded'])
logger.info(f"Total traffic: {traffic}") logger.info(f"Total traffic: {traffic}")
else:
logger.error(f"{data}")
return None
def get_rootfolder(logger): def get_rootfolder(logger):
headers = {'authorization': f'Bearer {TOKEN}',} headers = {'authorization': f'Bearer {TOKEN}',}
# data = requests.get(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers).json() data = requests.get(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers).json()
data = reqst(f'https://api.gofile.io/accounts/{ACCOUNT_ID}', headers=headers, logger=logger, method="get")
root_folder = data.get("data", {}).get("rootFolder", {}) root_folder = data.get("data", {}).get("rootFolder", {})
if root_folder: if root_folder:
return root_folder return root_folder
@ -233,8 +137,7 @@ def get_rootfolder(logger):
def get_code(folderId, logger): def get_code(folderId, logger):
headers = {'authorization': f'Bearer {TOKEN}',} headers = {'authorization': f'Bearer {TOKEN}',}
params = (('wt', '4fd6sg89d7s6'),('cache', 'false'),) params = (('wt', '4fd6sg89d7s6'),('cache', 'false'),)
# data = requests.get(f'https://api.gofile.io/contents/{folderId}', headers=headers, params=params).json() data = requests.get(f'https://api.gofile.io/contents/{folderId}', headers=headers, params=params).json()
data = reqst(f'https://api.gofile.io/contents/{folderId}', headers=headers, params=params, logger=logger, method="get")
code = data.get("data", {}).get("code", {}) code = data.get("data", {}).get("code", {})
if code: if code:
return code return code
@ -246,8 +149,7 @@ def get_code(folderId, logger):
def get_children(id, logger): def get_children(id, logger):
headers = {'authorization': f'Bearer {TOKEN}',} headers = {'authorization': f'Bearer {TOKEN}',}
params = (('wt', '4fd6sg89d7s6'),('cache', 'false'),) params = (('wt', '4fd6sg89d7s6'),('cache', 'false'),)
# data = requests.get(f'https://api.gofile.io/contents/{id}', headers=headers, params=params).json() data = requests.get(f'https://api.gofile.io/contents/{id}', headers=headers, params=params).json()
data = reqst(f'https://api.gofile.io/contents/{id}', headers=headers, params=params, logger=logger, method="get")
children = data.get("data", {}).get("children", {}) children = data.get("data", {}).get("children", {})
if children: if children:
return children return children
@ -267,12 +169,11 @@ def createfolder(parentFolderId, folderName, logger):
data = {"parentFolderId": parentFolderId, "folderName": folderName} data = {"parentFolderId": parentFolderId, "folderName": folderName}
else: else:
data = {"parentFolderId": parentFolderId} data = {"parentFolderId": parentFolderId}
# response = requests.post("https://api.gofile.io/contents/createFolder", headers=headers, json=data).json() response = requests.post("https://api.gofile.io/contents/createFolder", headers=headers, json=data).json()
response = reqst("https://api.gofile.io/contents/createFolder", headers=headers, json=data, logger=logger, method="post")
if response["status"] == "ok": if response["status"] == "ok":
name = response["data"]["name"] name = response["data"]["name"]
code = response["data"]["code"] code = response["data"]["code"]
folderId = response["data"]["id"] folderId = response["data"]["folderId"]
logger.debug(f"""Folder {name} created with code {code} and folderId {folderId}""") logger.debug(f"""Folder {name} created with code {code} and folderId {folderId}""")
return folderId return folderId
else: else:
@ -280,57 +181,15 @@ def createfolder(parentFolderId, folderName, logger):
return None return None
def read_in_chunks(file_object, CHUNK_SIZE):
while True:
data = file_object.read(CHUNK_SIZE)
if not data:
break
yield data
def uploadfile(serverName, folderId, filePath, logger): def uploadfile(serverName, folderId, filePath, logger):
# reference : https://api.video/blog/tutorials/upload-a-big-video-file-using-python/ headers = {"Authorization": f"Bearer {TOKEN}"}
files = {
'file': (filePath, open(filePath, 'rb')),
'folderId': (None, folderId),
}
start_time = time.time() start_time = time.time()
# CHUNK_SIZE = 6000000 response = requests.post(f"https://{serverName}.gofile.io/contents/uploadfile", headers=headers, files=files).json()
# content_size = os.stat(filePath).st_size
# f = open(filePath, "rb")
# index = 0
# offset = 0
# headers = {"Authorization": f"Bearer {TOKEN}", 'content-type': 'multipart/form-data',}
# with tqdm(total=content_size, unit='B', unit_scale=True, desc='Uploading', leave=False) as progress_bar:
# for chunk in read_in_chunks(f, CHUNK_SIZE):
# offset = index + len(chunk)
# headers['Content-Range'] = 'bytes %s-%s/%s' % (index, offset - 1, content_size)
# index = offset
# try:
# # file = {"file": chunk, 'folderId': (None, folderId)}
# # response = requests.post(f"https://{serverName}.gofile.io/contents/uploadfile", files=file, headers=headers)
# # files = {"file": chunk}
# # data = {"folderId": folderId}
# files = {"file": chunk,}
# response = requests.post(f"https://{serverName}.gofile.io/contents/uploadfile",files=files,headers=headers)
# logger.debug("r: %s, Content-Range: %s" % (response, headers['Content-Range']))
# progress_bar.update(len(chunk))
# except Exception as e:
# logger.error(f"Error: {e}")
# logger.debug(f"{response.text}")
# response = response.json()
command = [
"curl",
"-X", "POST",
f"https://{serverName}.gofile.io/contents/uploadfile",
"-H", f"Authorization: Bearer {TOKEN}",
"-F", f"file=@{filePath}",
"-F", f"folderId={folderId}",
]
response = subprocess.run(command, capture_output=True, text=True)
try:
response_json = json.loads(response.stdout)
except json.JSONDecodeError:
logger.error("Failed to parse response as JSON.")
return None
speed, elapsed_time = calculate_upload_speed(filePath, start_time) speed, elapsed_time = calculate_upload_speed(filePath, start_time)
response = response_json
if response["status"] == "ok": if response["status"] == "ok":
logger.debug(response) logger.debug(response)
name = response["data"]["name"] name = response["data"]["name"]
@ -343,11 +202,10 @@ def uploadfile(serverName, folderId, filePath, logger):
return None return None
def actionFolder(folderId, attributeValue, logger): def actionFolder(folderId, attributeValue):
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {TOKEN}"} headers = {"Content-Type": "application/json", "Authorization": f"Bearer {TOKEN}"}
data = {"attribute": "public", "attributeValue": attributeValue} data = {"attribute": "public", "attributeValue": attributeValue}
# response = requests.put(f"https://api.gofile.io/contents/{folderId}/update", headers=headers, json=data).json() response = requests.put(f"https://api.gofile.io/contents/{folderId}/update", headers=headers, json=data).json()
response = reqst(f"https://api.gofile.io/contents/{folderId}/update", headers=headers, json=data, logger=logger, method="put")
if response["status"] == "ok": if response["status"] == "ok":
return True return True
else: else:
@ -370,17 +228,9 @@ def upload(filePath, folderPath, folderName, parentFolderId, private, logger):
logger.error("File not found") logger.error("File not found")
sys.exit() sys.exit()
# Getting servers
servers = getservers(logger) servers = getservers(logger)
if servers: if servers:
if len(servers) > 1: # If there are multiple servers, check the size of the files
if max([os.path.getsize(file) for file in files]) > 100 * 1024 * 1024: # 100 MB in bytes
logger.debug("One of the file have a size > 100 MB. Fetching best server...")
serverName = test_servers(servers, logger)
else:
serverName = random.choice(servers) serverName = random.choice(servers)
else:
serverName = servers[0]
logger.debug(f"Selected server: {serverName}") logger.debug(f"Selected server: {serverName}")
if folderName and parentFolderId: if folderName and parentFolderId:
@ -397,33 +247,30 @@ def upload(filePath, folderPath, folderName, parentFolderId, private, logger):
parentFolderId = parentFolderId parentFolderId = parentFolderId
logger.debug(f"FolderId: {parentFolderId}") logger.debug(f"FolderId: {parentFolderId}")
else: else:
# parentFolderId = PRIVATE_PARENT_ID parentFolderId = None
logger.info(f"Creating folder: {folderName} for PRIVATE_PARENT_ID: {PRIVATE_PARENT_ID}")
folderId = createfolder(PRIVATE_PARENT_ID, None, logger)
parentFolderId = folderId
logger.debug(f"FolderId: {parentFolderId}") logger.debug(f"FolderId: {parentFolderId}")
for file in files: for file in files:
if parentFolderId: if parentFolderId:
logger.info(f"Uploading file: '{file}' ({file_size(file)}) to: '{parentFolderId}' on: '{serverName}'") logger.info(f"Uploading file: '{file}' ({file_size(file)}) to: '{parentFolderId}' on: '{serverName}'")
else: else:
logger.info(f"Uploading file: '{file}' ({file_size(file)}) on: '{serverName}'") logger.info(f"Uploading file: {file} ({file_size(file)}) on: {serverName}")
downloadPage, parentFolderId, speed, elapsed_time = uploadfile(serverName, parentFolderId, file, logger) downloadPage, parentFolderId, speed, elapsed_time = uploadfile(serverName, parentFolderId, file, logger)
logger.info(f"File uploaded to: {downloadPage} in {elapsed_time} at {speed}") logger.info(f"File uploaded to: {downloadPage} in {elapsed_time} at {speed}")
if not private: if not private:
action = actionFolder(parentFolderId, "true", logger) action = actionFolder(parentFolderId, "true")
if action: if action:
logger.info("Folder made public") logger.info("Folder made public")
else: else:
logger.error(f"{action}") logger.error(f"{action}")
else: else:
action = actionFolder(parentFolderId, "false", logger) action = actionFolder(parentFolderId, "false")
if action: if action:
logger.info("Folder made private") logger.info("Folder made private")
else: else:
logger.error(f"{action}") logger.error(f"{action}")
play_sound(logger) play_sound()
else: else:
time.sleep(10) time.sleep(10)
sys.exit() sys.exit()
@ -432,15 +279,9 @@ def upload(filePath, folderPath, folderName, parentFolderId, private, logger):
def downloadFile(downloadUrl, path, logger): def downloadFile(downloadUrl, path, logger):
start_time = time.time() start_time = time.time()
headers = {"Authorization": f"Bearer {TOKEN}"} headers = {"Authorization": f"Bearer {TOKEN}"}
response = requests.get(downloadUrl, headers=headers, stream=True) response = requests.get(downloadUrl, headers=headers)
# response = reqst(downloadUrl, headers=headers, logger=logger, method="get") with open(path, "wb") as f:
total_size = int(response.headers.get('content-length', 0)) f.write(response.content)
with open(path, "wb") as f, tqdm(total=total_size, unit='B', unit_scale=True, desc='Downloading', leave=False) as progress_bar:
for chunk in response.iter_content(1024):
if chunk:
f.write(chunk)
progress_bar.update(len(chunk))
logger.debug(f"File downloaded: {path}") logger.debug(f"File downloaded: {path}")
speed, elapsed_time = calculate_upload_speed(path, start_time) speed, elapsed_time = calculate_upload_speed(path, start_time)
return speed, elapsed_time return speed, elapsed_time
@ -485,7 +326,7 @@ def download(folderId, folderPath, force, logger):
speed, elapsed_time = downloadFile(downloadUrl, path, logger) speed, elapsed_time = downloadFile(downloadUrl, path, logger)
logger.info(f"File download to: {path} in {elapsed_time} at {speed}") logger.info(f"File download to: {path} in {elapsed_time} at {speed}")
nbdone += 1 nbdone += 1
play_sound(logger) play_sound()
def opt(): def opt():
@ -518,7 +359,6 @@ def init():
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
load_dotenv() load_dotenv()
global TOKEN global TOKEN
global PRIVATE_PARENT_ID global PRIVATE_PARENT_ID
global ACCOUNT_ID global ACCOUNT_ID
@ -584,8 +424,4 @@ def init():
if __name__ == "__main__": if __name__ == "__main__":
try:
init() init()
except KeyboardInterrupt:
print("\nExiting...")
sys.exit()

View File

@ -1,5 +1,3 @@
cryptography==39.0.1 cryptography==39.0.1
python-dotenv==1.0.1 python-dotenv==1.0.1
Requests==2.32.3 Requests==2.32.3
simpleaudio==1.0.4
tqdm==4.65.0

View File

@ -10,8 +10,7 @@ tag=$1
source ~/miniconda3/etc/profile.d/conda.sh source ~/miniconda3/etc/profile.d/conda.sh
conda activate 310 conda activate 310
pip install -r requirements.txt python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist --static-libpython=no gofilecli.py
python -m nuitka --onefile --assume-yes-for-downloads --output-dir=dist --static-libpython=no gofilecli.py --include-data-files=./assets/sounds/Blow_edited.wav=assets/sounds/Blow_edited.wav
mv dist/gofilecli.bin ./gofilecli mv dist/gofilecli.bin ./gofilecli
mkdir -p GoFileCLI_linux-arm64 mkdir -p GoFileCLI_linux-arm64