forked from creations/grabit
Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
03b9f53048 | |||
6ea44a5bf0 | |||
c5cc8bc4ff | |||
8760f14b9e | |||
1a31b8441d | |||
6040cb0142 | |||
270d531d6e |
7 changed files with 102 additions and 47 deletions
41
LICENSE
41
LICENSE
|
@ -1,21 +1,28 @@
|
||||||
MIT License
|
BSD 3-Clause License
|
||||||
|
|
||||||
Copyright (c) 2025 Creation's
|
Copyright (c) 2025, [fullname]
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Redistribution and use in source and binary forms, with or without
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
modification, are permitted provided that the following conditions are met:
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
copies or substantial portions of the Software.
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
this list of conditions and the following disclaimer in the documentation
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
and/or other materials provided with the distribution.
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
contributors may be used to endorse or promote products derived from
|
||||||
SOFTWARE.
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
|
@ -51,4 +51,4 @@ Upload clipboard image:
|
||||||
- Shows a preview of the uploaded image.
|
- Shows a preview of the uploaded image.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
[MIT](LICENSE)
|
[BSD-3](LICENSE)
|
||||||
|
|
|
@ -123,6 +123,24 @@ setup_domain() {
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$change_options" =~ ^(y|Y)$ ]]; then
|
if [[ "$change_options" =~ ^(y|Y)$ ]]; then
|
||||||
|
while true; do
|
||||||
|
echo -ne "${CYAN}Enter override domain for accessing files (e.g. random.domain.com): ${RESET}"
|
||||||
|
read override_domain
|
||||||
|
|
||||||
|
if [[ -z "$override_domain" ]]; then
|
||||||
|
echo -e "${YELLOW}No override domain set.${RESET}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$override_domain" =~ ^[a-zA-Z0-9.-]+$ ]]; then
|
||||||
|
set_value "x-zipline-domain" "$override_domain"
|
||||||
|
echo -e "${GREEN}x-zipline-domain set to: $override_domain${RESET}"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Invalid format. Must be like: domain.tld (no https, no trailing slash). Try again or press Enter to skip.${RESET}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
echo -ne "${CYAN}Enter the number of max views (default: 0): ${RESET}"
|
echo -ne "${CYAN}Enter the number of max views (default: 0): ${RESET}"
|
||||||
read max_views
|
read max_views
|
||||||
while [[ -n "$max_views" && ! "$max_views" =~ ^[0-9]+$ ]]; do
|
while [[ -n "$max_views" && ! "$max_views" =~ ^[0-9]+$ ]]; do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
VENV_DIR="$SCRIPT_DIR/.venv"
|
VENV_DIR="$HOME/.config/grabIT/.venv"
|
||||||
|
|
||||||
setup_venv() {
|
setup_venv() {
|
||||||
if [[ ! -d "$VENV_DIR" ]]; then
|
if [[ ! -d "$VENV_DIR" ]]; then
|
||||||
|
|
|
@ -4,7 +4,7 @@ import tkinter as tk
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
import screeninfo, sys, os
|
import screeninfo, sys, os
|
||||||
|
|
||||||
def show_image(image_path, box_width=400, box_height=300, hover_header=None, click_url=None):
|
def show_image(image_path, max_width=400, max_height=300, hover_header=None, click_url=None):
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.overrideredirect(True)
|
root.overrideredirect(True)
|
||||||
root.withdraw()
|
root.withdraw()
|
||||||
|
@ -13,8 +13,25 @@ def show_image(image_path, box_width=400, box_height=300, hover_header=None, cli
|
||||||
root.attributes("-alpha", 0.85)
|
root.attributes("-alpha", 0.85)
|
||||||
|
|
||||||
img = Image.open(image_path)
|
img = Image.open(image_path)
|
||||||
img.thumbnail((box_width, box_height))
|
|
||||||
|
img_ratio = img.width / img.height
|
||||||
|
box_ratio = max_width / max_height
|
||||||
|
|
||||||
|
if img.width > max_width or img.height > max_height:
|
||||||
|
if img_ratio > box_ratio:
|
||||||
|
new_width = max_width
|
||||||
|
new_height = int(max_width / img_ratio)
|
||||||
|
else:
|
||||||
|
new_height = max_height
|
||||||
|
new_width = int(max_height * img_ratio)
|
||||||
|
try:
|
||||||
|
resample = Image.Resampling.LANCZOS
|
||||||
|
except AttributeError:
|
||||||
|
resample = Image.ANTIALIAS
|
||||||
|
img = img.resize((new_width, new_height), resample)
|
||||||
|
|
||||||
img_tk = ImageTk.PhotoImage(img)
|
img_tk = ImageTk.PhotoImage(img)
|
||||||
|
img_width, img_height = img.size
|
||||||
|
|
||||||
monitors = screeninfo.get_monitors()
|
monitors = screeninfo.get_monitors()
|
||||||
primary_screen = next((m for m in monitors if m.is_primary), monitors[0])
|
primary_screen = next((m for m in monitors if m.is_primary), monitors[0])
|
||||||
|
@ -24,35 +41,40 @@ def show_image(image_path, box_width=400, box_height=300, hover_header=None, cli
|
||||||
screen_width = primary_screen.width
|
screen_width = primary_screen.width
|
||||||
screen_height = primary_screen.height
|
screen_height = primary_screen.height
|
||||||
|
|
||||||
x_pos = screen_x + screen_width - box_width - 20
|
x_pos = screen_x + screen_width - img_width - 20
|
||||||
y_pos = screen_y + screen_height - box_height - 60
|
y_pos = screen_y + screen_height - img_height - 60
|
||||||
|
|
||||||
root.geometry(f"{box_width}x{box_height}+{x_pos}+{y_pos}")
|
root.geometry(f"{img_width}x{img_height}+{x_pos}+{y_pos}")
|
||||||
|
|
||||||
frame = tk.Frame(root, bg="black")
|
label = tk.Label(root, image=img_tk, borderwidth=0)
|
||||||
frame.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
label = tk.Label(frame, image=img_tk, borderwidth=0)
|
|
||||||
label.image = img_tk
|
label.image = img_tk
|
||||||
label.place(relx=0.5, rely=0.5, anchor="center")
|
label.pack()
|
||||||
|
|
||||||
header_label = tk.Label(root, text=hover_header, bg="black", fg="white", font=("Arial", 10))
|
header_label = tk.Label(root, text=hover_header, bg="black", fg="white", font=("Arial", 10))
|
||||||
|
header_visible = [False]
|
||||||
|
|
||||||
def show_header(event):
|
def update_hover_state():
|
||||||
if hover_header:
|
x, y = root.winfo_pointerx() - root.winfo_rootx(), root.winfo_pointery() - root.winfo_rooty()
|
||||||
header_label.place(relx=0.5, rely=0, anchor="n", relwidth=1)
|
inside_label = 0 <= x <= img_width and 0 <= y <= img_height
|
||||||
|
inside_header = header_label.winfo_ismapped() and header_label.winfo_containing(x + root.winfo_rootx(), y + root.winfo_rooty()) is not None
|
||||||
|
|
||||||
def hide_header(event):
|
if hover_header and (inside_label or inside_header):
|
||||||
if hover_header:
|
if not header_visible[0]:
|
||||||
header_label.place_forget()
|
header_label.place(relx=0.5, rely=0, anchor="n", relwidth=1)
|
||||||
|
header_visible[0] = True
|
||||||
|
else:
|
||||||
|
if header_visible[0]:
|
||||||
|
header_label.place_forget()
|
||||||
|
header_visible[0] = False
|
||||||
|
|
||||||
|
root.after(100, update_hover_state)
|
||||||
|
|
||||||
def close_window(event=None):
|
def close_window(event=None):
|
||||||
root.destroy()
|
root.destroy()
|
||||||
|
|
||||||
root.bind("<Button-1>", close_window if click_url is None else lambda e: os.system(f"xdg-open {click_url}"))
|
root.bind("<Button-1>", close_window if click_url is None else lambda e: os.system(f"xdg-open {click_url}"))
|
||||||
root.bind("<Enter>", show_header)
|
|
||||||
root.bind("<Leave>", hide_header)
|
|
||||||
|
|
||||||
|
update_hover_state()
|
||||||
root.after(5000, close_window)
|
root.after(5000, close_window)
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ declare -A ALLOWED_KEYS=(
|
||||||
["x-zipline-image-compression-percent"]="^.+$"
|
["x-zipline-image-compression-percent"]="^.+$"
|
||||||
["x-zipline-original-name"]="^.+$"
|
["x-zipline-original-name"]="^.+$"
|
||||||
["x-zipline-format"]="^.+$"
|
["x-zipline-format"]="^.+$"
|
||||||
|
["x-zipline-domain"]="^.+$"
|
||||||
)
|
)
|
||||||
|
|
||||||
REQUIRED_KEYS=(
|
REQUIRED_KEYS=(
|
||||||
|
|
27
main.sh
27
main.sh
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
[[ "$SCRIPT_DIR" == "/usr/bin" ]] && SCRIPT_DIR="/usr/share/grabit"
|
||||||
|
|
||||||
source "$SCRIPT_DIR/helpers/variables.sh"
|
source "$SCRIPT_DIR/helpers/variables.sh"
|
||||||
source "$SCRIPT_DIR/helpers/installer.sh"
|
source "$SCRIPT_DIR/helpers/installer.sh"
|
||||||
|
@ -136,7 +137,10 @@ if [[ ${#MISSING_COMMANDS[@]} -gt 0 ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
send_notification() {
|
send_notification() {
|
||||||
[[ "$SHOW_NOTIFICATIONS" == "false" ]] && return
|
local force="$4"
|
||||||
|
if [[ "$SHOW_NOTIFICATIONS" == "false" && "$force" != "true" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
local title="$1"
|
local title="$1"
|
||||||
local message="$2"
|
local message="$2"
|
||||||
|
@ -320,19 +324,16 @@ fi
|
||||||
|
|
||||||
HEADERS=()
|
HEADERS=()
|
||||||
if [[ "$SERVICE" == "zipline" ]]; then
|
if [[ "$SERVICE" == "zipline" ]]; then
|
||||||
declare -A ZIPLINE_HEADERS
|
mapfile -t zipline_keys < <(get_starting_with "x-zipline" | jq -r 'to_entries[] | "\(.key)=\(.value)"')
|
||||||
ZIPLINE_HEADERS=$(get_starting_with "x-zipline")
|
for entry in "${zipline_keys[@]}"; do
|
||||||
for key in "${!ZIPLINE_HEADERS[@]}"; do
|
key="${entry%%=*}"
|
||||||
header_name="${key#ZIPLINE__}" | tr '[:upper:]' '[:lower:]' | tr '_' '-'
|
value="${entry#*=}"
|
||||||
header_value="${ZIPLINE_HEADERS[$key]}"
|
headers+=("-H" "$key: $value")
|
||||||
headers+=("-H" "$header_name: $header_value")
|
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
headers+=("-H" "${UPLOAD_HEADERS[$SERVICE]}: $AUTH")
|
headers+=("-H" "${UPLOAD_HEADERS[$SERVICE]}: $AUTH")
|
||||||
|
|
||||||
echo headers "${headers[@]}"
|
|
||||||
|
|
||||||
FILE_URL=""
|
FILE_URL=""
|
||||||
RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/upload_response.json \
|
RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/upload_response.json \
|
||||||
-X POST -F "file=@$FILE" "${headers[@]}" "$DOMAIN")
|
-X POST -F "file=@$FILE" "${headers[@]}" "$DOMAIN")
|
||||||
|
@ -344,12 +345,14 @@ rm /tmp/upload_response.json
|
||||||
if [[ "$HTTP_CODE" -ne 200 ]]; then
|
if [[ "$HTTP_CODE" -ne 200 ]]; then
|
||||||
echo -e "${RED}Error: Upload failed with status code $HTTP_CODE.${RESET}"
|
echo -e "${RED}Error: Upload failed with status code $HTTP_CODE.${RESET}"
|
||||||
echo "$BODY"
|
echo "$BODY"
|
||||||
|
send_notification "Upload failed" "Status code: $HTTP_CODE" "" "true"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! echo "$BODY" | jq . &>/dev/null; then
|
if ! echo "$BODY" | jq . &>/dev/null; then
|
||||||
echo -e "${RED}Error: Invalid JSON response from server.${RESET}"
|
echo -e "${RED}Error: Invalid JSON response from server.${RESET}"
|
||||||
echo "$BODY"
|
echo "$BODY"
|
||||||
|
send_notification "Upload failed" "Invalid JSON from $SERVICE" "" "true"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -357,6 +360,7 @@ FILE_URL=$(echo "$BODY" | jq -r ".${UPLOAD_JSON_KEYS[$SERVICE]}")
|
||||||
if [[ "$FILE_URL" == "null" || -z "$FILE_URL" ]]; then
|
if [[ "$FILE_URL" == "null" || -z "$FILE_URL" ]]; then
|
||||||
echo -e "${RED}Error: File URL not found in response.${RESET}"
|
echo -e "${RED}Error: File URL not found in response.${RESET}"
|
||||||
echo "$BODY"
|
echo "$BODY"
|
||||||
|
send_notification "Upload failed" "Missing file URL in response" "" "true"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -385,7 +389,10 @@ if [[ "$MIME_TYPE" == image/* ]]; then
|
||||||
else
|
else
|
||||||
if [[ "$SHOW_NOTIFICATIONS" == "true" ]]; then
|
if [[ "$SHOW_NOTIFICATIONS" == "true" ]]; then
|
||||||
send_notification "Uploaded to $SERVICE" "$FILE_URL"
|
send_notification "Uploaded to $SERVICE" "$FILE_URL"
|
||||||
play_sound
|
play_sound
|
||||||
|
else
|
||||||
|
send_notification "Uploaded to $SERVICE" "$FILE_URL" "" "true"
|
||||||
|
play_sound
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue