mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-07 12:05:35 +00:00
Bump v2.9.5
This commit is contained in:
parent
3e5b126c07
commit
64e382c32e
44
README.md
44
README.md
@ -45,6 +45,7 @@
|
|||||||
- 📥 [Download](#m3u8_download-settings)
|
- 📥 [Download](#m3u8_download-settings)
|
||||||
- 🔍 [Parser](#m3u8_parser-settings)
|
- 🔍 [Parser](#m3u8_parser-settings)
|
||||||
- 📝 [Command](#command)
|
- 📝 [Command](#command)
|
||||||
|
- 🔍 [Global search](#global-search)
|
||||||
- 💻 [Examples of terminal](#examples-of-terminal-usage)
|
- 💻 [Examples of terminal](#examples-of-terminal-usage)
|
||||||
- 🔧 [Manual domain configuration](#update-domains)
|
- 🔧 [Manual domain configuration](#update-domains)
|
||||||
- 🐳 [Docker](#docker)
|
- 🐳 [Docker](#docker)
|
||||||
@ -637,19 +638,41 @@ Note: If `use_api` is set to `false` and no `domains.json` file is found, the sc
|
|||||||
#### 💡 Adding a New Site to the Legacy API
|
#### 💡 Adding a New Site to the Legacy API
|
||||||
If you want to add a new site to the legacy API, just message me on the Discord server, and I'll add it!
|
If you want to add a new site to the legacy API, just message me on the Discord server, and I'll add it!
|
||||||
|
|
||||||
# COMMAND
|
# Global Search
|
||||||
|
|
||||||
- Download a specific season by entering its number.
|
You can now search across multiple streaming sites at once using the Global Search feature. This allows you to find content more efficiently without having to search each site individually.
|
||||||
* **Example:** `1` will download *Season 1* only.
|
|
||||||
|
|
||||||
- Use the wildcard `*` to download every available season.
|
## Using Global Search
|
||||||
* **Example:** `*` will download all seasons in the series.
|
|
||||||
|
|
||||||
- Specify a range of seasons using a hyphen `-`.
|
The Global Search feature provides a unified interface to search across all supported sites:
|
||||||
* **Example:** `1-2` will download *Seasons 1 and 2*.
|
|
||||||
|
|
||||||
- Enter a season number followed by `-*` to download from that season to the end.
|
## Search Options
|
||||||
* **Example:** `3-*` will download from *Season 3* to the final season.
|
|
||||||
|
When using Global Search, you have three ways to select which sites to search:
|
||||||
|
|
||||||
|
1. **Search all sites** - Searches across all available streaming sites
|
||||||
|
2. **Search by category** - Group sites by their categories (movies, series, anime, etc.)
|
||||||
|
3. **Select specific sites** - Choose individual sites to include in your search
|
||||||
|
|
||||||
|
## Navigation and Selection
|
||||||
|
|
||||||
|
After performing a search:
|
||||||
|
|
||||||
|
1. Results are displayed in a consolidated table showing:
|
||||||
|
- Title
|
||||||
|
- Media type (movie, TV series, etc.)
|
||||||
|
- Source site
|
||||||
|
|
||||||
|
2. Select an item by number to view details or download
|
||||||
|
|
||||||
|
3. The system will automatically use the appropriate site's API to handle the download
|
||||||
|
|
||||||
|
## Command Line Arguments
|
||||||
|
|
||||||
|
The Global Search can be configured from the command line:
|
||||||
|
|
||||||
|
- `--global` - Perform a global search across multiple sites.
|
||||||
|
- `-s`, `--search` - Specify the search terms.
|
||||||
|
|
||||||
# Examples of terminal usage
|
# Examples of terminal usage
|
||||||
|
|
||||||
@ -662,6 +685,9 @@ python test_run.py --specific_list_audio ita,eng --specific_list_subtitles eng,s
|
|||||||
|
|
||||||
# Keep console open after download
|
# Keep console open after download
|
||||||
python test_run.py --not_close true
|
python test_run.py --not_close true
|
||||||
|
|
||||||
|
# Use global search
|
||||||
|
python test_run.py --global -s "cars"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
|
@ -10,10 +10,11 @@ from rich.prompt import Prompt
|
|||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from .site import title_search, media_search_manager, table_show_manager
|
from .site import title_search, media_search_manager, table_show_manager
|
||||||
from .title import download_title
|
from .title import download_title
|
||||||
|
|
||||||
@ -29,30 +30,43 @@ console = Console()
|
|||||||
msg = Prompt()
|
msg = Prompt()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|
||||||
|
def process_search_result(select_title):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Handles the search result and initiates the download for either a film or series.
|
||||||
"""
|
"""
|
||||||
|
download_title(select_title)
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
if string_to_search is None:
|
if string_to_search is None:
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Perform the database search
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# If only the database is needed, return the manager
|
||||||
if get_onylDatabase:
|
if get_onlyDatabase:
|
||||||
return media_search_manager
|
return media_search_manager
|
||||||
|
|
||||||
if len_database > 0:
|
if len_database > 0:
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
|
||||||
# Download title
|
|
||||||
download_title(select_title)
|
download_title(select_title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
||||||
|
|
||||||
# Retry
|
# If no results are found, ask again
|
||||||
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
search()
|
search()
|
@ -62,7 +62,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
'seader': tr.find_all("td")[-5].get_text(strip=True),
|
'seader': tr.find_all("td")[-5].get_text(strip=True),
|
||||||
'leacher': tr.find_all("td")[-4].get_text(strip=True),
|
'leacher': tr.find_all("td")[-4].get_text(strip=True),
|
||||||
'date': tr.find_all("td")[-3].get_text(strip=True).replace("'", ""),
|
'date': tr.find_all("td")[-3].get_text(strip=True).replace("'", ""),
|
||||||
'size': tr.find_all("td")[-2].get_text(strip=True)
|
'size': tr.find_all("td")[-2].get_text(strip=True),
|
||||||
|
'type': 'torrent'
|
||||||
}
|
}
|
||||||
media_search_manager.add_media(title_info)
|
media_search_manager.add_media(title_info)
|
||||||
|
|
||||||
|
@ -2,19 +2,22 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# External library
|
# External library
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.prompt import Prompt
|
from rich.prompt import Prompt
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
||||||
from .site import title_search, table_show_manager, media_search_manager
|
from .site import title_search, table_show_manager, media_search_manager
|
||||||
from .film import download_film
|
from .film import download_film
|
||||||
from .series import download_series
|
from .series import download_series
|
||||||
@ -30,51 +33,76 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def get_user_input(string_to_search: str = None):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Asks the user to input a search term.
|
||||||
|
Handles both Telegram bot input and direct input.
|
||||||
"""
|
"""
|
||||||
|
if string_to_search is None:
|
||||||
if site_constant.TELEGRAM_BOT:
|
if site_constant.TELEGRAM_BOT:
|
||||||
bot = get_bot_instance()
|
bot = get_bot_instance()
|
||||||
|
|
||||||
if string_to_search is None:
|
|
||||||
|
|
||||||
# Chiedi la scelta all'utente con il bot Telegram
|
|
||||||
string_to_search = bot.ask(
|
string_to_search = bot.ask(
|
||||||
"key_search",
|
"key_search",
|
||||||
f"Inserisci la parola da cercare\noppure back per tornare alla scelta: ",
|
f"Enter the search term\nor type 'back' to return to the menu: ",
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
if string_to_search == 'back':
|
if string_to_search == 'back':
|
||||||
# Riavvia lo script
|
|
||||||
# Chiude il processo attuale e avvia una nuova istanza dello script
|
# Restart the script
|
||||||
subprocess.Popen([sys.executable] + sys.argv)
|
subprocess.Popen([sys.executable] + sys.argv)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
if string_to_search is None:
|
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
||||||
|
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
return string_to_search
|
||||||
|
|
||||||
# Return list of elements
|
|
||||||
if get_onylDatabase:
|
|
||||||
return media_search_manager
|
|
||||||
|
|
||||||
if len_database > 0:
|
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
||||||
|
|
||||||
|
def process_search_result(select_title):
|
||||||
|
"""
|
||||||
|
Handles the search result and initiates the download for either a film or series.
|
||||||
|
"""
|
||||||
if select_title.type == 'tv':
|
if select_title.type == 'tv':
|
||||||
download_series(select_title)
|
download_series(select_title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
download_film(select_title)
|
download_film(select_title)
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the user input for the search term
|
||||||
|
string_to_search = get_user_input(string_to_search)
|
||||||
|
|
||||||
|
# Perform the database search
|
||||||
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
|
# If only the database is needed, return the manager
|
||||||
|
if get_onlyDatabase:
|
||||||
|
return media_search_manager
|
||||||
|
|
||||||
|
if site_constant.TELEGRAM_BOT:
|
||||||
|
bot = get_bot_instance()
|
||||||
|
|
||||||
|
if len_database > 0:
|
||||||
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
|
|
||||||
# Retry
|
if site_constant.TELEGRAM_BOT:
|
||||||
|
bot.send_message(f"No results found, please try again", None)
|
||||||
|
|
||||||
|
# If no results are found, ask again
|
||||||
|
string_to_search = get_user_input()
|
||||||
search()
|
search()
|
@ -1,4 +1,4 @@
|
|||||||
# 3.12.23
|
# 16.03.25
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -8,13 +8,14 @@ import httpx
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
||||||
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance, TelegramSession
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Util.os import os_manager
|
from StreamingCommunity.Util.os import os_manager
|
||||||
from StreamingCommunity.Util.message import start_message
|
from StreamingCommunity.Util.message import start_message
|
||||||
from StreamingCommunity.Util.headers import get_headers
|
from StreamingCommunity.Util.headers import get_headers
|
||||||
from StreamingCommunity.Util.config_json import config_manager
|
from StreamingCommunity.Util.config_json import config_manager
|
||||||
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
||||||
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance, TelegramSession
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 3.12.23
|
# 16.03.25
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 10.12.23
|
# 16.03.25
|
||||||
|
|
||||||
|
|
||||||
# External libraries
|
# External libraries
|
||||||
@ -6,11 +6,12 @@ import httpx
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
||||||
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Util.config_json import config_manager
|
from StreamingCommunity.Util.config_json import config_manager
|
||||||
from StreamingCommunity.Util.headers import get_userAgent
|
from StreamingCommunity.Util.headers import get_userAgent
|
||||||
from StreamingCommunity.Util.table import TVShowManager
|
from StreamingCommunity.Util.table import TVShowManager
|
||||||
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
@ -61,10 +62,8 @@ def title_search(title_search: str) -> int:
|
|||||||
# Create soup istance
|
# Create soup istance
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
soup = BeautifulSoup(response.text, "html.parser")
|
||||||
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
# Collect data from soup
|
# Collect data from soup
|
||||||
for movie_div in soup.find_all("div", class_="movie"):
|
for i, movie_div in enumerate(soup.find_all("div", class_="movie")):
|
||||||
|
|
||||||
title_tag = movie_div.find("h2", class_="movie-title")
|
title_tag = movie_div.find("h2", class_="movie-title")
|
||||||
title = title_tag.find("a").get_text(strip=True)
|
title = title_tag.find("a").get_text(strip=True)
|
||||||
@ -86,8 +85,6 @@ def title_search(title_search: str) -> int:
|
|||||||
choice_text = f"{i} - {title} ({tipo})"
|
choice_text = f"{i} - {title} ({tipo})"
|
||||||
choices.append(choice_text)
|
choices.append(choice_text)
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if site_constant.TELEGRAM_BOT:
|
if site_constant.TELEGRAM_BOT:
|
||||||
if choices:
|
if choices:
|
||||||
bot.send_message(f"Lista dei risultati:", choices)
|
bot.send_message(f"Lista dei risultati:", choices)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 01.03.24
|
# 16.03.25
|
||||||
|
|
||||||
# External libraries
|
# External libraries
|
||||||
import httpx
|
import httpx
|
||||||
|
@ -11,11 +11,12 @@ from rich.prompt import Prompt
|
|||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from .site import title_search, media_search_manager, table_show_manager
|
from .site import title_search, media_search_manager, table_show_manager
|
||||||
from .film_serie import download_film, download_series
|
from .film_serie import download_film, download_series
|
||||||
|
|
||||||
@ -31,53 +32,73 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def get_user_input(string_to_search: str = None):
|
||||||
|
"""
|
||||||
|
Asks the user to input a search term.
|
||||||
|
Handles both Telegram bot input and direct input.
|
||||||
|
"""
|
||||||
|
if string_to_search is None:
|
||||||
if site_constant.TELEGRAM_BOT:
|
if site_constant.TELEGRAM_BOT:
|
||||||
bot = get_bot_instance()
|
bot = get_bot_instance()
|
||||||
|
|
||||||
if string_to_search is None:
|
|
||||||
|
|
||||||
# Chiedi la scelta all'utente con il bot Telegram
|
|
||||||
string_to_search = bot.ask(
|
string_to_search = bot.ask(
|
||||||
"key_search",
|
"key_search",
|
||||||
f"Inserisci la parola da cercare\noppure back per tornare alla scelta: ",
|
f"Enter the search term\nor type 'back' to return to the menu: ",
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
if string_to_search == 'back':
|
if string_to_search == 'back':
|
||||||
# Riavvia lo script
|
|
||||||
# Chiude il processo attuale e avvia una nuova istanza dello script
|
# Restart the script
|
||||||
subprocess.Popen([sys.executable] + sys.argv)
|
subprocess.Popen([sys.executable] + sys.argv)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if string_to_search is None:
|
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
||||||
|
|
||||||
# Search on database
|
return string_to_search
|
||||||
len_database = title_search(string_to_search)
|
|
||||||
|
|
||||||
# Return list of elements
|
def process_search_result(select_title):
|
||||||
if get_onylDatabase:
|
"""
|
||||||
return media_search_manager
|
Handles the search result and initiates the download for either a film or series.
|
||||||
|
"""
|
||||||
if len_database > 0:
|
|
||||||
|
|
||||||
# Select title from list (type: TV \ Movie \ OVA)
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
||||||
|
|
||||||
if select_title.type == 'Movie' or select_title.type == 'OVA':
|
|
||||||
download_film(select_title)
|
|
||||||
|
|
||||||
else:
|
|
||||||
download_series(select_title)
|
download_series(select_title)
|
||||||
|
|
||||||
else:
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
if site_constant.TELEGRAM_BOT:
|
"""
|
||||||
bot.send_message(f"Nessun risultato trovato riprova", None)
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onlyDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the user input for the search term
|
||||||
|
string_to_search = get_user_input(string_to_search)
|
||||||
|
|
||||||
|
# Perform the database search
|
||||||
|
len_database = title_search(string_to_search)
|
||||||
|
|
||||||
|
##If only the database is needed, return the manager
|
||||||
|
if get_onlyDatabase:
|
||||||
|
return media_search_manager
|
||||||
|
|
||||||
|
if site_constant.TELEGRAM_BOT:
|
||||||
|
bot = get_bot_instance()
|
||||||
|
|
||||||
|
if len_database > 0:
|
||||||
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
|
|
||||||
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
|
|
||||||
# Retry
|
if site_constant.TELEGRAM_BOT:
|
||||||
|
bot.send_message(f"No results found, please try again", None)
|
||||||
|
|
||||||
|
# If no results are found, ask again
|
||||||
|
string_to_search = get_user_input()
|
||||||
search()
|
search()
|
@ -77,10 +77,8 @@ def get_real_title(record):
|
|||||||
"""
|
"""
|
||||||
if record['title_eng'] is not None:
|
if record['title_eng'] is not None:
|
||||||
return record['title_eng']
|
return record['title_eng']
|
||||||
|
|
||||||
elif record['title'] is not None:
|
elif record['title'] is not None:
|
||||||
return record['title']
|
return record['title']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return record['title_it']
|
return record['title_it']
|
||||||
|
|
||||||
|
@ -10,10 +10,11 @@ from rich.prompt import Prompt
|
|||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from .site import title_search, media_search_manager, table_show_manager
|
from .site import title_search, media_search_manager, table_show_manager
|
||||||
from .film import download_film
|
from .film import download_film
|
||||||
|
|
||||||
@ -29,10 +30,26 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def process_search_result(select_title):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Handles the search result and initiates the download for either a film or series.
|
||||||
"""
|
"""
|
||||||
|
# !!! ADD TYPE DONT WORK FOR SERIE
|
||||||
|
download_film(select_title)
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
if string_to_search is None:
|
if string_to_search is None:
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
@ -40,21 +57,16 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
## If only the database is needed, return the manager
|
||||||
if get_onylDatabase:
|
if get_onlyDatabase:
|
||||||
return media_search_manager
|
return media_search_manager
|
||||||
|
|
||||||
if len_database > 0:
|
if len_database > 0:
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
# !!! ADD TYPE DONT WORK FOR SERIE
|
|
||||||
download_film(select_title)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
||||||
|
|
||||||
# Retry
|
# If no results are found, ask again
|
||||||
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
search()
|
search()
|
@ -62,7 +62,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
|
|
||||||
title_info = {
|
title_info = {
|
||||||
'name': title,
|
'name': title,
|
||||||
'url': url
|
'url': url,
|
||||||
|
'type': 'film'
|
||||||
}
|
}
|
||||||
|
|
||||||
media_search_manager.add_media(title_info)
|
media_search_manager.add_media(title_info)
|
||||||
|
@ -12,6 +12,7 @@ from rich.prompt import Prompt
|
|||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
@ -30,10 +31,28 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def process_search_result(select_title):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Handles the search result and initiates the download for either a film or series.
|
||||||
"""
|
"""
|
||||||
|
if "Serie TV" in str(select_title.type):
|
||||||
|
download_thread(select_title)
|
||||||
|
else:
|
||||||
|
logging.error(f"Not supported: {select_title.type}")
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
if string_to_search is None:
|
if string_to_search is None:
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
@ -41,24 +60,16 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# If only the database is needed, return the manager
|
||||||
if get_onylDatabase:
|
if get_onlyDatabase:
|
||||||
return media_search_manager
|
return media_search_manager
|
||||||
|
|
||||||
if len_database > 0:
|
if len_database > 0:
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
# Download only film
|
|
||||||
if "Serie TV" in str(select_title.type):
|
|
||||||
download_thread(select_title)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.error(f"Not supported: {select_title.type}")
|
|
||||||
|
|
||||||
else:
|
# If no results are found, ask again
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
|
|
||||||
# Retry
|
|
||||||
search()
|
search()
|
@ -11,6 +11,7 @@ from rich.prompt import Prompt
|
|||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
@ -29,10 +30,25 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def process_search_result(select_title):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Handles the search result and initiates the download for either a film or series.
|
||||||
"""
|
"""
|
||||||
|
download_series(select_title)
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
if string_to_search is None:
|
if string_to_search is None:
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
@ -40,20 +56,16 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# If only the database is needed, return the manager
|
||||||
if get_onylDatabase:
|
if get_onlyDatabase:
|
||||||
return media_search_manager
|
return media_search_manager
|
||||||
|
|
||||||
if len_database > 0:
|
if len_database > 0:
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
# Download only film
|
|
||||||
download_series(select_title)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
||||||
|
|
||||||
# Retry
|
# If no results are found, ask again
|
||||||
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
search()
|
search()
|
@ -63,7 +63,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
|
|
||||||
serie_info = {
|
serie_info = {
|
||||||
'name': title,
|
'name': title,
|
||||||
'url': link
|
'url': link,
|
||||||
|
'type': 'tv'
|
||||||
}
|
}
|
||||||
|
|
||||||
media_search_manager.add_media(serie_info)
|
media_search_manager.add_media(serie_info)
|
||||||
|
@ -5,12 +5,16 @@ from urllib.parse import quote_plus
|
|||||||
|
|
||||||
# External library
|
# External library
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.prompt import Prompt, Confirm
|
from rich.prompt import Prompt
|
||||||
|
|
||||||
|
|
||||||
|
# Internal utilities
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
from StreamingCommunity.Lib.TMBD import tmdb, Json_film
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from StreamingCommunity.Lib.TMBD import tmdb, Json_film
|
|
||||||
from .film import download_film
|
from .film import download_film
|
||||||
|
|
||||||
|
|
||||||
@ -25,16 +29,32 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def process_search_result(select_title):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Handles the search result and initiates the download for either a film or series.
|
||||||
"""
|
"""
|
||||||
|
download_film(select_title)
|
||||||
|
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
if string_to_search is None:
|
if string_to_search is None:
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
|
|
||||||
# Not available for the moment
|
# Not available for the moment
|
||||||
if get_onylDatabase:
|
if get_onlyDatabase:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
@ -47,7 +67,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
download_film(movie_details)
|
download_film(movie_details)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
||||||
|
|
||||||
# Retry
|
# If no results are found, ask again
|
||||||
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
search()
|
search()
|
@ -12,11 +12,12 @@ from rich.prompt import Prompt
|
|||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
||||||
from .site import title_search, table_show_manager, media_search_manager
|
from .site import title_search, table_show_manager, media_search_manager
|
||||||
from .film import download_film
|
from .film import download_film
|
||||||
from .series import download_series
|
from .series import download_series
|
||||||
@ -33,54 +34,76 @@ msg = Prompt()
|
|||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
def get_user_input(string_to_search: str = None):
|
||||||
"""
|
"""
|
||||||
Main function of the application for film and series.
|
Asks the user to input a search term.
|
||||||
|
Handles both Telegram bot input and direct input.
|
||||||
"""
|
"""
|
||||||
|
if string_to_search is None:
|
||||||
if site_constant.TELEGRAM_BOT:
|
if site_constant.TELEGRAM_BOT:
|
||||||
bot = get_bot_instance()
|
bot = get_bot_instance()
|
||||||
|
|
||||||
if string_to_search is None:
|
|
||||||
|
|
||||||
# Chiedi la scelta all'utente con il bot Telegram
|
|
||||||
string_to_search = bot.ask(
|
string_to_search = bot.ask(
|
||||||
"key_search",
|
"key_search",
|
||||||
f"Inserisci la parola da cercare\noppure back per tornare alla scelta: ",
|
f"Enter the search term\nor type 'back' to return to the menu: ",
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
if string_to_search == 'back':
|
if string_to_search == 'back':
|
||||||
# Riavvia lo script
|
|
||||||
# Chiude il processo attuale e avvia una nuova istanza dello script
|
# Restart the script
|
||||||
subprocess.Popen([sys.executable] + sys.argv)
|
subprocess.Popen([sys.executable] + sys.argv)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if string_to_search is None:
|
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
||||||
|
|
||||||
len_database = title_search(quote_plus(string_to_search))
|
return string_to_search
|
||||||
|
|
||||||
# Return list of elements
|
|
||||||
if get_onylDatabase:
|
|
||||||
return media_search_manager
|
|
||||||
|
|
||||||
if len_database > 0:
|
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
||||||
|
|
||||||
|
def process_search_result(select_title):
|
||||||
|
"""
|
||||||
|
Handles the search result and initiates the download for either a film or series.
|
||||||
|
"""
|
||||||
if select_title.type == 'tv':
|
if select_title.type == 'tv':
|
||||||
download_series(select_title)
|
download_series(select_title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
download_film(select_title)
|
download_film(select_title)
|
||||||
|
|
||||||
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
||||||
|
"""
|
||||||
|
Main function of the application for search film, series and anime.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
string_to_search (str, optional): String to search for
|
||||||
|
get_onylDatabase (bool, optional): If True, return only the database object
|
||||||
|
direct_item (dict, optional): Direct item to process (bypass search)
|
||||||
|
"""
|
||||||
|
if direct_item:
|
||||||
|
select_title = MediaItem(**direct_item)
|
||||||
|
process_search_result(select_title)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the user input for the search term
|
||||||
|
string_to_search = get_user_input(string_to_search)
|
||||||
|
|
||||||
|
# Perform the database search
|
||||||
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
|
# If only the database is needed, return the manager
|
||||||
|
if get_onlyDatabase:
|
||||||
|
return media_search_manager
|
||||||
|
|
||||||
|
if site_constant.TELEGRAM_BOT:
|
||||||
|
bot = get_bot_instance()
|
||||||
|
|
||||||
|
if len_database > 0:
|
||||||
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
||||||
|
process_search_result(select_title)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
||||||
|
|
||||||
if site_constant.TELEGRAM_BOT:
|
if site_constant.TELEGRAM_BOT:
|
||||||
bot.send_message(f"Nessun risultato trovato riprova", None)
|
bot.send_message(f"No results found, please try again", None)
|
||||||
|
|
||||||
# Retry
|
# If no results are found, ask again
|
||||||
|
string_to_search = get_user_input()
|
||||||
search()
|
search()
|
@ -1,5 +1,5 @@
|
|||||||
__title__ = 'StreamingCommunity'
|
__title__ = 'StreamingCommunity'
|
||||||
__version__ = '2.9.4'
|
__version__ = '2.9.5'
|
||||||
__author__ = 'Arrowar'
|
__author__ = 'Arrowar'
|
||||||
__description__ = 'A command-line program to download film'
|
__description__ = 'A command-line program to download film'
|
||||||
__copyright__ = 'Copyright 2024'
|
__copyright__ = 'Copyright 2024'
|
||||||
|
315
StreamingCommunity/global_search.py
Normal file
315
StreamingCommunity/global_search.py
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
# 17.03.25
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import glob
|
||||||
|
import logging
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
|
||||||
|
# External library
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.prompt import Prompt
|
||||||
|
from rich.table import Table
|
||||||
|
from rich.progress import Progress
|
||||||
|
|
||||||
|
|
||||||
|
# Internal utilities
|
||||||
|
from StreamingCommunity.Util.message import start_message
|
||||||
|
|
||||||
|
|
||||||
|
# Variable
|
||||||
|
console = Console()
|
||||||
|
msg = Prompt()
|
||||||
|
|
||||||
|
|
||||||
|
# !!! DA METTERE IN COMUNE CON QUELLA DI RUN
|
||||||
|
def load_search_functions():
|
||||||
|
modules = []
|
||||||
|
loaded_functions = {}
|
||||||
|
excluded_sites = set()
|
||||||
|
|
||||||
|
# Find api home directory
|
||||||
|
if getattr(sys, 'frozen', False): # Modalità PyInstaller
|
||||||
|
base_path = os.path.join(sys._MEIPASS, "StreamingCommunity")
|
||||||
|
else:
|
||||||
|
base_path = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
api_dir = os.path.join(base_path, 'Api', 'Site')
|
||||||
|
init_files = glob.glob(os.path.join(api_dir, '*', '__init__.py'))
|
||||||
|
|
||||||
|
# Retrieve modules and their indices
|
||||||
|
for init_file in init_files:
|
||||||
|
|
||||||
|
# Get folder name as module name
|
||||||
|
module_name = os.path.basename(os.path.dirname(init_file))
|
||||||
|
|
||||||
|
# Se il modulo è nella lista da escludere, saltalo
|
||||||
|
if module_name in excluded_sites:
|
||||||
|
continue
|
||||||
|
|
||||||
|
logging.info(f"Load module name: {module_name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Dynamically import the module
|
||||||
|
mod = importlib.import_module(f'StreamingCommunity.Api.Site.{module_name}')
|
||||||
|
|
||||||
|
# Get 'indice' from the module
|
||||||
|
indice = getattr(mod, 'indice', 0)
|
||||||
|
is_deprecate = bool(getattr(mod, '_deprecate', True))
|
||||||
|
use_for = getattr(mod, '_useFor', 'other')
|
||||||
|
|
||||||
|
if not is_deprecate:
|
||||||
|
modules.append((module_name, indice, use_for))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[red]Failed to import module {module_name}: {str(e)}")
|
||||||
|
|
||||||
|
# Sort modules by 'indice'
|
||||||
|
modules.sort(key=lambda x: x[1])
|
||||||
|
|
||||||
|
# Load search functions in the sorted order
|
||||||
|
for module_name, _, use_for in modules:
|
||||||
|
|
||||||
|
# Construct a unique alias for the module
|
||||||
|
module_alias = f'{module_name}_search'
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Dynamically import the module
|
||||||
|
mod = importlib.import_module(f'StreamingCommunity.Api.Site.{module_name}')
|
||||||
|
|
||||||
|
# Get the search function from the module (assuming the function is named 'search' and defined in __init__.py)
|
||||||
|
search_function = getattr(mod, 'search')
|
||||||
|
|
||||||
|
# Add the function to the loaded functions dictionary
|
||||||
|
loaded_functions[module_alias] = (search_function, use_for)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[red]Failed to load search function from module {module_name}: {str(e)}")
|
||||||
|
|
||||||
|
return loaded_functions
|
||||||
|
|
||||||
|
def global_search(search_terms: str = None, selected_sites: list = None):
|
||||||
|
"""
|
||||||
|
Perform a search across multiple sites based on selection.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
search_terms (str, optional): The terms to search for. If None, will prompt the user.
|
||||||
|
selected_sites (list, optional): List of site aliases to search. If None, will search all sites.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Consolidated search results from all searched sites.
|
||||||
|
"""
|
||||||
|
search_functions = load_search_functions()
|
||||||
|
all_results = {}
|
||||||
|
|
||||||
|
if search_terms is None:
|
||||||
|
search_terms = msg.ask("\n[purple]Enter search terms for global search: ").strip()
|
||||||
|
|
||||||
|
# Organize sites by category for better display
|
||||||
|
sites_by_category = {}
|
||||||
|
for alias, (func, category) in search_functions.items():
|
||||||
|
if category not in sites_by_category:
|
||||||
|
sites_by_category[category] = []
|
||||||
|
sites_by_category[category].append((alias, func))
|
||||||
|
|
||||||
|
# If no sites are specifically selected, prompt the user
|
||||||
|
if selected_sites is None:
|
||||||
|
console.print("\n[bold green]Select sites to search:[/bold green]")
|
||||||
|
console.print("[bold cyan]1.[/bold cyan] Search all sites")
|
||||||
|
console.print("[bold cyan]2.[/bold cyan] Search by category")
|
||||||
|
console.print("[bold cyan]3.[/bold cyan] Select specific sites")
|
||||||
|
|
||||||
|
choice = msg.ask("[green]Enter your choice (1-3)", choices=["1", "2", "3"], default="1")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
# Search all sites
|
||||||
|
selected_sites = list(search_functions.keys())
|
||||||
|
|
||||||
|
elif choice == "2":
|
||||||
|
# Search by category
|
||||||
|
console.print("\n[bold green]Select categories to search:[/bold green]")
|
||||||
|
for i, category in enumerate(sites_by_category.keys(), 1):
|
||||||
|
console.print(f"[bold cyan]{i}.[/bold cyan] {category.capitalize()}")
|
||||||
|
|
||||||
|
category_choices = msg.ask("[green]Enter category numbers separated by commas", default="1")
|
||||||
|
selected_categories = [list(sites_by_category.keys())[int(c.strip())-1] for c in category_choices.split(",")]
|
||||||
|
|
||||||
|
selected_sites = []
|
||||||
|
for category in selected_categories:
|
||||||
|
for alias, _ in sites_by_category.get(category, []):
|
||||||
|
selected_sites.append(alias)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Select specific sites
|
||||||
|
console.print("\n[bold green]Select specific sites to search:[/bold green]")
|
||||||
|
|
||||||
|
for i, (alias, _) in enumerate(search_functions.items(), 1):
|
||||||
|
site_name = alias.split("_")[0].capitalize()
|
||||||
|
console.print(f"[bold cyan]{i}.[/bold cyan] {site_name}")
|
||||||
|
|
||||||
|
site_choices = msg.ask("[green]Enter site numbers separated by commas", default="1")
|
||||||
|
selected_indices = [int(c.strip())-1 for c in site_choices.split(",")]
|
||||||
|
selected_sites = [list(search_functions.keys())[i] for i in selected_indices if i < len(search_functions)]
|
||||||
|
|
||||||
|
# Display progress information
|
||||||
|
console.print(f"\n[bold green]Searching for:[/bold green] [yellow]{search_terms}[/yellow]")
|
||||||
|
console.print(f"[bold green]Searching across:[/bold green] {len(selected_sites)} sites")
|
||||||
|
|
||||||
|
with Progress() as progress:
|
||||||
|
search_task = progress.add_task("[cyan]Searching...", total=len(selected_sites))
|
||||||
|
|
||||||
|
# Search each selected site
|
||||||
|
for alias in selected_sites:
|
||||||
|
site_name = alias.split("_")[0].capitalize()
|
||||||
|
progress.update(search_task, description=f"[cyan]Searching {site_name}...")
|
||||||
|
|
||||||
|
func, _ = search_functions[alias]
|
||||||
|
try:
|
||||||
|
# Call the search function with get_onlyDatabase=True to get database object
|
||||||
|
database = func(search_terms, get_onlyDatabase=True)
|
||||||
|
|
||||||
|
# Check if database has media_list attribute and it's not empty
|
||||||
|
if database and hasattr(database, 'media_list') and len(database.media_list) > 0:
|
||||||
|
# Store media_list items with additional source information
|
||||||
|
all_results[alias] = []
|
||||||
|
for element in database.media_list:
|
||||||
|
# Convert element to dictionary if it's an object
|
||||||
|
if hasattr(element, '__dict__'):
|
||||||
|
item_dict = element.__dict__.copy()
|
||||||
|
else:
|
||||||
|
item_dict = {} # Fallback for non-object items
|
||||||
|
|
||||||
|
# Add source information
|
||||||
|
item_dict['source'] = site_name
|
||||||
|
item_dict['source_alias'] = alias
|
||||||
|
all_results[alias].append(item_dict)
|
||||||
|
|
||||||
|
console.print(f"[green]Found {len(database.media_list)} results from {site_name}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[bold red]Error searching {site_name}:[/bold red] {str(e)}")
|
||||||
|
|
||||||
|
progress.update(search_task, advance=1)
|
||||||
|
|
||||||
|
# Display the consolidated results
|
||||||
|
if all_results:
|
||||||
|
all_media_items = []
|
||||||
|
for alias, results in all_results.items():
|
||||||
|
for item in results:
|
||||||
|
all_media_items.append(item)
|
||||||
|
|
||||||
|
# Display consolidated results
|
||||||
|
display_consolidated_results(all_media_items, search_terms)
|
||||||
|
|
||||||
|
# Allow user to select an item
|
||||||
|
selected_item = select_from_consolidated_results(all_media_items)
|
||||||
|
if selected_item:
|
||||||
|
# Process the selected item - download or further actions
|
||||||
|
process_selected_item(selected_item, search_functions)
|
||||||
|
|
||||||
|
else:
|
||||||
|
console.print(f"\n[bold red]No results found for:[/bold red] [yellow]{search_terms}[/yellow]")
|
||||||
|
|
||||||
|
# Optionally offer to search again or return to main menu
|
||||||
|
if msg.ask("[green]Search again? (y/n)", choices=["y", "n"], default="y") == "y":
|
||||||
|
global_search()
|
||||||
|
|
||||||
|
return all_results
|
||||||
|
|
||||||
|
def display_consolidated_results(all_media_items, search_terms):
|
||||||
|
"""
|
||||||
|
Display consolidated search results from multiple sites.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
all_media_items (list): List of media items from all searched sites.
|
||||||
|
search_terms (str): The search terms used.
|
||||||
|
"""
|
||||||
|
time.sleep(1)
|
||||||
|
start_message()
|
||||||
|
|
||||||
|
console.print(f"\n[bold green]Search results for:[/bold green] [yellow]{search_terms}[/yellow] \n")
|
||||||
|
|
||||||
|
table = Table(show_header=True, header_style="bold cyan")
|
||||||
|
table.add_column("#", style="dim", width=4)
|
||||||
|
table.add_column("Title", min_width=20)
|
||||||
|
table.add_column("Type", width=15)
|
||||||
|
table.add_column("Source", width=25)
|
||||||
|
|
||||||
|
for i, item in enumerate(all_media_items, 1):
|
||||||
|
|
||||||
|
# Extract values from item dict, with fallbacks if keys don't exist
|
||||||
|
title = item.get('title', item.get('name', 'Unknown'))
|
||||||
|
media_type = item.get('type', item.get('media_type', 'Unknown'))
|
||||||
|
source = item.get('source', 'Unknown')
|
||||||
|
|
||||||
|
table.add_row(
|
||||||
|
str(i),
|
||||||
|
str(title),
|
||||||
|
str(media_type),
|
||||||
|
str(source),
|
||||||
|
)
|
||||||
|
|
||||||
|
console.print(table)
|
||||||
|
|
||||||
|
def select_from_consolidated_results(all_media_items):
|
||||||
|
"""
|
||||||
|
Allow user to select an item from consolidated results.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
all_media_items (list): List of media items from all searched sites.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The selected media item or None if no selection was made.
|
||||||
|
"""
|
||||||
|
if not all_media_items:
|
||||||
|
return None
|
||||||
|
|
||||||
|
max_index = len(all_media_items)
|
||||||
|
choice = msg.ask(
|
||||||
|
f"[green]Select item # (1-{max_index}) or 0 to cancel",
|
||||||
|
choices=[str(i) for i in range(max_index + 1)],
|
||||||
|
default="1",
|
||||||
|
show_choices=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if choice == "0":
|
||||||
|
return None
|
||||||
|
|
||||||
|
return all_media_items[int(choice) - 1]
|
||||||
|
|
||||||
|
def process_selected_item(selected_item, search_functions):
|
||||||
|
"""
|
||||||
|
Process the selected item - download the media using the appropriate site API.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
selected_item (dict): The selected media item.
|
||||||
|
search_functions (dict): Dictionary of search functions by alias.
|
||||||
|
"""
|
||||||
|
source_alias = selected_item.get('source_alias')
|
||||||
|
if not source_alias or source_alias not in search_functions:
|
||||||
|
console.print("[bold red]Error: Cannot process this item - source information missing.[/bold red]")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the appropriate search function for this source
|
||||||
|
func, _ = search_functions[source_alias]
|
||||||
|
|
||||||
|
console.print(f"\n[bold green]Processing selection from:[/bold green] {selected_item.get('source')}")
|
||||||
|
|
||||||
|
# Extract necessary information to pass to the site's search function
|
||||||
|
item_id = selected_item.get('id', selected_item.get('media_id'))
|
||||||
|
item_type = selected_item.get('type', selected_item.get('media_type', 'unknown'))
|
||||||
|
item_title = selected_item.get('title', selected_item.get('name', 'Unknown'))
|
||||||
|
|
||||||
|
if item_id:
|
||||||
|
console.print(f"[bold green]Selected item:[/bold green] {item_title} (ID: {item_id}, Type: {item_type})")
|
||||||
|
|
||||||
|
# Call the site's search function with direct_item parameter to process download
|
||||||
|
try:
|
||||||
|
func(direct_item=selected_item)
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[bold red]Error processing download:[/bold red] {str(e)}")
|
||||||
|
else:
|
||||||
|
console.print("[bold red]Error: Item ID not found.[/bold red]")
|
@ -18,6 +18,7 @@ from rich.prompt import Prompt
|
|||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
|
from .global_search import global_search
|
||||||
from StreamingCommunity.Util.message import start_message
|
from StreamingCommunity.Util.message import start_message
|
||||||
from StreamingCommunity.Util.config_json import config_manager
|
from StreamingCommunity.Util.config_json import config_manager
|
||||||
from StreamingCommunity.Util.os import os_summary
|
from StreamingCommunity.Util.os import os_summary
|
||||||
@ -54,6 +55,7 @@ def run_function(func: Callable[..., None], close_console: bool = False, search_
|
|||||||
func(search_terms)
|
func(search_terms)
|
||||||
|
|
||||||
|
|
||||||
|
# !!! DA METTERE IN COMUNE CON QUELLA DI GLOBAL
|
||||||
def load_search_functions():
|
def load_search_functions():
|
||||||
modules = []
|
modules = []
|
||||||
loaded_functions = {}
|
loaded_functions = {}
|
||||||
@ -237,6 +239,11 @@ def main(script_id = 0):
|
|||||||
'--specific_list_subtitles', type=str, help='Comma-separated list of specific subtitle languages to download (e.g., eng,spa).'
|
'--specific_list_subtitles', type=str, help='Comma-separated list of specific subtitle languages to download (e.g., eng,spa).'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add global search option
|
||||||
|
parser.add_argument(
|
||||||
|
'--global', action='store_true', help='Perform a global search across multiple sites.'
|
||||||
|
)
|
||||||
|
|
||||||
# Add arguments for search functions
|
# Add arguments for search functions
|
||||||
color_map = {
|
color_map = {
|
||||||
"anime": "red",
|
"anime": "red",
|
||||||
@ -253,6 +260,7 @@ def main(script_id = 0):
|
|||||||
parser.add_argument(f'-{short_option}', f'--{long_option}', action='store_true', help=f'Search for {alias.split("_")[0]} on streaming platforms.')
|
parser.add_argument(f'-{short_option}', f'--{long_option}', action='store_true', help=f'Search for {alias.split("_")[0]} on streaming platforms.')
|
||||||
|
|
||||||
parser.add_argument('-s', '--search', default=None, help='Search terms')
|
parser.add_argument('-s', '--search', default=None, help='Search terms')
|
||||||
|
|
||||||
# Parse command-line arguments
|
# Parse command-line arguments
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -280,6 +288,11 @@ def main(script_id = 0):
|
|||||||
|
|
||||||
config_manager.write_config()
|
config_manager.write_config()
|
||||||
|
|
||||||
|
# Check if global search is requested
|
||||||
|
if getattr(args, 'global'):
|
||||||
|
global_search(search_terms)
|
||||||
|
return
|
||||||
|
|
||||||
# Map command-line arguments to functions
|
# Map command-line arguments to functions
|
||||||
arg_to_function = {alias: func for alias, (func, _) in search_functions.items()}
|
arg_to_function = {alias: func for alias, (func, _) in search_functions.items()}
|
||||||
|
|
||||||
@ -295,13 +308,18 @@ def main(script_id = 0):
|
|||||||
# Create dynamic prompt message and choices
|
# Create dynamic prompt message and choices
|
||||||
choice_labels = {str(i): (alias.split("_")[0].capitalize(), use_for) for i, (alias, (_, use_for)) in enumerate(search_functions.items())}
|
choice_labels = {str(i): (alias.split("_")[0].capitalize(), use_for) for i, (alias, (_, use_for)) in enumerate(search_functions.items())}
|
||||||
|
|
||||||
|
# Add global search option to the menu
|
||||||
|
#global_search_key = str(len(choice_labels))
|
||||||
|
#choice_labels[global_search_key] = ("Global Search", "all")
|
||||||
|
#input_to_function[global_search_key] = global_search
|
||||||
|
|
||||||
# Display the category legend in a single line
|
# Display the category legend in a single line
|
||||||
legend_text = " | ".join([f"[{color}]{category.capitalize()}[/{color}]" for category, color in color_map.items()])
|
legend_text = " | ".join([f"[{color}]{category.capitalize()}[/{color}]" for category, color in color_map.items()])
|
||||||
console.print(f"\n[bold green]Category Legend:[/bold green] {legend_text}")
|
console.print(f"\n[bold green]Category Legend:[/bold green] {legend_text}")
|
||||||
|
|
||||||
# Construct the prompt message with color-coded site names
|
# Construct the prompt message with color-coded site names
|
||||||
prompt_message = "[green]Insert category [white](" + ", ".join(
|
prompt_message = "[green]Insert category [white](" + ", ".join(
|
||||||
[f"{key}: [{color_map[label[1]]}]{label[0]}[/{color_map[label[1]]}]" for key, label in choice_labels.items()]
|
[f"{key}: [{color_map.get(label[1], 'white')}]{label[0]}[/{color_map.get(label[1], 'white')}]" for key, label in choice_labels.items()]
|
||||||
) + "[white])"
|
) + "[white])"
|
||||||
|
|
||||||
if TELEGRAM_BOT:
|
if TELEGRAM_BOT:
|
||||||
@ -330,10 +348,16 @@ def main(script_id = 0):
|
|||||||
|
|
||||||
# Run the corresponding function based on user input
|
# Run the corresponding function based on user input
|
||||||
if category in input_to_function:
|
if category in input_to_function:
|
||||||
run_function(input_to_function[category], search_terms = args.search)
|
"""if category == global_search_key:
|
||||||
|
# Run global search
|
||||||
|
run_function(input_to_function[category], search_terms=search_terms)
|
||||||
|
|
||||||
|
else:"""
|
||||||
|
|
||||||
|
# Run normal site-specific search
|
||||||
|
run_function(input_to_function[category], search_terms=search_terms)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if TELEGRAM_BOT:
|
if TELEGRAM_BOT:
|
||||||
bot.send_message(f"Categoria non valida", None)
|
bot.send_message(f"Categoria non valida", None)
|
||||||
|
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
# 12.11.24
|
|
||||||
|
|
||||||
# Fix import
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
src_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
||||||
sys.path.append(src_path)
|
|
||||||
|
|
||||||
|
|
||||||
# Other
|
|
||||||
import glob
|
|
||||||
import logging
|
|
||||||
import importlib
|
|
||||||
from rich.console import Console
|
|
||||||
|
|
||||||
|
|
||||||
# Other import
|
|
||||||
from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
|
||||||
|
|
||||||
|
|
||||||
# Variable
|
|
||||||
console = Console()
|
|
||||||
|
|
||||||
|
|
||||||
def load_search_functions():
|
|
||||||
modules = []
|
|
||||||
loaded_functions = {}
|
|
||||||
|
|
||||||
# Traverse the Api directory
|
|
||||||
api_dir = os.path.join(os.path.dirname(__file__), '..', 'StreamingCommunity', 'Api', 'Site')
|
|
||||||
init_files = glob.glob(os.path.join(api_dir, '*', '__init__.py'))
|
|
||||||
|
|
||||||
logging.info(f"Base folder path: {api_dir}")
|
|
||||||
logging.info(f"Api module path: {init_files}")
|
|
||||||
|
|
||||||
# Retrieve modules and their indices
|
|
||||||
for init_file in init_files:
|
|
||||||
|
|
||||||
# Get folder name as module name
|
|
||||||
module_name = os.path.basename(os.path.dirname(init_file))
|
|
||||||
logging.info(f"Load module name: {module_name}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Dynamically import the module
|
|
||||||
mod = importlib.import_module(f'StreamingCommunity.Api.Site.{module_name}')
|
|
||||||
|
|
||||||
# Get 'indice' from the module
|
|
||||||
indice = getattr(mod, 'indice', 0)
|
|
||||||
is_deprecate = bool(getattr(mod, '_deprecate', True))
|
|
||||||
use_for = getattr(mod, '_useFor', 'other')
|
|
||||||
|
|
||||||
if not is_deprecate:
|
|
||||||
modules.append((module_name, indice, use_for))
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"[red]Failed to import module {module_name}: {str(e)}")
|
|
||||||
|
|
||||||
# Sort modules by 'indice'
|
|
||||||
modules.sort(key=lambda x: x[1])
|
|
||||||
|
|
||||||
# Load search functions in the sorted order
|
|
||||||
for module_name, _, use_for in modules:
|
|
||||||
|
|
||||||
# Construct a unique alias for the module
|
|
||||||
module_alias = f'{module_name}_search'
|
|
||||||
logging.info(f"Module alias: {module_alias}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Dynamically import the module
|
|
||||||
mod = importlib.import_module(f'StreamingCommunity.Api.Site.{module_name}')
|
|
||||||
|
|
||||||
# Get the search function from the module (assuming the function is named 'search' and defined in __init__.py)
|
|
||||||
search_function = getattr(mod, 'search')
|
|
||||||
|
|
||||||
# Add the function to the loaded functions dictionary
|
|
||||||
loaded_functions[module_alias] = (search_function, use_for)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"[red]Failed to load search function from module {module_name}: {str(e)}")
|
|
||||||
|
|
||||||
return loaded_functions
|
|
||||||
|
|
||||||
|
|
||||||
def search_all_sites(loaded_functions, search_string, max_sites=10):
|
|
||||||
total_len_database = 0
|
|
||||||
site_count = 0
|
|
||||||
|
|
||||||
for module_alias, (search_function, use_for) in loaded_functions.items():
|
|
||||||
if max_sites is not None and site_count >= max_sites:
|
|
||||||
break
|
|
||||||
|
|
||||||
console.print(f"\n[blue]Searching in module: {module_alias} [white](Use for: {use_for})")
|
|
||||||
|
|
||||||
try:
|
|
||||||
database: MediaManager = search_function(search_string, get_onylDatabase=True)
|
|
||||||
len_database = len(database.media_list)
|
|
||||||
|
|
||||||
for element in database.media_list:
|
|
||||||
print(element.__dict__)
|
|
||||||
|
|
||||||
console.print(f"[green]Database length for {module_alias}: {len_database}")
|
|
||||||
total_len_database += len_database
|
|
||||||
site_count += 1
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"[red]Error while executing search function for {module_alias}: {str(e)}")
|
|
||||||
|
|
||||||
return total_len_database
|
|
||||||
|
|
||||||
|
|
||||||
# Main
|
|
||||||
search_string = "cars"
|
|
||||||
loaded_functions = load_search_functions()
|
|
||||||
|
|
||||||
total_len = search_all_sites(loaded_functions, search_string)
|
|
||||||
console.print(f"\n[cyan]Total number of results from all sites: {total_len}")
|
|
2
setup.py
2
setup.py
@ -10,7 +10,7 @@ with open(os.path.join(os.path.dirname(__file__), "requirements.txt"), "r", enco
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="StreamingCommunity",
|
name="StreamingCommunity",
|
||||||
version="2.9.4",
|
version="2.9.5",
|
||||||
long_description=read_readme(),
|
long_description=read_readme(),
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
author="Lovi-0",
|
author="Lovi-0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user