Skip to content

Commit

Permalink
Add support for uploading Viber stickers
Browse files Browse the repository at this point in the history
  • Loading branch information
laggykiller committed Jun 9, 2024
1 parent b0e02aa commit 9dacb5a
Show file tree
Hide file tree
Showing 20 changed files with 647 additions and 21 deletions.
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ RUN wget -O- https://updates.signal.org/desktop/apt/keys.asc | gpg --dearmor > s
apt update -y && \
apt install --no-install-recommends -y signal-desktop

# Install Viber Desktop
RUN curl -o /tmp/viber.deb -L https://download.cdn.viber.com/cdn/desktop/Linux/viber.deb && \
apt install --no-install-recommends -y /tmp/viber.deb libgl1 libevent-2.1-7 libwebpdemux2 libxslt1.1 libxkbfile1 libegl1 libopengl0 libqt5gui5 && \
rm /tmp/viber.deb

RUN apt purge -y curl wget gpg git && \
apt clean autoclean && \
apt autoremove --yes && \
Expand Down
38 changes: 25 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,27 @@ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--cus
[--input-dir INPUT_DIR]
[--download-auto DOWNLOAD_AUTO | --download-signal DOWNLOAD_SIGNAL | --download-telegram DOWNLOAD_TELEGRAM | --download-line DOWNLOAD_LINE | --download-kakao DOWNLOAD_KAKAO | --download-viber DOWNLOAD_VIBER]
[--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE]
[--export-signal | --export-telegram | --export-telegram-emoji | --export-whatsapp | --export-imessage]
[--export-signal | --export-telegram | --export-telegram-emoji | --export-whatsapp | --export-viber | --export-imessage]
[--no-compress]
[--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,imessage_small,imessage_medium,imessage_large,custom}]
[--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
[--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
[--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
[--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
[--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
[--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--padding-percent PADDING_PERCENT]
[--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX]
[--vid-format VID_FORMAT] [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER]
[--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
[--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
[--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX]
[--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX]
[--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX]
[--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX]
[--padding-percent PADDING_PERCENT] [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX]
[--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT] [--img-format IMG_FORMAT]
[--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD]
[--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID]
[--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
[--signal-data-dir SIGNAL_DATA_DIR] [--telegram-token TELEGRAM_TOKEN]
[--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth]
[--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
[--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN]
[--kakao-get-auth] [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
[--kakao-country-code KAKAO_COUNTRY_CODE] [--kakao-phone-number KAKAO_PHONE_NUMBER]
[--line-get-auth] [--line-cookies LINE_COOKIES] [--save-cred SAVE_CRED]
[--line-get-auth] [--line-cookies LINE_COOKIES] [--viber-auth VIBER_AUTH]
[--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH]
[--save-cred SAVE_CRED]
CLI for stickers-convert
Expand Down Expand Up @@ -163,6 +166,7 @@ Output options:
--export-telegram-emoji
Upload to Telegram (Custom emoji)
--export-whatsapp Create a .wastickers file for uploading to WhatsApp
--export-viber Upload to Viber
--export-imessage Create Xcode project for importing to iMessage
Compression options:
Expand Down Expand Up @@ -281,6 +285,14 @@ Credentials options:
--line-get-auth Get Line cookies from browser, which is required to create custom message stickers.
--line-cookies LINE_COOKIES
Set Line cookies, which is required to create custom message stickers.
--viber-auth VIBER_AUTH
Set Viber authentication data.
Required for uploading Viber stickers.
--viber-get-auth VIBER_GET_AUTH
Generate Viber authentication data.
--viber-bin-path VIBER_BIN_PATH
Specify location of Viber Desktop application.
Useful for portable installation.
--save-cred SAVE_CRED
Save Signal and Telegram credentials.
```
Expand Down Expand Up @@ -453,5 +465,5 @@ See [docs/TODO.md](docs/TODO.md)
- Banner generated from [GitHub Socialify](https://socialify.git.ci/)

## DISCLAIMER
- The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao or Sticker Maker.
- The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao, Viber, iMessage or Sticker Maker.
- The author of this repo is NOT repsonsible for any legal consequences and loss incurred from using this repo.
21 changes: 18 additions & 3 deletions docs/guide_viber.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
# Downloading Viber stickers
sticker-convert supports downloading viber stickers from share link of sticker pack.

sticker-convert can also convert images to png with 490x490 for uploading to viber manually.
It should be noted that Viber is able to resize images for you, so it may not be necessary
to use sticker-convert for creating Viber sticker pack.
# Uploading Viber stickers
Viber authentication data required for uploading Viber stickers, which could be fetched
from Viber Desktop application automatically:
1. Install Viber Desktop
2. Login to Viber Desktop
3. In sticker-convert, press `Generate` button (In GUI) or `--viber-get-auth` (In CLI)

Notice:
- Viber Desktop would be closed, launched and closed again when getting auth data.
- It may take a minute to get auth data.
- On macOS, you need to disable SIP and will be asked for user password.
- For atypical installation of Viber Desktop, you may specify Viber Desktop application
location by using `--viber-bin-path`.
- `m_token`, `m_ts` and `member_id` are required.
- `m_ts` is the unix timestamp when `m_token` is generated.
- `m_token` expires after 13800 seconds (230 minutes).

# References
For more info, please refer to https://help.viber.com/hc/en-us/articles/9204828903837-Use-and-create-stickers-on-Rakuten-Viber
1 change: 1 addition & 0 deletions requirements-type.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
types-beautifulsoup4
types-psutil
types-Pillow
types-requests
types-tqdm
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ numpy>=1.22.4
Pillow~=10.3.0
pyoxipng~=9.0.0
python-telegram-bot~=21.2
psutil~=5.9.8
PyMemoryEditor~=1.5.22
requests~=2.32.3
rlottie_python~=1.3.5
signalstickers-client-fork-laggykiller~=3.3.0.post2
Expand Down
18 changes: 18 additions & 0 deletions src/sticker_convert/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
from sticker_convert.utils.auth.get_line_auth import GetLineAuth
from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
from sticker_convert.utils.callback import Callback
from sticker_convert.utils.files.json_manager import JsonManager
from sticker_convert.utils.url_detect import UrlDetect
Expand Down Expand Up @@ -452,6 +453,9 @@ def get_opt_cred(self, args: Namespace) -> CredOption:
line_cookies=args.line_cookies
if args.line_cookies
else creds.get("line", {}).get("cookies"),
viber_auth=args.viber_auth
if args.viber_auth
else creds.get("viber", {}).get("auth"),
)

if args.kakao_get_auth:
Expand Down Expand Up @@ -501,6 +505,20 @@ def get_opt_cred(self, args: Namespace) -> CredOption:
"Failed to get Line cookies. Have you logged in the web browser?"
)

if args.viber_get_auth:
get_viber_auth = GetViberAuth()

viber_bin_path = None
if args.viber_bin_path:
viber_bin_path = args.viber_bin_path

viber_auth, msg = get_viber_auth.get_cred(viber_bin_path)

if viber_auth:
opt_cred.viber_auth = viber_auth

self.cb.msg(msg)

if args.save_cred:
creds_path = CONFIG_DIR / "creds.json"
JsonManager.save_json(creds_path, opt_cred.to_dict())
Expand Down
9 changes: 9 additions & 0 deletions src/sticker_convert/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ def declare_variables(self) -> None:
self.kakao_country_code_var = StringVar(self)
self.kakao_phone_number_var = StringVar(self)
self.line_cookies_var = StringVar(self)
self.viber_auth_var = StringVar(self)
self.viber_bin_path_var = StringVar(self)

# Config
self.settings_save_cred_var = BooleanVar()
Expand Down Expand Up @@ -385,6 +387,7 @@ def apply_creds(self) -> None:
self.creds.get("kakao", {}).get("phone_number", "")
)
self.line_cookies_var.set(self.creds.get("line", {}).get("cookies", ""))
self.viber_auth_var.set(self.creds.get("viber", {}).get("auth", ""))

def get_input_name(self) -> str:
return [
Expand Down Expand Up @@ -545,6 +548,7 @@ def get_opt_cred(self) -> CredOption:
kakao_country_code=self.kakao_country_code_var.get(),
kakao_phone_number=self.kakao_phone_number_var.get(),
line_cookies=self.line_cookies_var.get(),
viber_auth=self.viber_auth_var.get(),
)

def start_process(self) -> None:
Expand Down Expand Up @@ -771,6 +775,11 @@ def highlight_fields(self) -> bool:
else:
self.cred_frame.telegram_userid_entry.config(bootstyle="default") # type: ignore

if output_option == "viber" and not self.viber_auth_var.get():
self.cred_frame.viber_auth_entry.config(bootstyle="warning") # type: ignore
else:
self.cred_frame.viber_auth_entry.config(bootstyle="default") # type: ignore

if (
urlparse(url).netloc == "e.kakao.com"
and not self.kakao_auth_token_var.get()
Expand Down
21 changes: 21 additions & 0 deletions src/sticker_convert/gui_components/frames/cred_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from sticker_convert.gui_components.windows.kakao_get_auth_window import KakaoGetAuthWindow
from sticker_convert.gui_components.windows.line_get_auth_window import LineGetAuthWindow
from sticker_convert.gui_components.windows.signal_get_auth_window import SignalGetAuthWindow
from sticker_convert.gui_components.windows.viber_get_auth_window import ViberGetAuthWindow

if TYPE_CHECKING:
from sticker_convert.gui import GUI # type: ignore
Expand Down Expand Up @@ -103,6 +104,20 @@ def __init__(self, gui: "GUI", *args: Any, **kwargs: Any) -> None:
bootstyle="secondary", # type: ignore
)

self.viber_auth_lbl = Label(
self, text="Viber auth", width=18, justify="left", anchor="w"
)
self.viber_auth_entry = Entry(
self, textvariable=self.gui.viber_auth_var, width=35
)
self.viber_auth_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
self.viber_get_auth_btn = Button(
self,
text="Generate",
command=self.cb_viber_get_auth,
bootstyle="secondary", # type: ignore
)

self.help_btn = Button(
self,
text="Get help",
Expand Down Expand Up @@ -133,6 +148,9 @@ def __init__(self, gui: "GUI", *args: Any, **kwargs: Any) -> None:
self.line_cookies_lbl.grid(column=0, row=6, sticky="w", padx=3, pady=3)
self.line_cookies_entry.grid(column=1, row=6, sticky="w", padx=3, pady=3)
self.line_get_auth_btn.grid(column=2, row=6, sticky="e", padx=3, pady=3)
self.viber_auth_lbl.grid(column=0, row=7, sticky="w", padx=3, pady=3)
self.viber_auth_entry.grid(column=1, row=7, sticky="w", padx=3, pady=3)
self.viber_get_auth_btn.grid(column=2, row=7, sticky="e", padx=3, pady=3)
self.help_btn.grid(column=2, row=8, sticky="e", padx=3, pady=3)

def cb_cred_help(self, *_: Any) -> None:
Expand All @@ -150,6 +168,9 @@ def cb_signal_get_auth(self, *_: Any) -> None:
def cb_line_get_auth(self, *_: Any) -> None:
LineGetAuthWindow(self.gui)

def cb_viber_get_auth(self, *_: Any) -> None:
ViberGetAuthWindow(self.gui)

def set_states(self, state: str) -> None:
self.signal_uuid_entry.config(state=state)
self.signal_password_entry.config(state=state)
Expand Down
143 changes: 143 additions & 0 deletions src/sticker_convert/gui_components/windows/viber_get_auth_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
import platform
from functools import partial
from pathlib import Path
from subprocess import Popen
from tkinter import filedialog
from typing import Any

from ttkbootstrap import Button, Entry, Frame, Label # type: ignore

from sticker_convert.gui_components.gui_utils import GUIUtils
from sticker_convert.gui_components.windows.base_window import BaseWindow
from sticker_convert.utils.auth.get_viber_auth import GetViberAuth


class ViberGetAuthWindow(BaseWindow):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

self.title("Get Viber auth data")

self.cb_msg_block_viber = partial(self.gui.cb_msg_block, parent=self)
self.cb_ask_str_viber = partial(self.gui.cb_ask_str, parent=self)

self.frame_info = Frame(self.scrollable_frame)
self.frame_btns = Frame(self.scrollable_frame)
self.frame_config = Frame(self.scrollable_frame)

self.frame_info.grid(column=0, row=0, sticky="news", padx=3, pady=3)
self.frame_btns.grid(column=0, row=1, sticky="news", padx=3, pady=3)
self.frame_config.grid(column=0, row=2, sticky="news", padx=3, pady=3)

# Info frame
self.explanation_lbl0 = Label(
self.frame_info,
text="Please install Viber Desktop and login first.",
justify="left",
anchor="w",
)
self.explanation_lbl1 = Label(
self.frame_info,
text="It may take a minute to get auth data.",
justify="left",
anchor="w",
)
self.explanation_lbl2 = None
if platform.system() == "Darwin":
self.explanation_lbl2 = Label(
self.frame_info,
text="You need to disable SIP and will be asked for user password.",
justify="left",
anchor="w",
)

self.explanation_lbl0.grid(column=0, row=0, sticky="w", padx=3, pady=3)
self.explanation_lbl1.grid(column=0, row=1, sticky="w", padx=3, pady=3)
if self.explanation_lbl2 is not None:
self.explanation_lbl2.grid(column=0, row=2, sticky="w", padx=3, pady=3)

# Start button frame
self.launch_btn = Button(
self.frame_btns,
text="Launch Viber Desktop",
command=self.cb_launch_viber,
bootstyle="secondary", # type: ignore
)

self.get_cred_btn = Button(
self.frame_btns,
text="Get auth data",
command=self.cb_get_cred,
bootstyle="default", # type: ignore
)

self.launch_btn.pack()
self.get_cred_btn.pack()

# Config frame
self.setdir_lbl = Label(
self.frame_config,
text=self.gui.help["cred"]["viber_bin_path"],
justify="left",
anchor="w",
)

self.setdir_entry = Entry(
self.frame_config,
textvariable=self.gui.viber_bin_path_var,
width=32,
)
self.setdir_btn = Button(
self.frame_config,
text="Choose",
command=self.cb_setdir,
width=8,
bootstyle="secondary", # type: ignore
)

self.setdir_lbl.grid(column=0, row=0, columnspan=2, sticky="w", padx=3, pady=3)
self.setdir_entry.grid(column=0, row=1, sticky="w", padx=3, pady=3)
self.setdir_btn.grid(column=1, row=1, sticky="e", padx=3, pady=3)

GUIUtils.finalize_window(self)

def cb_get_cred(self) -> None:
m = GetViberAuth()

viber_bin_path = None
if self.gui.viber_bin_path_var.get():
viber_bin_path = self.gui.viber_bin_path_var.get()

viber_auth, msg = m.get_cred(viber_bin_path)

if viber_auth:
if not self.gui.creds.get("viber"):
self.gui.creds["viber"] = {}
self.gui.creds["viber"]["auth"] = viber_auth
self.gui.viber_auth_var.set(viber_auth)

self.gui.save_creds()
self.gui.highlight_fields()

self.cb_msg_block_viber(msg)

def cb_launch_viber(self) -> None:
m = GetViberAuth()
viber_bin_path = m.get_viber_desktop()

if self.gui.viber_auth_var.get():
viber_bin_path = self.gui.viber_auth_var.get()

if viber_bin_path:
Popen([viber_bin_path])
else:
self.cb_msg_block_viber("Error: Viber Desktop not installed.")

def cb_setdir(self) -> None:
orig_input_dir = self.gui.viber_bin_path_var.get()
if not Path(orig_input_dir).is_dir():
orig_input_dir = ""
input_dir = filedialog.askdirectory(initialdir=orig_input_dir)
if input_dir:
self.gui.viber_bin_path_var.set(input_dir)
Loading

0 comments on commit 9dacb5a

Please sign in to comment.