1 Commits

Author SHA1 Message Date
Paperclip
5fdc576054 Trim nonfunctional API-all domains
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-26 20:38:31 +02:00
6 changed files with 210 additions and 34 deletions

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Python 3
API_ALL_DOMAINS = (
{
'label': 'Filmpalast.to',
'domain': 'filmpalast.to',
'url': 'http://filmpalast.to/',
},
{
'label': 'KinoGer.com',
'domain': 'kinoger.com',
'url': 'https://kinoger.com/',
},
{
'label': 'KinoX.to',
'domain': 'kinox.to',
'url': 'https://kinox.to/',
},
{
'label': 'MovieDream.co',
'domain': 'moviedream.co',
'url': 'https://moviedream.co/',
},
{
'label': 'StreamWorld.to',
'domain': 'streamworld.to',
'url': 'http://streamworld.to/',
},
{
'label': 'Moflix-Stream',
'domain': 'moflix-stream.xyz',
'url': 'https://moflix-stream.xyz/',
},
)
API_ALL_DEFAULT_DOMAIN = 'kinox.to'

View File

@@ -36,6 +36,7 @@ class cPluginHandler:
pluginDB = self.__getPluginDB()
update = False
fileNames = self.__getFileNamesFromFolder(self.defaultFolder)
forceSearchPlugins = {'api_all', 'kinoger'}
for fileName in fileNames:
plugin = {'name': '', 'identifier': '', 'icon': '', 'domain': '', 'globalsearch': '', 'modified': 0}
@@ -52,6 +53,10 @@ class cPluginHandler:
except Exception:
pass
if fileName in forceSearchPlugins and globalSearchStatus != 'true':
cConfig().setSetting('global_search_' + fileName, 'true')
globalSearchStatus = 'true'
if fileName not in pluginDB or modTime > plugin['modified'] or globalSearchStatus:
pluginData = self.__getPluginData(fileName, self.defaultFolder)
if pluginData:

View File

@@ -314,7 +314,7 @@
</setting>
<setting id="global_search_api_all" type="boolean" label="30052">
<level>0</level>
<default>False</default>
<default>True</default>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_api_all">False</dependency>
</dependencies>
@@ -322,18 +322,15 @@
</setting>
<setting id="plugin_api_all.domain" type="string" label="30278" help="">
<level>0</level>
<default>kinokiste.eu</default>
<default>kinox.to</default>
<constraints>
<options>
<option label="HDFilme">hdfilme.me</option>
<option label="Kinokiste">kinokiste.eu</option>
<option label="Kinoz">kinoz.org</option>
<option label="KKiste">kkiste.eu</option>
<option label="Movie2k">movie2k.ch</option>
<option label="Movie4k">movie4k.sx</option>
<option label="Streamcloud">streamcloud.sx</option>
<option label="StreamKiste">streamkiste.sx</option>
<option label="XCine">xcine.io</option>
<option label="Filmpalast.to">filmpalast.to</option>
<option label="KinoGer.com">kinoger.com</option>
<option label="KinoX.to">kinox.to</option>
<option label="MovieDream.co">moviedream.co</option>
<option label="StreamWorld.to">streamworld.to</option>
<option label="Moflix-Stream">moflix-stream.xyz</option>
<allowempty>true</allowempty>
</options>
</constraints>
@@ -532,15 +529,20 @@
</setting>
<setting id="plugin_hdfilme.domain" type="string" label="30278" help="">
<level>3</level>
<default/>
<default>hdfilme.garden</default>
<constraints>
<options>
<option label="HDFilme.tv">hdfilme.tv</option>
<option label="HDFilme.garden">hdfilme.garden</option>
<option label="HDFilme.legal">hdfilme.legal</option>
</options>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_hdfilme">false</dependency>
<dependency type="visible" operator="!is" setting="plugin_hdfilme">false</dependency>
</dependencies>
<control type="edit" format="string">
<control type="spinner" format="string">
<heading>30278</heading>
</control>
</setting>
@@ -576,15 +578,20 @@
</setting>
<setting id="plugin_hdfilme_1.domain" type="string" label="30278" help="">
<level>3</level>
<default/>
<default>hdfilme.legal</default>
<constraints>
<options>
<option label="HDFilme.tv">hdfilme.tv</option>
<option label="HDFilme.legal">hdfilme.legal</option>
<option label="HDFilme.my">hdfilme.my</option>
</options>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_hdfilme_1">false</dependency>
<dependency type="visible" operator="!is" setting="plugin_hdfilme_1">false</dependency>
</dependencies>
<control type="edit" format="string">
<control type="spinner" format="string">
<heading>30278</heading>
</control>
</setting>
@@ -648,7 +655,7 @@
</setting>
<setting id="global_search_kinoger" type="boolean" label="30052">
<level>0</level>
<default>False</default>
<default>True</default>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_kinoger">False</dependency>
</dependencies>
@@ -756,9 +763,11 @@
</setting>
<setting id="plugin_kinox.domain" type="string" label="30278" help="">
<level>3</level>
<default>kinoz.to</default><default/>
<default>ww22.kinoz.to</default>
<constraints>
<options>
<option label="kinox.to">kinox.to</option>
<option label="ww22.kinoz.to">ww22.kinoz.to</option>
<option label="kinoz.to">kinoz.to</option>
<option label="www12.kinoz.to">www12.kinoz.to</option>
<option label="www13.kinoz.to">www13.kinoz.to</option>
@@ -816,15 +825,19 @@
</setting>
<setting id="plugin_kkiste.domain" type="string" label="30278" help="">
<level>3</level>
<default/>
<default>kkiste.eu</default>
<constraints>
<options>
<option label="KKiste.ag">kkiste.ag</option>
<option label="KKiste.eu">kkiste.eu</option>
</options>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_kkiste">false</dependency>
<dependency type="visible" operator="!is" setting="plugin_kkiste">false</dependency>
</dependencies>
<control type="edit" format="string">
<control type="spinner" format="string">
<heading>30278</heading>
</control>
</setting>
@@ -992,15 +1005,19 @@
</setting>
<setting id="plugin_movie4k.domain" type="string" label="30278" help="">
<level>3</level>
<default/>
<default>movie4k.sx</default>
<constraints>
<options>
<option label="Movie4k.org">movie4k.org</option>
<option label="Movie4k.sx">movie4k.sx</option>
</options>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="enable" operator="!is" setting="plugin_movie4k">false</dependency>
<dependency type="visible" operator="!is" setting="plugin_movie4k">false</dependency>
</dependencies>
<control type="edit" format="string">
<control type="spinner" format="string">
<heading>30278</heading>
</control>
</setting>
@@ -1055,6 +1072,7 @@
<constraints>
<options>
<option label="S.to">s.to</option>
<option label="stream.to">stream.to</option>
<option label="SerienStream.to">serienstream.to</option>
<option label="SerienStream.stream(VPN)">serienstream.stream</option>
<option label="Proxy Server">186.2.175.5</option>
@@ -1662,4 +1680,4 @@
</group>
</category>
</section>
</settings>
</settings>

View File

@@ -8,6 +8,9 @@
import re
import xbmcgui
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urlparse
from resources.lib.handler.ParameterHandler import ParameterHandler
from resources.lib.handler.requestHandler import cRequestHandler
from resources.lib.tools import logger, cParser, cUtil
@@ -16,17 +19,89 @@ from resources.lib.config import cConfig
from resources.lib.gui.gui import cGui
from json import loads
from datetime import datetime
from resources.lib.data.api_all_domains import API_ALL_DOMAINS, API_ALL_DEFAULT_DOMAIN
# Globale Variable für die JSON-Daten
apiJson = None
# Domain Abfrage ###
def _normalize_domain(value):
if not value:
return ''
parsed = urlparse(value)
if parsed.hostname:
return parsed.hostname.lower()
return value.strip().lower()
def _get_default_domain():
registry = _get_domain_registry()
if API_ALL_DEFAULT_DOMAIN in registry:
return API_ALL_DEFAULT_DOMAIN
if API_ALL_DOMAINS:
return API_ALL_DOMAINS[0]['domain']
return API_ALL_DEFAULT_DOMAIN
def _get_domain_registry():
return {entry['domain']: entry for entry in API_ALL_DOMAINS}
def _get_configured_domain():
registry = _get_domain_registry()
configured = _normalize_domain(
cConfig().getSetting('plugin_' + SITE_IDENTIFIER + '.domain', _get_default_domain())
)
if configured in registry:
return configured
return _get_default_domain()
def _get_search_domains():
domains = []
configured = _get_configured_domain()
if configured:
domains.append(configured)
for entry in API_ALL_DOMAINS:
domain = entry['domain']
if domain not in domains:
domains.append(domain)
return domains
def _fetch_movies_for_domain(domain, sLang):
oRequest = cRequestHandler(
'https://' + domain + '/data/browse/?lang=%s&order_by=%s&page=%s&limit=0' % (sLang, 'new', '1'),
caching=True
)
oRequest.addHeaderEntry('Referer', 'https://' + domain + '/')
oRequest.addHeaderEntry('Origin', 'https://' + domain + '/')
oRequest.cacheTime = 60 * 60 * 48
sJson = oRequest.request()
aJson = loads(sJson)
movies = aJson.get('movies', [])
return movies if isinstance(movies, list) else []
def _movie_signature(movie):
return (
str(movie.get('_id', '')).strip(),
str(movie.get('title', '')).strip().lower(),
str(movie.get('year', '')).strip(),
)
SITE_NAME = 'API Suchmaschine'
SITE_ICON = 'api.png'
SITE_IDENTIFIER = 'api_all'
DOMAIN = cConfig().getSetting('plugin_' + SITE_IDENTIFIER + '.domain', 'movie4k.sx')
DOMAIN = _get_configured_domain()
STATUS = cConfig().getSetting('plugin_' + SITE_IDENTIFIER + '_status') # Status Code Abfrage der Domain
ACTIVE = cConfig().getSetting('plugin_' + SITE_IDENTIFIER) # Ob Plugin aktiviert ist oder nicht
ORIGIN = 'https://' + DOMAIN + '/'
@@ -367,7 +442,7 @@ def showEntries(entryUrl=False, sGui=False, sSearchText=False):
oGuiElement.setLanguage('EN')
oGuiElement.setMediaType('tvshow' if isTvshow else 'movie')
if 'runtime' in movie:
isMatch, sRuntime = cParser.parseSingleResult(movie['runtime'], '\d+')
isMatch, sRuntime = cParser.parseSingleResult(movie['runtime'], r'\d+')
if isMatch:
oGuiElement.addItemValue('duration', sRuntime)
params.setParam('entryUrl', URL_WATCH % str(movie['_id']))
@@ -564,7 +639,7 @@ def SSsearch(sGui=False, sSearchText=False):
oGuiElement.setLanguage('EN')
oGuiElement.setMediaType('tvshow' if isTvshow else 'movie')
if 'runtime' in movie:
isMatch, sRuntime = cParser.parseSingleResult(movie['runtime'], '\d+')
isMatch, sRuntime = cParser.parseSingleResult(movie['runtime'], r'\d+')
if isMatch:
oGuiElement.addItemValue('duration', sRuntime)
params.setParam('entryUrl', URL_WATCH % str(movie['_id']))
@@ -585,17 +660,34 @@ def loadMoviesData():
sLang = '3'
try:
oRequest = cRequestHandler(URL_SEARCH % (sLang, 'new', '1'), caching=True)
oRequest.addHeaderEntry('Referer', REFERER)
oRequest.addHeaderEntry('Origin', ORIGIN)
oRequest.cacheTime = 60 * 60 * 48 # HTML Cache Zeit 2 Tage
sJson = oRequest.request()
apiJson = loads(sJson)
logger.info('API-Daten erfolgreich geladen')
merged_movies = {}
domains = _get_search_domains()
with ThreadPoolExecutor(max_workers=min(8, len(domains) or 1)) as executor:
futures = {
executor.submit(_fetch_movies_for_domain, domain, sLang): domain
for domain in domains
}
for future in as_completed(futures):
domain = futures[future]
try:
movies = future.result()
except Exception:
logger.info('API-Daten konnten von %s nicht geladen werden' % domain)
continue
for movie in movies:
if not isinstance(movie, dict) or '_id' not in movie:
continue
merged_movies.setdefault(_movie_signature(movie), movie)
apiJson = {'movies': list(merged_movies.values())}
logger.info('API-Daten erfolgreich aus %d Domains geladen' % len(domains))
except:
logger.error('Fehler beim Laden der API-Daten')
apiJson = {'movies': []}
# Daten werden lazy beim ersten Zugriff geladen (siehe SSsearch)
# loadMoviesData() - entfernt: beschleunigt den Import/Start erheblich
# loadMoviesData() - entfernt: beschleunigt den Import/Start erheblich

View File

@@ -270,10 +270,33 @@ def showHosters():
sHtmlContent = cRequestHandler(sUrl, ignoreErrors=True, caching=False).request()
pattern = r"show[^>]\d,[^>][^>]'([^']+)"
isMatch, aResult = cParser.parse(sHtmlContent, pattern)
if not isMatch:
isMatch, packed = cParser.parseSingleResult(sHtmlContent, r'(eval\s*\(function.*?)</script>')
if isMatch:
from resources.lib import jsunpacker
sHtmlContent = jsunpacker.unpack(packed)
isMatchM3u8, aResultM3u8 = cParser.parse(sHtmlContent, r'(https?://[^"\']+\.m3u8[^"\']*)')
if isMatchM3u8:
isMatch = True
if not aResult:
aResult = aResultM3u8
else:
for sM3u8Url in aResultM3u8:
if sM3u8Url not in aResult:
aResult.append(sM3u8Url)
if isMatch:
for sUrl in aResult:
try:
if 'kinoger.ru' in sUrl: continue
if '.m3u8' in sUrl:
hoster = {
'link': sUrl + '|Referer=https%3A%2F%2Fkinoger.com%2F' + headers,
'name': 'KinoGer.com [I][HLS][/I]',
'quality': '720',
'resolved': True
}
hosters.append(hoster)
continue
# oRequest = cRequestHandler(sUrl, caching=False, ignoreErrors=True)
# oRequest.addHeaderEntry('Referer', 'https://kinoger.com/')
# sHtmlContent = oRequest.request() # Durchsucht sHtml Content
@@ -429,4 +452,4 @@ def content_decryptor(html_content,passphrase):
# Return the decrypted data as a JSON object
return json.loads(plain_text.decode())
else:
return None
return None