diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..089c5cb --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,48 @@ +name: Build and Release with PyInstaller + +on: + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Cache Python dependencies + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install fake-useragent==1.1.3 + + - name: Build executable with PyInstaller + run: | + pyinstaller --onefile --hidden-import=pycryptodomex --hidden-import=fake_useragent --hidden-import=qbittorrentapi --hidden-import=qbittorrent --hidden-import=googlesearch --hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm --hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode --hidden-import=jsbeautifier --hidden-import=pathvalidate --hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES --hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding --hidden-import=Cryptodome.Random --hidden-import=Pillow --hidden-import=pyTelegramBotAPI --additional-hooks-dir=pyinstaller/hooks --add-data "StreamingCommunity;StreamingCommunity" --name=StreamingCommunity --icon="StreamingCommunity/Test/Media/62809003.ico" test_run.py + + - name: Upload executable as artifact + uses: actions/upload-artifact@v3 + with: + name: StreamingCommunity + path: dist/StreamingCommunity.exe + + - name: Create or update GitHub release + uses: softprops/action-gh-release@v1 + with: + files: dist/StreamingCommunity.exe + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/update-loc-badge.yml b/.github/workflows/update-loc-badge.yml index ab23e14..eadfba5 100644 --- a/.github/workflows/update-loc-badge.yml +++ b/.github/workflows/update-loc-badge.yml @@ -18,12 +18,12 @@ jobs: - name: Count Lines of Code run: | LOC=$(cloc . --json | jq '.SUM.code') - echo "{\"schemaVersion\": 1, \"label\": \"Lines of Code\", \"message\": \"$LOC\", \"color\": \"green\"}" > Test/Util/loc-badge.json + echo "{\"schemaVersion\": 1, \"label\": \"Lines of Code\", \"message\": \"$LOC\", \"color\": \"green\"}" > Test/Media/loc-badge.json - name: Commit and Push LOC Badge run: | git config --local user.name "GitHub Actions" git config --local user.email "actions@github.com" - git add Test/Util/loc-badge.json + git add Test/Media/loc-badge.json git commit -m "Update lines of code badge" || echo "No changes to commit" git push \ No newline at end of file diff --git a/.gitignore b/.gitignore index 231113a..d7cc0b7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,8 +23,6 @@ share/python-wheels/ # PyInstaller *.manifest *.spec -setup.py -MANIFEST.in # Installer logs pip-log.txt diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..e02a32e --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +recursive-include StreamingCommunity * +recursive-include StreamingCommunity/Api * +recursive-include StreamingCommunity/Lib * \ No newline at end of file diff --git a/README.md b/README.md index 0381241..88c0e0a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Project Logo + Project Logo

@@ -25,7 +25,7 @@ PyPI Downloads - Lines of Code + Lines of Code

diff --git a/StreamingCommunity/Api/Site/cb01new/film.py b/StreamingCommunity/Api/Site/cb01new/film.py index 249329d..392612b 100644 --- a/StreamingCommunity/Api/Site/cb01new/film.py +++ b/StreamingCommunity/Api/Site/cb01new/film.py @@ -37,7 +37,6 @@ def download_film(select_title: MediaItem) -> str: console.print(f"[cyan]You can safely stop the download with [bold]Ctrl+c[bold] [cyan] \n") # Setup api manger - print(select_title.url) video_source = VideoSource(select_title.url) # Define output path diff --git a/StreamingCommunity/Lib/Downloader/HLS/downloader.py b/StreamingCommunity/Lib/Downloader/HLS/downloader.py index 4fbb583..e3e124c 100644 --- a/StreamingCommunity/Lib/Downloader/HLS/downloader.py +++ b/StreamingCommunity/Lib/Downloader/HLS/downloader.py @@ -506,8 +506,8 @@ class HLS_Downloader: file_size = internet_manager.format_file_size(os.path.getsize(self.path_manager.output_path)) duration = print_duration_table(self.path_manager.output_path, description=False, return_string=True) + print() panel_content = ( - f"[bold green]Download completed![/bold green]\n" f"[cyan]File size: [bold red]{file_size}[/bold red]\n" f"[cyan]Duration: [bold]{duration}[/bold]\n" f"[cyan]Output: [bold]{os.path.abspath(self.path_manager.output_path)}[/bold]" diff --git a/StreamingCommunity/Lib/Downloader/HLS/segments.py b/StreamingCommunity/Lib/Downloader/HLS/segments.py index b17b453..cfc0da5 100644 --- a/StreamingCommunity/Lib/Downloader/HLS/segments.py +++ b/StreamingCommunity/Lib/Downloader/HLS/segments.py @@ -87,6 +87,7 @@ class M3U8_Segments: self.info_maxRetry = 0 self.info_nRetry = 0 self.info_nFailed = 0 + self.active_retries = 0 self.active_retries_lock = threading.Lock() @@ -170,7 +171,8 @@ class M3U8_Segments: client_params = { 'headers': random_headers(self.key_base_url) if hasattr(self, 'key_base_url') else {'User-Agent': get_headers()}, 'timeout': MAX_TIMEOOUT, - 'follow_redirects': True + 'follow_redirects': True, + 'http2': False } if THERE_IS_PROXY_LIST and index is not None and hasattr(self, 'valid_proxy'): @@ -178,7 +180,7 @@ class M3U8_Segments: return httpx.Client(**client_params) - def download_segment(self, ts_url: str, index: int, progress_bar: tqdm, backoff_factor: float = 1.3) -> None: + def download_segment(self, ts_url: str, index: int, progress_bar: tqdm, backoff_factor: float = 1.1) -> None: """ Downloads a TS segment and adds it to the segment queue with retry logic. @@ -186,7 +188,6 @@ class M3U8_Segments: - ts_url (str): The URL of the TS segment. - index (int): The index of the segment. - progress_bar (tqdm): Progress counter for tracking download progress. - - retries (int): The number of times to retry on failure (default is 3). - backoff_factor (float): The backoff factor for exponential backoff (default is 1.5 seconds). """ for attempt in range(REQUEST_MAX_RETRY): @@ -289,7 +290,7 @@ class M3U8_Segments: buffer[index] = segment_content except queue.Empty: - self.current_timeout = min(MAX_TIMEOOUT, self.current_timeout * 1.25) + self.current_timeout = min(MAX_TIMEOOUT, self.current_timeout * 1.1) if self.stop_event.is_set(): break @@ -323,7 +324,7 @@ class M3U8_Segments: # Configure workers and delay max_workers = self._get_worker_count(type) delay = max(PROXY_START_MIN, min(PROXY_START_MAX, 1 / (len(self.valid_proxy) + 1))) if THERE_IS_PROXY_LIST else TQDM_DELAY_WORKER - + # Download segments with completion verification with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [] @@ -373,7 +374,6 @@ class M3U8_Segments: return self._generate_results(type) - def _get_bar_format(self, description: str) -> str: """ Generate platform-appropriate progress bar format. diff --git a/StreamingCommunity/Upload/update.py b/StreamingCommunity/Upload/update.py index 39fd94b..566c355 100644 --- a/StreamingCommunity/Upload/update.py +++ b/StreamingCommunity/Upload/update.py @@ -5,14 +5,17 @@ import sys import time +# External library +import httpx + + # Internal utilities from .version import __version__, __author__, __title__ from StreamingCommunity.Util.console import console +from StreamingCommunity.Util._jsonConfig import config_manager +from StreamingCommunity.Util.headers import get_headers -# External library -import httpx - # Variable if getattr(sys, 'frozen', False): # Modalità PyInstaller @@ -26,8 +29,19 @@ def update(): Check for updates on GitHub and display relevant information. """ try: - response_reposity = httpx.get(f"https://api.github.com/repos/{__author__}/{__title__}").json() - response_releases = httpx.get(f"https://api.github.com/repos/{__author__}/{__title__}/releases").json() + response_reposity = httpx.get( + url=f"https://api.github.com/repos/{__author__}/{__title__}", + headers={'user-agent': get_headers()}, + timeout=config_manager.get_int("REQUESTS", "timeout"), + follow_redirects=True + ).json() + + response_releases = httpx.get( + url=f"https://api.github.com/repos/{__author__}/{__title__}/releases", + headers={'user-agent': get_headers()}, + timeout=config_manager.get_int("REQUESTS", "timeout"), + follow_redirects=True + ).json() except Exception as e: console.print(f"[red]Error accessing GitHub API: {e}") diff --git a/StreamingCommunity/Util/message.py b/StreamingCommunity/Util/message.py index 804541c..96aee0a 100644 --- a/StreamingCommunity/Util/message.py +++ b/StreamingCommunity/Util/message.py @@ -17,12 +17,12 @@ def start_message(): """Display a stylized start message in the console.""" msg = r''' - __ __ _ _____ __ _ - / //_/(_)________ ____ _ __ / ___// /_________ ____ _____ ___ (_)___ ____ _ - / ,< / / ___/ __ \/ __ \ | |/_/ \__ \/ __/ ___/ _ \/ __ `/ __ `__ \/ / __ \/ __ `/ - / /| |/ / / / /_/ / / / / _> < ___/ / /_/ / / __/ /_/ / / / / / / / / / / /_/ / -/_/ |_/_/_/ \____/_/ /_/ /_/|_| /____/\__/_/ \___/\__,_/_/ /_/ /_/_/_/ /_/\__, / - /____/ + ___ _____ __ _ + / | ______________ _ ______ ______ _ __ / ___// /_________ ____ _____ ___ (_)___ ____ _ + / /| | / ___/ ___/ __ \ | /| / / __ `/ ___/ | |/_/ \__ \/ __/ ___/ _ \/ __ `/ __ `__ \/ / __ \/ __ `/ + / ___ |/ / / / / /_/ / |/ |/ / /_/ / / _> < ___/ / /_/ / / __/ /_/ / / / / / / / / / / /_/ / +/_/ |_/_/ /_/ \____/|__/|__/\__,_/_/ /_/|_| /____/\__/_/ \___/\__,_/_/ /_/ /_/_/_/ /_/\__, / + /____/ '''.rstrip() if CLEAN: diff --git a/StreamingCommunity/Util/os.py b/StreamingCommunity/Util/os.py index fb8479c..90216d0 100644 --- a/StreamingCommunity/Util/os.py +++ b/StreamingCommunity/Util/os.py @@ -307,24 +307,6 @@ class OsSummary: else: # linux return os.path.join(home, '.local', 'bin', 'binary') - def get_executable_version(self, command: list): - """ - Get the version of a given command-line executable. - - Args: - command (list): The command to run, e.g., `['ffmpeg', '-version']`. - - Returns: - str: The version string of the executable. - """ - try: - version_output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode().split('\n')[0] - return version_output.split(" ")[2] - - except (FileNotFoundError, subprocess.CalledProcessError): - console.print(f"{command[0]} not found", style="bold red") - sys.exit(0) - def check_ffmpeg_location(self, command: list) -> str: """ Check if a specific executable (ffmpeg or ffprobe) is located using the given command. @@ -464,11 +446,7 @@ class OsSummary: console.log("[red]Can't locate ffmpeg or ffprobe") sys.exit(0) - ffmpeg_version = self.get_executable_version([self.ffmpeg_path, '-version']) - ffprobe_version = self.get_executable_version([self.ffprobe_path, '-version']) - 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]") - console.print(f"[cyan]Exe versions[white]: [bold red]ffmpeg {ffmpeg_version}, ffprobe {ffprobe_version}[/bold red]") # Handle requirements.txt if not getattr(sys, 'frozen', False): diff --git a/Test/Media/62809003.ico b/Test/Media/62809003.ico new file mode 100644 index 0000000..ff16d28 Binary files /dev/null and b/Test/Media/62809003.ico differ diff --git a/Test/Util/loc-badge.json b/Test/Media/loc-badge.json similarity index 100% rename from Test/Util/loc-badge.json rename to Test/Media/loc-badge.json diff --git a/config.json b/config.json index 98c88a8..11a0a66 100644 --- a/config.json +++ b/config.json @@ -28,7 +28,7 @@ "proxy_start_max": 0.5 }, "M3U8_DOWNLOAD": { - "tqdm_delay": 0.05, + "tqdm_delay": 0.01, "default_video_workser": 12, "default_audio_workser": 12, "download_audio": true, diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..abfd3b2 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +from setuptools import setup, find_packages + +def read_readme(): + with open("README.md", "r", encoding="utf-8") as fh: + return fh.read() + +with open("requirements.txt", "r", encoding="utf-8-sig") as f: + required_packages = f.read().splitlines() + print(required_packages) + +setup( + name="StreamingCommunity", + version="2.5.2", + long_description=read_readme(), + long_description_content_type="text/markdown", + author="Lovi-0", + url="https://github.com/Lovi-0/StreamingCommunity", + packages=find_packages(include=["StreamingCommunity", "StreamingCommunity.*"]), + install_requires=required_packages, + python_requires='>=3.8', + entry_points={ + "console_scripts": [ + "streamingcommunity=StreamingCommunity.run:main", + ], + }, + include_package_data=True, + keywords="streaming community", + project_urls={ + "Bug Reports": "https://github.com/Lovi-0/StreamingCommunity/issues", + "Source": "https://github.com/Lovi-0/StreamingCommunity", + } +)