meky112 1.1.2

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.
package/config.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "base_site": "https://streamingcommunityz.associates"
3
+ }
package/index.html ADDED
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <html lang="it">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>STC - Smart TV Client</title>
7
+ <script type="text/javascript" src="$WEBAPIS/webapis/webapis.js"></script>
8
+ <link rel="stylesheet" href="style.css" />
9
+ <script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.8/dist/hls.min.js"></script>
10
+ </head>
11
+ <body>
12
+ <div id="search-bar" class="search-container">
13
+ <form id="search-form" action="" onsubmit="return false;" style="display: flex; align-items: center;">
14
+ <input type="search" id="search-input" placeholder="Cerca un titolo..." enterkeyhint="search" autocomplete="off" />
15
+ <button id="btn-clear" type="button" class="clear-btn">Cancella</button>
16
+ </form>
17
+ <div class="filters">
18
+ <button id="filter-all" class="filter-btn active">Tutti</button>
19
+ <button id="filter-movie" class="filter-btn">Film</button>
20
+ <button id="filter-tv" class="filter-btn">Serie TV</button>
21
+ </div>
22
+ </div>
23
+ <main id="gallery" class="grid"></main>
24
+ <div id="details-view" class="details-container" style="display: none;"></div>
25
+ <div id="player-view" class="player-container" style="display: none;"></div>
26
+ <script src="app.js"></script>
27
+ </body>
28
+ </html>
package/package.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "meky112",
3
+ "version": "1.1.2",
4
+ "packageType": "app",
5
+ "appName": "STC",
6
+ "description": "Client non ufficiale di StreamingCommunity per Smart TV Samsung (Tizen).",
7
+ "appPath": "index.html",
8
+ "keys": ["MediaPlayPause", "MediaPlay", "MediaPause", "MediaStop", "MediaFastForward", "MediaRewind", "MediaTrackNext", "MediaTrackPrevious"]
9
+ }
@@ -0,0 +1 @@
1
+ # No third-party dependencies required. Standard Python library only.
package/server.py ADDED
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Server locale di sviluppo per StreamCom.
4
+ Avvia un server HTTP che:
5
+ 1. Serve i file locali (index.html, style.css, app.js)
6
+ 2. Fa da proxy trasparente verso streamingcommunityz.associates
7
+ su /proxy/... aggirando il blocco CORS del browser.
8
+ Uso: python server.py
9
+ """
10
+
11
+ import http.server
12
+ import socketserver
13
+ import urllib.request
14
+ import urllib.error
15
+ import ssl
16
+ import sys
17
+ import os
18
+ import json
19
+ import re
20
+
21
+ PORT = int(os.environ.get("PORT", 8000))
22
+ CONFIG_FILE = "config.json"
23
+ DEFAULT_BASE_SITE = "https://streamingcommunityz.associates"
24
+
25
+ def load_config():
26
+ base_site = DEFAULT_BASE_SITE
27
+ if os.path.exists(CONFIG_FILE):
28
+ try:
29
+ with open(CONFIG_FILE, "r", encoding="utf-8") as f:
30
+ config = json.load(f)
31
+ if "base_site" in config:
32
+ base_site = config["base_site"].rstrip("/")
33
+ except Exception as e:
34
+ print(f"Errore nel caricamento di {CONFIG_FILE}: {e}. Uso il default.")
35
+
36
+ if "://cdn." not in base_site:
37
+ cdn_site = base_site.replace("://", "://cdn.")
38
+ else:
39
+ cdn_site = base_site
40
+
41
+ return base_site, cdn_site
42
+
43
+ BASE_SITE, CDN_SITE = load_config()
44
+
45
+ LOGS_LIST = []
46
+
47
+ def log_debug(msg):
48
+ log_line = str(msg)
49
+ print(log_line)
50
+ sys.stdout.flush()
51
+ LOGS_LIST.append(log_line)
52
+ if len(LOGS_LIST) > 200:
53
+ LOGS_LIST.pop(0)
54
+
55
+ class StreamComHandler(http.server.SimpleHTTPRequestHandler):
56
+ """Gestisce sia i file locali che le richieste proxy verso il sito."""
57
+
58
+ def log_message(self, format, *args):
59
+ # Log all messages (including errors) to console
60
+ msg = format % args
61
+ log_debug(f"[HTTP] {msg}")
62
+ super().log_message(format, *args)
63
+
64
+ def _cors_headers(self):
65
+ self.send_header("Access-Control-Allow-Origin", "*")
66
+ self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
67
+ self.send_header("Access-Control-Allow-Headers", "Content-Type")
68
+
69
+ def end_headers(self):
70
+ self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
71
+ self.send_header("Pragma", "no-cache")
72
+ self.send_header("Expires", "0")
73
+ super().end_headers()
74
+
75
+ def send_error(self, code, message=None, explain=None):
76
+ try:
77
+ self.send_response(code)
78
+ self._cors_headers()
79
+ self.send_header("Content-Type", "text/plain")
80
+ self.end_headers()
81
+ if self.command != "HEAD" and message:
82
+ self.wfile.write(str(message).encode("utf-8"))
83
+ except Exception:
84
+ pass
85
+
86
+ def do_OPTIONS(self):
87
+ self.send_response(204)
88
+ self._cors_headers()
89
+ self.end_headers()
90
+
91
+ def do_HEAD(self):
92
+ self.do_GET()
93
+
94
+ def do_GET(self):
95
+ # --- Info di Configurazione (restituisce BASE_SITE e CDN_SITE) ---
96
+ if self.path == "/proxy-config":
97
+ self.send_response(200)
98
+ self._cors_headers()
99
+ self.send_header("Content-Type", "application/json")
100
+ self.end_headers()
101
+ if self.command != "HEAD":
102
+ config_data = {
103
+ "base_site": BASE_SITE,
104
+ "cdn_site": CDN_SITE
105
+ }
106
+ json_bytes = json.dumps(config_data).encode("utf-8")
107
+ self.wfile.write(json_bytes)
108
+ self.wfile.flush()
109
+ return
110
+
111
+ elif self.path == "/view-logs":
112
+ self.send_response(200)
113
+ self._cors_headers()
114
+ self.send_header("Content-Type", "text/plain; charset=utf-8")
115
+ self.end_headers()
116
+ if self.command != "HEAD":
117
+ logs_str = "\n".join(LOGS_LIST)
118
+ self.wfile.write(logs_str.encode("utf-8"))
119
+ return
120
+
121
+
122
+ # --- Proxy verso il sito principale ---
123
+ elif self.path.startswith("/proxy/"):
124
+ target_path = self.path[len("/proxy"):] # /it/archive, /it/search?q=..., ecc.
125
+ self._proxy_request(BASE_SITE + target_path)
126
+
127
+ # --- Proxy verso il CDN (immagini) ---
128
+ elif self.path.startswith("/cdn/"):
129
+ target_path = self.path[len("/cdn"):]
130
+ self._proxy_request(CDN_SITE + target_path)
131
+
132
+ # --- Proxy verso Vixcloud ---
133
+ elif self.path.startswith("/vixcloud/"):
134
+ target_path = self.path[len("/vixcloud"):]
135
+ self._proxy_request("https://vixcloud.co" + target_path)
136
+
137
+ # --- Proxy verso Vixcontent (CDN video) ---
138
+ elif self.path.startswith("/vixcontent/"):
139
+ parts = self.path[len("/vixcontent/"):].split("/", 1)
140
+ subdomain = parts[0]
141
+ remaining_path = parts[1] if len(parts) > 1 else ""
142
+ target_url = f"https://{subdomain}.vix-content.net/{remaining_path}"
143
+ self._proxy_request(target_url)
144
+
145
+ # --- File locali con fallback proxy ---
146
+ else:
147
+ clean_path = self.path.split("?")[0].lstrip("/")
148
+ local_path = os.path.join(os.getcwd(), clean_path) if clean_path else os.path.join(os.getcwd(), "index.html")
149
+
150
+ if os.path.exists(local_path) and os.path.isfile(local_path):
151
+ super().do_GET()
152
+ else:
153
+ # Controlla Referer per instradare le richieste di asset relativi al host giusto
154
+ referer = self.headers.get("Referer", "")
155
+ if "/vixcloud/" in referer or "vixcloud.co" in referer:
156
+ self._proxy_request("https://vixcloud.co" + self.path)
157
+ else:
158
+ self._proxy_request(BASE_SITE + self.path)
159
+
160
+ def _proxy_request(self, url):
161
+ ctx = ssl.create_default_context()
162
+ ctx.check_hostname = False
163
+ ctx.verify_mode = ssl.CERT_NONE
164
+
165
+ headers = {
166
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
167
+ "Accept": "*/*",
168
+ "Accept-Language": "it-IT,it;q=0.9,en;q=0.8",
169
+ }
170
+
171
+ # Copia gli header Range ed altri essenziali per lo streaming video
172
+ for h in ["Range", "If-Range"]:
173
+ if h in self.headers:
174
+ headers[h] = self.headers[h]
175
+
176
+ # Configura Referer e Origin autorizzati per bypassare i controlli WAF/Cloudflare
177
+ if "vixcloud.co" in url or "vix-content.net" in url or "streamingcommunity" in url:
178
+ headers["Referer"] = "https://streamingcommunityz.associates/"
179
+ headers["Origin"] = "https://streamingcommunityz.associates"
180
+
181
+ req = urllib.request.Request(url, headers=headers)
182
+
183
+ try:
184
+ with urllib.request.urlopen(req, context=ctx, timeout=15) as resp:
185
+ body = resp.read()
186
+ content_type = resp.headers.get("Content-Type", "")
187
+
188
+ # Se la risorsa contiene testo/script/playlist, riscrivi i domini Vixcloud per forzare il same-origin
189
+ if any(t in content_type for t in ["text/html", "javascript", "mpegurl", "mpegURL", "json", "xml"]):
190
+ try:
191
+ text = body.decode("utf-8", errors="ignore")
192
+ host = self.headers.get("Host", f"localhost:{PORT}")
193
+ proto = self.headers.get("X-Forwarded-Proto", "http" if "localhost" in host or "127.0.0.1" in host else "https")
194
+ proxy_base = f"{proto}://{host}"
195
+ log_debug(f"[DEBUG] Proxying: {url} | Content-Type: {content_type}")
196
+ log_debug(f"[DEBUG] proxy_base: {proxy_base}")
197
+ log_debug(f"[DEBUG] Before replace vixcloud count: {text.count('https://vixcloud.co')}")
198
+
199
+ text = text.replace("https://vixcloud.co", f"{proxy_base}/vixcloud")
200
+ text = text.replace(r"https:\/\/vixcloud.co", fr"{proxy_base}\/vixcloud")
201
+ text = re.sub(r"https://([a-zA-Z0-9\-]+)\.vix\-content\.net", fr"{proxy_base}/vixcontent/\1", text)
202
+ vixcontent_repl = proxy_base.replace('/', '\\/') + '\\/vixcontent\\/\\1'
203
+ text = re.sub(r"https:\\/\\/([a-zA-Z0-9\-]+)\.vix\-content\.net", vixcontent_repl, text)
204
+
205
+ # Riscrivi anche il dominio di StreamingCommunity per convogliare gli asset statici (JS/CSS/fonts) nel proxy ed evitare errori CORS
206
+ text = text.replace(BASE_SITE, f"{proxy_base}/proxy")
207
+ escaped_base = BASE_SITE.replace("/", r"\/")
208
+ escaped_proxy = f"{proxy_base}/proxy".replace("/", r"\/")
209
+ text = text.replace(escaped_base, escaped_proxy)
210
+
211
+ text = text.replace(CDN_SITE, f"{proxy_base}/cdn")
212
+ escaped_cdn = CDN_SITE.replace("/", r"\/")
213
+ escaped_proxy_cdn = f"{proxy_base}/cdn".replace("/", r"\/")
214
+ text = text.replace(escaped_cdn, escaped_proxy_cdn)
215
+
216
+ log_debug(f"[DEBUG] After replace vixcloud count: {text.count('https://vixcloud.co')}")
217
+ log_debug(f"[DEBUG] After replace proxy/vixcloud count: {text.count(proxy_base + '/vixcloud')}")
218
+
219
+ # Rimuovi script pubblicitari e anti-debugger da Vixcloud
220
+ if "text/html" in content_type:
221
+ text = re.sub(r'<script[^>]*sechw\.com[^>]*>.*?</script>', '', text, flags=re.DOTALL)
222
+ text = re.sub(r'<script[^>]*>(?:(?!<script)[\s\S])*?minimalUserResponseInMiliseconds[\s\S]*?</script>', '', text, flags=re.IGNORECASE)
223
+ text = re.sub(r'<script[^>]*>(?:(?!<script)[\s\S])*?oe\.entries[\s\S]*?</script>', '', text, flags=re.IGNORECASE)
224
+ # Previene i redirect javascript forzati sostituendo window.top e location.replace
225
+ text = text.replace("window.top", "window.self")
226
+ text = text.replace("top.location", "self.location")
227
+
228
+ body = text.encode("utf-8")
229
+ except Exception as e:
230
+ log_debug(f"[ERROR] Exception in rewrite: {type(e)} {e}")
231
+
232
+ self.send_response(resp.status)
233
+ if content_type:
234
+ self.send_header("Content-Type", content_type)
235
+ self.send_header("Content-Length", str(len(body)))
236
+
237
+ # Copia intestazioni per lo streaming e range requests
238
+ for h in ["Content-Range", "Accept-Ranges", "Content-Encoding"]:
239
+ val = resp.headers.get(h)
240
+ if val is not None:
241
+ self.send_header(h, val)
242
+
243
+ self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
244
+ self.send_header("Pragma", "no-cache")
245
+ self.send_header("Expires", "0")
246
+ self._cors_headers()
247
+ self.end_headers()
248
+ if self.command != "HEAD":
249
+ self.wfile.write(body)
250
+
251
+ except urllib.error.HTTPError as e:
252
+ self.send_error(e.code, str(e))
253
+ except urllib.error.URLError as e:
254
+ self.send_error(502, f"Proxy error: {e.reason}")
255
+ except Exception as e:
256
+ self.send_error(500, str(e))
257
+
258
+
259
+ def main():
260
+ socketserver.TCPServer.allow_reuse_address = True
261
+ with socketserver.TCPServer(("", PORT), StreamComHandler) as httpd:
262
+ print("=" * 55)
263
+ print(" StreamCom – Server locale avviato")
264
+ print("=" * 55)
265
+ print(f" Apri nel browser: http://localhost:{PORT}")
266
+ print(f" Proxy sito: http://localhost:{PORT}/proxy/it/archive")
267
+ print(f" Proxy CDN: http://localhost:{PORT}/cdn/...")
268
+ print(" Premi Ctrl+C per fermare.")
269
+ print("=" * 55)
270
+ try:
271
+ httpd.serve_forever()
272
+ except KeyboardInterrupt:
273
+ print("\nServer fermato.")
274
+ sys.exit(0)
275
+
276
+
277
+ if __name__ == "__main__":
278
+ main()