anifetch-cli 1.0.1__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. {anifetch_cli-1.0.1/src/anifetch_cli.egg-info → anifetch_cli-1.0.4}/PKG-INFO +43 -6
  2. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/README.md +43 -6
  3. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/pyproject.toml +1 -1
  4. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/cli.py +24 -1
  5. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/core.py +74 -41
  6. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/renderer.py +3 -1
  7. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/utils.py +147 -4
  8. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4/src/anifetch_cli.egg-info}/PKG-INFO +43 -6
  9. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/LICENSE +0 -0
  10. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/setup.cfg +0 -0
  11. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/__init__.py +0 -0
  12. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/__main__.py +0 -0
  13. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/assets/example.mp4 +0 -0
  14. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch/keyreader.py +0 -0
  15. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch_cli.egg-info/SOURCES.txt +0 -0
  16. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch_cli.egg-info/dependency_links.txt +0 -0
  17. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch_cli.egg-info/entry_points.txt +0 -0
  18. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch_cli.egg-info/requires.txt +0 -0
  19. {anifetch_cli-1.0.1 → anifetch_cli-1.0.4}/src/anifetch_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anifetch-cli
3
- Version: 1.0.1
3
+ Version: 1.0.4
4
4
  Summary: Animated terminal fetch with video and audio support.
5
5
  Author-email: Notenlish <notenlish@gmail.com>
6
6
  Maintainer: Immelancholy
@@ -33,11 +33,34 @@ This is a small tool built with fastfetch/neofetch, ffmpeg and chafa. It allows
33
33
 
34
34
  ## Installation
35
35
 
36
- ### Installation for Linux
36
+ **Quick Links Installation Guide For:**
37
37
 
38
- Recommended Python version: 3.11 and later. If you use NixOS refer to [Installation for NixOS](#installation-for-nixos).
38
+ [Linux](#installation-for-linux-system) • [Windows](#installation-for-windows-winget-or-scoop) • [macOS](#installation-for-macos-homebrew)• [Manual](#manual-installation) • [Development](#developer-installation)
39
39
 
40
- Run this in the terminal.
40
+ ### Installation for Linux System
41
+ Recommended Python version: 3.11 and later.
42
+
43
+ #### Installation for Arch / Arch-based distros (Community maintained)
44
+
45
+ Anifetch is available in the AUR package [anifetch-cli](https://aur.archlinux.org/packages/anifetch-cli), maintained by @AmmarSyamil.
46
+
47
+ Install it from the terminal. For example, with Yay:
48
+
49
+ ```bash
50
+ yay -S anifetch-cli
51
+ ```
52
+
53
+ After installation, run this to test if anifetch was installed correctly:
54
+
55
+ ```bash
56
+ anifetch example.mp4
57
+ ```
58
+ Please read our [User guide](#user-guide) for more info on how to use anifetch.
59
+
60
+ #### Installation for other Linux Distro.
61
+ If you use NixOS refer to Installation for [NixOS](#installation-for-nixos).
62
+
63
+ Install it from the terminal. For example, with Yay:
41
64
 
42
65
  ```bash
43
66
  curl https://raw.githubusercontent.com/Notenlish/anifetch/refs/heads/main/install.sh | bash
@@ -49,10 +72,12 @@ After installation, run this to test if anifetch was installed correctly:
49
72
  anifetch example.mp4
50
73
  ```
51
74
 
75
+
52
76
  Please read our [User guide](#user-guide) for more info on how to use anifetch.
53
77
 
54
78
  ---
55
79
 
80
+
56
81
  ### Installation for Windows (Winget or Scoop)
57
82
 
58
83
  Check whether you have winget installed by running `winget` in the windows terminal. If you dont have it, install it [here](https://github.com/microsoft/winget-cli/?tab=readme-ov-file#installing-the-client). If you want, you can use [Scoop](https://scoop.sh/) instead. Just replace the `winget` part with `scoop`.
@@ -72,7 +97,10 @@ After installing the necessary dependencies using winget/scoop, install anifetch
72
97
  > [!WARNING]
73
98
  > **Do not** install `anifetch` on pypi, it is not related with this project. Install `anifetch-cli`.
74
99
 
75
- ### Installation for MacOS with Homebrew
100
+ Please read our [Post installation](#post-installation) and [User guide](#user-guide) for more info on how to use anifetch.
101
+
102
+
103
+ ### Installation for macOS (HomeBrew)
76
104
 
77
105
  Install homebrew if you haven't installed it already by following the guide [here](https://brew.sh/).
78
106
 
@@ -199,7 +227,7 @@ After you've done these steps, rebuild your system.
199
227
 
200
228
  ---
201
229
 
202
- ### Developer Installation (for contributors):
230
+ ### Developer Installation
203
231
 
204
232
  ```bash
205
233
  git clone https://github.com/Notenlish/anifetch.git
@@ -265,6 +293,13 @@ _Note : by default, the video `example.mp4` can directly be used as an example._
265
293
  - `--quality`: Changes the output quality of ffmpeg when extracting frames. This doesn't have much effect on the quality or speed from my testing, so you shouldn't need to change this. 2 highest quality, 10 lowest quality.
266
294
  - `--loop`: Determines how many times the animation should loop. Default is -1(always loop).
267
295
  - `--no-key-exit`: Don't exit anifetch when user presses a key.
296
+ - `--no-input-restore`: Disable restoring pressed keys back into the terminal after stopping Anifetch. Use this if your OS gives security prompts saying `"Anifetch" is requesting special priviliges` when you press a key to stop Anifetch.
297
+ - `-c` / `--config`: Specify a non-default config for Neofetch/Fastfetch.
298
+ - Accepts a path or preset name (e.g. `main`).
299
+ - Neofetch (Linux/macOS): `~/.config/neofetch/main.conf`
300
+ - Fastfetch (Linux/macOS): `~/.config/fastfetch/main.jsonc`
301
+ - Fastfetch (Windows): `%APPDATA%\fastfetch\main.jsonc`
302
+ - See [Customizing Fastfetch/Neofetch](#customizing-fastfetchneofetch-output) for config details.
268
303
 
269
304
  ### Cached files:
270
305
 
@@ -320,6 +355,8 @@ Make sure to install the dependencies listed on [Prerequisites](#Prerequisites).
320
355
 
321
356
  If weird characters are appearing in your terminal then your terminals font probably can't render some characters. Consider installling [nerdfonts](https://www.nerdfonts.com/).
322
357
 
358
+ If your OS is prompting you about `"Anifetch" is requesting special priviliges` or something similiar after pressing a key to stop the running Anifetch instance, add this argument: `--no-input-restore`. The technical reason for this is that Anifetch records the keys you press and enters them back to the terminal on your behalf. That way you can immediately run whatever command you want, without having to re-enter a key or two. Certain OS's have built-in protections against this as a security notice, which is why you might encounter a security prompt.
359
+
323
360
  ## Notes
324
361
 
325
362
  Anifetch attempts to cache the animation so that it doesn't need to render them again when you run it with the same file. However, if the name of the file is the same, but it's contents has changed, it won't re-render it. In that case, you will need to add `--force-render` as an argument to `anifetch.py` so that it re-renders it. You only have to do this only once when you change the file contents.
@@ -6,11 +6,34 @@ This is a small tool built with fastfetch/neofetch, ffmpeg and chafa. It allows
6
6
 
7
7
  ## Installation
8
8
 
9
- ### Installation for Linux
9
+ **Quick Links Installation Guide For:**
10
10
 
11
- Recommended Python version: 3.11 and later. If you use NixOS refer to [Installation for NixOS](#installation-for-nixos).
11
+ [Linux](#installation-for-linux-system) • [Windows](#installation-for-windows-winget-or-scoop) • [macOS](#installation-for-macos-homebrew)• [Manual](#manual-installation) • [Development](#developer-installation)
12
12
 
13
- Run this in the terminal.
13
+ ### Installation for Linux System
14
+ Recommended Python version: 3.11 and later.
15
+
16
+ #### Installation for Arch / Arch-based distros (Community maintained)
17
+
18
+ Anifetch is available in the AUR package [anifetch-cli](https://aur.archlinux.org/packages/anifetch-cli), maintained by @AmmarSyamil.
19
+
20
+ Install it from the terminal. For example, with Yay:
21
+
22
+ ```bash
23
+ yay -S anifetch-cli
24
+ ```
25
+
26
+ After installation, run this to test if anifetch was installed correctly:
27
+
28
+ ```bash
29
+ anifetch example.mp4
30
+ ```
31
+ Please read our [User guide](#user-guide) for more info on how to use anifetch.
32
+
33
+ #### Installation for other Linux Distro.
34
+ If you use NixOS refer to Installation for [NixOS](#installation-for-nixos).
35
+
36
+ Install it from the terminal. For example, with Yay:
14
37
 
15
38
  ```bash
16
39
  curl https://raw.githubusercontent.com/Notenlish/anifetch/refs/heads/main/install.sh | bash
@@ -22,10 +45,12 @@ After installation, run this to test if anifetch was installed correctly:
22
45
  anifetch example.mp4
23
46
  ```
24
47
 
48
+
25
49
  Please read our [User guide](#user-guide) for more info on how to use anifetch.
26
50
 
27
51
  ---
28
52
 
53
+
29
54
  ### Installation for Windows (Winget or Scoop)
30
55
 
31
56
  Check whether you have winget installed by running `winget` in the windows terminal. If you dont have it, install it [here](https://github.com/microsoft/winget-cli/?tab=readme-ov-file#installing-the-client). If you want, you can use [Scoop](https://scoop.sh/) instead. Just replace the `winget` part with `scoop`.
@@ -45,7 +70,10 @@ After installing the necessary dependencies using winget/scoop, install anifetch
45
70
  > [!WARNING]
46
71
  > **Do not** install `anifetch` on pypi, it is not related with this project. Install `anifetch-cli`.
47
72
 
48
- ### Installation for MacOS with Homebrew
73
+ Please read our [Post installation](#post-installation) and [User guide](#user-guide) for more info on how to use anifetch.
74
+
75
+
76
+ ### Installation for macOS (HomeBrew)
49
77
 
50
78
  Install homebrew if you haven't installed it already by following the guide [here](https://brew.sh/).
51
79
 
@@ -172,7 +200,7 @@ After you've done these steps, rebuild your system.
172
200
 
173
201
  ---
174
202
 
175
- ### Developer Installation (for contributors):
203
+ ### Developer Installation
176
204
 
177
205
  ```bash
178
206
  git clone https://github.com/Notenlish/anifetch.git
@@ -238,6 +266,13 @@ _Note : by default, the video `example.mp4` can directly be used as an example._
238
266
  - `--quality`: Changes the output quality of ffmpeg when extracting frames. This doesn't have much effect on the quality or speed from my testing, so you shouldn't need to change this. 2 highest quality, 10 lowest quality.
239
267
  - `--loop`: Determines how many times the animation should loop. Default is -1(always loop).
240
268
  - `--no-key-exit`: Don't exit anifetch when user presses a key.
269
+ - `--no-input-restore`: Disable restoring pressed keys back into the terminal after stopping Anifetch. Use this if your OS gives security prompts saying `"Anifetch" is requesting special priviliges` when you press a key to stop Anifetch.
270
+ - `-c` / `--config`: Specify a non-default config for Neofetch/Fastfetch.
271
+ - Accepts a path or preset name (e.g. `main`).
272
+ - Neofetch (Linux/macOS): `~/.config/neofetch/main.conf`
273
+ - Fastfetch (Linux/macOS): `~/.config/fastfetch/main.jsonc`
274
+ - Fastfetch (Windows): `%APPDATA%\fastfetch\main.jsonc`
275
+ - See [Customizing Fastfetch/Neofetch](#customizing-fastfetchneofetch-output) for config details.
241
276
 
242
277
  ### Cached files:
243
278
 
@@ -293,6 +328,8 @@ Make sure to install the dependencies listed on [Prerequisites](#Prerequisites).
293
328
 
294
329
  If weird characters are appearing in your terminal then your terminals font probably can't render some characters. Consider installling [nerdfonts](https://www.nerdfonts.com/).
295
330
 
331
+ If your OS is prompting you about `"Anifetch" is requesting special priviliges` or something similiar after pressing a key to stop the running Anifetch instance, add this argument: `--no-input-restore`. The technical reason for this is that Anifetch records the keys you press and enters them back to the terminal on your behalf. That way you can immediately run whatever command you want, without having to re-enter a key or two. Certain OS's have built-in protections against this as a security notice, which is why you might encounter a security prompt.
332
+
296
333
  ## Notes
297
334
 
298
335
  Anifetch attempts to cache the animation so that it doesn't need to render them again when you run it with the same file. However, if the name of the file is the same, but it's contents has changed, it won't re-render it. In that case, you will need to add `--force-render` as an argument to `anifetch.py` so that it re-renders it. You only have to do this only once when you change the file contents.
@@ -325,4 +362,4 @@ I dont remember where I got the example.mp4 video from, if you know the source o
325
362
 
326
363
  ## Star History
327
364
 
328
- [![Star History Chart](https://api.star-history.com/svg?repos=Notenlish/anifetch&type=Date)](https://www.star-history.com/#Notenlish/anifetch&Date)
365
+ [![Star History Chart](https://api.star-history.com/svg?repos=Notenlish/anifetch&type=Date)](https://www.star-history.com/#Notenlish/anifetch&Date)
@@ -24,7 +24,7 @@ keywords = [
24
24
  "fastfetch",
25
25
  "anifetch",
26
26
  ]
27
- version = "1.0.1"
27
+ version = "1.0.4"
28
28
  description = "Animated terminal fetch with video and audio support."
29
29
  # If I put everyone here it messes with the "author" meta section.
30
30
  authors = [{ name = "Notenlish", email = "notenlish@gmail.com" }]
@@ -75,7 +75,6 @@ parser.add_argument(
75
75
  help="Disabled by default. Anifetch saves the filename to check if the file has changed, if the name is same, it won't render it again. If enabled, the video will be forcefully rendered, whether it has the same name or not. Please note that it only checks for filename, if you changed the framerate then you'll need to force render.",
76
76
  )
77
77
  parser.add_argument(
78
- "-C",
79
78
  "--center",
80
79
  default=False,
81
80
  action="store_true",
@@ -112,6 +111,16 @@ parser.add_argument(
112
111
  action="store_false",
113
112
  )
114
113
 
114
+ parser.add_argument(
115
+ "--no-input-restore",
116
+ help=(
117
+ "Disable restoring pressed keys back into the terminal after stopping Anifetch. "
118
+ "By default Anifetch re-enters your key presses automatically. "
119
+ "On some systems (eg: Wayland/KDE) Anifetch may trigger a security prompt which can be annoying, add this argument to fix it."
120
+ ),
121
+ action="store_false",
122
+ )
123
+
115
124
  parser.add_argument(
116
125
  "--quality",
117
126
  "-q",
@@ -160,6 +169,7 @@ parser.add_argument(
160
169
  help="Delete one or more caches by number(s) (as listed with --cache-list)",
161
170
  )
162
171
  parser.add_argument(
172
+ "-C",
163
173
  "--clear",
164
174
  required=False,
165
175
  action="store_true",
@@ -174,6 +184,19 @@ parser.add_argument(
174
184
  action="store_true",
175
185
  )
176
186
 
187
+ parser.add_argument(
188
+ "-c",
189
+ "--config",
190
+ default="",
191
+ help="Specify non-default config file for Neofetch/Fastfetch. Use a path or a preset name.\n"
192
+ "Examples:\n"
193
+ "- Linux/macOS:\n"
194
+ " - Neofetch: 'main' → ~/.config/neofetch/main.conf\n"
195
+ " - Fastfetch: 'main' → ~/.config/fastfetch/main.jsonc\n"
196
+ "- Windows:\n"
197
+ " - Fastfetch: 'main' → %%APPDATA%%\\fastfetch\\main.jsonc",
198
+ )
199
+
177
200
 
178
201
  def parse_args():
179
202
  return parser.parse_args()
@@ -16,7 +16,7 @@ from .utils import (
16
16
  get_ext_from_codec,
17
17
  get_data_path,
18
18
  default_asset_presence_check,
19
- get_video_dimensions,
19
+ get_media_dimensions,
20
20
  get_neofetch_status,
21
21
  print_verbose,
22
22
  normal_print,
@@ -32,6 +32,11 @@ from .utils import (
32
32
  get_fetch_output,
33
33
  make_template_from_fetch_lines,
34
34
  clear_screen_soft,
35
+ check_is_video,
36
+ check_is_image,
37
+ check_video_transparency,
38
+ check_image_transparency,
39
+ split_to_frames,
35
40
  )
36
41
  from typing import Literal
37
42
  from concurrent.futures import ThreadPoolExecutor, Future
@@ -126,9 +131,6 @@ def run_anifetch(args):
126
131
  sys.exit(0)
127
132
 
128
133
  filename = pathlib.Path(args.filename)
129
- IS_GIF = False
130
- if args.filename:
131
- IS_GIF = True
132
134
 
133
135
  # If the filename is relative, check if it exists in the assets directory.
134
136
  if not filename.exists():
@@ -143,6 +145,31 @@ def run_anifetch(args):
143
145
  )
144
146
  sys.exit(1)
145
147
 
148
+ if not filename.is_file():
149
+ print("[ERROR] Filename is not a file. Please give an file.")
150
+ sys.exit(1)
151
+
152
+ IS_IMAGE = False
153
+ IS_GIF = False
154
+ IS_VIDEO = False
155
+ IS_TRANSPARENT = False
156
+ if filename.suffix == ".gif":
157
+ IS_GIF = True
158
+ IS_TRANSPARENT = True
159
+ else:
160
+ IS_VIDEO = check_is_video(filename)
161
+ if IS_VIDEO:
162
+ IS_TRANSPARENT = check_video_transparency(filename)
163
+ if not IS_GIF and not IS_VIDEO:
164
+ IS_IMAGE = check_is_image(filename)
165
+ IS_TRANSPARENT = check_image_transparency(filename)
166
+
167
+ if (not IS_GIF) and (not IS_IMAGE) and (not IS_VIDEO):
168
+ print("[ERROR] File is neither a gif, image or video.")
169
+ sys.exit(1)
170
+
171
+ # TODO: make sure image mode also works as well. currently it raises a runtime Error
172
+
146
173
  newpath = ASSET_PATH / filename.name
147
174
 
148
175
  try:
@@ -220,7 +247,7 @@ def run_anifetch(args):
220
247
  # automatically calculate height if not given
221
248
  if should_update and ("--height" not in sys.argv and "-H" not in sys.argv):
222
249
  try:
223
- vid_w, vid_h = get_video_dimensions(ASSET_PATH / args.filename)
250
+ vid_w, vid_h = get_media_dimensions(ASSET_PATH / args.filename)
224
251
  except RuntimeError as e:
225
252
  print(f"[ERROR] {e}")
226
253
  sys.exit(1)
@@ -232,7 +259,7 @@ def run_anifetch(args):
232
259
 
233
260
  # Get the fetch output(neofetch/fastfetch)
234
261
  fetch_output: list[str] = get_fetch_output(
235
- not args.neofetch, neofetch_status, args.force
262
+ not args.neofetch, neofetch_status, args.force, args.config
236
263
  )
237
264
 
238
265
  # copy fetch_output to fetch_lines
@@ -258,38 +285,27 @@ def run_anifetch(args):
258
285
  stdout = None if args.verbose else subprocess.DEVNULL
259
286
  stderr = None if args.verbose else subprocess.PIPE
260
287
 
261
- try:
262
- result_ffmpeg = subprocess.run(
263
- [
264
- "ffmpeg",
265
- "-i",
266
- f"{args.filename}",
267
- "-vf",
268
- f"fps={args.framerate},format=rgba",
269
- "-q:v",
270
- str(
271
- min(max(args.quality or 6, 2), 10)
272
- ), # 2-5 high quality, 6-10 lower
273
- str(CACHE_PATH / "video/%05d.png")
274
- if IS_GIF
275
- else str(CACHE_PATH / "video/%05d.jpg"),
276
- ],
277
- stdout=stdout,
278
- stderr=stderr,
279
- text=True,
280
- )
281
- except FileNotFoundError as e:
282
- if e.errno == errno.ENOENT:
283
- print(
284
- "The command Ffmpeg was not found. You probably forgot to install it. You can install it by going to here: https://ffmpeg.org/download.html\n If you installed Ffmpeg but it still doesn't work, check your PATH."
288
+ if IS_IMAGE:
289
+ shutil.copy(
290
+ args.filename, VIDEO_DIR / f"{0:05d}.{filename.suffix}"
291
+ ) # just a file named 00000.{suffix}
292
+ else: # video or gif
293
+ try:
294
+ result_ffmpeg = split_to_frames(
295
+ args, CACHE_PATH, IS_TRANSPARENT, stdout, stderr
285
296
  )
286
- raise SystemExit
297
+ except FileNotFoundError as e:
298
+ if e.errno == errno.ENOENT:
299
+ print(
300
+ "The command Ffmpeg was not found. You probably forgot to install it. You can install it by going to here: https://ffmpeg.org/download.html\n If you installed Ffmpeg but it still doesn't work, check your PATH."
301
+ )
302
+ raise SystemExit
303
+ else:
304
+ raise
287
305
  else:
288
- raise
289
- else:
290
- if result_ffmpeg.returncode != 0:
291
- print(f"[ERROR] ffmpeg failed: {result_ffmpeg.stderr}")
292
- sys.exit(1)
306
+ if result_ffmpeg.returncode != 0:
307
+ print(f"[ERROR] ffmpeg failed: {result_ffmpeg.stderr}")
308
+ sys.exit(1)
293
309
 
294
310
  print_verbose(should_print_verbose, args.sound_flag_given)
295
311
 
@@ -314,8 +330,6 @@ def run_anifetch(args):
314
330
 
315
331
  cleaned_dict["sound_saved_path"] = args.sound_saved_path
316
332
 
317
- cleaned_dict["sound_saved_path"] = args.sound_saved_path
318
-
319
333
  print_verbose(should_print_verbose, args.sound_saved_path)
320
334
 
321
335
  # If the new anim frames is shorter than the old one, then in /output there will be both new and old frames.
@@ -480,9 +494,26 @@ def run_anifetch(args):
480
494
  else:
481
495
  pass
482
496
 
483
- if renderer.last_key:
497
+ if renderer.last_key and args.no_input_restore:
484
498
  from pynput.keyboard import Controller, Key
485
499
 
500
+ KEY_MAP = {
501
+ # Windows sequences
502
+ "àH": Key.up,
503
+ "àP": Key.down,
504
+ "àK": Key.left,
505
+ "àM": Key.right,
506
+ "\x00H": Key.up,
507
+ "\x00P": Key.down,
508
+ # Unix/macOS ANSI sequences
509
+ "\x1b[A": Key.up,
510
+ "\x1b[B": Key.down,
511
+ "\x1b[C": Key.right,
512
+ "\x1b[D": Key.left,
513
+ "\x1b[H": Key.home,
514
+ "\x1b[F": Key.end,
515
+ }
516
+
486
517
  keyboard = Controller()
487
518
 
488
519
  # needed because if I only enter one key even though the user pressed a bunch of keys the keys will be entered disorderly(only the a single key is not automatically entered and the other keys are entered)
@@ -493,13 +524,15 @@ def run_anifetch(args):
493
524
  keyboard.press(Key.home)
494
525
  keyboard.release(Key.home)
495
526
 
496
- keyboard.press(renderer.last_key)
527
+ translated_key = KEY_MAP.get(renderer.last_key, renderer.last_key)
528
+
529
+ keyboard.press(translated_key)
497
530
 
498
531
  # end of line
499
532
  keyboard.press(Key.end)
500
533
  keyboard.release(Key.end)
501
534
 
502
- keyboard.release(renderer.last_key)
535
+ keyboard.release(translated_key)
503
536
 
504
537
  if pathlib.Path(VIDEO_DIR).exists():
505
538
  shutil.rmtree(VIDEO_DIR) # no need to keep the video frames.
@@ -366,7 +366,9 @@ class Renderer:
366
366
  # index += 1
367
367
 
368
368
  if self.no_key_exit:
369
- k = self.key_reader.poll()
369
+ k = (
370
+ self.key_reader.poll()
371
+ ) # instead of this maybe use pynput.keyboard.listener instead.
370
372
  if k is not None:
371
373
  # if k in ("q", "Q"):
372
374
  self.last_key = k
@@ -234,6 +234,7 @@ def strip_ansi(text):
234
234
  def get_text_length_of_formatted_text(text: str):
235
235
  text = strip_ansi(text)
236
236
  return len(text)
237
+ # return get_character_width(text)
237
238
 
238
239
 
239
240
  def get_ext_from_codec(codec):
@@ -354,15 +355,40 @@ def get_fetch_output(
354
355
  use_fastfetch: bool,
355
356
  neofetch_status: Literal["neofetch", "uninstalled", "wrapper"],
356
357
  force_neofetch: bool,
358
+ config_file: str,
357
359
  ):
358
360
  fetch_output: list[str]
361
+
359
362
  if not use_fastfetch: # use neofetch
360
363
  if (
361
364
  neofetch_status == "wrapper" and force_neofetch
362
365
  ) or neofetch_status == "neofetch":
363
366
  # Get Neofetch Output
367
+
368
+ output: list = ["neofetch", "--off"]
369
+ if config_file:
370
+ if config_file.endswith(
371
+ ".conf"
372
+ ): # if user input config path directly (~/.config/neofetch/custom.conf or /home/user/custom.conf etc.)
373
+ if not Path(config_file).exists():
374
+ print(
375
+ f"Config file {config_file} not found. Make sure the path is correct.",
376
+ file=sys.stderr,
377
+ )
378
+ sys.exit(1)
379
+ else: # if user input a preset name, look for it in ~/.config/neofetch/{preset_name}.conf
380
+ config_file = str(
381
+ Path.home() / ".config/neofetch" / f"{config_file}.conf"
382
+ )
383
+ if not Path(config_file).exists():
384
+ print(
385
+ f"Config file {config_file} not found. Make sure the preset name is correct and the corresponding config file exists in ~/.config/neofetch/.",
386
+ file=sys.stderr,
387
+ )
388
+ sys.exit(1)
389
+ output += ["--config", config_file]
364
390
  fetch_output = subprocess.check_output(
365
- ["neofetch", "--off"], text=True
391
+ output, text=True, encoding="utf-8", errors="replace"
366
392
  ).splitlines()
367
393
 
368
394
  elif neofetch_status == "uninstalled":
@@ -378,11 +404,37 @@ def get_fetch_output(
378
404
  file=sys.stderr,
379
405
  )
380
406
  sys.exit(1)
381
- else:
407
+ else: # use fastfetch
382
408
  try:
409
+ output: list = ["fastfetch", "--logo", "none", "--pipe", "false"]
410
+ if config_file:
411
+ if config_file.endswith(
412
+ ".jsonc"
413
+ ): # if user input config path directly (~/.config/fastfetch/custom.jsonc or /home/user/custom.jsonc)
414
+ if not Path(config_file).exists():
415
+ print(
416
+ f"Config file {config_file} not found. Make sure the path is correct.",
417
+ file=sys.stderr,
418
+ )
419
+ sys.exit(1)
420
+
421
+ # this part is actually optional because fastfetch have built in tools like this but this is for checking valid config
422
+ else: # if user input a preset name, look for it in ~/.config/fastfetch/{preset_name}.jsonc
423
+ config_file = str(
424
+ Path.home() / ".config/fastfetch" / f"{config_file}.jsonc"
425
+ )
426
+ if not Path(config_file).exists():
427
+ print(
428
+ f"Config file {config_file} not found. Make sure the preset name is correct and the corresponding config file exists in ~/.config/fastfetch/.",
429
+ file=sys.stderr,
430
+ )
431
+ sys.exit(1)
432
+ output += ["--config", config_file]
433
+
383
434
  fetch_output = subprocess.check_output(
384
- ["fastfetch", "--logo", "none", "--pipe", "false"], text=True
435
+ output, text=True, encoding="utf-8", errors="replace"
385
436
  ).splitlines()
437
+
386
438
  except FileNotFoundError as e:
387
439
  if e.errno == errno.ENOENT:
388
440
  print(
@@ -411,6 +463,7 @@ def make_template_from_fetch_lines(
411
463
  template: list[str] = "\n".join(fetch_lines)
412
464
  # Only do this once instead of for every line.
413
465
  template_actual_width = get_text_length_of_formatted_text(fetch_lines[0])
466
+ # template_actual_width = max((get_text_length_of_formatted_text(line) for line in fetch_lines), default=0)
414
467
  return (template, template_actual_width)
415
468
 
416
469
 
@@ -441,7 +494,10 @@ def render_frame(path: Path, width: int, height: int, chafa_args: str) -> str:
441
494
  return p.stdout
442
495
 
443
496
 
444
- def get_video_dimensions(filename):
497
+ def get_media_dimensions(filename):
498
+ """
499
+ Works for both gif, video and image.
500
+ """
445
501
  cmd = [
446
502
  "ffprobe",
447
503
  "-v",
@@ -481,6 +537,8 @@ def clean_cache_args(cache_args: dict) -> dict:
481
537
  "center",
482
538
  "loop",
483
539
  "no_key_exit",
540
+ "no_input_restore",
541
+ "config",
484
542
  )
485
543
  cleaned = deepcopy(cache_args) # need to deepcopy to not modify original dict.
486
544
  for key in args_to_remove:
@@ -568,3 +626,88 @@ def threaded_chafa_frame_gen(
568
626
  with open((OUTPUT_DIR / f).with_suffix(".txt"), "w", encoding="utf-8") as file:
569
627
  file.write(out)
570
628
  return i, out
629
+
630
+
631
+ def check_is_image(filename: pathlib.Path):
632
+ IMAGE_EXTENSIONS = (
633
+ ".apng",
634
+ ".png",
635
+ ".webp",
636
+ ".jpg",
637
+ ".jpeg",
638
+ ".tiff",
639
+ ".tif",
640
+ ".bmp",
641
+ ".ico",
642
+ ".avif",
643
+ ".jfif",
644
+ ".svg",
645
+ )
646
+ if any([filename.suffix == ext for ext in IMAGE_EXTENSIONS]):
647
+ return True
648
+ return False
649
+
650
+
651
+ def check_image_transparency(filename: pathlib.Path):
652
+ IMAGE_EXTENSIONS_WITH_ALPHA = (".png", ".webp", ".tiff", ".bmp", ".ico", ".avif")
653
+ if any([filename.suffix == ext for ext in IMAGE_EXTENSIONS_WITH_ALPHA]):
654
+ return True
655
+ return False
656
+
657
+
658
+ def check_is_video(filename: pathlib.Path):
659
+ VIDEO_EXTENSIONS = (
660
+ ".mp4",
661
+ ".mov",
662
+ ".avi",
663
+ ".mkv",
664
+ ".webm",
665
+ ".flv",
666
+ ".wmv",
667
+ ".m4v",
668
+ ".mpg",
669
+ ".mpeg",
670
+ )
671
+ if any([filename.suffix == ext for ext in VIDEO_EXTENSIONS]):
672
+ return True
673
+ return False
674
+
675
+
676
+ def check_video_transparency(filename: pathlib.Path):
677
+ result = subprocess.run(
678
+ [
679
+ "ffprobe",
680
+ "-v",
681
+ "error",
682
+ "-select_streams",
683
+ "v:0",
684
+ "-show_entries",
685
+ "stream=pix_fmt",
686
+ "-of",
687
+ "csv=p=0",
688
+ str(filename),
689
+ ],
690
+ capture_output=True,
691
+ )
692
+ pix_fmt = result.stdout.strip().decode("utf-8")
693
+ return "a" in pix_fmt
694
+
695
+
696
+ def split_to_frames(args, CACHE_PATH, IS_TRANSPARENT, stdout, stderr):
697
+ return subprocess.run(
698
+ [
699
+ "ffmpeg",
700
+ "-i",
701
+ f"{args.filename}",
702
+ "-vf",
703
+ f"fps={args.framerate},format=rgba",
704
+ "-q:v",
705
+ str(min(max(args.quality or 6, 2), 10)), # 2-5 high quality, 6-10 lower
706
+ str(CACHE_PATH / "video/%05d.png")
707
+ if IS_TRANSPARENT
708
+ else str(CACHE_PATH / "video/%05d.jpg"),
709
+ ],
710
+ stdout=stdout,
711
+ stderr=stderr,
712
+ text=True,
713
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anifetch-cli
3
- Version: 1.0.1
3
+ Version: 1.0.4
4
4
  Summary: Animated terminal fetch with video and audio support.
5
5
  Author-email: Notenlish <notenlish@gmail.com>
6
6
  Maintainer: Immelancholy
@@ -33,11 +33,34 @@ This is a small tool built with fastfetch/neofetch, ffmpeg and chafa. It allows
33
33
 
34
34
  ## Installation
35
35
 
36
- ### Installation for Linux
36
+ **Quick Links Installation Guide For:**
37
37
 
38
- Recommended Python version: 3.11 and later. If you use NixOS refer to [Installation for NixOS](#installation-for-nixos).
38
+ [Linux](#installation-for-linux-system) • [Windows](#installation-for-windows-winget-or-scoop) • [macOS](#installation-for-macos-homebrew)• [Manual](#manual-installation) • [Development](#developer-installation)
39
39
 
40
- Run this in the terminal.
40
+ ### Installation for Linux System
41
+ Recommended Python version: 3.11 and later.
42
+
43
+ #### Installation for Arch / Arch-based distros (Community maintained)
44
+
45
+ Anifetch is available in the AUR package [anifetch-cli](https://aur.archlinux.org/packages/anifetch-cli), maintained by @AmmarSyamil.
46
+
47
+ Install it from the terminal. For example, with Yay:
48
+
49
+ ```bash
50
+ yay -S anifetch-cli
51
+ ```
52
+
53
+ After installation, run this to test if anifetch was installed correctly:
54
+
55
+ ```bash
56
+ anifetch example.mp4
57
+ ```
58
+ Please read our [User guide](#user-guide) for more info on how to use anifetch.
59
+
60
+ #### Installation for other Linux Distro.
61
+ If you use NixOS refer to Installation for [NixOS](#installation-for-nixos).
62
+
63
+ Install it from the terminal. For example, with Yay:
41
64
 
42
65
  ```bash
43
66
  curl https://raw.githubusercontent.com/Notenlish/anifetch/refs/heads/main/install.sh | bash
@@ -49,10 +72,12 @@ After installation, run this to test if anifetch was installed correctly:
49
72
  anifetch example.mp4
50
73
  ```
51
74
 
75
+
52
76
  Please read our [User guide](#user-guide) for more info on how to use anifetch.
53
77
 
54
78
  ---
55
79
 
80
+
56
81
  ### Installation for Windows (Winget or Scoop)
57
82
 
58
83
  Check whether you have winget installed by running `winget` in the windows terminal. If you dont have it, install it [here](https://github.com/microsoft/winget-cli/?tab=readme-ov-file#installing-the-client). If you want, you can use [Scoop](https://scoop.sh/) instead. Just replace the `winget` part with `scoop`.
@@ -72,7 +97,10 @@ After installing the necessary dependencies using winget/scoop, install anifetch
72
97
  > [!WARNING]
73
98
  > **Do not** install `anifetch` on pypi, it is not related with this project. Install `anifetch-cli`.
74
99
 
75
- ### Installation for MacOS with Homebrew
100
+ Please read our [Post installation](#post-installation) and [User guide](#user-guide) for more info on how to use anifetch.
101
+
102
+
103
+ ### Installation for macOS (HomeBrew)
76
104
 
77
105
  Install homebrew if you haven't installed it already by following the guide [here](https://brew.sh/).
78
106
 
@@ -199,7 +227,7 @@ After you've done these steps, rebuild your system.
199
227
 
200
228
  ---
201
229
 
202
- ### Developer Installation (for contributors):
230
+ ### Developer Installation
203
231
 
204
232
  ```bash
205
233
  git clone https://github.com/Notenlish/anifetch.git
@@ -265,6 +293,13 @@ _Note : by default, the video `example.mp4` can directly be used as an example._
265
293
  - `--quality`: Changes the output quality of ffmpeg when extracting frames. This doesn't have much effect on the quality or speed from my testing, so you shouldn't need to change this. 2 highest quality, 10 lowest quality.
266
294
  - `--loop`: Determines how many times the animation should loop. Default is -1(always loop).
267
295
  - `--no-key-exit`: Don't exit anifetch when user presses a key.
296
+ - `--no-input-restore`: Disable restoring pressed keys back into the terminal after stopping Anifetch. Use this if your OS gives security prompts saying `"Anifetch" is requesting special priviliges` when you press a key to stop Anifetch.
297
+ - `-c` / `--config`: Specify a non-default config for Neofetch/Fastfetch.
298
+ - Accepts a path or preset name (e.g. `main`).
299
+ - Neofetch (Linux/macOS): `~/.config/neofetch/main.conf`
300
+ - Fastfetch (Linux/macOS): `~/.config/fastfetch/main.jsonc`
301
+ - Fastfetch (Windows): `%APPDATA%\fastfetch\main.jsonc`
302
+ - See [Customizing Fastfetch/Neofetch](#customizing-fastfetchneofetch-output) for config details.
268
303
 
269
304
  ### Cached files:
270
305
 
@@ -320,6 +355,8 @@ Make sure to install the dependencies listed on [Prerequisites](#Prerequisites).
320
355
 
321
356
  If weird characters are appearing in your terminal then your terminals font probably can't render some characters. Consider installling [nerdfonts](https://www.nerdfonts.com/).
322
357
 
358
+ If your OS is prompting you about `"Anifetch" is requesting special priviliges` or something similiar after pressing a key to stop the running Anifetch instance, add this argument: `--no-input-restore`. The technical reason for this is that Anifetch records the keys you press and enters them back to the terminal on your behalf. That way you can immediately run whatever command you want, without having to re-enter a key or two. Certain OS's have built-in protections against this as a security notice, which is why you might encounter a security prompt.
359
+
323
360
  ## Notes
324
361
 
325
362
  Anifetch attempts to cache the animation so that it doesn't need to render them again when you run it with the same file. However, if the name of the file is the same, but it's contents has changed, it won't re-render it. In that case, you will need to add `--force-render` as an argument to `anifetch.py` so that it re-renders it. You only have to do this only once when you change the file contents.
File without changes
File without changes