diff --git a/README.md b/README.md index 174ecdb..b048926 100644 --- a/README.md +++ b/README.md @@ -4,42 +4,56 @@ ## 📘 Overview -`tsticker` is a command-line interface (CLI) tool designed to streamline the creation and management of Telegram -stickers. It automatically adjusts image sizes and suggests appropriate emojis based on image names. The tool supports -both static and animated stickers (in webm format). +`tsticker` is a telegram sticker pack management cli. -Just by adding or deleting files, you can easily update the contents of your sticker pack - making it incredibly -user-friendly! +Just put your images in the `/stickers` directory and run `tsticker push` to override your cloud sticker +with local stickers. ![intro](.github/intro.png) -## ✨ Key Features +Or you can use the `tsticker sync` command to override your local sticker pack with the cloud sticker pack. -- **Emoji Suggestions:** Automatically suggests emojis based on image names, enhancing user experience. -- **Automatic Image Adjustment:** Resizes and adjusts images to meet Telegram's sticker requirements. -- **Support for Multiple Sticker Types:** Manages both static and animated stickers seamlessly. -- **git-like Operations:** Follows a workflow similar to Git with `init`, `sync`, and `push` commands. -- **Support Gif Conversion:** No problem with transparent background GIF conversion. +Simple? Yes, it is! -## 📋 Prerequisites +- Auto select emoji for sticker +- Auto resize image for sticker +- Auto convert (gif,webm,mov ...) to webm for animated sticker + +## 📦 Commands -Ensure the following dependencies are installed before using `tsticker`: +| Command | Description | +|---------------------|--------------------------------------------------------------------------------------------------| +| `tsticker init` | Initializes a new sticker pack. | +| `tsticker sync` | **Override**, Syncs the sticker pack from your local directory with changes from the cloud. | +| `tsticker push` | **Override**, Pushes changes from your local directory to the cloud, updating existing stickers. | +| `tsticker login` | Logs in to your Telegram account. | +| `tsticker logout` | Logs out of your Telegram account. | +| `tsticker help` | Displays help information for the CLI. | +| `tsticker download` | Downloads the sticker pack from the cloud to your local directory. | +| `tsticker trace` | Import cloud sticker pack from url. | -| Dependency | Installation Link | -|------------|-----------------------------------------------------| -| **ffmpeg** | [Download ffmpeg](https://ffmpeg.org/download.html) | +| Example | Description | +|------------------------------------------------------------------|------------------------------------------| +| `tsticker init -s regular -n 'sticker_id' -t 'My sticker title'` | Initialize a new sticker | +| `tsticker sync` | Sync sticker pack | +| `tsticker push` | Push sticker pack | +| `tsticker login -t -u ` | Log in to Telegram | +| `tsticker logout` | Log out of Telegram | +| `tsticker download -l ` | Download sticker pack, cant make changes | +| `tsticker trace -l ` | Import sticker pack(can make changes) | -## 🛠️ Installation +**If you encounter any issues, please [create a new Issue](https://github.com/sudoskys/tsticker/issues) on our GitHub +repository.** -### Installing Dependencies +## 📋 Prerequisites -Install necessary dependencies based on your operating system: +Wait! Before installing `tsticker`, ensure that your computer meets the following requirements: -You need install [ImageMagick](https://docs.wand-py.org/en/0.6.12/guide/install.html) before using this CLI. +- [install ffmpeg](https://ffmpeg.org/download.html) -Install Guide: https://docs.wand-py.org/en/0.6.12/guide/install.html +- [install ImageMagick](https://docs.wand-py.org/en/0.6.12/guide/install.html) -### Installing `tsticker` +## Installing `tsticker` The recommended way to install `tsticker` is through `pipx` for isolated environments: @@ -60,9 +74,14 @@ If you want to upgrade `tsticker` to the latest version, use the following comma pipx upgrade tsticker ``` -## 🔑 Bot Token Setup +## 🔑 Login with Telegram -To create and manage stickers with `tsticker`, you need a Telegram Bot Token. Follow these steps: +We need create a bot as a bridge to manage stickers. + +Remember the bot can **only** **auto** manage stickers **created by the bot itself**, once you lost your bot, you can +only manage stickers manually. + +To create and manage stickers with `tsticker`, you need a **Telegram Bot Token**. Follow these steps: 1. Open Telegram and search for the [BotFather](https://t.me/BotFather) bot. 2. Start a conversation with BotFather and send the command `/newbot`. @@ -70,76 +89,46 @@ To create and manage stickers with `tsticker`, you need a Telegram Bot Token. Fo The bot token provided by BotFather will be used as your `BotToken`. -We use https://pypi.org/project/keyring/ to manage your tokens, which may require additional steps. If you encounter -problems, refer to: https://github.com/jaraco/keyring - -## 🚀 Usage - -### Initial Setup +Win + R, type `cmd`, and press Enter to open the command prompt. Run the following command to login -**Log in to your Telegram account:** +Replace `` with your Telegram bot token and `` with your Telegram user ID (you can get your user ID +from [getidsbot](https://t.me/getidsbot) by sending `/my_id`). ```bash tsticker login -t -u ``` -Replace `` with your Telegram bot token and `` with your Telegram user ID (you can get your user ID -from [getidsbot](https://t.me/getidsbot)). - -### Main Commands - -| Command | Description | -|-----------------|------------------------------------------------------------------------------------| -| `tsticker init` | Initializes a new sticker pack. | -| `tsticker sync` | Syncs the sticker pack from your local directory with changes from the cloud. | -| `tsticker push` | Pushes changes from your local directory to the cloud, updating existing stickers. | - -**Example usage:** - -```bash -mkdir -cd -tsticker init -n -t -``` +We use https://pypi.org/project/keyring/ to manage your tokens, which may require additional steps. If you encounter +problems, refer to: https://github.com/jaraco/keyring -- ``: The desired directory name for your sticker pack. -- ``: The title for your sticker pack. +## Adding or Removing Stickers -### Adding or Removing Stickers +Just put your images in the `/stickers` directory and run `tsticker push` to override your cloud sticker pack with +the local sticker pack. We support almost all image formats, including `png`, `jpg`, `jpeg`, `gif`, `webm`, and +`mov` and so on. -To manage your stickers, simply add or remove images or animated files (GIFs/WebMs) in `/stickers` directory. After -making changes, use the following command to synchronize with your Telegram sticker pack: +Please don't operate lots of stickers at once time, if there is any error, it will break your workflow, but you can +use `tsticker sync` to recover. ```bash tsticker push ``` -If you encounter any issues, please [create a new Issue](https://github.com/sudoskys/tsticker/issues) on our GitHub -repository. +even there are auto-resize and auto-convert, there still have some bad input such as too large image, too long video, so +be careful. -## ⚠️ Important Notes +## Limitations of `tsticker` -| Note | Description | -|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **No Support for Tgs Stickers** | `tgs` format is not supported for this cli. | -| **Rate Limiting** | Each request is throttled to 2 seconds to avoid being blocked by Telegram. | -| **Limited Emoji Auto-Selection** | Automatic emoji selection may not work optimally for all languages, primarily supported for English. check `github@telegram_sticker_utils:telegram_sticker_utils/core/rules.json` | -| **Rate Limits** | Avoid excessive uploads in a short period to prevent Telegram from throttling your bot's actions. | -| **Security** | Keep your bot token secure. Stickers can only be managed through your bot or the official @Stickers bot by the sticker pack creator. | +| Note | Description | +|---------------------------------|----------------------------------------------------------------------------------------------------------------------| +| **No Support for Tgs Stickers** | `tgs` format is not supported for this cli. We using mixed `png` and `webm` format for static and animated stickers. | +| **Rate Limiting** | Each request is throttled to 2 seconds to avoid being blocked by Telegram. | +| **Only Bot User** | Stickers can only be managed through your bot or the official @Stickers bot by the sticker pack creator. | ## 📄 License `tsticker` is released under the MIT License. See [LICENSE](LICENSE) for more information. -## 🤝 Contributing - -Contributions are welcome! If you want to contribute, please follow our [Contributing Guide](CONTRIBUTING.md). - -## 🙏 Acknowledgments - -Special thanks to all contributors who have made `tsticker` better. For issues or feature requests, please use -the [GitHub issue tracker](https://github.com/sudoskys/tsticker/issues). - --- Enhance your Telegram sticker creation process with `tsticker` and become part of our community striving to simplify diff --git a/src/tsticker/cli.py b/src/tsticker/cli.py index 2c7b29e..1311a01 100644 --- a/src/tsticker/cli.py +++ b/src/tsticker/cli.py @@ -321,22 +321,21 @@ async def logout(): @asyncclick.command() -@asyncclick.option('-d', '--download-dir', default='.', help='Directory to download stickers') @asyncclick.option('-l', '--link', required=True, help='Link for downloading stickers') -async def download(download_dir: str, link: str): +async def download(link: str): """Download stickers from Telegram.""" credentials = get_credentials() if not credentials: - console.print("[bold red]You are not logged in. Please login first.[/]") + console.print("[bold red]You are not logged in. To access telegram api, you need to login first.[/]") return pack_name = link.removesuffix("/").split("/")[-1] - download_dir = pathlib.Path(download_dir) - if not download_dir.exists(): - console.print(f"[bold red]Download directory does not exist: {download_dir}[/]") + root_download_dir = pathlib.Path(os.getcwd()) + if not root_download_dir.exists(): + console.print(f"[bold red]Download directory does not exist: {root_download_dir}[/]") return - console.print(f"[bold blue]Preparing to download pack: {pack_name} to {download_dir.as_posix()}[/]") + console.print(f"[bold blue]Preparing to download pack: {pack_name} to {root_download_dir.as_posix()}[/]") telegram_bot = AsyncTeleBot(credentials.token) - await download_sticker_set(pack_name, telegram_bot, download_dir) + await download_sticker_set(pack_name, telegram_bot, root_download_dir) console.print("[bold green]Download completed![/]") @@ -351,21 +350,29 @@ async def trace(link: str): _pack_name = link.removesuffix("/").split("/")[-1] try: telegram_bot = AsyncTeleBot(credentials.token) - cloud_sticker_set = await limited_request( + cloud_sticker_set: StickerSet = await limited_request( AsyncTeleBot(credentials.token).get_sticker_set(_pack_name) ) except Exception as e: - console.print(f"[bold red]Failed to get sticker set for {_pack_name}: {e}[/]") + console.print( + f"[bold red]Cant fetch stickers named {_pack_name}: {e}, you cant import a non-exist pack.[/]" + ) return console.print( - f"[bold blue]Cloud sticker with pack name:[/] {cloud_sticker_set.pack_name}\n" - f"[bold blue]Pack Title:[/] {cloud_sticker_set.pack_title} \n" + f"[bold blue]Cloud sticker with pack name:[/] {cloud_sticker_set.name}\n" + f"[bold blue]Pack Title:[/] {cloud_sticker_set.title} \n" f"[bold blue]Sticker Type:[/] {cloud_sticker_set.sticker_type}" ) + if not cloud_sticker_set.name.endswith("_by_" + credentials.bot_user.username): + console.print( + f"[bold red]You can only change sticker-set created by BOT USER now logged: @{credentials.bot_user.username} {credentials.bot_user.full_name}[/]" + ) + console.print(f"[bold red]The pack name should end with `_by_{credentials.bot_user.username}` [/]") + return root_dir = pathlib.Path(os.getcwd()) # 尝试使用 Packname 创建文件夹 try: - sticker_dir = root_dir.joinpath(cloud_sticker_set.pack_name) + sticker_dir = root_dir.joinpath(cloud_sticker_set.name) if sticker_dir.exists(): console.print(f"[bold red]Pack directory already exists:[/] {sticker_dir}") return @@ -377,10 +384,10 @@ async def trace(link: str): index_file = sticker_dir.joinpath("index.json") index_file.write_text( StickerIndexFile.create( - title=cloud_sticker_set.pack_title, - name=cloud_sticker_set.pack_name, + title=cloud_sticker_set.title, + name=cloud_sticker_set.name, sticker_type=cloud_sticker_set.sticker_type, - operator_id=str(cloud_sticker_set.bot_user.id) + operator_id=str(credentials.bot_user.id) ).model_dump_json(indent=2) ) # 创建资源文件夹 @@ -457,7 +464,8 @@ async def init( # 创建 App with console.status("[bold blue]Retrieving sticker...[/]", spinner='dots'): try: - sticker_set = await limited_request(telegram_bot.get_sticker_set(index_file_model.name)) + sticker_set: Optional[StickerSet] = await limited_request( + telegram_bot.get_sticker_set(index_file_model.name)) except Exception as e: if "STICKERSET_INVALID" in str(e): sticker_set = None @@ -513,7 +521,7 @@ async def sync(): return with console.status("[bold magenta]Retrieving sticker...[/]", spinner='dots'): try: - now_sticker_set = await limited_request( + now_sticker_set: Optional[StickerSet] = await limited_request( telegram_bot.get_sticker_set(local_sticker.name) ) except Exception as e: @@ -753,7 +761,7 @@ async def push(): # 获取云端文件 with console.status("[bold yellow]Retrieving sticker...[/]", spinner='dots'): try: - sticker_set = await limited_request(telegram_bot.get_sticker_set(local_sticker.name)) + sticker_set: Optional[StickerSet] = await limited_request(telegram_bot.get_sticker_set(local_sticker.name)) except Exception as e: if "STICKERSET_INVALID" in str(e): sticker_set = None @@ -772,7 +780,7 @@ async def push(): # 同步索引文件 with console.status("[bold yellow]Synchronizing index...[/]", spinner='dots'): try: - sticker_set = await limited_request(telegram_bot.get_sticker_set(local_sticker.name)) + sticker_set: Optional[StickerSet] = await limited_request(telegram_bot.get_sticker_set(local_sticker.name)) except Exception as e: if "STICKERSET_INVALID" in str(e): sticker_set = None