Open azgaresncf opened 7 months ago
I'm going to make a PR.
Yes, I know that the workflow have problem. So what you're saying is that I need to add an account to have the permission?
Yeah, but I can give a throwaway account (maybe on Discord if you want to).
Yeah, but I can give a throwaway account (maybe on Discord if you want to).
Yes, please. You can send it to me on Discord if you want.
{
'callId': '<callid>',
'errorCode': '<error>',
'errorDetails': 'Your request is blocked because of security issues.',
'errorMessage': 'Invalid parameter value',
'apiVersion': 2,
'statusCode': 400,
'statusReason': 'Bad Request',
'time': '<time>',
'errorFlags': 'missingKey'
}
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail !
#!/bin/bash
# Informations d'authentification
USERNAME="fauxcompte@yopmail.com"
PASSWORD="password12345"
OUTPUT="$3"
USER_AGENT="Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like MacOS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
# Nom du groupe de la playlist.
# possibilité d'utiliser $thematic_label au lieu d'une chaîne de caractères.
# ATTENTION Si `$thematic_label` est utilisé alors la variable doit être définie dans la boucle while de la fonction build_playlist
# la variable sera à décommenter
group_name="\"TF1 Plus\""
# Proxy ne fonctionne pas.
# PROXY="94.23.252.168:9180"
# Page d'accueil de TF1
TF1_DIRECT_URL="https://www.tf1.fr/direct"
# URL de l'API Gigya
AUTH_URL="https://compte.tf1.fr/accounts.login"
SESSION_URL="https://www.tf1.fr/token/gigya/web"
#GIGYA_API_KEY="$(curl -sL "$TF1_DIRECT_URL" | grep -oP 'apiKey=\K[^&]+')"
GIGYA_API_KEY="$(curl -sL "$TF1_DIRECT_URL" | grep -oP '(?<=gigya":{"apiKey":")[^",]+')"
# URL GraphQL pour obtenir la liste des chaînes
GRAPHQL_URL="https://www.tf1.fr/graphql/web"
# Fonction d'authentification
login() {
local username="$1"
local password="$2"
# Authentification avec TF1 en utilisant le proxy
res=$(curl -sL -X POST "$AUTH_URL" -d "loginID=$username&password=$password&APIKey=$GIGYA_API_KEY&includeUserInfo=true" -H "Referer: $TF1_DIRECT_URL" -A "$USER_AGENT" --compressed)
# Si l'authentification réussit, obtenir le token Gigya
if [ "$(echo "$res" | jq -r '.statusCode')" == "200" ]; then
uid=$(echo "$res" | jq -r '.userInfo.UID')
signature=$(echo "$res" | jq -r '.userInfo.UIDSignature')
timestamp=$(echo "$res" | jq -r '.userInfo.signatureTimestamp')
session_res=$(curl -sL -X POST "$SESSION_URL" -d "{\"uid\": \"$uid\", \"signature\": \"$signature\", \"timestamp\": $timestamp, \"consent_ids\": [\"1\", \"2\", \"3\", \"4\", \"10001\", \"10003\", \"10005\", \"10007\", \"10013\", \"10015\", \"10017\", \"10019\", \"10009\", \"10011\", \"13002\", \"13001\", \"10004\", \"10014\", \"10016\", \"10018\", \"10020\", \"10010\", \"10012\", \"10006\", \"10008\"]}" --compressed)
if [ "$(echo "$session_res" | jq -r '.right')" == "BASIC" ]; then
user_token=$(echo "$session_res" | jq -r '.token')
return 0 # Authentification réussie
else
return 1 # Échec de l'authentification
fi
else
return 1 # Échec de l'authentification
fi
}
# Fonction pour encoder la requête JSON dans l'URL
json_encode() {
echo -n "$1" | jq -s -R -r @uri
}
# Fonction pour obtenir la liste des chaînes avec certains détails
get_channel_list() {
# Identifiant GraphQL, sujet à modification
GRAPHQL_ID="ecf53113697d74c6a7771ad8ed018b5a22ae7a06"
# Requête GraphQL
graphql_query=$(json_encode '{"ofChannelTypes":["DIGITAL","TV","EVENT"],"limit":500}')
encoded_url="$GRAPHQL_URL?id=${GRAPHQL_ID}&variables=$graphql_query"
# Utiliser curl avec l'URL encodée et le proxy
response=$(curl -sL --globoff "$encoded_url" --compressed)
# Analyse de la réponse JSON et formatage en CSV
channel_list=$(echo "$response" | jq -r '.data.lives.items[] | [.channel.live.streamId, .channel.slug, .channel.thematic.slug, .channel.thematic.label, .channel.id, .channel.type, .channel.decoration.logo.sourcesWithScales[0].url, .channel.label] | @csv' | sed 's/null//g')
# echo "streamId, slug, label, thematic_slug, thematic_label, id, type, logo"
echo "$channel_list"
}
# Fonction pour obtenir les URLs HLS
function get_hls_urls() {
# URL de l'API de TF1
URL_API="https://mediainfo.tf1.fr/mediainfocombo"
CHANNELID="$1"
# echo "Authentification réussie"
if [ -n "$CHANNELID" ]; then
URL_API="${URL_API}/${CHANNELID}"
API_RESPONSE=$(curl -s "${URL_API}?pver=5015000&format=hls" -A "$USER_AGENT" --header "authorization: Bearer $user_token" --compressed)
# Analyser la réponse JSON
status_code=$(echo "$API_RESPONSE" | jq -r '.delivery.code')
if [ "$status_code" == "200" ]; then
# Extraction de l'URL du flux HLS
hls_url=$(echo "$API_RESPONSE" | jq -r '.delivery.url')
# Si l'URL se termine par hls-sd.m3u8, changer pour hls-hd.m3u8
if [[ $hls_url == *hls-sd.m3u8 ]]; then
hls_url="${hls_url/hls-sd.m3u8/hls-hd.m3u8}"
fi
echo "$hls_url"
else
error_message=$(echo "$API_RESPONSE" | jq -r '.delivery.code')
echo "Erreur API : $error_message"
fi
else
echo "Chaîne non trouvée dans la liste."
fi
}
# Fonction pour construire la playlist
function build_playlist() {
group_option="$1"
# Obtenir la liste des chaînes
CHANNELS_LIST=$(get_channel_list)
# Authentification
if login "$USERNAME" "$PASSWORD"; then
# echo "$user_token"
# Analyser la sortie CSV
while IFS="," read -r streamId slug thematic_slug thematic_label id type logo label; do
CHANNELID="$(echo "$streamId" | tr -d \")"
name="$label"
clean_name="$(echo "$name" | tr -d \, | tr -d \")"
if [[ "$group_option" == "thematic" ]]; then
m3u_group_name="$thematic_label"
else
m3u_group_name="$group_name"
fi
echo "#EXTINF:-1 tvg-name=\"$clean_name\" tvg-logo=$logo group-title=${m3u_group_name},$clean_name"
get_hls_urls "$CHANNELID"
done <<<"$CHANNELS_LIST"
else
echo "Échec de l'authentification. Vérifiez votre nom d'utilisateur et votre mot de passe."
fi
}
build_playlist
Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail !
Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, est-ce possible d'avoir le script en python s'il vous plaît ?
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail ! Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, est-ce possible d'avoir le script en python s'il vous plaît ?
Je vais te le convertir.
import requests
import json
import urllib.parse
# Informations d'authentification
USERNAME = "fauxcompte@yopmail.com"
PASSWORD = "password12345"
USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like MacOS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
group_name = "TF1 Plus"
# URL et clés d'API
TF1_DIRECT_URL = "https://www.tf1.fr/direct"
AUTH_URL = "https://compte.tf1.fr/accounts.login"
SESSION_URL = "https://www.tf1.fr/token/gigya/web"
GIGYA_API_KEY = requests.get(TF1_DIRECT_URL).text.split('gigya":{"apiKey":"')[1].split('"')[0]
GRAPHQL_URL = "https://www.tf1.fr/graphql/web"
GRAPHQL_ID = "ecf53113697d74c6a7771ad8ed018b5a22ae7a06"
def login(username, password):
payload = {
"loginID": username,
"password": password,
"APIKey": GIGYA_API_KEY,
"includeUserInfo": "true"
}
headers = {
"Referer": TF1_DIRECT_URL,
"User-Agent": USER_AGENT
}
res = requests.post(AUTH_URL, data=payload, headers=headers)
res_json = res.json()
if res_json.get('statusCode') == 200:
uid = res_json['userInfo']['UID']
signature = res_json['userInfo']['UIDSignature']
timestamp = res_json['userInfo']['signatureTimestamp']
session_payload = {
"uid": uid,
"signature": signature,
"timestamp": timestamp,
"consent_ids": ["1", "2", "3", "4", "10001", "10003", "10005", "10007", "10013", "10015", "10017", "10019", "10009", "10011", "13002", "13001", "10004", "10014", "10016", "10018", "10020", "10010", "10012", "10006", "10008"]
}
session_res = requests.post(SESSION_URL, json=session_payload)
session_res_json = session_res.json()
if session_res_json.get('right') == "BASIC":
user_token = session_res_json['token']
return user_token
return None
def json_encode(data):
return urllib.parse.quote(json.dumps(data))
def get_channel_list():
graphql_query = json_encode({"ofChannelTypes": ["DIGITAL", "TV", "EVENT"], "limit": 500})
encoded_url = f"{GRAPHQL_URL}?id={GRAPHQL_ID}&variables={graphql_query}"
response = requests.get(encoded_url)
channel_list = response.json()['data']['lives']['items']
return [
(
item['channel']['live']['streamId'],
item['channel']['slug'],
item['channel']['thematic']['slug'],
item['channel']['thematic']['label'],
item['channel']['id'],
item['channel']['type'],
item['channel']['decoration']['logo']['sourcesWithScales'][0]['url'],
item['channel']['label']
) for item in channel_list
]
def get_hls_urls(channel_id, user_token):
URL_API = f"https://mediainfo.tf1.fr/mediainfocombo/{channel_id}?pver=5015000&format=hls"
headers = {
"User-Agent": USER_AGENT,
"authorization": f"Bearer {user_token}"
}
api_response = requests.get(URL_API, headers=headers)
api_response_json = api_response.json()
if api_response_json.get('delivery', {}).get('code') == "200":
hls_url = api_response_json['delivery']['url']
if hls_url.endswith("hls-sd.m3u8"):
hls_url = hls_url.replace("hls-sd.m3u8", "hls-hd.m3u8")
return hls_url
return None
def build_playlist(group_option="thematic"):
user_token = login(USERNAME, PASSWORD)
if not user_token:
print("Échec de l'authentification. Vérifiez votre nom d'utilisateur et votre mot de passe.")
return
channel_list = get_channel_list()
for stream_id, slug, thematic_slug, thematic_label, id_, type_, logo, label in channel_list:
channel_id = stream_id.strip('"')
clean_name = label.replace(',', '').replace('"', '')
if group_option == "thematic":
m3u_group_name = thematic_label
else:
m3u_group_name = group_name
print(f'#EXTINF:-1 tvg-name="{clean_name}" tvg-logo={logo} group-title={m3u_group_name},{clean_name}')
hls_url = get_hls_urls(channel_id, user_token)
if hls_url:
print(hls_url)
else:
print("Chaîne non trouvée dans la liste.")
if __name__ == "__main__":
build_playlist()
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail ! Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, est-ce possible d'avoir le script en python s'il vous plaît ?
Je vais te le convertir.
Merci Azgar ! Je suis entrain de tester le script avec un autre compte temporaire, car celui-ci a été bloqué. Pour moi, je n'ai pas de lien dans la playlist donc j'ai debug pour voir ce qui n'allait pas. Le script arrive bien à tout avoir, mais il n'arrive pas à le mettre dans la playlist. J'essaye de trouver un moyen pour régler ce problème.
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail ! Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, est-ce possible d'avoir le script en python s'il vous plaît ?
Je vais te le convertir.
Merci Azgar ! Je suis entrain de tester le script avec un autre compte temporaire, car celui-ci a été bloqué. Pour moi, je n'ai pas de lien dans la playlist donc j'ai debug pour voir ce qui n'allait pas. Le script arrive bien à tout avoir, mais il n'arrive pas à le mettre dans la playlist. J'essaye de trouver un moyen pour régler ce problème.
Attention, sur les workflows cela ne fonctionne pas comme ça, il faut passer par un vpn... Oui c'est con mais j'ai perdu plus de 8h avant de tilter "merde... Github c'est américain !" ...
Bonjour, c'est le docteur Bash ! À prendre 6 fois par jour en alternant les comptes yopmail ! Bon, c'est encore un peu expérimental mais cela fonctionne en 720p. Bonne journée.
Bonjour, est-ce possible d'avoir le script en python s'il vous plaît ?
Je vais te le convertir.
Merci Azgar ! Je suis entrain de tester le script avec un autre compte temporaire, car celui-ci a été bloqué. Pour moi, je n'ai pas de lien dans la playlist donc j'ai debug pour voir ce qui n'allait pas. Le script arrive bien à tout avoir, mais il n'arrive pas à le mettre dans la playlist. J'essaye de trouver un moyen pour régler ce problème.
Attention, sur les workflows cela ne fonctionne pas comme ça, il faut passer par un vpn... Oui c'est con mais j'ai perdu plus de 8h avant de tilter "merde... Github c'est américain !" ...
Je n'essayais pas sur un workflow, mais merci pour l'info ! Donc la on a un autre problème...
À chaque problème sa solution... Solution bretonne à tester :
Par contre je n'ai jamais essayé, je me sert de mon smartphone avec termux pour renouveler les URL toutes les 4h. Les connexions 4/5G ont une IP dynamique si on redémarre la connexion (activer /désactiver dans les paramètres de la sim) donc difficile de Blacklister les IP de SFR/free/orange.
Autre chose concernant le script, enfin plutôt l'API de TF1, c'est une merde pas croyable, il suffit d'oublier d'activer 1 cookie (1008 par exemple) pour vous donner la sensation que le compte est bloqué.
Comme il faut envoyer les requêtes en json (nique la logique... ) c'est un enfer à scripter correctement, une virgule oublié et hop, pas de réponse ou un beau 403 dans ta tronche...
Si cela peut vous aider, regardez du côté de https://github.com/Catch-up-TV-and-More/plugin.video.catchuptvandmore , en fouillant dans les modules vous trouverez votre bonheur.
Quand au vpn, il est possible de mettre un VPN sur un workflow si c'est le but.
Bon, c'est un peu des conseils basique mais j'ai bloqué réellement 8h à cause de tout ça donc je partage. 😉
Courage.
À chaque problème sa solution... Solution bretonne à tester :
Par contre je n'ai jamais essayé, je me sert de mon smartphone avec termux pour renouveler les URL toutes les 4h. Les connexions 4/5G ont une IP dynamique si on redémarre la connexion (activer /désactiver dans les paramètres de la sim) donc difficile de Blacklister les IP de SFR/free/orange.
Autre chose concernant le script, enfin plutôt l'API de TF1, c'est une merde pas croyable, il suffit d'oublier d'activer 1 cookie (1008 par exemple) pour vous donner la sensation que le compte est bloqué.
Comme il faut envoyer les requêtes en json (nique la logique... ) c'est un enfer à scripter correctement, une virgule oublié et hop, pas de réponse ou un beau 403 dans ta tronche...
Si cela peut vous aider, regardez du côté de https://github.com/Catch-up-TV-and-More/plugin.video.catchuptvandmore , en fouillant dans les modules vous trouverez votre bonheur.
Quand au vpn, il est possible de mettre un VPN sur un workflow si c'est le but.
Bon, c'est un peu des conseils basique mais j'ai bloqué réellement 8h à cause de tout ça donc je partage. 😉
Courage.
Bon, après quelques essais, j'avais abandonné, mais j'ai repris le développement du workflow (et de tout le projet au final). J'ai mis le VPN FDN et il marche très bien, j'ai mis un compte TF1 avec GitHub Secret et maintenant, j'ai un autre problème. Le script arrive bien à prendre les images de TF1 mais il n'arrive pas à avoir les liens des chaînes… J'ai essayé de voir les cookies, Tout accepté. J'ai essayé de debug et il y a marqué Permission insuffisante… Alors, j'ai essayé avec un autre compte et toujours la même erreur… Je ne comprends pas ce qu'il ne va pas.
…
Je viens de revérifier le fichier "TF1.m3u8" quand j'écris ça… Il se trouve qu'il y a des liens (pas tous), mais que le script ne les mets pas? Donc ça veut dire que ça vient du script?? Je ne comprends plus rien…
À chaque problème sa solution... Solution bretonne à tester : VPN gratuit sans inscription Par contre je n'ai jamais essayé, je me sert de mon smartphone avec termux pour renouveler les URL toutes les 4h. Les connexions 4/5G ont une IP dynamique si on redémarre la connexion (activer /désactiver dans les paramètres de la sim) donc difficile de Blacklister les IP de SFR/free/orange. Autre chose concernant le script, enfin plutôt l'API de TF1, c'est une merde pas croyable, il suffit d'oublier d'activer 1 cookie (1008 par exemple) pour vous donner la sensation que le compte est bloqué. Comme il faut envoyer les requêtes en json (nique la logique... ) c'est un enfer à scripter correctement, une virgule oublié et hop, pas de réponse ou un beau 403 dans ta tronche... Si cela peut vous aider, regardez du côté de https://github.com/Catch-up-TV-and-More/plugin.video.catchuptvandmore , en fouillant dans les modules vous trouverez votre bonheur. Quand au vpn, il est possible de mettre un VPN sur un workflow si c'est le but. Bon, c'est un peu des conseils basique mais j'ai bloqué réellement 8h à cause de tout ça donc je partage. 😉 Courage.
Bon, après quelques essais, j'avais abandonné, mais j'ai repris le développement du workflow (et de tout le projet au final). J'ai mis le VPN FDN et il marche très bien, j'ai mis un compte TF1 avec GitHub Secret et maintenant, j'ai un autre problème. Le script arrive bien à prendre les images de TF1 mais il n'arrive pas à avoir les liens des chaînes… J'ai essayé de voir les cookies, Tout accepté. J'ai essayé de debug et il y a marqué Permission insuffisante… Alors, j'ai essayé avec un autre compte et toujours la même erreur… Je ne comprends pas ce qu'il ne va pas.
…
Je viens de revérifier le fichier "TF1.m3u8" quand j'écris ça… Il se trouve qu'il y a des liens (pas tous), mais que le script ne les mets pas? Donc ça veut dire que ça vient du script?? Je ne comprends plus rien…
WOW. J'ai enfin réparé ce problème… Mais ce n'est pas avec le script d'origine. J'ai utilisé Streamlink et GitHub Secret, car j'ai découvert qu'on pouvait extraire le lien avec Streamlink... J'ai fait des tests et c'est enfin bon. Merci encore pour votre aide, car le VPN et GitHub Secret reste utile.
WOW. J'ai enfin réparé ce problème… Mais ce n'est pas avec le script d'origine. J'ai utilisé Streamlink et GitHub Secret, car j'ai découvert qu'on pouvait extraire le lien avec Streamlink... J'ai fait des tests et c'est enfin bon. Merci encore pour votre aide, car le VPN et GitHub Secret reste utile.
Au final, ce n'est PAS bon, Streamlink ne détecte plus de stream et j'arrive pas à comprendre pourquoi… J'avais fait des tests, mais là, sans aucune raison, le script ne fonctionne plus.
Deux possibilités: soit TF1 bloque le VPN, car il y a nouvelle IP à chaque fois que le workflow se lance (LCI marche étonnamment.), soit c'est vraiment Streamlink ou le script qui a un problème. (LCI utilise le même script.)
Edit: Le workflow remarche mais je laisse l'issue ouverte au cas où.
I've tried the TF1's program, and the API throws an "Permission insuffisante" error.
The only way to fetch the TF1's stream is to provide an account.