StreamingCommunity 2.5.0__py3-none-any.whl → 2.5.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.
Potentially problematic release.
This version of StreamingCommunity might be problematic. Click here for more details.
- 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/Helper/Vixcloud/js_parser.py +143 -0
- StreamingCommunity/Api/Player/Helper/Vixcloud/util.py +136 -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/Player/ddl.py +89 -0
- StreamingCommunity/Api/Player/maxstream.py +151 -0
- StreamingCommunity/Api/Player/supervideo.py +194 -0
- StreamingCommunity/Api/Player/vixcloud.py +273 -0
- StreamingCommunity/Api/Site/1337xx/__init__.py +51 -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/1337xx/costant.py +15 -0
- StreamingCommunity/Api/Site/1337xx/site.py +89 -0
- StreamingCommunity/Api/Site/1337xx/title.py +64 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +51 -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/altadefinizionegratis/costant.py +19 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/film.py +72 -0
- StreamingCommunity/Api/Site/altadefinizionegratis/site.py +95 -0
- StreamingCommunity/Api/Site/animeunity/__init__.py +51 -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/costant.py +19 -0
- StreamingCommunity/Api/Site/animeunity/film_serie.py +135 -0
- StreamingCommunity/Api/Site/animeunity/site.py +175 -0
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +97 -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/__init__.py +52 -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/cb01new/costant.py +19 -0
- StreamingCommunity/Api/Site/cb01new/film.py +71 -0
- StreamingCommunity/Api/Site/cb01new/site.py +83 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +56 -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/costant.py +20 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +145 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +99 -0
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +85 -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/__init__.py +51 -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/costant.py +19 -0
- StreamingCommunity/Api/Site/guardaserie/series.py +198 -0
- StreamingCommunity/Api/Site/guardaserie/site.py +90 -0
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +110 -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/__init__.py +52 -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/costant.py +19 -0
- StreamingCommunity/Api/Site/ilcorsaronero/site.py +72 -0
- StreamingCommunity/Api/Site/ilcorsaronero/title.py +44 -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/ilcorsaronero/util/ilCorsarScraper.py +149 -0
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +49 -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/mostraguarda/costant.py +19 -0
- StreamingCommunity/Api/Site/mostraguarda/film.py +101 -0
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +56 -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/costant.py +19 -0
- StreamingCommunity/Api/Site/streamingcommunity/film.py +75 -0
- StreamingCommunity/Api/Site/streamingcommunity/series.py +207 -0
- StreamingCommunity/Api/Site/streamingcommunity/site.py +143 -0
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +124 -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/SearchType.py +101 -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/__init__.py +5 -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/Util/get_domain.py +202 -0
- StreamingCommunity/Api/Template/Util/manage_ep.py +179 -0
- StreamingCommunity/Api/Template/Util/recall_search.py +37 -0
- StreamingCommunity/Api/Template/__init__.py +3 -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/Api/Template/site.py +87 -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/HLS/downloader.py +1008 -0
- StreamingCommunity/Lib/Downloader/HLS/proxyes.py +110 -0
- StreamingCommunity/Lib/Downloader/HLS/segments.py +573 -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/MP4/downloader.py +155 -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/TOR/downloader.py +296 -0
- StreamingCommunity/Lib/Downloader/__init__.py +5 -0
- StreamingCommunity/Lib/Downloader/__pycache__/__init__.cpython-313.pyc +0 -0
- StreamingCommunity/Lib/Downloader/__pycache__/__init__.cpython-39.pyc +0 -0
- StreamingCommunity/Lib/FFmpeg/__init__.py +4 -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/FFmpeg/capture.py +170 -0
- StreamingCommunity/Lib/FFmpeg/command.py +296 -0
- StreamingCommunity/Lib/FFmpeg/util.py +249 -0
- StreamingCommunity/Lib/M3U8/__init__.py +6 -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/M3U8/decryptor.py +165 -0
- StreamingCommunity/Lib/M3U8/estimator.py +229 -0
- StreamingCommunity/Lib/M3U8/parser.py +666 -0
- StreamingCommunity/Lib/M3U8/url_fixer.py +58 -0
- StreamingCommunity/Lib/TMBD/__init__.py +2 -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/Lib/TMBD/obj_tmbd.py +39 -0
- StreamingCommunity/Lib/TMBD/tmdb.py +346 -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/Upload/update.py +67 -0
- StreamingCommunity/Upload/version.py +5 -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/Util/_jsonConfig.py +228 -0
- StreamingCommunity/Util/call_stack.py +42 -0
- StreamingCommunity/Util/color.py +20 -0
- StreamingCommunity/Util/console.py +12 -0
- StreamingCommunity/Util/ffmpeg_installer.py +371 -0
- StreamingCommunity/Util/headers.py +160 -0
- StreamingCommunity/Util/logger.py +62 -0
- StreamingCommunity/Util/message.py +64 -0
- StreamingCommunity/Util/os.py +507 -0
- StreamingCommunity/Util/table.py +229 -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.0.dist-info → StreamingCommunity-2.5.2.dist-info}/METADATA +1 -1
- StreamingCommunity-2.5.2.dist-info/RECORD +264 -0
- StreamingCommunity-2.5.0.dist-info/RECORD +0 -8
- {StreamingCommunity-2.5.0.dist-info → StreamingCommunity-2.5.2.dist-info}/LICENSE +0 -0
- {StreamingCommunity-2.5.0.dist-info → StreamingCommunity-2.5.2.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.5.0.dist-info → StreamingCommunity-2.5.2.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-2.5.0.dist-info → StreamingCommunity-2.5.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
# 24.01.24
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import shutil
|
|
8
|
+
import hashlib
|
|
9
|
+
import logging
|
|
10
|
+
import platform
|
|
11
|
+
import subprocess
|
|
12
|
+
import contextlib
|
|
13
|
+
import urllib.request
|
|
14
|
+
import importlib.metadata
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# External library
|
|
18
|
+
import httpx
|
|
19
|
+
from unidecode import unidecode
|
|
20
|
+
from pathvalidate import sanitize_filename, sanitize_filepath
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Internal utilities
|
|
24
|
+
from .ffmpeg_installer import check_ffmpeg
|
|
25
|
+
from StreamingCommunity.Util.console import console, msg
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class OsManager:
|
|
30
|
+
def __init__(self):
|
|
31
|
+
self.system = self._detect_system()
|
|
32
|
+
self.max_length = self._get_max_length()
|
|
33
|
+
|
|
34
|
+
def _detect_system(self) -> str:
|
|
35
|
+
"""Detect and normalize operating system name."""
|
|
36
|
+
system = platform.system().lower()
|
|
37
|
+
if system not in ['windows', 'darwin', 'linux']:
|
|
38
|
+
raise ValueError(f"Unsupported operating system: {system}")
|
|
39
|
+
return system
|
|
40
|
+
|
|
41
|
+
def _get_max_length(self) -> int:
|
|
42
|
+
"""Get max filename length based on OS."""
|
|
43
|
+
return 255 if self.system == 'windows' else 4096
|
|
44
|
+
|
|
45
|
+
def _normalize_windows_path(self, path: str) -> str:
|
|
46
|
+
"""Normalize Windows paths."""
|
|
47
|
+
if not path or self.system != 'windows':
|
|
48
|
+
return path
|
|
49
|
+
|
|
50
|
+
# Preserve network paths (UNC and IP-based)
|
|
51
|
+
if path.startswith('\\\\') or path.startswith('//'):
|
|
52
|
+
return path.replace('/', '\\')
|
|
53
|
+
|
|
54
|
+
# Handle drive letters
|
|
55
|
+
if len(path) >= 2 and path[1] == ':':
|
|
56
|
+
drive = path[0:2]
|
|
57
|
+
rest = path[2:].replace('/', '\\').lstrip('\\')
|
|
58
|
+
return f"{drive}\\{rest}"
|
|
59
|
+
|
|
60
|
+
return path.replace('/', '\\')
|
|
61
|
+
|
|
62
|
+
def _normalize_mac_path(self, path: str) -> str:
|
|
63
|
+
"""Normalize macOS paths."""
|
|
64
|
+
if not path or self.system != 'darwin':
|
|
65
|
+
return path
|
|
66
|
+
|
|
67
|
+
# Convert Windows separators to Unix
|
|
68
|
+
normalized = path.replace('\\', '/')
|
|
69
|
+
|
|
70
|
+
# Ensure absolute paths start with /
|
|
71
|
+
if normalized.startswith('/'):
|
|
72
|
+
return os.path.normpath(normalized)
|
|
73
|
+
|
|
74
|
+
return normalized
|
|
75
|
+
|
|
76
|
+
def get_sanitize_file(self, filename: str) -> str:
|
|
77
|
+
"""Sanitize filename."""
|
|
78
|
+
if not filename:
|
|
79
|
+
return filename
|
|
80
|
+
|
|
81
|
+
# Decode and sanitize
|
|
82
|
+
decoded = unidecode(filename)
|
|
83
|
+
sanitized = sanitize_filename(decoded)
|
|
84
|
+
|
|
85
|
+
# Split name and extension
|
|
86
|
+
name, ext = os.path.splitext(sanitized)
|
|
87
|
+
|
|
88
|
+
# Calculate available length for name considering the '...' and extension
|
|
89
|
+
max_name_length = self.max_length - len('...') - len(ext)
|
|
90
|
+
|
|
91
|
+
# Truncate name if it exceeds the max name length
|
|
92
|
+
if len(name) > max_name_length:
|
|
93
|
+
name = name[:max_name_length] + '...'
|
|
94
|
+
|
|
95
|
+
# Ensure the final file name includes the extension
|
|
96
|
+
return name + ext
|
|
97
|
+
|
|
98
|
+
def get_sanitize_path(self, path: str) -> str:
|
|
99
|
+
"""Sanitize complete path."""
|
|
100
|
+
if not path:
|
|
101
|
+
return path
|
|
102
|
+
|
|
103
|
+
# Decode unicode characters
|
|
104
|
+
decoded = unidecode(path)
|
|
105
|
+
|
|
106
|
+
# Basic path sanitization
|
|
107
|
+
sanitized = sanitize_filepath(decoded)
|
|
108
|
+
|
|
109
|
+
if self.system == 'windows':
|
|
110
|
+
# Handle network paths (UNC or IP-based)
|
|
111
|
+
if path.startswith('\\\\') or path.startswith('//'):
|
|
112
|
+
parts = path.replace('/', '\\').split('\\')
|
|
113
|
+
# Keep server/IP and share name as is
|
|
114
|
+
sanitized_parts = parts[:4]
|
|
115
|
+
# Sanitize remaining parts
|
|
116
|
+
if len(parts) > 4:
|
|
117
|
+
sanitized_parts.extend([
|
|
118
|
+
self.get_sanitize_file(part)
|
|
119
|
+
for part in parts[4:]
|
|
120
|
+
if part
|
|
121
|
+
])
|
|
122
|
+
return '\\'.join(sanitized_parts)
|
|
123
|
+
|
|
124
|
+
# Handle drive letters
|
|
125
|
+
elif len(path) >= 2 and path[1] == ':':
|
|
126
|
+
drive = path[:2]
|
|
127
|
+
rest = path[2:].lstrip('\\').lstrip('/')
|
|
128
|
+
path_parts = [drive] + [
|
|
129
|
+
self.get_sanitize_file(part)
|
|
130
|
+
for part in rest.replace('/', '\\').split('\\')
|
|
131
|
+
if part
|
|
132
|
+
]
|
|
133
|
+
return '\\'.join(path_parts)
|
|
134
|
+
|
|
135
|
+
# Regular path
|
|
136
|
+
else:
|
|
137
|
+
parts = path.replace('/', '\\').split('\\')
|
|
138
|
+
return '\\'.join(p for p in parts if p)
|
|
139
|
+
else:
|
|
140
|
+
# Handle Unix-like paths (Linux and macOS)
|
|
141
|
+
is_absolute = path.startswith('/')
|
|
142
|
+
parts = path.replace('\\', '/').split('/')
|
|
143
|
+
sanitized_parts = [
|
|
144
|
+
self.get_sanitize_file(part)
|
|
145
|
+
for part in parts
|
|
146
|
+
if part
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
result = '/'.join(sanitized_parts)
|
|
150
|
+
if is_absolute:
|
|
151
|
+
result = '/' + result
|
|
152
|
+
|
|
153
|
+
return result
|
|
154
|
+
|
|
155
|
+
def create_path(self, path: str, mode: int = 0o755) -> bool:
|
|
156
|
+
"""
|
|
157
|
+
Create directory path with specified permissions.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
path (str): Path to create.
|
|
161
|
+
mode (int, optional): Directory permissions. Defaults to 0o755.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
bool: True if path created successfully, False otherwise.
|
|
165
|
+
"""
|
|
166
|
+
try:
|
|
167
|
+
sanitized_path = self.get_sanitize_path(path)
|
|
168
|
+
os.makedirs(sanitized_path, mode=mode, exist_ok=True)
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
except Exception as e:
|
|
172
|
+
logging.error(f"Path creation error: {e}")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
def remove_folder(self, folder_path: str) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
Safely remove a folder.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
folder_path (str): Path of directory to remove.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
bool: Removal status.
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
shutil.rmtree(folder_path)
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
except OSError as e:
|
|
190
|
+
logging.error(f"Folder removal error: {e}")
|
|
191
|
+
return False
|
|
192
|
+
|
|
193
|
+
def remove_files_except_one(self, folder_path: str, keep_file: str) -> None:
|
|
194
|
+
"""
|
|
195
|
+
Delete all files in a folder except for one specified file.
|
|
196
|
+
|
|
197
|
+
Parameters:
|
|
198
|
+
- folder_path (str): The path to the folder containing the files.
|
|
199
|
+
- keep_file (str): The filename to keep in the folder.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
# List all files in the folder
|
|
204
|
+
files_in_folder = os.listdir(folder_path)
|
|
205
|
+
|
|
206
|
+
# Iterate over each file in the folder
|
|
207
|
+
for file_name in files_in_folder:
|
|
208
|
+
file_path = os.path.join(folder_path, file_name)
|
|
209
|
+
|
|
210
|
+
# Check if the file is not the one to keep and is a regular file
|
|
211
|
+
if file_name != keep_file and os.path.isfile(file_path):
|
|
212
|
+
os.remove(file_path) # Delete the file
|
|
213
|
+
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logging.error(f"An error occurred: {e}")
|
|
216
|
+
raise
|
|
217
|
+
|
|
218
|
+
def check_file(self, file_path: str) -> bool:
|
|
219
|
+
"""
|
|
220
|
+
Check if a file exists at the given file path.
|
|
221
|
+
|
|
222
|
+
Parameters:
|
|
223
|
+
file_path (str): The path to the file.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
bool: True if the file exists, False otherwise.
|
|
227
|
+
"""
|
|
228
|
+
try:
|
|
229
|
+
logging.info(f"Check if file exists: {file_path}")
|
|
230
|
+
return os.path.exists(file_path)
|
|
231
|
+
|
|
232
|
+
except Exception as e:
|
|
233
|
+
logging.error(f"An error occurred while checking file existence: {e}")
|
|
234
|
+
return False
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class InternManager():
|
|
238
|
+
|
|
239
|
+
def format_file_size(self, size_bytes: float) -> str:
|
|
240
|
+
"""
|
|
241
|
+
Formats a file size from bytes into a human-readable string representation.
|
|
242
|
+
|
|
243
|
+
Parameters:
|
|
244
|
+
size_bytes (float): Size in bytes to be formatted.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
str: Formatted string representing the file size with appropriate unit (B, KB, MB, GB, TB).
|
|
248
|
+
"""
|
|
249
|
+
if size_bytes <= 0:
|
|
250
|
+
return "0B"
|
|
251
|
+
|
|
252
|
+
units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
253
|
+
unit_index = 0
|
|
254
|
+
|
|
255
|
+
while size_bytes >= 1024 and unit_index < len(units) - 1:
|
|
256
|
+
size_bytes /= 1024
|
|
257
|
+
unit_index += 1
|
|
258
|
+
|
|
259
|
+
return f"{size_bytes:.2f} {units[unit_index]}"
|
|
260
|
+
|
|
261
|
+
def format_transfer_speed(self, bytes: float) -> str:
|
|
262
|
+
"""
|
|
263
|
+
Formats a transfer speed from bytes per second into a human-readable string representation.
|
|
264
|
+
|
|
265
|
+
Parameters:
|
|
266
|
+
bytes (float): Speed in bytes per second to be formatted.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
str: Formatted string representing the transfer speed with appropriate unit (Bytes/s, KB/s, MB/s).
|
|
270
|
+
"""
|
|
271
|
+
if bytes < 1024:
|
|
272
|
+
return f"{bytes:.2f} Bytes/s"
|
|
273
|
+
elif bytes < 1024 * 1024:
|
|
274
|
+
return f"{bytes / 1024:.2f} KB/s"
|
|
275
|
+
else:
|
|
276
|
+
return f"{bytes / (1024 * 1024):.2f} MB/s"
|
|
277
|
+
|
|
278
|
+
@staticmethod
|
|
279
|
+
def check_internet():
|
|
280
|
+
while True:
|
|
281
|
+
try:
|
|
282
|
+
httpx.get("https://www.google.com", timeout=15)
|
|
283
|
+
break
|
|
284
|
+
|
|
285
|
+
except urllib.error.URLError:
|
|
286
|
+
console.log("[bold red]Internet is not available. Waiting...[/bold red]")
|
|
287
|
+
time.sleep(5)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class OsSummary:
|
|
291
|
+
|
|
292
|
+
def __init__(self):
|
|
293
|
+
self.ffmpeg_path = None
|
|
294
|
+
self.ffprobe_path = None
|
|
295
|
+
self.ffplay_path = None
|
|
296
|
+
|
|
297
|
+
def get_executable_version(self, command: list):
|
|
298
|
+
"""
|
|
299
|
+
Get the version of a given command-line executable.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
command (list): The command to run, e.g., `['ffmpeg', '-version']`.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
str: The version string of the executable.
|
|
306
|
+
"""
|
|
307
|
+
try:
|
|
308
|
+
version_output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode().split('\n')[0]
|
|
309
|
+
return version_output.split(" ")[2]
|
|
310
|
+
|
|
311
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
312
|
+
console.print(f"{command[0]} not found", style="bold red")
|
|
313
|
+
sys.exit(0)
|
|
314
|
+
|
|
315
|
+
def check_ffmpeg_location(self, command: list) -> str:
|
|
316
|
+
"""
|
|
317
|
+
Check if a specific executable (ffmpeg or ffprobe) is located using the given command.
|
|
318
|
+
Returns the path of the executable or None if not found.
|
|
319
|
+
"""
|
|
320
|
+
try:
|
|
321
|
+
result = subprocess.check_output(command, text=True).strip()
|
|
322
|
+
return result.split('\n')[0] if result else None
|
|
323
|
+
|
|
324
|
+
except subprocess.CalledProcessError:
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
def get_library_version(self, lib_name: str):
|
|
328
|
+
"""
|
|
329
|
+
Retrieve the version of a Python library.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
lib_name (str): The name of the Python library.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
str: The library name followed by its version, or `-not installed` if not found.
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
version = importlib.metadata.version(lib_name)
|
|
339
|
+
return f"{lib_name}-{version}"
|
|
340
|
+
|
|
341
|
+
except importlib.metadata.PackageNotFoundError:
|
|
342
|
+
return f"{lib_name}-not installed"
|
|
343
|
+
|
|
344
|
+
def download_requirements(self, url: str, filename: str):
|
|
345
|
+
"""
|
|
346
|
+
Download the requirements.txt file from the specified URL if not found locally using requests.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
url (str): The URL to download the requirements file from.
|
|
350
|
+
filename (str): The local filename to save the requirements file as.
|
|
351
|
+
"""
|
|
352
|
+
try:
|
|
353
|
+
import requests
|
|
354
|
+
|
|
355
|
+
logging.info(f"{filename} not found locally. Downloading from {url}...")
|
|
356
|
+
response = requests.get(url)
|
|
357
|
+
|
|
358
|
+
if response.status_code == 200:
|
|
359
|
+
with open(filename, 'wb') as f:
|
|
360
|
+
f.write(response.content)
|
|
361
|
+
|
|
362
|
+
else:
|
|
363
|
+
logging.error(f"Failed to download {filename}. HTTP Status code: {response.status_code}")
|
|
364
|
+
sys.exit(0)
|
|
365
|
+
|
|
366
|
+
except Exception as e:
|
|
367
|
+
logging.error(f"Failed to download {filename}: {e}")
|
|
368
|
+
sys.exit(0)
|
|
369
|
+
|
|
370
|
+
def install_library(self, lib_name: str):
|
|
371
|
+
"""
|
|
372
|
+
Install a Python library using pip.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
lib_name (str): The name of the library to install.
|
|
376
|
+
"""
|
|
377
|
+
try:
|
|
378
|
+
console.print(f"Installing {lib_name}...", style="bold yellow")
|
|
379
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", lib_name])
|
|
380
|
+
console.print(f"{lib_name} installed successfully!", style="bold green")
|
|
381
|
+
|
|
382
|
+
except subprocess.CalledProcessError as e:
|
|
383
|
+
console.print(f"Failed to install {lib_name}: {e}", style="bold red")
|
|
384
|
+
sys.exit(1)
|
|
385
|
+
|
|
386
|
+
def check_python_version(self):
|
|
387
|
+
"""
|
|
388
|
+
Check if the installed Python is the official CPython distribution.
|
|
389
|
+
Exits with a message if not the official version.
|
|
390
|
+
"""
|
|
391
|
+
python_implementation = platform.python_implementation()
|
|
392
|
+
|
|
393
|
+
if python_implementation != "CPython":
|
|
394
|
+
console.print(f"[bold red]Warning: You are using a non-official Python distribution: {python_implementation}.[/bold red]")
|
|
395
|
+
console.print("Please install the official Python from [bold blue]https://www.python.org[/bold blue] and try again.", style="bold yellow")
|
|
396
|
+
sys.exit(0)
|
|
397
|
+
|
|
398
|
+
def get_system_summary(self):
|
|
399
|
+
"""
|
|
400
|
+
Generate a summary of the system environment.
|
|
401
|
+
|
|
402
|
+
Includes:
|
|
403
|
+
- Python version and implementation details.
|
|
404
|
+
- Operating system and architecture.
|
|
405
|
+
- Versions of `ffmpeg` and `ffprobe` executables.
|
|
406
|
+
- Installed Python libraries as listed in `requirements.txt`.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
# Check if Python is the official CPython
|
|
410
|
+
self.check_python_version()
|
|
411
|
+
|
|
412
|
+
# Check internet connectivity
|
|
413
|
+
InternManager().check_internet()
|
|
414
|
+
console.print("[bold blue]System Summary[/bold blue][white]:")
|
|
415
|
+
|
|
416
|
+
# Python version and platform
|
|
417
|
+
python_version = sys.version.split()[0]
|
|
418
|
+
python_implementation = platform.python_implementation()
|
|
419
|
+
arch = platform.machine()
|
|
420
|
+
os_info = platform.platform()
|
|
421
|
+
glibc_version = 'glibc ' + '.'.join(map(str, platform.libc_ver()[1]))
|
|
422
|
+
|
|
423
|
+
console.print(f"[cyan]Python[white]: [bold red]{python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})[/bold red]")
|
|
424
|
+
logging.info(f"Python: {python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})")
|
|
425
|
+
|
|
426
|
+
# Use the 'where' command on Windows and 'which' command on Unix-like systems
|
|
427
|
+
system_platform = platform.system().lower()
|
|
428
|
+
command = 'where' if system_platform == 'windows' else 'which'
|
|
429
|
+
|
|
430
|
+
# Locate ffmpeg and ffprobe from the PATH environment
|
|
431
|
+
if self.ffmpeg_path is not None and "binary" not in self.ffmpeg_path:
|
|
432
|
+
self.ffmpeg_path = self.check_ffmpeg_location([command, 'ffmpeg'])
|
|
433
|
+
|
|
434
|
+
if self.ffprobe_path is not None and "binary" not in self.ffprobe_path:
|
|
435
|
+
self.ffprobe_path = self.check_ffmpeg_location([command, 'ffprobe'])
|
|
436
|
+
|
|
437
|
+
# If ffmpeg or ffprobe is not located, fall back to using the check_ffmpeg function
|
|
438
|
+
if self.ffmpeg_path is None or self.ffprobe_path is None:
|
|
439
|
+
self.ffmpeg_path, self.ffprobe_path, self.ffplay_path = check_ffmpeg()
|
|
440
|
+
|
|
441
|
+
# If still not found, print error and exit
|
|
442
|
+
if self.ffmpeg_path is None or self.ffprobe_path is None:
|
|
443
|
+
console.log("[red]Can't locate ffmpeg or ffprobe")
|
|
444
|
+
sys.exit(0)
|
|
445
|
+
|
|
446
|
+
ffmpeg_version = self.get_executable_version([self.ffprobe_path, '-version'])
|
|
447
|
+
ffprobe_version = self.get_executable_version([self.ffprobe_path, '-version'])
|
|
448
|
+
|
|
449
|
+
console.print(f"[cyan]Path[white]: [red]ffmpeg [bold yellow]'{self.ffmpeg_path}'[/bold yellow][white], [red]ffprobe '[bold yellow]{self.ffprobe_path}'[/bold yellow]")
|
|
450
|
+
console.print(f"[cyan]Exe versions[white]: [bold red]ffmpeg {ffmpeg_version}, ffprobe {ffprobe_version}[/bold red]")
|
|
451
|
+
|
|
452
|
+
# Check if requirements.txt exists, if not on pyinstaller
|
|
453
|
+
if not getattr(sys, 'frozen', False):
|
|
454
|
+
requirements_file = 'requirements.txt'
|
|
455
|
+
|
|
456
|
+
if not os.path.exists(requirements_file):
|
|
457
|
+
self.download_requirements(
|
|
458
|
+
'https://raw.githubusercontent.com/Lovi-0/StreamingCommunity/refs/heads/main/requirements.txt',
|
|
459
|
+
requirements_file
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
# Read the optional libraries from the requirements file, get only name without version if "library==1.0.0"
|
|
463
|
+
optional_libraries = [line.strip().split("=")[0] for line in open(requirements_file, 'r', encoding='utf-8-sig')]
|
|
464
|
+
|
|
465
|
+
# Check if libraries are installed and prompt to install missing ones
|
|
466
|
+
for lib in optional_libraries:
|
|
467
|
+
installed_version = self.get_library_version(lib)
|
|
468
|
+
|
|
469
|
+
if 'not installed' in installed_version:
|
|
470
|
+
user_response = msg.ask(f"{lib} is not installed. Do you want to install it? (yes/no)", default="y")
|
|
471
|
+
|
|
472
|
+
if user_response.lower().strip() in ["yes", "y"]:
|
|
473
|
+
self.install_library(lib)
|
|
474
|
+
|
|
475
|
+
else:
|
|
476
|
+
logging.info(f"Library: {installed_version}")
|
|
477
|
+
|
|
478
|
+
console.print(f"[cyan]Libraries[white]: [bold red]{', '.join([self.get_library_version(lib) for lib in optional_libraries])}[/bold red]\n")
|
|
479
|
+
logging.info(f"Libraries: {', '.join([self.get_library_version(lib) for lib in optional_libraries])}")
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
# OTHER
|
|
483
|
+
os_manager = OsManager()
|
|
484
|
+
internet_manager = InternManager()
|
|
485
|
+
os_summary = OsSummary()
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@contextlib.contextmanager
|
|
489
|
+
def suppress_output():
|
|
490
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
|
491
|
+
yield
|
|
492
|
+
|
|
493
|
+
def compute_sha1_hash(input_string: str) -> str:
|
|
494
|
+
"""
|
|
495
|
+
Computes the SHA-1 hash of the input string.
|
|
496
|
+
|
|
497
|
+
Parameters:
|
|
498
|
+
- input_string (str): The string to be hashed.
|
|
499
|
+
|
|
500
|
+
Returns:
|
|
501
|
+
str: The SHA-1 hash of the input string.
|
|
502
|
+
"""
|
|
503
|
+
# Compute the SHA-1 hash
|
|
504
|
+
hashed_string = hashlib.sha1(input_string.encode()).hexdigest()
|
|
505
|
+
|
|
506
|
+
# Return the hashed string
|
|
507
|
+
return hashed_string
|