StreamingCommunity 1.7.6__py3-none-any.whl → 1.9.1__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.

Files changed (101) hide show
  1. StreamingCommunity/{Src/Api → Api}/Player/Helper/Vixcloud/js_parser.py +4 -1
  2. StreamingCommunity/{Src/Api → Api}/Player/Helper/Vixcloud/util.py +166 -166
  3. StreamingCommunity/{Src/Api → Api}/Player/ddl.py +89 -89
  4. StreamingCommunity/{Src/Api → Api}/Player/maxstream.py +151 -151
  5. StreamingCommunity/{Src/Api → Api}/Player/supervideo.py +193 -193
  6. StreamingCommunity/{Src/Api → Api}/Player/vixcloud.py +224 -212
  7. StreamingCommunity/{Src/Api → Api}/Site/1337xx/__init__.py +50 -50
  8. StreamingCommunity/{Src/Api → Api}/Site/1337xx/costant.py +15 -15
  9. StreamingCommunity/{Src/Api → Api}/Site/1337xx/site.py +83 -83
  10. StreamingCommunity/{Src/Api → Api}/Site/1337xx/title.py +66 -66
  11. StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/__init__.py +50 -50
  12. StreamingCommunity/{Src/Api/Site/mostraguarda → Api/Site/altadefinizione}/costant.py +15 -15
  13. StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/film.py +69 -69
  14. StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/site.py +86 -86
  15. StreamingCommunity/{Src/Api → Api}/Site/animeunity/__init__.py +50 -50
  16. StreamingCommunity/{Src/Api/Site/altadefinizione → Api/Site/animeunity}/costant.py +15 -15
  17. StreamingCommunity/{Src/Api → Api}/Site/animeunity/film_serie.py +130 -131
  18. StreamingCommunity/{Src/Api → Api}/Site/animeunity/site.py +164 -164
  19. StreamingCommunity/{Src/Api → Api}/Site/animeunity/util/ScrapeSerie.py +3 -3
  20. StreamingCommunity/{Src/Api → Api}/Site/bitsearch/__init__.py +51 -51
  21. StreamingCommunity/{Src/Api → Api}/Site/bitsearch/costant.py +15 -15
  22. StreamingCommunity/{Src/Api → Api}/Site/bitsearch/site.py +84 -84
  23. StreamingCommunity/{Src/Api → Api}/Site/bitsearch/title.py +47 -47
  24. StreamingCommunity/{Src/Api → Api}/Site/cb01new/__init__.py +51 -51
  25. StreamingCommunity/{Src/Api → Api}/Site/cb01new/costant.py +15 -15
  26. StreamingCommunity/{Src/Api → Api}/Site/cb01new/film.py +69 -69
  27. StreamingCommunity/{Src/Api → Api}/Site/cb01new/site.py +74 -74
  28. StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/__init__.py +57 -57
  29. StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/costant.py +16 -16
  30. StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/series.py +141 -142
  31. StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/site.py +92 -92
  32. StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/util/ScrapeSerie.py +84 -82
  33. StreamingCommunity/{Src/Api → Api}/Site/guardaserie/__init__.py +52 -52
  34. StreamingCommunity/{Src/Api/Site/piratebays → Api/Site/guardaserie}/costant.py +15 -15
  35. StreamingCommunity/{Src/Api → Api}/Site/guardaserie/series.py +195 -195
  36. StreamingCommunity/{Src/Api → Api}/Site/guardaserie/site.py +84 -84
  37. StreamingCommunity/{Src/Api → Api}/Site/guardaserie/util/ScrapeSerie.py +110 -110
  38. StreamingCommunity/{Src/Api → Api}/Site/mostraguarda/__init__.py +48 -48
  39. StreamingCommunity/{Src/Api/Site/animeunity → Api/Site/mostraguarda}/costant.py +15 -15
  40. StreamingCommunity/{Src/Api → Api}/Site/mostraguarda/film.py +94 -94
  41. StreamingCommunity/{Src/Api → Api}/Site/piratebays/__init__.py +50 -50
  42. StreamingCommunity/{Src/Api/Site/guardaserie → Api/Site/piratebays}/costant.py +15 -15
  43. StreamingCommunity/{Src/Api → Api}/Site/piratebays/site.py +88 -88
  44. StreamingCommunity/{Src/Api → Api}/Site/piratebays/title.py +45 -45
  45. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/__init__.py +55 -55
  46. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/costant.py +15 -15
  47. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/film.py +70 -70
  48. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/series.py +205 -203
  49. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/site.py +125 -125
  50. StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/util/ScrapeSerie.py +3 -3
  51. StreamingCommunity/{Src/Api → Api}/Template/Class/SearchType.py +101 -101
  52. StreamingCommunity/{Src/Api → Api}/Template/Util/__init__.py +4 -4
  53. StreamingCommunity/{Src/Api → Api}/Template/Util/get_domain.py +137 -137
  54. StreamingCommunity/{Src/Api → Api}/Template/Util/manage_ep.py +153 -153
  55. StreamingCommunity/{Src/Api → Api}/Template/Util/recall_search.py +37 -37
  56. StreamingCommunity/Api/Template/__init__.py +3 -0
  57. StreamingCommunity/{Src/Api → Api}/Template/site.py +87 -87
  58. StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/downloader.py +968 -968
  59. StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/proxyes.py +110 -110
  60. StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/segments.py +538 -540
  61. StreamingCommunity/{Src/Lib → Lib}/Downloader/MP4/downloader.py +156 -156
  62. StreamingCommunity/{Src/Lib → Lib}/Downloader/TOR/downloader.py +222 -222
  63. StreamingCommunity/{Src/Lib → Lib}/Downloader/__init__.py +4 -4
  64. StreamingCommunity/{Src/Lib → Lib}/Driver/driver_1.py +76 -76
  65. StreamingCommunity/{Src/Lib → Lib}/FFmpeg/__init__.py +4 -4
  66. StreamingCommunity/{Src/Lib → Lib}/FFmpeg/capture.py +170 -170
  67. StreamingCommunity/{Src/Lib → Lib}/FFmpeg/command.py +292 -292
  68. StreamingCommunity/{Src/Lib → Lib}/FFmpeg/util.py +241 -241
  69. StreamingCommunity/{Src/Lib → Lib}/M3U8/__init__.py +5 -5
  70. StreamingCommunity/{Src/Lib → Lib}/M3U8/decryptor.py +164 -129
  71. StreamingCommunity/{Src/Lib → Lib}/M3U8/estimator.py +175 -172
  72. StreamingCommunity/{Src/Lib → Lib}/M3U8/parser.py +666 -666
  73. StreamingCommunity/{Src/Lib → Lib}/M3U8/url_fixer.py +51 -51
  74. StreamingCommunity/Lib/TMBD/__init__.py +2 -0
  75. StreamingCommunity/{Src/Lib → Lib}/TMBD/obj_tmbd.py +39 -39
  76. StreamingCommunity/{Src/Lib → Lib}/TMBD/tmdb.py +345 -345
  77. StreamingCommunity/{Src/Upload → Upload}/update.py +68 -64
  78. StreamingCommunity/{Src/Upload → Upload}/version.py +5 -5
  79. StreamingCommunity/{Src/Util → Util}/_jsonConfig.py +204 -204
  80. StreamingCommunity/{Src/Util → Util}/call_stack.py +42 -42
  81. StreamingCommunity/{Src/Util → Util}/color.py +20 -20
  82. StreamingCommunity/{Src/Util → Util}/console.py +12 -12
  83. StreamingCommunity/Util/ffmpeg_installer.py +275 -0
  84. StreamingCommunity/{Src/Util → Util}/headers.py +147 -147
  85. StreamingCommunity/{Src/Util → Util}/logger.py +53 -53
  86. StreamingCommunity/{Src/Util → Util}/message.py +46 -46
  87. StreamingCommunity/{Src/Util → Util}/os.py +514 -417
  88. StreamingCommunity/{Src/Util → Util}/table.py +163 -163
  89. StreamingCommunity/run.py +202 -196
  90. {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/METADATA +126 -60
  91. StreamingCommunity-1.9.1.dist-info/RECORD +95 -0
  92. {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/WHEEL +1 -1
  93. StreamingCommunity/Src/Api/Site/animeunity/anime.py +0 -126
  94. StreamingCommunity/Src/Api/Site/ddlstreamitaly/Player/ScrapeSerie.py +0 -83
  95. StreamingCommunity/Src/Api/Site/guardaserie/Player/ScrapeSerie.py +0 -110
  96. StreamingCommunity/Src/Api/Template/__init__.py +0 -3
  97. StreamingCommunity/Src/Lib/TMBD/__init__.py +0 -2
  98. StreamingCommunity-1.7.6.dist-info/RECORD +0 -97
  99. {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/LICENSE +0 -0
  100. {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/entry_points.txt +0 -0
  101. {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/top_level.txt +0 -0
@@ -8,9 +8,9 @@ import httpx
8
8
 
9
9
 
10
10
  # Internal utilities
11
- from StreamingCommunity.Src.Util.headers import get_headers
12
- from StreamingCommunity.Src.Util._jsonConfig import config_manager
13
- from StreamingCommunity.Src.Api.Player.Helper.Vixcloud.util import SeasonManager, EpisodeManager
11
+ from StreamingCommunity.Util.headers import get_headers
12
+ from StreamingCommunity.Util._jsonConfig import config_manager
13
+ from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager, EpisodeManager
14
14
 
15
15
 
16
16
  # Variable
@@ -1,101 +1,101 @@
1
- # 07.07.24
2
-
3
- from typing import List, TypedDict
4
-
5
-
6
- class MediaItemData(TypedDict, total=False):
7
- id: int # GENERAL
8
- name: str # GENERAL
9
- type: str # GENERAL
10
- url: str # GENERAL
11
- size: str # GENERAL
12
- score: str # GENERAL
13
- date: str # GENERAL
14
- desc: str # GENERAL
15
-
16
- seeder: int # TOR
17
- leecher: int # TOR
18
-
19
- slug: str # SC
20
-
21
-
22
-
23
- class MediaItemMeta(type):
24
- def __new__(cls, name, bases, dct):
25
- def init(self, **kwargs):
26
- for key, value in kwargs.items():
27
- setattr(self, key, value)
28
-
29
- dct['__init__'] = init
30
-
31
- def get_attr(self, item):
32
- return self.__dict__.get(item, None)
33
-
34
- dct['__getattr__'] = get_attr
35
-
36
- def set_attr(self, key, value):
37
- self.__dict__[key] = value
38
-
39
- dct['__setattr__'] = set_attr
40
-
41
- return super().__new__(cls, name, bases, dct)
42
-
43
-
44
- class MediaItem(metaclass=MediaItemMeta):
45
- id: int # GENERAL
46
- name: str # GENERAL
47
- type: str # GENERAL
48
- url: str # GENERAL
49
- size: str # GENERAL
50
- score: str # GENERAL
51
- date: str # GENERAL
52
- desc: str # GENERAL
53
-
54
- seeder: int # TOR
55
- leecher: int # TOR
56
-
57
- slug: str # SC
58
-
59
-
60
- class MediaManager:
61
- def __init__(self):
62
- self.media_list: List[MediaItem] = []
63
-
64
- def add_media(self, data: dict) -> None:
65
- """
66
- Add media to the list.
67
-
68
- Args:
69
- data (dict): Media data to add.
70
- """
71
- self.media_list.append(MediaItem(**data))
72
-
73
- def get(self, index: int) -> MediaItem:
74
- """
75
- Get a media item from the list by index.
76
-
77
- Args:
78
- index (int): The index of the media item to retrieve.
79
-
80
- Returns:
81
- MediaItem: The media item at the specified index.
82
- """
83
- return self.media_list[index]
84
-
85
- def get_length(self) -> int:
86
- """
87
- Get the number of media items in the list.
88
-
89
- Returns:
90
- int: Number of media items.
91
- """
92
- return len(self.media_list)
93
-
94
- def clear(self) -> None:
95
- """
96
- This method clears the media list.
97
- """
98
- self.media_list.clear()
99
-
100
- def __str__(self):
101
- return f"MediaManager(num_media={len(self.media_list)})"
1
+ # 07.07.24
2
+
3
+ from typing import List, TypedDict
4
+
5
+
6
+ class MediaItemData(TypedDict, total=False):
7
+ id: int # GENERAL
8
+ name: str # GENERAL
9
+ type: str # GENERAL
10
+ url: str # GENERAL
11
+ size: str # GENERAL
12
+ score: str # GENERAL
13
+ date: str # GENERAL
14
+ desc: str # GENERAL
15
+
16
+ seeder: int # TOR
17
+ leecher: int # TOR
18
+
19
+ slug: str # SC
20
+
21
+
22
+
23
+ class MediaItemMeta(type):
24
+ def __new__(cls, name, bases, dct):
25
+ def init(self, **kwargs):
26
+ for key, value in kwargs.items():
27
+ setattr(self, key, value)
28
+
29
+ dct['__init__'] = init
30
+
31
+ def get_attr(self, item):
32
+ return self.__dict__.get(item, None)
33
+
34
+ dct['__getattr__'] = get_attr
35
+
36
+ def set_attr(self, key, value):
37
+ self.__dict__[key] = value
38
+
39
+ dct['__setattr__'] = set_attr
40
+
41
+ return super().__new__(cls, name, bases, dct)
42
+
43
+
44
+ class MediaItem(metaclass=MediaItemMeta):
45
+ id: int # GENERAL
46
+ name: str # GENERAL
47
+ type: str # GENERAL
48
+ url: str # GENERAL
49
+ size: str # GENERAL
50
+ score: str # GENERAL
51
+ date: str # GENERAL
52
+ desc: str # GENERAL
53
+
54
+ seeder: int # TOR
55
+ leecher: int # TOR
56
+
57
+ slug: str # SC
58
+
59
+
60
+ class MediaManager:
61
+ def __init__(self):
62
+ self.media_list: List[MediaItem] = []
63
+
64
+ def add_media(self, data: dict) -> None:
65
+ """
66
+ Add media to the list.
67
+
68
+ Args:
69
+ data (dict): Media data to add.
70
+ """
71
+ self.media_list.append(MediaItem(**data))
72
+
73
+ def get(self, index: int) -> MediaItem:
74
+ """
75
+ Get a media item from the list by index.
76
+
77
+ Args:
78
+ index (int): The index of the media item to retrieve.
79
+
80
+ Returns:
81
+ MediaItem: The media item at the specified index.
82
+ """
83
+ return self.media_list[index]
84
+
85
+ def get_length(self) -> int:
86
+ """
87
+ Get the number of media items in the list.
88
+
89
+ Returns:
90
+ int: Number of media items.
91
+ """
92
+ return len(self.media_list)
93
+
94
+ def clear(self) -> None:
95
+ """
96
+ This method clears the media list.
97
+ """
98
+ self.media_list.clear()
99
+
100
+ def __str__(self):
101
+ return f"MediaManager(num_media={len(self.media_list)})"
@@ -1,5 +1,5 @@
1
- # 23.11.24
2
-
3
- from .recall_search import execute_search
4
- from .get_domain import search_domain
1
+ # 23.11.24
2
+
3
+ from .recall_search import execute_search
4
+ from .get_domain import search_domain
5
5
  from .manage_ep import manage_selection, map_episode_title, validate_episode_selection, validate_selection
@@ -1,137 +1,137 @@
1
- # 18.06.24
2
-
3
- import sys
4
- from urllib.parse import urlparse
5
-
6
-
7
- # External libraries
8
- import httpx
9
- from googlesearch import search
10
-
11
-
12
- # Internal utilities
13
- from StreamingCommunity.Src.Util.headers import get_headers
14
- from StreamingCommunity.Src.Util.console import console, msg
15
- from StreamingCommunity.Src.Util._jsonConfig import config_manager
16
-
17
-
18
- def google_search(query):
19
- """
20
- Perform a Google search and return the first result.
21
-
22
- Args:
23
- query (str): The search query to execute on Google.
24
-
25
- Returns:
26
- str: The first URL result from the search, or None if no result is found.
27
- """
28
- # Perform the search on Google and limit to 1 result
29
- search_results = search(query, num_results=1)
30
-
31
- # Extract the first result
32
- first_result = next(search_results, None)
33
-
34
- if not first_result:
35
- console.print("[red]No results found.[/red]")
36
-
37
- return first_result
38
-
39
- def get_final_redirect_url(initial_url, max_timeout):
40
- """
41
- Follow redirects from the initial URL and return the final URL after all redirects.
42
-
43
- Args:
44
- initial_url (str): The URL to start with and follow redirects.
45
-
46
- Returns:
47
- str: The final URL after all redirects are followed.
48
- """
49
-
50
- # Create a client with redirects enabled
51
- try:
52
- with httpx.Client(follow_redirects=True, timeout=max_timeout, headers={'user-agent': get_headers()}) as client:
53
- response = client.get(initial_url)
54
- response.raise_for_status()
55
-
56
- # Capture the final URL after all redirects
57
- final_url = response.url
58
-
59
- return final_url
60
-
61
- except Exception as e:
62
- console.print(f"[cyan]Test url[white]: [red]{initial_url}, [cyan]error[white]: [red]{e}")
63
- return None
64
-
65
- def search_domain(site_name: str, base_url: str):
66
- """
67
- Search for a valid domain for the given site name and base URL.
68
-
69
- Parameters:
70
- - site_name (str): The name of the site to search the domain for.
71
- - base_url (str): The base URL to construct complete URLs.
72
- - follow_redirects (bool): To follow redirect url or not.
73
-
74
- Returns:
75
- tuple: The found domain and the complete URL.
76
- """
77
-
78
- # Extract config domain
79
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
80
- domain = str(config_manager.get_dict("SITE", site_name)['domain'])
81
-
82
- try:
83
-
84
- # Test the current domain
85
- response_follow = httpx.get(f"{base_url}.{domain}", headers={'user-agent': get_headers()}, timeout=max_timeout, follow_redirects=True)
86
- response_follow.raise_for_status()
87
-
88
- except Exception as e:
89
-
90
- query = base_url.split("/")[-1]
91
- first_url = google_search(query)
92
- console.print(f"[green]First url from google seach[white]: [red]{first_url}")
93
-
94
- if first_url:
95
- final_url = get_final_redirect_url(first_url, max_timeout)
96
-
97
- if final_url != None:
98
- console.print(f"\n[bold yellow]Suggestion:[/bold yellow] [white](Experimental)\n"
99
- f"[cyan]New final URL[white]: [green]{final_url}")
100
-
101
- def extract_domain(url):
102
- parsed_url = urlparse(url)
103
- domain = parsed_url.netloc
104
- return domain.split(".")[-1]
105
-
106
- new_domain_extract = extract_domain(str(final_url))
107
-
108
- if msg.ask(f"[red]Do you want to auto update config.json - '[green]{site_name}[red]' with domain: [green]{new_domain_extract}", choices=["y", "n"], default="y").lower() == "y":
109
-
110
- # Update domain in config.json
111
- config_manager.config['SITE'][site_name]['domain'] = new_domain_extract
112
- config_manager.write_config()
113
-
114
- # Return config domain
115
- #console.print(f"[cyan]Return domain: [red]{new_domain_extract} \n")
116
- return new_domain_extract, f"{base_url}.{new_domain_extract}"
117
-
118
- else:
119
- console.print("[bold red]\nManually change the domain in the JSON file.[/bold red]")
120
- raise
121
-
122
- else:
123
- console.print("[bold red]No valid URL to follow redirects.[/bold red]")
124
-
125
- # Ensure the URL is in string format before parsing
126
- parsed_url = urlparse(str(response_follow.url))
127
- parse_domain = parsed_url.netloc
128
- tld = parse_domain.split('.')[-1]
129
-
130
- if tld is not None:
131
-
132
- # Update domain in config.json
133
- config_manager.config['SITE'][site_name]['domain'] = tld
134
- config_manager.write_config()
135
-
136
- # Return config domain
137
- return tld, f"{base_url}.{tld}"
1
+ # 18.06.24
2
+
3
+ import sys
4
+ from urllib.parse import urlparse
5
+
6
+
7
+ # External libraries
8
+ import httpx
9
+ from googlesearch import search
10
+
11
+
12
+ # Internal utilities
13
+ from StreamingCommunity.Util.headers import get_headers
14
+ from StreamingCommunity.Util.console import console, msg
15
+ from StreamingCommunity.Util._jsonConfig import config_manager
16
+
17
+
18
+ def google_search(query):
19
+ """
20
+ Perform a Google search and return the first result.
21
+
22
+ Args:
23
+ query (str): The search query to execute on Google.
24
+
25
+ Returns:
26
+ str: The first URL result from the search, or None if no result is found.
27
+ """
28
+ # Perform the search on Google and limit to 1 result
29
+ search_results = search(query, num_results=1)
30
+
31
+ # Extract the first result
32
+ first_result = next(search_results, None)
33
+
34
+ if not first_result:
35
+ console.print("[red]No results found.[/red]")
36
+
37
+ return first_result
38
+
39
+ def get_final_redirect_url(initial_url, max_timeout):
40
+ """
41
+ Follow redirects from the initial URL and return the final URL after all redirects.
42
+
43
+ Args:
44
+ initial_url (str): The URL to start with and follow redirects.
45
+
46
+ Returns:
47
+ str: The final URL after all redirects are followed.
48
+ """
49
+
50
+ # Create a client with redirects enabled
51
+ try:
52
+ with httpx.Client(follow_redirects=True, timeout=max_timeout, headers={'user-agent': get_headers()}) as client:
53
+ response = client.get(initial_url)
54
+ response.raise_for_status()
55
+
56
+ # Capture the final URL after all redirects
57
+ final_url = response.url
58
+
59
+ return final_url
60
+
61
+ except Exception as e:
62
+ console.print(f"[cyan]Test url[white]: [red]{initial_url}, [cyan]error[white]: [red]{e}")
63
+ return None
64
+
65
+ def search_domain(site_name: str, base_url: str):
66
+ """
67
+ Search for a valid domain for the given site name and base URL.
68
+
69
+ Parameters:
70
+ - site_name (str): The name of the site to search the domain for.
71
+ - base_url (str): The base URL to construct complete URLs.
72
+ - follow_redirects (bool): To follow redirect url or not.
73
+
74
+ Returns:
75
+ tuple: The found domain and the complete URL.
76
+ """
77
+
78
+ # Extract config domain
79
+ max_timeout = config_manager.get_int("REQUESTS", "timeout")
80
+ domain = str(config_manager.get_dict("SITE", site_name)['domain'])
81
+
82
+ try:
83
+
84
+ # Test the current domain
85
+ response_follow = httpx.get(f"{base_url}.{domain}", headers={'user-agent': get_headers()}, timeout=max_timeout, follow_redirects=True)
86
+ response_follow.raise_for_status()
87
+
88
+ except Exception as e:
89
+
90
+ query = base_url.split("/")[-1]
91
+ first_url = google_search(query)
92
+ console.print(f"[green]First url from google seach[white]: [red]{first_url}")
93
+
94
+ if first_url:
95
+ final_url = get_final_redirect_url(first_url, max_timeout)
96
+
97
+ if final_url != None:
98
+ console.print(f"\n[bold yellow]Suggestion:[/bold yellow] [white](Experimental)\n"
99
+ f"[cyan]New final URL[white]: [green]{final_url}")
100
+
101
+ def extract_domain(url):
102
+ parsed_url = urlparse(url)
103
+ domain = parsed_url.netloc
104
+ return domain.split(".")[-1]
105
+
106
+ new_domain_extract = extract_domain(str(final_url))
107
+
108
+ if msg.ask(f"[red]Do you want to auto update config.json - '[green]{site_name}[red]' with domain: [green]{new_domain_extract}", choices=["y", "n"], default="y").lower() == "y":
109
+
110
+ # Update domain in config.json
111
+ config_manager.config['SITE'][site_name]['domain'] = new_domain_extract
112
+ config_manager.write_config()
113
+
114
+ # Return config domain
115
+ #console.print(f"[cyan]Return domain: [red]{new_domain_extract} \n")
116
+ return new_domain_extract, f"{base_url}.{new_domain_extract}"
117
+
118
+ else:
119
+ console.print("[bold red]\nManually change the domain in the JSON file.[/bold red]")
120
+ raise
121
+
122
+ else:
123
+ console.print("[bold red]No valid URL to follow redirects.[/bold red]")
124
+
125
+ # Ensure the URL is in string format before parsing
126
+ parsed_url = urlparse(str(response_follow.url))
127
+ parse_domain = parsed_url.netloc
128
+ tld = parse_domain.split('.')[-1]
129
+
130
+ if tld is not None:
131
+
132
+ # Update domain in config.json
133
+ config_manager.config['SITE'][site_name]['domain'] = tld
134
+ config_manager.write_config()
135
+
136
+ # Return config domain
137
+ return tld, f"{base_url}.{tld}"