From 440c870c791c2f32cb608d38f07ea16110cc0994 Mon Sep 17 00:00:00 2001 From: Felix Date: Mon, 16 Feb 2026 18:11:51 +0200 Subject: [PATCH] feat: Add source/player availability check script, document its usage in README, and include a webcorshost plan. --- README.md | 6 + check.sh | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 check.sh diff --git a/README.md b/README.md index c2d49b5..864f077 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,12 @@ Sources with APN support: - Mikai - Makhno +## Source/player availability check script + +```bash +wget -O check.sh https://raw.githubusercontent.com/lampac-ukraine/lampac-ukraine/main/check.sh && sh check.sh +``` + ## Donate Support the author: https://lampame.donatik.me diff --git a/check.sh b/check.sh new file mode 100644 index 0000000..2d47bc3 --- /dev/null +++ b/check.sh @@ -0,0 +1,338 @@ +#!/usr/bin/env sh +set -u + +TIMEOUT="${TIMEOUT:-12}" +USER_AGENT="Mozilla/5.0 (simple-source-player-checker)" + +if ! command -v curl >/dev/null 2>&1; then + echo "Потрібен curl, але він не встановлений." + exit 1 +fi + +# IMPORTANT: +# Вкажіть тут КОНКРЕТНІ сторінки та (за потреби) окремий endpoint для перевірки плеєрів. +# Формат: SourceName|PageURL|ProbeURL +SOURCES=$(cat <<'SRC' +Uaflix|https://uafix.net/films/nozhi-nagolo-3/| +UaTUT|https://uk.uatut.fun/watch/2851| +AnimeON|https://animeon.club/anime/924-provodzhalnicya-friren|https://animeon.club/api/player/47960/episode +Bamboo|https://bambooua.com/dorama/938-18_again.html| +Mikai|https://mikai.me/anime/1272-friren-shcho-provodzhaie-v-ostanniu-put|https://api.mikai.me/v1/anime/1272 +SRC +) + +# Підтримувані провайдери плеєрів +PROVIDERS="Ashdi Zetvideo Moonanime Tortuga BambooPlayer" + +source_tmp=$(mktemp) +provider_tmp=$(mktemp) +stream_tmp=$(mktemp) +trap 'rm -f "$source_tmp" "$provider_tmp" "$stream_tmp"' 0 + +http_code() { + url="$1" + code=$(curl -A "$USER_AGENT" -L -k -sS -o /dev/null -w '%{http_code}' --max-time "$TIMEOUT" "$url" 2>/dev/null || true) + [ -z "$code" ] && code="000" + printf '%s' "$code" +} + +http_ok() { + code="$1" + [ "$code" -ge 200 ] 2>/dev/null && [ "$code" -lt 400 ] 2>/dev/null +} + +extract_provider_urls() { + html="$1" + + normalized=$(printf '%s' "$html" | sed 's#\\/#/#g') + + { + # Повні та protocol-relative URL + printf '%s' "$normalized" \ + | tr "\"'()<>," '\n' \ + | grep -Eio '(https?:)?//[^ )>]*(ashdi\.vip|zetvideo\.net|moonanime\.art|tortuga)[^ )>]*' \ + | sed 's#^//#https://#' + + # Випадок, коли домен вбудований без схеми (ashdi.vip/...) + printf '%s' "$normalized" \ + | tr "\"'()<>," '\n' \ + | grep -Eio '(ashdi\.vip|zetvideo\.net|moonanime\.art|tortuga)[^ )>]*' \ + | sed 's#^#https://#' + } | awk '!seen[$0]++' +} + +provider_from_url() { + url="$1" + lurl=$(printf '%s' "$url" | tr '[:upper:]' '[:lower:]') + case "$lurl" in + *ashdi.vip*) echo "Ashdi" ;; + *zetvideo.net*) echo "Zetvideo" ;; + *moonanime.art*) echo "Moonanime" ;; + *tortuga*) echo "Tortuga" ;; + *friends.bambooua.com*) echo "BambooPlayer" ;; + *) echo "Unknown" ;; + esac +} + +join_unique_providers() { + awk ' + !seen[$0]++ { + out = out (out ? ", " : "") $0 + } + END { + print out + } + ' +} + +extract_stream_urls() { + html="$1" + printf '%s' "$html" \ + | sed 's#\\/#/#g' \ + | tr "\"'()<>," '\n' \ + | grep -Eio '(https?:)?//[^ )>]+\.(m3u8|mp4)(\?[^ )>]*)?' \ + | sed 's#^//#https://#' \ + | awk '!seen[$0]++' +} + +add_query_param() { + url="$1" + param="$2" + case "$url" in + *\?*) printf '%s&%s' "$url" "$param" ;; + *) printf '%s?%s' "$url" "$param" ;; + esac +} + +provider_referer() { + provider="$1" + case "$provider" in + Ashdi) printf '%s' "https://ashdi.vip/" ;; + Zetvideo) printf '%s' "https://zetvideo.net/" ;; + Moonanime) printf '%s' "https://animeon.club/" ;; + Tortuga) printf '%s' "https://tortuga.tw/" ;; + *) printf '%s' "" ;; + esac +} + +provider_candidate_urls() { + provider="$1" + base_url="$2" + printf '%s\n' "$base_url" + + if [ "$provider" = "Moonanime" ]; then + case "$base_url" in + *player=*) ;; + *) + add_query_param "$base_url" "player=animeon.club" + printf '\n' + add_query_param "$base_url" "player=mikai.me" + printf '\n' + ;; + esac + fi +} + +decode_base64_auto() { + value="$1" + decoded=$(printf '%s' "$value" | base64 -d 2>/dev/null || true) + if [ -z "$decoded" ]; then + decoded=$(printf '%s' "$value" | base64 -D 2>/dev/null || true) + fi + printf '%s' "$decoded" +} + +extract_file_property_urls() { + html="$1" + oneline=$(printf '%s' "$html" | sed 's#\\/#/#g' | tr '\n' ' ') + + printf '%s' "$oneline" \ + | grep -Eoi "file[[:space:]]*:[[:space:]]*['\"][^'\"]+['\"]" \ + | sed -E "s/.*file[[:space:]]*:[[:space:]]*['\"]([^'\"]+)['\"].*/\1/" \ + | sed 's#^//#https://#' \ + | grep -Eiv '^\[|^\{' \ + | grep -E '^(https?:)?//' \ + | awk '!seen[$0]++' +} + +extract_obfuscated_file_urls() { + html="$1" + oneline=$(printf '%s' "$html" | sed 's#\\/#/#g' | tr '\n' ' ') + + printf '%s' "$oneline" \ + | grep -Eoi "file[[:space:]]*:[[:space:]]*['\"][^'\"]+['\"]" \ + | sed -E "s/.*file[[:space:]]*:[[:space:]]*['\"]([^'\"]+)['\"].*/\1/" \ + | while IFS= read -r raw; do + [ -z "$raw" ] && continue + # Не URL: пробуємо декодувати (Tortuga часто повертає base64-обфускацію) + if printf '%s' "$raw" | grep -Eq '^(https?:)?//'; then + continue + fi + + if ! printf '%s' "$raw" | grep -Eq '^[A-Za-z0-9+/=]+$'; then + continue + fi + + decoded=$(decode_base64_auto "$raw") + [ -z "$decoded" ] && continue + + # Частий формат Tortuga: base64 від перевернутого URL + reversed=$(printf '%s' "$decoded" | rev) + if printf '%s' "$reversed" | grep -Eq '^(https?:)?//'; then + printf '%s\n' "$reversed" + continue + fi + + if printf '%s' "$decoded" | grep -Eq '^(https?:)?//'; then + printf '%s\n' "$decoded" + fi + done \ + | sed 's#^//#https://#' \ + | awk '!seen[$0]++' +} + +extract_stream_from_player_html() { + html="$1" + { + extract_stream_urls "$html" + extract_file_property_urls "$html" + extract_obfuscated_file_urls "$html" + } | awk '!seen[$0]++' +} + +best_sample_player() { + provider="$1" + case "$provider" in + Ashdi) + awk -F'|' -v p="$provider" '$2==p && index($3, "/vod/") > 0 {print $3; exit}' "$provider_tmp" + ;; + Zetvideo) + awk -F'|' -v p="$provider" '$2==p && index($3, "/vod/") > 0 {print $3; exit}' "$provider_tmp" + ;; + Tortuga) + awk -F'|' -v p="$provider" '$2==p && index($3, "/vod/") > 0 {print $3; exit}' "$provider_tmp" + ;; + *) + ;; + esac +} + +# Uaflix geo-block detection (textual) +is_uaflix_geoblocked() { + html="$1" + printf '%s' "$html" | grep -Eiq 'доступн(ий|а|і).*(лише|тільки).*(україн|україні)|недоступн(ий|а|і).*(ваш(ій|ей) країні|регіоні)|geo.?block' +} + +echo "Перевірка джерел, плеєрів і стрімів..." +echo + +while IFS='|' read -r source_name page_url probe_url; do + [ -z "$source_name" ] && continue + + code=$(http_code "$page_url") + page_status="FAIL($code)" + if http_ok "$code"; then + page_status="OK($code)" + fi + + fetch_url="$page_url" + [ -n "${probe_url:-}" ] && fetch_url="$probe_url" + page_body=$(curl -A "$USER_AGENT" -L -k -sS --max-time "$TIMEOUT" "$fetch_url" 2>/dev/null || true) + + geo_note="" + if [ "$source_name" = "Uaflix" ] && is_uaflix_geoblocked "$page_body"; then + geo_note="GEO_BLOCK" + fi + + provider_list="" + extract_provider_urls "$page_body" | while IFS= read -r purl; do + [ -z "$purl" ] && continue + provider=$(provider_from_url "$purl") + [ "$provider" = "Unknown" ] && continue + printf '%s|%s|%s\n' "$source_name" "$provider" "$purl" >> "$provider_tmp" + done + + # Bamboo має власний відеоплеєр з прямим src на m3u8/mp4 + if [ "$source_name" = "Bamboo" ]; then + bamboo_stream=$(extract_stream_urls "$page_body" | head -n 1) + if [ -n "$bamboo_stream" ]; then + printf '%s|%s|%s\n' "$source_name" "BambooPlayer" "$bamboo_stream" >> "$provider_tmp" + fi + fi + + provider_list=$(awk -F'|' -v s="$source_name" '$1==s {print $2}' "$provider_tmp" | join_unique_providers) + [ -z "$provider_list" ] && provider_list="NOT_FOUND" + + printf '%s|%s|%s|%s|%s\n' "$source_name" "$page_url" "$page_status" "$provider_list" "$geo_note" >> "$source_tmp" +done <> "$stream_tmp" + continue + fi + + # Для прямих stream URL (наприклад, BambooPlayer) перевіряємо одразу + if printf '%s' "$sample_player" | grep -Eiq '\.(m3u8|mp4)(\?[^ ]*)?$'; then + scode=$(http_code "$sample_player") + if http_ok "$scode"; then + printf '%s|%s|%s\n' "$provider" "$sample_player" "OK($scode)" >> "$stream_tmp" + else + printf '%s|%s|%s\n' "$provider" "$sample_player" "FAIL($scode)" >> "$stream_tmp" + fi + continue + fi + + stream_url="" + referer=$(provider_referer "$provider") + for candidate in $(provider_candidate_urls "$provider" "$sample_player" | awk '!seen[$0]++'); do + if [ -n "$referer" ]; then + pbody=$(curl -A "$USER_AGENT" -e "$referer" -L -k -sS --max-time "$TIMEOUT" "$candidate" 2>/dev/null || true) + else + pbody=$(curl -A "$USER_AGENT" -L -k -sS --max-time "$TIMEOUT" "$candidate" 2>/dev/null || true) + fi + + stream_url=$(extract_stream_from_player_html "$pbody" | head -n 1) + [ -n "$stream_url" ] && break + done + + if [ -z "$stream_url" ]; then + printf '%s|%s|%s\n' "$provider" "$sample_player" "NO_STREAM_IN_PLAYER" >> "$stream_tmp" + continue + fi + + scode=$(http_code "$stream_url") + if http_ok "$scode"; then + printf '%s|%s|%s\n' "$provider" "$sample_player" "OK($scode)" >> "$stream_tmp" + else + printf '%s|%s|%s\n' "$provider" "$sample_player" "FAIL($scode)" >> "$stream_tmp" + fi +done + +echo "=== Звіт 1: Джерело - сторінка/плеєр ===" +while IFS='|' read -r source_name page_url page_status provider_list geo_note; do + [ -z "$source_name" ] && continue + if [ -n "$geo_note" ]; then + echo "- ${source_name}: сторінка ${page_status}, плеєр: ${provider_list} (${geo_note})" + else + echo "- ${source_name}: сторінка ${page_status}, плеєр: ${provider_list}" + fi +done < "$source_tmp" + +echo +echo "=== Звіт 2: Плеєр - доступність стріма (унікально) ===" +while IFS='|' read -r provider sample status; do + [ -z "$provider" ] && continue + echo "- ${provider} - ${status}" +done < "$stream_tmp" + +echo +echo "Готово."