fid-ffmpeg 0.3.8__py3-none-any.whl → 0.4.2__py3-none-any.whl

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 (71) hide show
  1. fid_ffmpeg-0.4.2.dist-info/METADATA +192 -0
  2. fid_ffmpeg-0.4.2.dist-info/RECORD +65 -0
  3. {fid_ffmpeg-0.3.8.dist-info → fid_ffmpeg-0.4.2.dist-info}/WHEEL +1 -1
  4. fid_ffmpeg-0.4.2.dist-info/licenses/LICENSE +21 -0
  5. fid_ffmpeg-0.4.2.dist-info/top_level.txt +2 -0
  6. initial_files/error_handling.py +13 -0
  7. tasks/__init__.py +0 -0
  8. tasks/audio/__init__.py +0 -0
  9. tasks/audio/audio_interactive.py +96 -0
  10. tasks/audio/bitrate.py +0 -0
  11. tasks/audio/channels.py +0 -0
  12. tasks/audio/codec.py +0 -0
  13. tasks/audio/compressor.py +0 -0
  14. tasks/audio/delay.py +0 -0
  15. tasks/audio/denoise.py +0 -0
  16. tasks/audio/equalizer.py +0 -0
  17. tasks/audio/fade.py +0 -0
  18. tasks/audio/mix.py +0 -0
  19. tasks/audio/mute.py +12 -0
  20. tasks/audio/normalize.py +0 -0
  21. tasks/audio/replace.py +0 -0
  22. tasks/audio/speed.py +0 -0
  23. tasks/audio/trim.py +0 -0
  24. tasks/audio/volume.py +0 -0
  25. tasks/encode/__init__.py +0 -0
  26. tasks/encode/av1.py +0 -0
  27. tasks/encode/encode_interactive.py +35 -0
  28. tasks/encode/h264.py +0 -0
  29. tasks/encode/h265.py +0 -0
  30. tasks/extract/__init__.py +0 -0
  31. tasks/extract/attachments.py +0 -0
  32. tasks/extract/audio.py +12 -0
  33. tasks/extract/audio_channels.py +0 -0
  34. tasks/extract/audio_track.py +0 -0
  35. tasks/extract/chapters.py +0 -0
  36. tasks/extract/extract_interactive.py +75 -0
  37. tasks/extract/frames.py +14 -0
  38. tasks/extract/keyframes.py +0 -0
  39. tasks/extract/subtitles.py +0 -0
  40. tasks/extract/subtitles_convert.py +0 -0
  41. tasks/extract/subtitles_track.py +0 -0
  42. tasks/extract/thumbnails.py +0 -0
  43. tasks/info.py +11 -0
  44. tasks/stream/__init__.py +0 -0
  45. tasks/stream/dash.py +0 -0
  46. tasks/stream/hls.py +0 -0
  47. tasks/stream/http.py +0 -0
  48. tasks/stream/rtmp.py +0 -0
  49. tasks/stream/rtsp.py +0 -0
  50. tasks/stream/srt.py +0 -0
  51. tasks/stream/stream_interactive.py +56 -0
  52. tasks/stream/udp.py +0 -0
  53. tasks/video/__init__.py +0 -0
  54. tasks/video/compressor.py +14 -0
  55. tasks/video/concat.py +0 -0
  56. tasks/video/crop.py +0 -0
  57. tasks/video/fps.py +0 -0
  58. tasks/video/gif.py +12 -0
  59. tasks/video/resize.py +20 -0
  60. tasks/video/rotate.py +0 -0
  61. tasks/video/speed.py +0 -0
  62. tasks/video/trim.py +1 -0
  63. tasks/video/video_interactive.py +66 -0
  64. fid/fid.py +0 -72
  65. fid/welcome.py +0 -24
  66. fid_ffmpeg-0.3.8.dist-info/METADATA +0 -33
  67. fid_ffmpeg-0.3.8.dist-info/RECORD +0 -9
  68. fid_ffmpeg-0.3.8.dist-info/licenses/LICENSE +0 -8
  69. fid_ffmpeg-0.3.8.dist-info/top_level.txt +0 -1
  70. {fid_ffmpeg-0.3.8.dist-info → fid_ffmpeg-0.4.2.dist-info}/entry_points.txt +0 -0
  71. {fid → initial_files}/__init__.py +0 -0
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: fid-ffmpeg
3
+ Version: 0.4.2
4
+ Summary: FFmpeg-based CLI tool for video and audio operations like editing, extracting, streaming, and encoding
5
+ Author-email: Omar Abdalgwad <ahlawyomar95@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Omar Abdalgwad
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE .
27
+ Project-URL: Homepage, https://github.com/Omarabdalgwad/fid-FFmpeg
28
+ Project-URL: Repository, https://github.com/Omarabdalgwad/fid-FFmpeg.git
29
+ Project-URL: Documentation, https://github.com/Omarabdalgwad/fid-FFmpeg#readme
30
+ Project-URL: Issues, https://github.com/Omarabdalgwad/fid-FFmpeg/issues
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Programming Language :: Python :: 3.8
33
+ Classifier: Programming Language :: Python :: 3.9
34
+ Classifier: Programming Language :: Python :: 3.10
35
+ Classifier: Programming Language :: Python :: 3.11
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: OS Independent
39
+ Classifier: Topic :: Multimedia :: Video
40
+ Classifier: Topic :: Multimedia :: Sound/Audio
41
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
42
+ Requires-Python: >=3.8
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: typer>=0.7
46
+ Requires-Dist: questionary>=1.10
47
+ Requires-Dist: rich>=13.0
48
+ Requires-Dist: pyfiglet>=0.8
49
+ Dynamic: license-file
50
+
51
+ # fid-ffmpeg [![PyPI Downloads](https://static.pepy.tech/personalized-badge/fid-ffmpeg?period=total&units=international_system&left_color=black&right_color=green&left_text=downloads)](https://pepy.tech/project/fid-ffmpeg)
52
+
53
+ Python wrapper around the FFmpeg command line tool for video operations.
54
+
55
+ ```bash
56
+ fid
57
+ ```
58
+ https://github.com/user-attachments/assets/abcc8aa0-3ada-4548-8f99-987687cfccd9
59
+
60
+ ## Requirements
61
+
62
+ - python >=3.9 : [Download Python](https://www.python.org/downloads/)
63
+ - ffmpeg : [Download FFmpeg](https://www.ffmpeg.org/download.html)
64
+ - install fid-cli with pip :
65
+ ```bash
66
+ pip install fid-ffmpeg
67
+ ```
68
+ ## installation demo
69
+ https://github.com/user-attachments/assets/6063b46b-dd4a-4cb3-a318-869f37bcf60f
70
+
71
+ ## Usage
72
+ Run `fid` for the interactive menu, or use direct commands:
73
+
74
+ - `fid --help`: Show help for fid CLI.
75
+ - `fid info "videoPath"`: Get all info about the video.
76
+ - `fid audio "videoPath"`: Extract audio from the video.
77
+ - `fid mute "videoPath"`: Mute the video.
78
+ - `fid gif "videoPath"`: Create a GIF from the video.
79
+ - `fid frames "videoPath"`: Extract all video frames into a folder.
80
+ - `fid compress "videoPath"`: Compress the video to reduce file size.
81
+
82
+ For more advanced options, use the interactive mode by running `fid` without arguments.
83
+
84
+ ## Features
85
+ - Interactive CLI with menus for video, audio, extract, stream, and encode operations.
86
+ - Built with Typer for commands and Questionary for interactive prompts.
87
+ - Rich console output for a modern look.
88
+
89
+ ## Project Structure
90
+
91
+ ```
92
+ ```
93
+
94
+ FID
95
+ ├─ LICENSE
96
+ ├─ pyproject.toml
97
+ ├─ README.md
98
+ └─ src
99
+ ├─ fid.py
100
+ ├─ fid_interactive.py
101
+ ├─ initial_files
102
+ │ ├─ error_handling.py
103
+ │ └─ __init__.py
104
+ ├─ tasks
105
+ │ ├─ audio
106
+ │ │ ├─ audio_interactive.py
107
+ │ │ ├─ bitrate.py
108
+ │ │ ├─ channels.py
109
+ │ │ ├─ codec.py
110
+ │ │ ├─ compressor.py
111
+ │ │ ├─ delay.py
112
+ │ │ ├─ denoise.py
113
+ │ │ ├─ equalizer.py
114
+ │ │ ├─ fade.py
115
+ │ │ ├─ mix.py
116
+ │ │ ├─ mute.py
117
+ │ │ ├─ normalize.py
118
+ │ │ ├─ replace.py
119
+ │ │ ├─ speed.py
120
+ │ │ ├─ trim.py
121
+ │ │ ├─ volume.py
122
+ │ │ └─ __init__.py
123
+ │ ├─ encode
124
+ │ │ ├─ av1.py
125
+ │ │ ├─ encode_interactive.py
126
+ │ │ ├─ h264.py
127
+ │ │ ├─ h265.py
128
+ │ │ └─ __init__.py
129
+ │ ├─ extract
130
+ │ │ ├─ attachments.py
131
+ │ │ ├─ audio.py
132
+ │ │ ├─ audio_channels.py
133
+ │ │ ├─ audio_track.py
134
+ │ │ ├─ chapters.py
135
+ │ │ ├─ extract_interactive.py
136
+ │ │ ├─ frames.py
137
+ │ │ ├─ keyframes.py
138
+ │ │ ├─ subtitles.py
139
+ │ │ ├─ subtitles_convert.py
140
+ │ │ ├─ subtitles_track.py
141
+ │ │ ├─ thumbnails.py
142
+ │ │ └─ __init__.py
143
+ │ ├─ info.py
144
+ │ ├─ stream
145
+ │ │ ├─ dash.py
146
+ │ │ ├─ hls.py
147
+ │ │ ├─ http.py
148
+ │ │ ├─ rtmp.py
149
+ │ │ ├─ rtsp.py
150
+ │ │ ├─ srt.py
151
+ │ │ ├─ stream_interactive.py
152
+ │ │ ├─ udp.py
153
+ │ │ └─ __init__.py
154
+ │ ├─ video
155
+ │ │ ├─ compressor.py
156
+ │ │ ├─ concat.py
157
+ │ │ ├─ crop.py
158
+ │ │ ├─ fps.py
159
+ │ │ ├─ gif.py
160
+ │ │ ├─ resize.py
161
+ │ │ ├─ rotate.py
162
+ │ │ ├─ speed.py
163
+ │ │ ├─ trim.py
164
+ │ │ ├─ video_interactive.py
165
+ │ │ └─ __init__.py
166
+ │ └─ __init__.py
167
+ ├─ welcome.py
168
+ └─ __init__.py
169
+
170
+ ```
171
+
172
+ ## Contributing
173
+ Contributions are welcome! Fork the repo, create a branch, and submit a pull request. For major changes, open an issue first.
174
+
175
+ ## About
176
+ Python wrapper around the FFmpeg command line tool.
177
+
178
+ [PyPI Project](https://pypi.org/project/fid-ffmpeg/)
179
+
180
+ ### Topics
181
+ - audio
182
+ - python
183
+ - cli
184
+ - video
185
+ - ffmpeg
186
+ - frames
187
+ - gif
188
+ - compressor
189
+ - ffmpeg-wrapper
190
+ - rich
191
+ - mute
192
+ - typer-cli
@@ -0,0 +1,65 @@
1
+ fid_ffmpeg-0.4.2.dist-info/licenses/LICENSE,sha256=F-pOyGrwdERPucmVHPPrD37KZZ7sphCDJeAzG5gxFOw,1091
2
+ initial_files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ initial_files/error_handling.py,sha256=Z1gSb90rS2Vy4VZHS9Zk7OHPL2o6NOw4ipzBQTmjLbo,351
4
+ tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ tasks/info.py,sha256=lDrvHBGTp-PQFb-6jZ9FeB6ou4SNo4CO4Rc9SVPBHPo,367
6
+ tasks/audio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ tasks/audio/audio_interactive.py,sha256=U9D7yh2tXmJMP7nmmnOEYPoLBrPs2hNn3soNkYFLIRM,2519
8
+ tasks/audio/bitrate.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ tasks/audio/channels.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ tasks/audio/codec.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ tasks/audio/compressor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ tasks/audio/delay.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ tasks/audio/denoise.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ tasks/audio/equalizer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ tasks/audio/fade.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ tasks/audio/mix.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ tasks/audio/mute.py,sha256=OsPLClHQfWdJaUg_DOiJok0zKOtIhcAk6Ex7wuGUaFs,466
18
+ tasks/audio/normalize.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ tasks/audio/replace.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ tasks/audio/speed.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ tasks/audio/trim.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ tasks/audio/volume.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ tasks/encode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ tasks/encode/av1.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ tasks/encode/encode_interactive.py,sha256=pdzbFIeo_EDVK52LOLvhtzT33uivfc8gO4ANFzea1G4,861
26
+ tasks/encode/h264.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ tasks/encode/h265.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ tasks/extract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ tasks/extract/attachments.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ tasks/extract/audio.py,sha256=vsAcpzp7qauIRakxrbWmleSeXKJoqKqwYwK2QSYsejA,432
31
+ tasks/extract/audio_channels.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ tasks/extract/audio_track.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ tasks/extract/chapters.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ tasks/extract/extract_interactive.py,sha256=ctv-G4YnaS5vUZGKOYDgWpei-44YdXTnp1nAc1umzD0,2198
35
+ tasks/extract/frames.py,sha256=AXo5YYwcPqiGiNzIVh2rbgwdTAuOuFWQ_nVDlzTzOyo,506
36
+ tasks/extract/keyframes.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ tasks/extract/subtitles.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ tasks/extract/subtitles_convert.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ tasks/extract/subtitles_track.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ tasks/extract/thumbnails.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ tasks/stream/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ tasks/stream/dash.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ tasks/stream/hls.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ tasks/stream/http.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ tasks/stream/rtmp.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ tasks/stream/rtsp.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ tasks/stream/srt.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ tasks/stream/stream_interactive.py,sha256=WVOpW9g0HdwPcsMc5ed_RUHJQGgGmQ8Wu2uMXjr5Nz4,1439
49
+ tasks/stream/udp.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ tasks/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ tasks/video/compressor.py,sha256=cOBjww_BLYQuccZR0O1TCw5eIif0-loTb-RuZ4eZ7VI,578
52
+ tasks/video/concat.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ tasks/video/crop.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ tasks/video/fps.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ tasks/video/gif.py,sha256=o2_przDXUjNMxs0LlfQLRYK6xRsb2Lti0LRs0fSA07g,426
56
+ tasks/video/resize.py,sha256=aQTGZDiwCW2RhfX_7DMc7S-mqTuYsqw5G91xkDRZ5Y0,677
57
+ tasks/video/rotate.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
+ tasks/video/speed.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ tasks/video/trim.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
60
+ tasks/video/video_interactive.py,sha256=W9CODtlwwDjVjgWoRsj4Av-bP_e-3qT2QUtnr64Gdfg,1641
61
+ fid_ffmpeg-0.4.2.dist-info/METADATA,sha256=RdFI6w5Q45GDSvN4d-awmcrXaE9xc4kN0n01Ptl4LnA,6775
62
+ fid_ffmpeg-0.4.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
63
+ fid_ffmpeg-0.4.2.dist-info/entry_points.txt,sha256=wc8Iju3nkXAuyqF5NB1276l_AGtakuifMGR3D42dqB8,36
64
+ fid_ffmpeg-0.4.2.dist-info/top_level.txt,sha256=glIqk4p9N9EoHXTmkNQdRlbb1HpxOx2xuh9eO52I1E0,20
65
+ fid_ffmpeg-0.4.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Omar Abdalgwad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE .
@@ -0,0 +1,2 @@
1
+ initial_files
2
+ tasks
@@ -0,0 +1,13 @@
1
+ import typer
2
+ from pathlib import Path
3
+ import shutil
4
+
5
+ def ffmpeg():
6
+ if shutil.which("ffmpeg")is None:
7
+ print("ffmpeg isn't installed\n download from: https://ffmpeg.org/download.html")
8
+ raise typer.Exit()
9
+
10
+ def ckvideo(video_path:Path):
11
+ if not vid.exists():
12
+ print("file doesn't exist :)")
13
+ raise typer.Exit()
tasks/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,96 @@
1
+ import questionary
2
+ import typer
3
+ from .denoise import denoise
4
+ from .equalizer import equalizer
5
+ from .compressor import compress
6
+ from .codec import codec
7
+ from .bitrate import bitrate
8
+ from .channels import channels
9
+ from .delay import delay
10
+ from .fade import fade
11
+ from .trim import trim
12
+ from .replace import replace
13
+ from .mute import mute
14
+ from .mix import mix
15
+ from .speed import speed
16
+ from .normalize import normalize
17
+ from .volume import volume
18
+
19
+ def audio_main(video_path):
20
+
21
+ while True:
22
+ choice= questionary.select(
23
+ "select the editing option you want:",
24
+ choices=[
25
+ "volume up/down",
26
+ "mute audio",
27
+ "normalize audio",
28
+ "speed up/down",
29
+ "decrease noise",
30
+ "mix two audio files",
31
+ "compress audio file",
32
+ "equalize audio",
33
+ "change codec",
34
+ "change bitrate",
35
+ "change channels",
36
+ "add fade in/out",
37
+ "trim audio",
38
+ "replace audio",
39
+ "delay audio",
40
+ "Back to main menu",
41
+ "exit"
42
+ ]).ask()
43
+
44
+ if choice is None:
45
+ raise typer.Exit()
46
+
47
+ if choice== "volume up/down":
48
+ volume(video_path)
49
+
50
+ elif choice=="mute audio":
51
+ mute(video_path)
52
+
53
+ elif choice=="speed up/down":
54
+ speed(video_path)
55
+
56
+ elif choice=="normalize audio":
57
+ normalize(video_path)
58
+
59
+ elif choice=="decrease noise":
60
+ denoise(video_path)
61
+
62
+ elif choice=="mix two audio files":
63
+ mix(video_path)
64
+
65
+ elif choice=="compress audio file":
66
+ compress(video_path)
67
+
68
+ elif choice=="equalize audio":
69
+ equalizer(video_path)
70
+
71
+ elif choice=="change codec":
72
+ codec(video_path)
73
+
74
+ elif choice=="change bitrate":
75
+ bitrate(video_path)
76
+
77
+ elif choice=="change channels":
78
+ channels(video_path)
79
+
80
+ elif choice=="add fade in/out":
81
+ fade(video_path)
82
+
83
+ elif choice=="trim audio":
84
+ trim(video_path)
85
+
86
+ elif choice=="replace audio":
87
+ replace(video_path)
88
+
89
+ elif choice=="delay audio":
90
+ delay(video_path)
91
+
92
+ elif choice=="Back to main menu":
93
+ return
94
+
95
+ elif choice=="exit":
96
+ raise typer.Exit()
tasks/audio/bitrate.py ADDED
File without changes
File without changes
tasks/audio/codec.py ADDED
File without changes
File without changes
tasks/audio/delay.py ADDED
File without changes
tasks/audio/denoise.py ADDED
File without changes
File without changes
tasks/audio/fade.py ADDED
File without changes
tasks/audio/mix.py ADDED
File without changes
tasks/audio/mute.py ADDED
@@ -0,0 +1,12 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def mute_main(app: typer.Typer):
7
+ @app.command()
8
+ def mute(video_path: Path):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ mute_out=video_path.with_stem(f"{video_path.stem}_muted").with_suffix(video_path.suffix)
12
+ subprocess.run(["ffmpeg", "-i", str(video_path), "-c", "copy", "-an", "-y", str(mute_out)], check=True)
File without changes
tasks/audio/replace.py ADDED
File without changes
tasks/audio/speed.py ADDED
File without changes
tasks/audio/trim.py ADDED
File without changes
tasks/audio/volume.py ADDED
File without changes
File without changes
tasks/encode/av1.py ADDED
File without changes
@@ -0,0 +1,35 @@
1
+ import questionary
2
+ import typer
3
+ from .h264 import h264
4
+ from .h265 import h265
5
+ from .av1 import av1
6
+
7
+ def encode_main(video_path):
8
+
9
+ while True:
10
+ choice= questionary.select(
11
+ "select the encoding option you want:",
12
+ choices=[
13
+ "encode to h264",
14
+ "encode to h265",
15
+ "encode to av1",
16
+ "Back to main menu",
17
+ "exit"
18
+ ]).ask()
19
+ if choice is None:
20
+ raise typer.Exit()
21
+
22
+ if choice=="encode to h264":
23
+ h264(video_path)
24
+
25
+ elif choice=="encode to h265":
26
+ h265(video_path)
27
+
28
+ elif choice=="encode to av1":
29
+ av1(video_path)
30
+
31
+ elif choice=="Back to main menu":
32
+ return
33
+
34
+ elif choice=="exit":
35
+ raise typer.Exit()
tasks/encode/h264.py ADDED
File without changes
tasks/encode/h265.py ADDED
File without changes
File without changes
File without changes
tasks/extract/audio.py ADDED
@@ -0,0 +1,12 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def audio_main(app: typer.Typer):
7
+ @app.command()
8
+ def audio(video_path: Path):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ audio_out=video_path.with_suffix(".mp3")
12
+ subprocess.run(["ffmpeg", "-i", str(video_path), "-vn", "-acodec", "libmp3lame", "-y", str(audio_out)], check=True)
File without changes
File without changes
File without changes
@@ -0,0 +1,75 @@
1
+ import questionary
2
+ import typer
3
+ from .audio import audio
4
+ from .frames import frames
5
+ from .thumbnails import thumbnails
6
+ from .keyframes import keyframes
7
+ from .audio_track import audio_track
8
+ from .audio_channels import audio_channels
9
+ from .subtitles import subtitles
10
+ from .subtitles_track import subtitles_track
11
+ from .subtitles_convert import subtitles_convert
12
+ from .chapters import chapters
13
+ from .attachments import attachments
14
+
15
+ def extract_main(video_path):
16
+
17
+ while True:
18
+ choice= questionary.select(
19
+ "select the editing option you want:",
20
+ choices=[
21
+ "extract frames",
22
+ "extract audio",
23
+ "extract subtitles",
24
+ "extract chapters",
25
+ "extract thumbnails",
26
+ "extract keyframes",
27
+ "extract audio_track",
28
+ "extract audio_channels",
29
+ "extract subtitles_track",
30
+ "subtitles convert",
31
+ "extract attachments",
32
+ "Back to main menu",
33
+ "exit"
34
+ ]).ask()
35
+ if choice is None:
36
+ raise typer.Exit()
37
+
38
+ if choice=="extract audio":
39
+ audio(video_path)
40
+
41
+ elif choice=="extract frames":
42
+ frames(video_path)
43
+
44
+ elif choice=="extract subtitles":
45
+ subtitles(video_path)
46
+
47
+ elif choice=="extract chapters":
48
+ chapters(video_path)
49
+
50
+ elif choice=="extract thumbnails":
51
+ thumbnails(video_path)
52
+
53
+ elif choice=="extract keyframes":
54
+ keyframes(video_path)
55
+
56
+ elif choice=="extract audio_track":
57
+ audio_track(video_path)
58
+
59
+ elif choice=="extract audio_channels":
60
+ audio_channels(video_path)
61
+
62
+ elif choice=="extract subtitles_track":
63
+ subtitles_track(video_path)
64
+
65
+ elif choice=="subtitles convert":
66
+ subtitles_convert(video_path)
67
+
68
+ elif choice=="extract attachments":
69
+ attachments(video_path)
70
+
71
+ elif choice=="Back to main menu":
72
+ return
73
+
74
+ elif choice=="exit":
75
+ raise typer.Exit()
@@ -0,0 +1,14 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def frames_main(app: typer.Typer):
7
+ @app.command()
8
+ def frames(video_path: Path):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ Fdir= video_path.parent
12
+ frames_out= Fdir / "Frames" / video_path.stem
13
+ frames_out.mkdir(parents=True,exist_ok=True)
14
+ subprocess.run(["ffmpeg", "-i", str(video_path),str(frames_out/ "frame_%02d.png")],check=True )
File without changes
File without changes
File without changes
File without changes
File without changes
tasks/info.py ADDED
@@ -0,0 +1,11 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from .initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def info_main(app: typer.Typer):
7
+ @app.command()
8
+ def info(video_path: Path):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ subprocess.run(["ffprobe", "-v", "error", "-show_format", "-show_streams", str(video_path)], check=True)
File without changes
tasks/stream/dash.py ADDED
File without changes
tasks/stream/hls.py ADDED
File without changes
tasks/stream/http.py ADDED
File without changes
tasks/stream/rtmp.py ADDED
File without changes
tasks/stream/rtsp.py ADDED
File without changes
tasks/stream/srt.py ADDED
File without changes
@@ -0,0 +1,56 @@
1
+ import questionary
2
+ import typer
3
+ from .hls import hls
4
+ from .rtmp import rtmp
5
+ from .dash import dash
6
+ from .srt import srt
7
+ from .udp import udp
8
+ from .rtsp import rtsp
9
+ from .http import http
10
+
11
+ def stream_main(video_path):
12
+
13
+ while True:
14
+ choice= questionary.select(
15
+ "select the streaming option you want:",
16
+ choices=[
17
+ "stream with hls",
18
+ "stream with rtmp",
19
+ "stream with dash",
20
+ "stream with srt",
21
+ "stream with udp",
22
+ "stream with rtsp",
23
+ "stream with http",
24
+ "Back to main menu",
25
+ "exit"
26
+ ]).ask()
27
+
28
+ if choice is None:
29
+ raise typer.Exit()
30
+
31
+ if choice=="stream with hls":
32
+ hls(video_path)
33
+
34
+ elif choice=="stream with rtmp":
35
+ rtmp(video_path)
36
+
37
+ elif choice=="stream with dash":
38
+ dash(video_path)
39
+
40
+ elif choice=="stream with srt":
41
+ srt(video_path)
42
+
43
+ elif choice=="stream with udp":
44
+ udp(video_path)
45
+
46
+ elif choice=="stream with rtsp":
47
+ rtsp(video_path)
48
+
49
+ elif choice=="stream with http":
50
+ http(video_path)
51
+
52
+ elif choice=="Back to main menu":
53
+ return
54
+
55
+ elif choice=="exit":
56
+ raise typer.Exit()
tasks/stream/udp.py ADDED
File without changes
File without changes
@@ -0,0 +1,14 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def compress_main(app: typer.Typer):
7
+ @app.command()
8
+ def compress(video_path: Path, crf: int=28):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ compress_out= video_path.with_stem(f"{video_path.stem}_compressed").with_suffix(".mkv")
12
+ subprocess.run(
13
+ ["ffmpeg", "-i", str(video_path),"-c:v", "libx264", "-crf", str(crf), "-preset","medium","-c:a","aac","-b:a","96k","-y",str(compress_out),]
14
+ , check=True)
tasks/video/concat.py ADDED
File without changes
tasks/video/crop.py ADDED
File without changes
tasks/video/fps.py ADDED
File without changes
tasks/video/gif.py ADDED
@@ -0,0 +1,12 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def gif_main(app: typer.Typer):
7
+ @app.command()
8
+ def gif(video_path: Path):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ gif_out=video_path.with_suffix(".gif")
12
+ subprocess.run(["ffmpeg", "-i", str(video_path), "-t", "3", "-vf", "scale=320:-1", "-y", str(gif_out)], check=True)
tasks/video/resize.py ADDED
@@ -0,0 +1,20 @@
1
+ import typer
2
+ import subprocess
3
+ from pathlib import Path
4
+ from ...initial_files.error_handling import ffmpeg , ckvideo
5
+
6
+ def resize_main(app: typer.Typer):
7
+ @app.command()
8
+ def resize(video_path: Path, width: int):
9
+ ffmpeg()
10
+ ckvideo(video_path)
11
+ resize_out= video_path.with_stem(f"{video_path.stem}_{width}w").with_suffix(".mp4")
12
+ subprocess.run(
13
+ ["ffmpeg",
14
+ "-i", str(video_path),
15
+ "-vf", f"scale={width}:-1",
16
+ "-c:v", "libx264",
17
+ "-preset", "medium",
18
+ "-c:a", "copy",
19
+ "-y",
20
+ str(resize_out)], check=True)
tasks/video/rotate.py ADDED
File without changes
tasks/video/speed.py ADDED
File without changes
tasks/video/trim.py ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,66 @@
1
+ import questionary
2
+ import typer
3
+ from .compressor import compress
4
+ from .concat import concat
5
+ from .crop import crop
6
+ from .fps import fps
7
+ from .gif import gif
8
+ from .resize import resize
9
+ from .rotate import rotate
10
+ from .speed import speed
11
+ from .trim import trim
12
+
13
+ def video_main(video_path):
14
+
15
+ while True:
16
+ choice= questionary.select(
17
+ "select the editing option you want:",
18
+ choices=[
19
+ "compress the video",
20
+ "make gif",
21
+ "speed up/down",
22
+ "change fps",
23
+ "concat videos",
24
+ "crop video",
25
+ "resize video",
26
+ "rotate video",
27
+ "trim video",
28
+ "Back to main menu",
29
+ "exit"
30
+ ]).ask()
31
+
32
+ if choice is None:
33
+ raise typer.Exit()
34
+
35
+ if choice=="compress the video":
36
+ compress(video_path)
37
+
38
+ elif choice=="make gif":
39
+ gif(video_path)
40
+
41
+ elif choice=="speed up/down":
42
+ speed(video_path)
43
+
44
+ elif choice=="change fps":
45
+ fps(video_path)
46
+
47
+ elif choice=="concat videos":
48
+ concat(video_path)
49
+
50
+ elif choice=="crop video":
51
+ crop(video_path)
52
+
53
+ elif choice=="resize video":
54
+ resize(video_path)
55
+
56
+ elif choice=="rotate video":
57
+ rotate(video_path)
58
+
59
+ elif choice=="trim video":
60
+ trim(video_path)
61
+
62
+ elif choice=="Back to main menu":
63
+ return
64
+
65
+ elif choice=="exit":
66
+ raise typer.Exit()
fid/fid.py DELETED
@@ -1,72 +0,0 @@
1
- import typer
2
- import subprocess
3
- from pathlib import Path
4
- import shutil
5
- from .welcome import welcome
6
- app = typer.Typer()
7
-
8
- formats = [".mp4",".mov",".avi",".webm"]
9
-
10
- @app.callback(invoke_without_command=True)
11
- def start(ctx : typer.Context):
12
- if ctx.invoked_subcommand is None:
13
- welcome()
14
-
15
- def ffmpeg():
16
- if shutil.which("ffmpeg")is None:
17
- print("ffmpeg isn't installed\n download from: https://ffmpeg.org/download.html")
18
- raise typer.Exit()
19
-
20
- def ckvideo(vid:Path):
21
- if not vid.exists():
22
- print("file doesn't exist")
23
- raise typer.Exit()
24
-
25
-
26
- @app.command()
27
- def info(vid: Path):
28
- ffmpeg()
29
- ckvideo(vid)
30
- subprocess.run(["ffprobe", "-v", "error", "-show_format", "-show_streams", str(vid)], check=True)
31
-
32
- @app.command()
33
- def audio(vid: Path):
34
- ffmpeg()
35
- ckvideo(vid)
36
- audio=vid.with_suffix(".mp3")
37
- subprocess.run(["ffmpeg", "-i", str(vid), "-vn", "-acodec", "mp3", "-y", str(audio)], check=True)
38
-
39
-
40
- @app.command()
41
- def frames(vid: Path):
42
- ffmpeg()
43
- ckvideo(vid)
44
- Fdir= vid.parent
45
- frames= Fdir / "Frames" / vid.stem
46
- frames.mkdir(parents=True,exist_ok=True)
47
- subprocess.run(["ffmpeg", "-i", str(vid),str(frames/ "frame_%02d.png")],check=True )
48
-
49
- @app.command()
50
- def gif(vid: Path):
51
- ffmpeg()
52
- ckvideo(vid)
53
- gif=vid.with_suffix(".gif")
54
- subprocess.run(["ffmpeg", "-i", str(vid), "-t", "3", "-vf", "scale=320:-1", "-y", str(gif)], check=True)
55
-
56
-
57
- @app.command()
58
- def mute(vid: Path):
59
- ffmpeg()
60
- ckvideo(vid)
61
- mute=vid.with_stem(f"{vid.stem}_muted").with_suffix(vid.suffix)
62
- subprocess.run(["ffmpeg", "-i", str(vid), "-c", "copy", "-an", "-y", str(mute)], check=True)
63
-
64
- @app.command()
65
- def compress(vid: Path, crf: int=28):
66
- ffmpeg()
67
- ckvideo(vid)
68
- compress= vid.with_stem(f"{vid.stem}_compressed").with_suffix(".mkv")
69
- subprocess.run(["ffmpeg", "-i", str(vid),"-c:v", "libx264", "-crf", str(crf), "-preset","medium","-c:a","aac","-b:a","96k","-y",str(compress),], check=True)
70
-
71
- if __name__=="__main__":
72
- app()
fid/welcome.py DELETED
@@ -1,24 +0,0 @@
1
- from rich.console import Console
2
- from rich.panel import Panel
3
- from rich.text import Text
4
- import pyfiglet
5
-
6
- console = Console()
7
-
8
- def welcome():
9
- ascii=pyfiglet.figlet_format("fid-ffmpeg",font="slant")
10
- logo = Text(ascii)
11
- logo.stylize("bold gradient(blue, magenta)")
12
- console.print(logo, justify="center")
13
- content = (
14
- "[bold]fid-ffmpeg Helper[/bold]\n\n"
15
- "[green]Commands:[/green]\n"
16
- " • info Show video info\n"
17
- " • audio Extract audio\n"
18
- " • frames Extract frames\n"
19
- " • gif Create gif\n"
20
- " • mute Remove audio\n"
21
- " • compress Compress video\n\n"
22
- "[dim]Run : fid <command> <video path>[/dim]")
23
- console.print(
24
- Panel(content,title="fid-ffmpeg",border_style="cyan",expand=True))
@@ -1,33 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: fid-ffmpeg
3
- Version: 0.3.8
4
- Summary: based ffmpeg CLI for video operations
5
- Author-email: omar_abdalgwad <ahlawyomar95@gmail.com>
6
- Description-Content-Type: text/markdown
7
- License-File: LICENSE
8
- Requires-Dist: typer>=0.7
9
- Dynamic: license-file
10
-
11
- # fid-ffmpeg
12
- simple ffmpeg based cli for video operations
13
-
14
- ## installation
15
-
16
- - you need to install python >=3.9 : [Download Python](https://www.python.org/downloads/)
17
- - install ffmpeg : [Download FFmpeg](https://www.ffmpeg.org/download.html)
18
- - then install fid-cli with pip :
19
- ```bash
20
- pip install fid-ffmpeg
21
- ```
22
- ## installation demo
23
- https://github.com/user-attachments/assets/5c1bb2ac-1793-44b8-8240-bc71a1919d5a
24
-
25
- ## Commands
26
- | Command | Description |
27
- |---------|------------|
28
- | `fid --help` | show help for fid cli |
29
- | `fid info "videoPath"` | `to know all info about the video` |
30
- | `fid audio "videoPath"` | `extract audio from the video` |
31
- | `fid mute "videoPath"` | `mute the video` |
32
- | `fid gif "videoPath"` | `make a gif from the video` |
33
- | `fid frames "videoPath"` | `extract all video frames and add them in a folder`|
@@ -1,9 +0,0 @@
1
- fid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- fid/fid.py,sha256=o9o5y_s_2lR2bBrBP9FgH8VMr5nyQJt5_c6HrVRQw6Q,2094
3
- fid/welcome.py,sha256=hUyKUfdTlfROwZaHvqTQ_tNP_1ZLiV2iCYeddYOcHhI,827
4
- fid_ffmpeg-0.3.8.dist-info/licenses/LICENSE,sha256=8HFb3MtS3r_RTfGUr8mm6IbZocu4o4vc2f2U00Z3Tmc,255
5
- fid_ffmpeg-0.3.8.dist-info/METADATA,sha256=8SVS9YdsKZct1GzlAmvCSAYtvyeRvBfcd-YudAeHCSU,1126
6
- fid_ffmpeg-0.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- fid_ffmpeg-0.3.8.dist-info/entry_points.txt,sha256=wc8Iju3nkXAuyqF5NB1276l_AGtakuifMGR3D42dqB8,36
8
- fid_ffmpeg-0.3.8.dist-info/top_level.txt,sha256=5jgogeo314G3j_oXUp3BE4wBE3t82ijRwLwF1KnYiDg,4
9
- fid_ffmpeg-0.3.8.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Omar Abdalgwad
4
-
5
- Permission is granted to use, copy, modify, and distribute this software for any purpose,
6
- with or without fee, provided this notice is included.
7
-
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY
@@ -1 +0,0 @@
1
- fid
File without changes