StreamingCommunity 2.5.2__py3-none-any.whl → 2.5.5__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.
Potentially problematic release.
This version of StreamingCommunity might be problematic. Click here for more details.
- StreamingCommunity/Api/Player/Helper/Vixcloud/js_parser.py +143 -143
- StreamingCommunity/Api/Player/Helper/Vixcloud/util.py +136 -136
- StreamingCommunity/Api/Player/ddl.py +89 -89
- StreamingCommunity/Api/Player/maxstream.py +151 -151
- StreamingCommunity/Api/Player/supervideo.py +193 -193
- StreamingCommunity/Api/Player/vixcloud.py +272 -272
- StreamingCommunity/Api/Site/1337xx/__init__.py +51 -50
- StreamingCommunity/Api/Site/1337xx/costant.py +14 -14
- StreamingCommunity/Api/Site/1337xx/site.py +87 -89
- StreamingCommunity/Api/Site/1337xx/title.py +63 -64
- StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +74 -50
- StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +21 -19
- StreamingCommunity/Api/Site/altadefinizionegratis/film.py +81 -72
- StreamingCommunity/Api/Site/altadefinizionegratis/site.py +116 -94
- StreamingCommunity/Api/Site/animeunity/__init__.py +75 -50
- StreamingCommunity/Api/Site/animeunity/costant.py +21 -19
- StreamingCommunity/Api/Site/animeunity/film_serie.py +171 -134
- StreamingCommunity/Api/Site/animeunity/site.py +191 -174
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +97 -97
- StreamingCommunity/Api/Site/cb01new/__init__.py +51 -51
- StreamingCommunity/Api/Site/cb01new/costant.py +19 -19
- StreamingCommunity/Api/Site/cb01new/film.py +61 -71
- StreamingCommunity/Api/Site/cb01new/site.py +82 -82
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +55 -55
- StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +20 -20
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +149 -145
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +98 -98
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +84 -84
- StreamingCommunity/Api/Site/guardaserie/__init__.py +50 -50
- StreamingCommunity/Api/Site/guardaserie/costant.py +19 -19
- StreamingCommunity/Api/Site/guardaserie/series.py +199 -198
- StreamingCommunity/Api/Site/guardaserie/site.py +89 -89
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +110 -110
- StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +51 -51
- StreamingCommunity/Api/Site/ilcorsaronero/costant.py +18 -18
- StreamingCommunity/Api/Site/ilcorsaronero/site.py +71 -71
- StreamingCommunity/Api/Site/ilcorsaronero/title.py +44 -44
- StreamingCommunity/Api/Site/ilcorsaronero/util/ilCorsarScraper.py +149 -149
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +48 -48
- StreamingCommunity/Api/Site/mostraguarda/costant.py +18 -18
- StreamingCommunity/Api/Site/mostraguarda/film.py +90 -101
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +79 -55
- StreamingCommunity/Api/Site/streamingcommunity/costant.py +21 -19
- StreamingCommunity/Api/Site/streamingcommunity/film.py +86 -75
- StreamingCommunity/Api/Site/streamingcommunity/series.py +259 -207
- StreamingCommunity/Api/Site/streamingcommunity/site.py +156 -142
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +124 -124
- StreamingCommunity/Api/Template/Class/SearchType.py +101 -101
- StreamingCommunity/Api/Template/Util/__init__.py +4 -4
- StreamingCommunity/Api/Template/Util/get_domain.py +201 -201
- StreamingCommunity/Api/Template/Util/manage_ep.py +178 -178
- StreamingCommunity/Api/Template/Util/recall_search.py +37 -37
- StreamingCommunity/Api/Template/__init__.py +2 -2
- StreamingCommunity/Api/Template/site.py +87 -87
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +529 -1008
- StreamingCommunity/Lib/Downloader/HLS/proxyes.py +110 -110
- StreamingCommunity/Lib/Downloader/HLS/segments.py +446 -573
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +181 -155
- StreamingCommunity/Lib/Downloader/TOR/downloader.py +297 -295
- StreamingCommunity/Lib/Downloader/__init__.py +4 -4
- StreamingCommunity/Lib/FFmpeg/__init__.py +4 -4
- StreamingCommunity/Lib/FFmpeg/capture.py +170 -170
- StreamingCommunity/Lib/FFmpeg/command.py +264 -296
- StreamingCommunity/Lib/FFmpeg/util.py +248 -248
- StreamingCommunity/Lib/M3U8/__init__.py +5 -5
- StreamingCommunity/Lib/M3U8/decryptor.py +164 -164
- StreamingCommunity/Lib/M3U8/estimator.py +146 -228
- StreamingCommunity/Lib/M3U8/parser.py +666 -666
- StreamingCommunity/Lib/M3U8/url_fixer.py +57 -57
- StreamingCommunity/Lib/TMBD/__init__.py +1 -1
- StreamingCommunity/Lib/TMBD/obj_tmbd.py +39 -39
- StreamingCommunity/Lib/TMBD/tmdb.py +345 -345
- StreamingCommunity/TelegramHelp/__init__.py +0 -0
- StreamingCommunity/TelegramHelp/request_manager.py +82 -0
- StreamingCommunity/TelegramHelp/session.py +56 -0
- StreamingCommunity/TelegramHelp/telegram_bot.py +561 -0
- StreamingCommunity/Upload/update.py +75 -67
- StreamingCommunity/Upload/version.py +5 -5
- StreamingCommunity/Util/_jsonConfig.py +227 -228
- StreamingCommunity/Util/call_stack.py +42 -42
- StreamingCommunity/Util/color.py +20 -20
- StreamingCommunity/Util/console.py +12 -12
- StreamingCommunity/Util/ffmpeg_installer.py +342 -370
- StreamingCommunity/Util/headers.py +159 -159
- StreamingCommunity/Util/logger.py +61 -61
- StreamingCommunity/Util/message.py +36 -64
- StreamingCommunity/Util/os.py +500 -507
- StreamingCommunity/Util/table.py +271 -228
- StreamingCommunity/run.py +352 -245
- {StreamingCommunity-2.5.2.dist-info → StreamingCommunity-2.5.5.dist-info}/LICENSE +674 -674
- {StreamingCommunity-2.5.2.dist-info → StreamingCommunity-2.5.5.dist-info}/METADATA +601 -543
- StreamingCommunity-2.5.5.dist-info/RECORD +96 -0
- {StreamingCommunity-2.5.2.dist-info → StreamingCommunity-2.5.5.dist-info}/entry_points.txt +0 -1
- StreamingCommunity/Api/Player/Helper/Vixcloud/__pycache__/js_parser.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/Helper/Vixcloud/__pycache__/js_parser.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Player/Helper/Vixcloud/__pycache__/util.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/Helper/Vixcloud/__pycache__/util.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/ddl.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/ddl.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/maxstream.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/maxstream.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/supervideo.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/supervideo.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/vixcloud.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Player/__pycache__/vixcloud.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/title.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/1337xx/__pycache__/title.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/film.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/film.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/film_serie.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/film_serie.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/util/__pycache__/ScrapeSerie.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/animeunity/util/__pycache__/ScrapeSerie.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/film.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/film.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/cb01new/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/series.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/series.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/util/__pycache__/ScrapeSerie.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/util/__pycache__/ScrapeSerie.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/series.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/series.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/util/__pycache__/ScrapeSerie.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/guardaserie/util/__pycache__/ScrapeSerie.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/title.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__pycache__/title.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/util/__pycache__/ilCorsarScraper.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/ilcorsaronero/util/__pycache__/ilCorsarScraper.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/film.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/mostraguarda/__pycache__/film.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/costant.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/costant.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/film.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/film.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/series.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/series.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/util/__pycache__/ScrapeSerie.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Site/streamingcommunity/util/__pycache__/ScrapeSerie.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/Class/__pycache__/SearchType.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/Class/__pycache__/SearchType.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/get_domain.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/get_domain.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/manage_ep.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/manage_ep.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/recall_search.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/Util/__pycache__/recall_search.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Api/Template/__pycache__/site.cpython-313.pyc +0 -0
- StreamingCommunity/Api/Template/__pycache__/site.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/downloader.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/downloader.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/proxyes.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/proxyes.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/segments.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/HLS/__pycache__/segments.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/MP4/__pycache__/downloader.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/MP4/__pycache__/downloader.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/TOR/__pycache__/downloader.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/TOR/__pycache__/downloader.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/Downloader/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/capture.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/capture.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/command.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/command.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/util.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__pycache__/util.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/decryptor.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/decryptor.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/estimator.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/estimator.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/parser.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/parser.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/url_fixer.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/M3U8/__pycache__/url_fixer.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/obj_tmbd.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/obj_tmbd.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/tmdb.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/TMBD/__pycache__/tmdb.cpython-39.pyc +0 -0
- StreamingCommunity/Upload/__pycache__/update.cpython-313.pyc +0 -0
- StreamingCommunity/Upload/__pycache__/update.cpython-39.pyc +0 -0
- StreamingCommunity/Upload/__pycache__/version.cpython-313.pyc +0 -0
- StreamingCommunity/Upload/__pycache__/version.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/_jsonConfig.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/_jsonConfig.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/call_stack.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/call_stack.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/color.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/color.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/console.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/console.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/ffmpeg_installer.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/ffmpeg_installer.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/headers.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/headers.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/logger.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/logger.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/message.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/message.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/os.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/os.cpython-39.pyc +0 -0
- StreamingCommunity/Util/__pycache__/table.cpython-313.pyc +0 -0
- StreamingCommunity/Util/__pycache__/table.cpython-39.pyc +0 -0
- StreamingCommunity/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/__pycache__/run.cpython-313.pyc +0 -0
- StreamingCommunity/__pycache__/run.cpython-39.pyc +0 -0
- StreamingCommunity-2.5.2.dist-info/RECORD +0 -264
- {StreamingCommunity-2.5.2.dist-info → StreamingCommunity-2.5.5.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.5.2.dist-info → StreamingCommunity-2.5.5.dist-info}/top_level.txt +0 -0
|
@@ -1,371 +1,343 @@
|
|
|
1
|
-
# 24.01.2024
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import tarfile
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
from typing import Optional, Tuple
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# External library
|
|
16
|
-
|
|
17
|
-
from rich.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
FFMPEG_CONFIGURATION = {
|
|
26
|
-
'windows': {
|
|
27
|
-
'base_dir': lambda home: os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary'),
|
|
28
|
-
'download_url': 'https://github.com/
|
|
29
|
-
'file_extension': '.
|
|
30
|
-
'executables': ['ffmpeg
|
|
31
|
-
},
|
|
32
|
-
'darwin': {
|
|
33
|
-
'base_dir': lambda home: os.path.join(home, 'Applications', 'binary'),
|
|
34
|
-
'download_url': 'https://github.com/eugeneware/ffmpeg-static/releases/download/
|
|
35
|
-
'file_extension': '.
|
|
36
|
-
'executables': ['ffmpeg', 'ffprobe'
|
|
37
|
-
},
|
|
38
|
-
'linux': {
|
|
39
|
-
'base_dir': lambda home: os.path.join(home, '.local', 'bin', 'binary'),
|
|
40
|
-
'download_url': 'https://github.com/eugeneware/ffmpeg-static/releases/download/
|
|
41
|
-
'file_extension': '.
|
|
42
|
-
'executables': ['ffmpeg', 'ffprobe'
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class FFMPEGDownloader:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
'
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
'
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
ffprobe_path = subprocess.check_output(
|
|
344
|
-
['where', 'ffprobe'], stderr=subprocess.DEVNULL, text=True
|
|
345
|
-
).strip().split('\n')[0]
|
|
346
|
-
|
|
347
|
-
ffplay_path = subprocess.check_output(
|
|
348
|
-
['where', 'ffplay'], stderr=subprocess.DEVNULL, text=True
|
|
349
|
-
).strip().split('\n')[0]
|
|
350
|
-
|
|
351
|
-
return ffmpeg_path, ffprobe_path, ffplay_path
|
|
352
|
-
|
|
353
|
-
except subprocess.CalledProcessError:
|
|
354
|
-
logging.warning("One or more FFmpeg binaries were not found with command where")
|
|
355
|
-
|
|
356
|
-
# Linux detection
|
|
357
|
-
else:
|
|
358
|
-
ffmpeg_path = shutil.which('ffmpeg')
|
|
359
|
-
ffprobe_path = shutil.which('ffprobe')
|
|
360
|
-
ffplay_path = shutil.which('ffplay')
|
|
361
|
-
|
|
362
|
-
if ffmpeg_path and ffprobe_path:
|
|
363
|
-
return ffmpeg_path, ffprobe_path, ffplay_path
|
|
364
|
-
|
|
365
|
-
# If executables were not found, attempt to download FFmpeg
|
|
366
|
-
downloader = FFMPEGDownloader()
|
|
367
|
-
return downloader.download()
|
|
368
|
-
|
|
369
|
-
except Exception as e:
|
|
370
|
-
logging.error(f"Error checking or downloading FFmpeg executables: {e}")
|
|
1
|
+
# 24.01.2024
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import glob
|
|
5
|
+
import gzip
|
|
6
|
+
import shutil
|
|
7
|
+
import tarfile
|
|
8
|
+
import zipfile
|
|
9
|
+
import logging
|
|
10
|
+
import platform
|
|
11
|
+
import subprocess
|
|
12
|
+
from typing import Optional, Tuple
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# External library
|
|
16
|
+
import requests
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRemainingColumn
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Variable
|
|
22
|
+
console = Console()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
FFMPEG_CONFIGURATION = {
|
|
26
|
+
'windows': {
|
|
27
|
+
'base_dir': lambda home: os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary'),
|
|
28
|
+
'download_url': 'https://github.com/eugeneware/ffmpeg-static/releases/latest/download/ffmpeg-win32-{arch}.gz',
|
|
29
|
+
'file_extension': '.gz',
|
|
30
|
+
'executables': ['ffmpeg-win32-{arch}', 'ffprobe-win32-{arch}']
|
|
31
|
+
},
|
|
32
|
+
'darwin': {
|
|
33
|
+
'base_dir': lambda home: os.path.join(home, 'Applications', 'binary'),
|
|
34
|
+
'download_url': 'https://github.com/eugeneware/ffmpeg-static/releases/latest/download/ffmpeg-darwin-{arch}.gz',
|
|
35
|
+
'file_extension': '.gz',
|
|
36
|
+
'executables': ['ffmpeg-darwin-{arch}', 'ffprobe-darwin-{arch}']
|
|
37
|
+
},
|
|
38
|
+
'linux': {
|
|
39
|
+
'base_dir': lambda home: os.path.join(home, '.local', 'bin', 'binary'),
|
|
40
|
+
'download_url': 'https://github.com/eugeneware/ffmpeg-static/releases/latest/download/ffmpeg-linux-{arch}.gz',
|
|
41
|
+
'file_extension': '.gz',
|
|
42
|
+
'executables': ['ffmpeg-linux-{arch}', 'ffprobe-linux-{arch}']
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class FFMPEGDownloader:
|
|
48
|
+
def __init__(self):
|
|
49
|
+
self.os_name = self._detect_system()
|
|
50
|
+
self.arch = self._detect_arch()
|
|
51
|
+
self.home_dir = os.path.expanduser('~')
|
|
52
|
+
self.base_dir = self._get_base_directory()
|
|
53
|
+
|
|
54
|
+
def _detect_system(self) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Detect and normalize the operating system name.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
str: Normalized operating system name ('windows', 'darwin', or 'linux')
|
|
60
|
+
"""
|
|
61
|
+
system = platform.system().lower()
|
|
62
|
+
if system in FFMPEG_CONFIGURATION:
|
|
63
|
+
return system
|
|
64
|
+
raise ValueError(f"Unsupported operating system: {system}")
|
|
65
|
+
|
|
66
|
+
def _detect_arch(self) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Detect and normalize the system architecture.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
str: Normalized architecture name (e.g., 'x86_64', 'arm64')
|
|
72
|
+
"""
|
|
73
|
+
machine = platform.machine().lower()
|
|
74
|
+
arch_map = {
|
|
75
|
+
'amd64': 'x64',
|
|
76
|
+
'x86_64': 'x64',
|
|
77
|
+
'x64': 'x64',
|
|
78
|
+
'arm64': 'arm64',
|
|
79
|
+
'aarch64': 'arm64',
|
|
80
|
+
'armv7l': 'arm',
|
|
81
|
+
'i386': 'ia32',
|
|
82
|
+
'i686': 'ia32'
|
|
83
|
+
}
|
|
84
|
+
return arch_map.get(machine, machine)
|
|
85
|
+
|
|
86
|
+
def _get_base_directory(self) -> str:
|
|
87
|
+
"""
|
|
88
|
+
Get and create the base directory for storing FFmpeg binaries.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
str: Path to the base directory
|
|
92
|
+
"""
|
|
93
|
+
base_dir = FFMPEG_CONFIGURATION[self.os_name]['base_dir'](self.home_dir)
|
|
94
|
+
os.makedirs(base_dir, exist_ok=True)
|
|
95
|
+
return base_dir
|
|
96
|
+
|
|
97
|
+
def _check_existing_binaries(self) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
|
98
|
+
"""
|
|
99
|
+
Check if FFmpeg binaries already exist in the base directory.
|
|
100
|
+
Enhanced to check both the binary directory and system paths on macOS.
|
|
101
|
+
"""
|
|
102
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
103
|
+
executables = config['executables']
|
|
104
|
+
found_executables = []
|
|
105
|
+
|
|
106
|
+
# For macOS, check both binary directory and system paths
|
|
107
|
+
if self.os_name == 'darwin':
|
|
108
|
+
potential_paths = [
|
|
109
|
+
'/usr/local/bin',
|
|
110
|
+
'/opt/homebrew/bin',
|
|
111
|
+
'/usr/bin',
|
|
112
|
+
self.base_dir
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
for executable in executables:
|
|
116
|
+
found = None
|
|
117
|
+
for path in potential_paths:
|
|
118
|
+
full_path = os.path.join(path, executable)
|
|
119
|
+
if os.path.exists(full_path) and os.access(full_path, os.X_OK):
|
|
120
|
+
found = full_path
|
|
121
|
+
break
|
|
122
|
+
found_executables.append(found)
|
|
123
|
+
else:
|
|
124
|
+
|
|
125
|
+
# Original behavior for other operating systems
|
|
126
|
+
for executable in executables:
|
|
127
|
+
exe_paths = glob.glob(os.path.join(self.base_dir, executable))
|
|
128
|
+
found_executables.append(exe_paths[0] if exe_paths else None)
|
|
129
|
+
|
|
130
|
+
return tuple(found_executables) if len(found_executables) == 3 else (None, None, None)
|
|
131
|
+
|
|
132
|
+
def _get_latest_version(self, repo: str) -> Optional[str]:
|
|
133
|
+
"""
|
|
134
|
+
Get the latest FFmpeg version from the GitHub releases page.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Optional[str]: The latest version string, or None if retrieval fails.
|
|
138
|
+
"""
|
|
139
|
+
try:
|
|
140
|
+
# Use GitHub API to fetch the latest release
|
|
141
|
+
response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest')
|
|
142
|
+
response.raise_for_status()
|
|
143
|
+
latest_release = response.json()
|
|
144
|
+
|
|
145
|
+
# Extract the tag name or version from the release
|
|
146
|
+
return latest_release.get('tag_name')
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logging.error(f"Unable to get version from GitHub: {e}")
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
def _download_file(self, url: str, destination: str) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Download a file from URL with a Rich progress bar display.
|
|
155
|
+
|
|
156
|
+
Parameters:
|
|
157
|
+
url (str): The URL to download the file from. Should be a direct download link.
|
|
158
|
+
destination (str): Local file path where the downloaded file will be saved.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
bool: True if download was successful, False otherwise.
|
|
162
|
+
"""
|
|
163
|
+
try:
|
|
164
|
+
response = requests.get(url, stream=True)
|
|
165
|
+
response.raise_for_status()
|
|
166
|
+
total_size = int(response.headers.get('content-length', 0))
|
|
167
|
+
|
|
168
|
+
with open(destination, 'wb') as file, \
|
|
169
|
+
Progress(
|
|
170
|
+
SpinnerColumn(),
|
|
171
|
+
TextColumn("[progress.description]{task.description}"),
|
|
172
|
+
BarColumn(),
|
|
173
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
174
|
+
TimeRemainingColumn()
|
|
175
|
+
) as progress:
|
|
176
|
+
|
|
177
|
+
download_task = progress.add_task("[green]Downloading FFmpeg", total=total_size)
|
|
178
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
179
|
+
size = file.write(chunk)
|
|
180
|
+
progress.update(download_task, advance=size)
|
|
181
|
+
return True
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logging.error(f"Download error: {e}")
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
def _extract_and_copy_binaries(self, archive_path: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
|
187
|
+
"""
|
|
188
|
+
Extract FFmpeg binaries from the downloaded archive and copy them to the base directory.
|
|
189
|
+
|
|
190
|
+
Parameters:
|
|
191
|
+
archive_path (str): Path to the downloaded archive file
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to the extracted ffmpeg,
|
|
195
|
+
ffprobe, and ffplay executables. Returns None for each executable that couldn't be extracted.
|
|
196
|
+
"""
|
|
197
|
+
try:
|
|
198
|
+
extraction_path = os.path.join(self.base_dir, 'temp_extract')
|
|
199
|
+
os.makedirs(extraction_path, exist_ok=True)
|
|
200
|
+
|
|
201
|
+
if archive_path.endswith('.zip'):
|
|
202
|
+
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
|
|
203
|
+
zip_ref.extractall(extraction_path)
|
|
204
|
+
elif archive_path.endswith('.tar.xz'):
|
|
205
|
+
with tarfile.open(archive_path) as tar_ref:
|
|
206
|
+
tar_ref.extractall(extraction_path)
|
|
207
|
+
elif archive_path.endswith('.gz'):
|
|
208
|
+
file_name = os.path.basename(archive_path)[:-3] # Remove extension .gz
|
|
209
|
+
output_path = os.path.join(extraction_path, file_name)
|
|
210
|
+
with gzip.open(archive_path, 'rb') as f_in, open(output_path, 'wb') as f_out:
|
|
211
|
+
shutil.copyfileobj(f_in, f_out)
|
|
212
|
+
else:
|
|
213
|
+
raise ValueError("Unsupported archive format")
|
|
214
|
+
|
|
215
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
216
|
+
executables = config['executables']
|
|
217
|
+
found_paths = []
|
|
218
|
+
|
|
219
|
+
for executable in executables:
|
|
220
|
+
exe_paths = glob.glob(os.path.join(extraction_path, '**', executable), recursive=True)
|
|
221
|
+
if exe_paths:
|
|
222
|
+
dest_path = os.path.join(self.base_dir, executable)
|
|
223
|
+
shutil.copy2(exe_paths[0], dest_path)
|
|
224
|
+
|
|
225
|
+
if self.os_name != 'windows':
|
|
226
|
+
os.chmod(dest_path, 0o755)
|
|
227
|
+
|
|
228
|
+
found_paths.append(dest_path)
|
|
229
|
+
else:
|
|
230
|
+
found_paths.append(None)
|
|
231
|
+
|
|
232
|
+
shutil.rmtree(extraction_path, ignore_errors=True)
|
|
233
|
+
os.remove(archive_path)
|
|
234
|
+
|
|
235
|
+
return tuple(found_paths) if len(found_paths) == 3 else (None, None, None)
|
|
236
|
+
|
|
237
|
+
except Exception as e:
|
|
238
|
+
logging.error(f"Extraction/copy error: {e}")
|
|
239
|
+
return None, None, None
|
|
240
|
+
|
|
241
|
+
def download(self) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
|
242
|
+
"""
|
|
243
|
+
Main method to download and set up FFmpeg executables.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
|
|
247
|
+
Returns None for each executable that couldn't be downloaded or set up.
|
|
248
|
+
"""
|
|
249
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
250
|
+
executables = [exe.format(arch=self.arch) for exe in config['executables']]
|
|
251
|
+
|
|
252
|
+
for executable in executables:
|
|
253
|
+
download_url = f"https://github.com/eugeneware/ffmpeg-static/releases/latest/download/{executable}.gz"
|
|
254
|
+
download_path = os.path.join(self.base_dir, f"{executable}.gz")
|
|
255
|
+
final_path = os.path.join(self.base_dir, executable)
|
|
256
|
+
|
|
257
|
+
console.print(f"[bold blue]Downloading {executable} from GitHub[/]")
|
|
258
|
+
if not self._download_file(download_url, download_path):
|
|
259
|
+
return None, None, None
|
|
260
|
+
|
|
261
|
+
with gzip.open(download_path, 'rb') as f_in, open(final_path, 'wb') as f_out:
|
|
262
|
+
shutil.copyfileobj(f_in, f_out)
|
|
263
|
+
|
|
264
|
+
os.chmod(final_path, 0o755)
|
|
265
|
+
os.remove(download_path)
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
os.path.join(self.base_dir, executables[0]),
|
|
269
|
+
os.path.join(self.base_dir, executables[1]),
|
|
270
|
+
None
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
def check_ffmpeg() -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
|
274
|
+
"""
|
|
275
|
+
Check for FFmpeg executables in the system and download them if not found.
|
|
276
|
+
Enhanced detection for macOS systems.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
|
|
280
|
+
"""
|
|
281
|
+
try:
|
|
282
|
+
system_platform = platform.system().lower()
|
|
283
|
+
|
|
284
|
+
# Special handling for macOS
|
|
285
|
+
if system_platform == 'darwin':
|
|
286
|
+
|
|
287
|
+
# Common installation paths on macOS
|
|
288
|
+
potential_paths = [
|
|
289
|
+
'/usr/local/bin', # Homebrew default
|
|
290
|
+
'/opt/homebrew/bin', # Apple Silicon Homebrew
|
|
291
|
+
'/usr/bin', # System default
|
|
292
|
+
os.path.expanduser('~/Applications/binary'), # Custom installation
|
|
293
|
+
'/Applications/binary' # Custom installation
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
for path in potential_paths:
|
|
297
|
+
ffmpeg_path = os.path.join(path, 'ffmpeg')
|
|
298
|
+
ffprobe_path = os.path.join(path, 'ffprobe')
|
|
299
|
+
ffplay_path = os.path.join(path, 'ffplay')
|
|
300
|
+
|
|
301
|
+
if (os.path.exists(ffmpeg_path) and os.path.exists(ffprobe_path) and
|
|
302
|
+
os.access(ffmpeg_path, os.X_OK) and os.access(ffprobe_path, os.X_OK)):
|
|
303
|
+
|
|
304
|
+
# Return found executables, with ffplay being optional
|
|
305
|
+
ffplay_path = ffplay_path if os.path.exists(ffplay_path) else None
|
|
306
|
+
return ffmpeg_path, ffprobe_path, ffplay_path
|
|
307
|
+
|
|
308
|
+
# Windows detection
|
|
309
|
+
elif system_platform == 'windows':
|
|
310
|
+
try:
|
|
311
|
+
ffmpeg_path = subprocess.check_output(
|
|
312
|
+
['where', 'ffmpeg'], stderr=subprocess.DEVNULL, text=True
|
|
313
|
+
).strip().split('\n')[0]
|
|
314
|
+
|
|
315
|
+
ffprobe_path = subprocess.check_output(
|
|
316
|
+
['where', 'ffprobe'], stderr=subprocess.DEVNULL, text=True
|
|
317
|
+
).strip().split('\n')[0]
|
|
318
|
+
|
|
319
|
+
ffplay_path = subprocess.check_output(
|
|
320
|
+
['where', 'ffplay'], stderr=subprocess.DEVNULL, text=True
|
|
321
|
+
).strip().split('\n')[0]
|
|
322
|
+
|
|
323
|
+
return ffmpeg_path, ffprobe_path, ffplay_path
|
|
324
|
+
|
|
325
|
+
except subprocess.CalledProcessError:
|
|
326
|
+
logging.warning("One or more FFmpeg binaries were not found with command where")
|
|
327
|
+
|
|
328
|
+
# Linux detection
|
|
329
|
+
else:
|
|
330
|
+
ffmpeg_path = shutil.which('ffmpeg')
|
|
331
|
+
ffprobe_path = shutil.which('ffprobe')
|
|
332
|
+
ffplay_path = shutil.which('ffplay')
|
|
333
|
+
|
|
334
|
+
if ffmpeg_path and ffprobe_path:
|
|
335
|
+
return ffmpeg_path, ffprobe_path, ffplay_path
|
|
336
|
+
|
|
337
|
+
# If executables were not found, attempt to download FFmpeg
|
|
338
|
+
downloader = FFMPEGDownloader()
|
|
339
|
+
return downloader.download()
|
|
340
|
+
|
|
341
|
+
except Exception as e:
|
|
342
|
+
logging.error(f"Error checking or downloading FFmpeg executables: {e}")
|
|
371
343
|
return None, None, None
|