Recherche des tweets de réponse avec l'API Tweeter
This commit is contained in:
557
app/Http/Controllers/APIController.php
Normal file
557
app/Http/Controllers/APIController.php
Normal file
@@ -0,0 +1,557 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Subscriber\Oauth\Oauth1;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class APIController extends Controller
|
||||
{
|
||||
protected $twitterHeaders = [
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-attest-token' => 'no_token',
|
||||
];
|
||||
|
||||
public function retweet($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => json_encode([
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true,
|
||||
]),
|
||||
"variables" => json_encode([
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"tweet_id" => $tweetid,
|
||||
"includeEditControl" => true,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
])
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('24zITFB5aD73PxYtmc6pkA/CreateRetweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function reply($user, $tweetid, $text)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => json_encode([
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true
|
||||
]),
|
||||
"variables" => json_encode([
|
||||
"nullcast" => false,
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"batch_compose" => "BatchSubsequent",
|
||||
"includeCommunityTweetRelationship" => false,
|
||||
"reply" => [
|
||||
"exclude_reply_user_ids" => [],
|
||||
"in_reply_to_tweet_id" => $tweetid,
|
||||
],
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
"tweet_text" => $text,
|
||||
]),
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('2ambiU1P_BmZ_CZ1yQ8E1Q/CreateTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function follow($user, $follow)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/1.1/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('friendships/create.json?screen_name='.$follow.'&follow=true', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth' // Assurez-vous que l'authentification OAuth est incluse
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function like($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"variables" => [
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"tweet_id" => $tweetid,
|
||||
"includeEditControl" => true
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('lI07N6Otwv1PhnEgXILM7A/FavoriteTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
}
|
||||
public function tweet($user, $text)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => [
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true
|
||||
],
|
||||
"variables" => [
|
||||
"nullcast" => false,
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"includeCommunityTweetRelationship" => false,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
"tweet_text" => $text
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('2ambiU1P_BmZ_CZ1yQ8E1Q/CreateTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function unread($user)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/2/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('badge_count/badge_count.json?supports_ntab_urt=true', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth' // Assurez-vous que l'authentification OAuth est incluse
|
||||
]);
|
||||
|
||||
|
||||
$unred = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
// L'URL des deux liens
|
||||
$url = 'https://myx.ovh/nova/resources/accounts/'.$user->id;
|
||||
|
||||
$keyboard = [
|
||||
'inline_keyboard' => [
|
||||
[
|
||||
['text' => 'Cliquez ici pour plus d\'infos', 'url' => $url]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Convertir le tableau de clavier en JSON
|
||||
$keyboardJson = json_encode($keyboard);
|
||||
|
||||
if ($unred['dm_unread_count'] > 0) {
|
||||
|
||||
$text = "Un nouveau message pour le compte ".$user->name;
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501', // Remplacez par votre chat_id
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
|
||||
|
||||
}elseif ($unred['ntab_unread_count'] > 0) {
|
||||
|
||||
$text = "Une notification pour le compte ".$user->name;
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501', // Remplacez par votre chat_id
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getweets($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
'variables' => [
|
||||
'referrer' => 'home',
|
||||
'includeTweetImpression' => true,
|
||||
'includeHasBirdwatchNotes' => false,
|
||||
'isReaderMode' => false,
|
||||
'includeEditPerspective' => false,
|
||||
'includeEditControl' => true,
|
||||
'focalTweetId' => $tweetid,
|
||||
'includeCommunityTweetRelationship' => true,
|
||||
'includeTweetVisibilityNudge' => true
|
||||
],
|
||||
'features' => [
|
||||
'longform_notetweets_inline_media_enabled' => true,
|
||||
'super_follow_badge_privacy_enabled' => true,
|
||||
'longform_notetweets_rich_text_read_enabled' => true,
|
||||
'super_follow_user_api_enabled' => true,
|
||||
'unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' => true,
|
||||
'super_follow_tweet_api_enabled' => true,
|
||||
'articles_api_enabled' => true,
|
||||
'android_graphql_skip_api_media_color_palette' => true,
|
||||
'creator_subscriptions_tweet_preview_api_enabled' => true,
|
||||
'freedom_of_speech_not_reach_fetch_enabled' => true,
|
||||
'tweetypie_unmention_optimization_enabled' => true,
|
||||
'longform_notetweets_consumption_enabled' => true,
|
||||
'subscriptions_verification_info_enabled' => true,
|
||||
'blue_business_profile_image_shape_enabled' => true,
|
||||
'tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' => true,
|
||||
'immersive_video_status_linkable_timestamps' => true,
|
||||
'super_follow_exclusive_tweet_notifications_enabled' => true
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
// Initialisation du tableau des tweets à l'extérieur de la boucle
|
||||
$tweets = [];
|
||||
|
||||
// Initialisation du curseur à null avant le début de la boucle
|
||||
$cursor = null;
|
||||
|
||||
// Nombre de tours
|
||||
$maxLoops = 10;
|
||||
|
||||
// Boucle pour exécuter 5 tours
|
||||
for ($loop = 1; $loop <= $maxLoops; $loop++) {
|
||||
// Si ce n'est pas le premier tour, ajouter le curseur dans les paramètres
|
||||
if ($loop > 1 && $cursor !== null) {
|
||||
$params['variables']['cursor'] = $cursor; // Ajouter la valeur du curseur au paramètre
|
||||
}
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('NAHO_rBo3Yf1hBXROp7Msg/ConversationTimelineV2', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
// Décoder la réponse
|
||||
$data = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
// Réinitialiser le curseur à chaque tour
|
||||
$cursor = null;
|
||||
|
||||
// Navigation dans le tableau pour extraire les données
|
||||
$instructions = $data['data']['timeline_response']['instructions'] ?? [];
|
||||
foreach ($instructions as $instruction) {
|
||||
// Vérification si l'instruction est de type 'TimelineAddEntries'
|
||||
if ($instruction['__typename'] === 'TimelineAddEntries') {
|
||||
// Parcours des entrées (entries) dans chaque instruction
|
||||
foreach ($instruction['entries'] as $entry) {
|
||||
// Vérifier si l'entrée contient un tweet
|
||||
if (isset($entry['content']['items'][0]['item']['content']['tweetResult'])) {
|
||||
// Récupérer le texte complet du tweet
|
||||
$tweets[] = $entry['content']['items'][0]['item']['content']['tweetResult']['result']['legacy']['full_text'] ?? '';
|
||||
}
|
||||
|
||||
// Vérifier si l'entrée contient un curseur, dont l'entryId commence par 'cursor-bottom'
|
||||
if (isset($entry['content']['content']['value']) && str_starts_with($entry['entryId'], 'cursor-bottom')) {
|
||||
// Récupérer la valeur du curseur
|
||||
$cursor = $entry['content']['content']['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $tweets;
|
||||
}
|
||||
|
||||
public function newstweet($user)
|
||||
{
|
||||
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
$newArray = [];
|
||||
$existingConversationIds = []; // Tableau pour suivre les IDs de conversation déjà vus
|
||||
|
||||
$search = [
|
||||
'1177177387475378177',
|
||||
'1491472590891888645',
|
||||
'1642170070351638534',
|
||||
'1533089245576970240',
|
||||
'1493931667731406848',
|
||||
'1513789977938776070',
|
||||
'1531291630040391682',
|
||||
'1741188576845455676'
|
||||
];
|
||||
|
||||
foreach ($search as $list) {
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
// Ajouter les en-têtes personnalisés
|
||||
$headers = [
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-attest-token' => 'no_token',
|
||||
];
|
||||
|
||||
$params = [
|
||||
"features" => [
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"unified_cards_ad_metadata_container_dynamic_card_content_query_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true,
|
||||
],
|
||||
"variables" => [
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"rest_id" => $list,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('LgWGBhvCVo5vHMsokMdEWA/ListTimeline', [
|
||||
'headers' => $headers, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
$data = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
$tweets = $data['data']['list']['timeline_response']['timeline']['instructions'][0]['entries'];
|
||||
|
||||
foreach ($tweets as $item) {
|
||||
if (isset($item['content']['content']['tweetResult']['result']['legacy']['retweeted_status_result'])) {
|
||||
// Tweet retweeté, ignorer
|
||||
} elseif (isset($item['content']['content']['tweetResult']['result']['legacy'])) {
|
||||
$news = $item['content']['content']['tweetResult']['result']['legacy'];
|
||||
$conversationId = $news['conversation_id_str'];
|
||||
|
||||
// Vérifier si le tweet a déjà été ajouté en fonction de l'ID de la conversation
|
||||
if (in_array($conversationId, $existingConversationIds)) {
|
||||
continue; // Si le tweet existe déjà, passer à l'itération suivante
|
||||
}
|
||||
|
||||
// Ajouter l'ID de conversation à la liste des IDs déjà vus
|
||||
$existingConversationIds[] = $conversationId;
|
||||
|
||||
// Ajouter le tweet si le nombre de réponses, de favoris ou de retweets est supérieur à 50
|
||||
if ($news['reply_count'] > 10 || $news['favorite_count'] > 10 || $news['retweet_count'] > 10) {
|
||||
$newArray[] = $news;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache::put('news', $newArray, 1800);
|
||||
|
||||
return $newArray;
|
||||
|
||||
}
|
||||
|
||||
private function Oauth1($user)
|
||||
{
|
||||
// Créer le stack pour gérer l'authentification OAuth
|
||||
$stack = HandlerStack::create();
|
||||
|
||||
$middleware = new Oauth1([
|
||||
'consumer_key' => '3nVuSoBZnx6U4vzUxf5w',
|
||||
'consumer_secret' => 'Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys',
|
||||
'token' => $user->oauth_token,
|
||||
'token_secret' => $user->oauth_token_secret
|
||||
]);
|
||||
|
||||
$stack->push($middleware);
|
||||
|
||||
return $stack;
|
||||
}
|
||||
|
||||
}
|
||||
341
app/Http/Controllers/AccountController.php
Normal file
341
app/Http/Controllers/AccountController.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\ProcessNews;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use App\Http\Controllers\APIController;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function login($id)
|
||||
{
|
||||
$user = Account::find($id);
|
||||
|
||||
$username = $user->name;
|
||||
$password = $user->password;
|
||||
$email = $user->rambler_email;
|
||||
$rambler_password = $user->rambler_password;
|
||||
|
||||
$proxy = 'http://xtjnmwvl-'.$id.':lp7iv1lq9glu@p.webshare.io:80';
|
||||
|
||||
// Clés et jetons de Twitter
|
||||
$TW_CONSUMER_KEY = '3nVuSoBZnx6U4vzUxf5w';
|
||||
$TW_CONSUMER_SECRET = 'Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys';
|
||||
$TW_ANDROID_BASIC_TOKEN = 'Basic ' . base64_encode("$TW_CONSUMER_KEY:$TW_CONSUMER_SECRET");
|
||||
|
||||
// Requête pour obtenir le bearer token
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => $TW_ANDROID_BASIC_TOKEN,
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
])->asForm()->post('https://api.twitter.com/oauth2/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
]);
|
||||
|
||||
$bearerToken = collect($response->json())->implode(' ');
|
||||
|
||||
// Requête pour obtenir le guest token
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => 'https://api.twitter.com/1.1/guest/activate.json',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 0,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Authorization: ' . $bearerToken
|
||||
),
|
||||
));
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
curl_close($curl);
|
||||
$reponse = json_decode($response, true);
|
||||
$guestToken = $reponse['guest_token'];
|
||||
|
||||
// Configuration des en-têtes pour les futures requêtes
|
||||
$twitterHeaders = [
|
||||
'Authorization' => $bearerToken,
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-attest-token' => 'no_token',
|
||||
'X-Guest-Token' => $guestToken,
|
||||
];
|
||||
|
||||
// Initialisation de la session avec Laravel HTTP pour le flux de connexion
|
||||
// Étape 1 : Commencer le flux de connexion
|
||||
$task1 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json?flow_name=login&api_version=1&known_device_token=', [
|
||||
'input_flow_data' => [
|
||||
'country_code' => null,
|
||||
'flow_context' => [
|
||||
'start_location' => [
|
||||
'location' => 'deeplink',
|
||||
],
|
||||
],
|
||||
'requested_variant' => null,
|
||||
'target_user_id' => 0,
|
||||
],
|
||||
]);
|
||||
|
||||
// Stockage de l'en-tête 'att' pour les futures requêtes
|
||||
$twitterHeaders['att'] = $task1->header('att');
|
||||
|
||||
sleep(5);
|
||||
|
||||
// Étape 2 : Saisie du nom d'utilisateur
|
||||
$task2 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task1->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $username,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterUserIdentifier',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
sleep(5);
|
||||
|
||||
if ($task2->json()['subtasks'][0]['subtask_id'] === 'LoginEnterAlternateIdentifierSubtask') {
|
||||
$task2bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task2->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $email,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterAlternateIdentifierSubtask',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$task2 = $task2bis;
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
|
||||
// Étape 3 : Saisie du mot de passe
|
||||
$task3 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task2->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_password' => [
|
||||
'password' => $password,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterPassword',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
if ($task3->json()['subtasks'][0]['subtask_id'] === 'LoginAcid') {
|
||||
sleep(5);
|
||||
if(isset($task3->json()['subtasks'][0]['enter_text']['hint_text'])){
|
||||
$code = $this->getCodeFromLastEmail($email, $rambler_password);
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $code,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginAcid',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}else{
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $email,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginAcid',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
$task3 = $task3bis;
|
||||
}
|
||||
|
||||
if($task3->json()['subtasks'][0]['subtask_id'] === 'LoginEnterOtp'){
|
||||
$code = $this->getCodeFromLastEmail($email, $rambler_password);
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $code,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterOtp',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$task3 = $task3bis;
|
||||
}
|
||||
|
||||
if($task3->json()['subtasks']['0']['subtask_id'] == 'LoginSuccessSubtask' ){
|
||||
$user->update([
|
||||
'oauth_token' => $task3->json()['subtasks']['0']['open_account']['oauth_token'],
|
||||
'oauth_token_secret' => $task3->json()['subtasks']['0']['open_account']['oauth_token_secret'],
|
||||
'known_device_token' => $task3->json()['subtasks']['0']['open_account']['known_device_token'],
|
||||
'enable' => true,
|
||||
]);
|
||||
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private function getCodeFromLastEmail($email, $password)
|
||||
{
|
||||
// Attendre 15 secondes avant de vérifier les emails
|
||||
sleep(15);
|
||||
|
||||
// Configurer le client IMAP de manière dynamique
|
||||
$clientManager = new ClientManager();
|
||||
|
||||
$client = $clientManager->make([
|
||||
'host' => 'imap.rambler.ru',
|
||||
'port' => '993',
|
||||
'encryption' => 'ssl',
|
||||
'validate_cert' => true,
|
||||
'username' => $email,
|
||||
'password' => $password,
|
||||
'protocol' => 'imap'
|
||||
]);
|
||||
|
||||
// Se connecter au compte
|
||||
$client->connect();
|
||||
|
||||
// Sélectionner la boîte de réception
|
||||
$folder = $client->getFolder('INBOX');
|
||||
|
||||
// Récupérer le dernier email de l'expéditeur "verify@x.com"
|
||||
$messages = $folder->messages()->all()->get();
|
||||
$count = count($messages);
|
||||
$message = $messages[$count - 1];
|
||||
|
||||
if ($message) {
|
||||
// Vérifier le titre de l'email
|
||||
$subject = $message->getSubject();
|
||||
|
||||
// Chercher le code dans le sujet
|
||||
if (preg_match('/Your X confirmation code is (\w+)/', $subject, $matches)) {
|
||||
return $matches[1]; // Retourner le code trouvé dans le titre
|
||||
}
|
||||
|
||||
// Si aucun code trouvé dans le sujet, vérifier le corps du mail
|
||||
$body = $message->getTextBody();
|
||||
if (preg_match('/\b(\d{6})\b/', $body, $matches)) {
|
||||
return $matches[1]; // Retourner le code trouvé dans le corps
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function tweetnews()
|
||||
{
|
||||
// Vérifier si la queue est vide (en fonction de votre driver)
|
||||
$queue = Queue::getDefaultDriver(); // Par défaut, c'est 'default'
|
||||
|
||||
$jobsCount = Queue::size($queue);
|
||||
|
||||
if ($jobsCount === 0) {
|
||||
|
||||
$accounts = Account::where('enable', true)->get();
|
||||
|
||||
foreach($accounts as $user){
|
||||
|
||||
$API = new APIController();
|
||||
|
||||
//On check les notifs
|
||||
$API->unread($user);
|
||||
|
||||
if (Cache::has('news')) {
|
||||
$news = Cache::get('news');
|
||||
}else{
|
||||
$news = $API->newstweet($user);
|
||||
}
|
||||
|
||||
shuffle($news);
|
||||
|
||||
$nb = rand(1,3);
|
||||
|
||||
if (count($news) >= $nb) {
|
||||
$selectedArticles = array_slice($news, 0, $nb);
|
||||
|
||||
foreach ($selectedArticles as $article) {
|
||||
|
||||
$tweetid = $article['conversation_id_str'];
|
||||
$API->retweet($user, $tweetid);
|
||||
sleep(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
function auto($contestId)
|
||||
{
|
||||
$contest = Contest::find($contestId);
|
||||
|
||||
if (!$contest) {
|
||||
session()->flash('error', 'Concours introuvable.');
|
||||
return;
|
||||
}
|
||||
|
||||
flash()->success('Concours ' . $contest->name . ' en cours de participation');
|
||||
|
||||
// Récupération des comptes activés
|
||||
$accounts = Account::where('enable', true)->get();
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
ProcessTweet::dispatch($contest->id, $account->id); // Envoi du tweet pour participer
|
||||
}
|
||||
|
||||
// Mise à jour du concours pour indiquer qu'il a été participé
|
||||
$contest->participated = true;
|
||||
$contest->save();
|
||||
|
||||
// Recharger les concours
|
||||
$this->resetPage(); // Reset pagination to the first page
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/BotController.php
Normal file
118
app/Http/Controllers/BotController.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\TwitterController;
|
||||
use App\Models\Account;
|
||||
use App\Models\Block;
|
||||
use App\Models\Concour;
|
||||
use App\Models\Contest;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Illuminate\Http\Request;
|
||||
use Throwable;
|
||||
|
||||
class BotController extends Controller
|
||||
{
|
||||
|
||||
public function getSpecialComment($user,$id){
|
||||
|
||||
$user = Account::find($user);
|
||||
|
||||
$API = new APIController();
|
||||
|
||||
// On check les notifs
|
||||
$texts = $API->getweets($user, $id);
|
||||
|
||||
// Filtrer les phrases vides
|
||||
$texts = array_filter($texts, function($phrase) {
|
||||
return !empty(trim($phrase)); // Ignore les chaînes vides ou contenant uniquement des espaces
|
||||
});
|
||||
|
||||
// Initialiser un tableau pour stocker les occurrences des phrases
|
||||
$occurrences = [];
|
||||
|
||||
foreach ($texts as $index1 => $phrase1) {
|
||||
foreach ($texts as $index2 => $phrase2) {
|
||||
if ($index1 !== $index2) {
|
||||
$similarity = $this->cosineSimilarity($phrase1, $phrase2);
|
||||
// Vous pouvez ajuster le seuil de similarité en fonction de vos besoins
|
||||
if ($similarity > 0.5) {
|
||||
// Incrémenter le compteur pour les deux phrases
|
||||
$occurrences[$index1] = isset($occurrences[$index1]) ? $occurrences[$index1] + 1 : 1;
|
||||
$occurrences[$index2] = isset($occurrences[$index2]) ? $occurrences[$index2] + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trouver l'index de la phrase avec le comptage le plus élevé
|
||||
$indexPhrasePlusFrequente = (!empty($occurrences)) ? array_search(max($occurrences), $occurrences) : null;
|
||||
|
||||
// Récupérer la phrase avec le comptage le plus élevé
|
||||
$phrasePlusFrequente = ($indexPhrasePlusFrequente !== null) ? $texts[$indexPhrasePlusFrequente] : null;
|
||||
|
||||
if ($phrasePlusFrequente != null) {
|
||||
// Supprimer les hashtags
|
||||
$phrasePlusFrequente = preg_replace('/#\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les tags
|
||||
$phrasePlusFrequente = preg_replace('/@\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les emojis
|
||||
$phrasePlusFrequente = $this->remove_emojis($phrasePlusFrequente);
|
||||
|
||||
return $phrasePlusFrequente;
|
||||
} else {
|
||||
$tweetcomments = config('twitter.sentence_for_random_comment');
|
||||
return Arr::random($tweetcomments);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function cosineSimilarity($text1, $text2)
|
||||
{
|
||||
$words1 = str_word_count(strtolower($text1), 1);
|
||||
$words2 = str_word_count(strtolower($text2), 1);
|
||||
|
||||
$allWords = array_unique(array_merge($words1, $words2));
|
||||
$vector1 = $vector2 = [];
|
||||
|
||||
// Construire les vecteurs avec les fréquences des mots
|
||||
foreach ($allWords as $word) {
|
||||
$vector1[] = in_array($word, $words1) ? 1 : 0;
|
||||
$vector2[] = in_array($word, $words2) ? 1 : 0;
|
||||
}
|
||||
|
||||
$dotProduct = 0;
|
||||
|
||||
// Calculer le produit scalaire des vecteurs
|
||||
for ($i = 0; $i < count($allWords); $i++) {
|
||||
$dotProduct += $vector1[$i] * $vector2[$i];
|
||||
}
|
||||
|
||||
$magnitude1 = sqrt(array_sum($vector1));
|
||||
$magnitude2 = sqrt(array_sum($vector2));
|
||||
|
||||
if ($magnitude1 * $magnitude2 == 0) {
|
||||
return 0; // Pour éviter une division par zéro
|
||||
}
|
||||
|
||||
return $dotProduct / ($magnitude1 * $magnitude2);
|
||||
}
|
||||
|
||||
private function remove_emojis($string)
|
||||
{
|
||||
// Match all emojis (including extended ones)
|
||||
$regex_emojis = '/[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}]/u';
|
||||
$clear_string = preg_replace($regex_emojis, '', $string);
|
||||
|
||||
return $clear_string;
|
||||
}
|
||||
|
||||
}
|
||||
521
app/Http/Controllers/ContestController.php
Normal file
521
app/Http/Controllers/ContestController.php
Normal file
@@ -0,0 +1,521 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Block;
|
||||
use App\Models\Contest;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
|
||||
class ContestController extends Controller
|
||||
{
|
||||
public function twitterlist()
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
|
||||
// Création des informations d'authentification
|
||||
$username = 'MyX';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', 'https://nitter-myx.fly.dev/i/lists/1686126753205387264');
|
||||
|
||||
$i = 1;
|
||||
|
||||
while ($i < 50){
|
||||
$results = $crawler->filterXPath('//div[@class="timeline-item "]')->each(function ($node) {
|
||||
$id = ($node->filterXPath('//*[@class="tweet-link"]'))->attr('href');
|
||||
$created_at = ($node->filterXPath('//span[@class="tweet-date"]/a'))->attr('title');
|
||||
$text = ($node->filterXPath('//*[@class="tweet-content media-body"]'))->text();
|
||||
$screen = ($node->filterXPath('//a[@class="username"]'))->text();
|
||||
$fullname = ($node->filterXPath('//a[@class="fullname"]'))->text();
|
||||
$imageNode = $node->filterXPath('//a[@class="still-image"]');
|
||||
$nbretweet = ($node->filterXPath('//*[@class="tweet-stat"][2]'))->text();
|
||||
$nbretweet = str_replace(',', '', $nbretweet);
|
||||
$nblike = ($node->filterXPath('//*[@class="tweet-stat"][4]'))->text();
|
||||
$nblike = str_replace(',', '', $nblike);
|
||||
$nbreply = ($node->filterXPath('//*[@class="tweet-stat"][1]'))->text();
|
||||
$nbreply = str_replace(',', '', $nbreply);
|
||||
|
||||
//Modifications
|
||||
if ($imageNode->count() > 0) {
|
||||
$picture = $imageNode->attr('href');
|
||||
$picture = urldecode($picture);
|
||||
$picture = str_replace('/pic/orig/', 'https://pbs.twimg.com/', $picture);
|
||||
}else{
|
||||
$picture = null;
|
||||
}
|
||||
|
||||
$screen = str_replace('@', '', $screen);
|
||||
$id = str_replace('/'.$screen.'/status/', '', $id);
|
||||
$id = str_replace('#m', '', $id);
|
||||
|
||||
$contest = Contest::where('tweetid', $id)->first();
|
||||
$fake = Block::where('screen_name', $screen)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
if(!$contest && !$fake && $nbretweet > 100 && $containsBlacklistedWord !== true) {
|
||||
$regex_detect_rts =
|
||||
[
|
||||
"/\bRT\b/",
|
||||
"/RETWEET/i",
|
||||
"/REPUBL/i",
|
||||
"/REPOST/i",
|
||||
];
|
||||
foreach ($regex_detect_rts as $regex_detect_rt) {
|
||||
//if (strstr($string, $url)) { // mine version
|
||||
preg_match($regex_detect_rt, $text, $invites);
|
||||
if (isset($invites[0])) {
|
||||
$rt = true;
|
||||
}
|
||||
}
|
||||
|
||||
//On verifie que si RT
|
||||
if (isset($rt)) {
|
||||
$inputs = array();
|
||||
//On recherche la date de fin du concours
|
||||
$date = $this->getDate($text);
|
||||
if ($date != null) {
|
||||
$fin = $date;
|
||||
} else {
|
||||
$fin = $this->getTwitterDate($created_at);
|
||||
}
|
||||
//On recherche la date de fin du concours
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
|
||||
Contest::create([
|
||||
'name' => $fullname,
|
||||
'screen' => $screen,
|
||||
'description' => $text,
|
||||
'url' => 'https://x.com/'.$screen.'/status/'.$id,
|
||||
'picture' => $picture,
|
||||
'tweetid' => $id,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $nbretweet,
|
||||
'nblike' => $nblike,
|
||||
'nbreply' => $nbreply,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
$nextPageButton = $crawler->filterXPath('//div[@class="show-more"]/a')->link();
|
||||
$url = $nextPageButton->getUri();
|
||||
$crawler = $client->request('GET', $url);
|
||||
$i++;
|
||||
}
|
||||
|
||||
$reponse = $client->getResponse();
|
||||
var_dump($reponse);
|
||||
|
||||
echo 'Fait !';
|
||||
|
||||
}
|
||||
|
||||
public function searchcontest()
|
||||
{
|
||||
$search = [
|
||||
'giveaway',
|
||||
'#concours',
|
||||
'concours like',
|
||||
'concours rt',
|
||||
'concours follow',
|
||||
'#JeuConcours',
|
||||
'JeuConcours',
|
||||
'jeu concours',
|
||||
'offre follow gagnant',
|
||||
'concours pour gagner',
|
||||
'gagner rt',
|
||||
'Gagnez rt follow',
|
||||
'RT follow',
|
||||
'concours rt like',
|
||||
'concours rt fav',
|
||||
'RT tweet Follow',
|
||||
'concours rt follow',
|
||||
'rt follow tas',
|
||||
'rt follow tirage au sort',
|
||||
'rt follow gagner',
|
||||
'rt follow commente',
|
||||
'rt suivre concours',
|
||||
'rt suivez concours',
|
||||
'rt suivre tirage au sort',
|
||||
'rt suivre tas',
|
||||
'concours remporter',
|
||||
'remporter rt',
|
||||
'concours tas le',
|
||||
'concours résultats le rt',
|
||||
'tirage au sort concours',
|
||||
'concours résultat le rt'
|
||||
];
|
||||
|
||||
$k = array_rand($search);
|
||||
$phrase = $search[$k];
|
||||
|
||||
$date = Carbon::now()->subDays(2)->format('Y-m-d');
|
||||
|
||||
$url = 'https://nitter-myx.fly.dev/search?f=tweets&q='.urlencode('min_replies:100 '.$phrase).'&e-nativeretweets=on&e-replies=on&&since='.$date;
|
||||
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
|
||||
// Création des informations d'authentification
|
||||
$username = 'MyX';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', $url);
|
||||
|
||||
$crawler->filterXPath('//div[@class="timeline-item "]')->each(function ($node) {
|
||||
$id = ($node->filterXPath('//*[@class="tweet-link"]'))->attr('href');
|
||||
$created_at = ($node->filterXPath('//span[@class="tweet-date"]/a'))->attr('title');
|
||||
$text = ($node->filterXPath('//*[@class="tweet-content media-body"]'))->text();
|
||||
$screen = ($node->filterXPath('//a[@class="username"]'))->text();
|
||||
$fullname = ($node->filterXPath('//a[@class="fullname"]'))->text();
|
||||
$imageNode = $node->filterXPath('//a[@class="still-image"]');
|
||||
$nbretweet = ($node->filterXPath('//*[@class="tweet-stat"][2]'))->text();
|
||||
$nbretweet = str_replace(',', '', $nbretweet);
|
||||
$nblike = ($node->filterXPath('//*[@class="tweet-stat"][4]'))->text();
|
||||
$nblike = str_replace(',', '', $nblike);
|
||||
$nbreply = ($node->filterXPath('//*[@class="tweet-stat"][1]'))->text();
|
||||
$nbreply = str_replace(',', '', $nbreply);
|
||||
|
||||
//Modifications
|
||||
if ($imageNode->count() > 0) {
|
||||
$picture = $imageNode->attr('href');
|
||||
$picture = urldecode($picture);
|
||||
$picture = str_replace('/pic/orig/', 'https://pbs.twimg.com/', $picture);
|
||||
} else {
|
||||
$picture = null;
|
||||
}
|
||||
|
||||
$screen = str_replace('@', '', $screen);
|
||||
$id = str_replace('/' . $screen . '/status/', '', $id);
|
||||
$id = str_replace('#m', '', $id);
|
||||
|
||||
$contest = Contest::where('tweetid', $id)->first();
|
||||
$fake = Block::where('screen_name', $screen)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
if (!$contest && !$fake && $nbretweet > 1000 && $containsBlacklistedWord !== true) {
|
||||
|
||||
$regex_detect_rts =
|
||||
[
|
||||
"/\bRT\b/",
|
||||
"/RETWEET/i",
|
||||
"/REPUBL/i",
|
||||
"/REPOST/i",
|
||||
"/LIKE/i",
|
||||
"/MENTION/i",
|
||||
];
|
||||
|
||||
foreach ($regex_detect_rts as $regex_detect_rt) {
|
||||
//if (strstr($string, $url)) { // mine version
|
||||
preg_match($regex_detect_rt, $text, $invites);
|
||||
if (isset($invites[0])) {
|
||||
$rt = true;
|
||||
}
|
||||
}
|
||||
|
||||
//On verifie que si RT
|
||||
if (isset($rt)) {
|
||||
$inputs = array();
|
||||
//On recherche la date de fin du concours
|
||||
$date = $this->getDate($text);
|
||||
if ($date != null) {
|
||||
$fin = $date;
|
||||
} else {
|
||||
$fin = $this->getTwitterDate($created_at);
|
||||
}
|
||||
//On recherche la date de fin du concours
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
|
||||
Contest::create([
|
||||
'name' => $fullname,
|
||||
'screen' => $screen,
|
||||
'description' => $text,
|
||||
'url' => 'https://x.com/' . $screen . '/status/' . $id,
|
||||
'picture' => $picture,
|
||||
'tweetid' => $id,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $nbretweet,
|
||||
'nblike' => $nblike,
|
||||
'nbreply' => $nbreply,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
$reponse = $client->getResponse();
|
||||
var_dump($reponse);
|
||||
|
||||
echo 'Fait !';
|
||||
|
||||
}
|
||||
|
||||
public function import()
|
||||
{
|
||||
|
||||
$response = Http::get('https://rtandfollow.com/apibot');
|
||||
$tweets = $response->json();
|
||||
|
||||
foreach($tweets as $status) {
|
||||
|
||||
$tweetid = $status['tweetid'];
|
||||
$screen_name = $status['organizer']['screen_name'];
|
||||
$text = $status['description'];
|
||||
|
||||
$concours = Contest::where('tweetid', $tweetid)->first();
|
||||
$blocking = Block::where('screen_name', $screen_name)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
//On verifie que le concours n'est pas dans la BDD ou que l'utilisateur n'est pas bloqué
|
||||
if (empty($concours) and empty($blocking) and $containsBlacklistedWord !== true) {
|
||||
|
||||
//On recherche la date de fin du concours
|
||||
$fin = $status['fin'];
|
||||
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
Contest::create([
|
||||
'name' => $status['organizer']['name'],
|
||||
'screen' => $screen_name,
|
||||
'description' => $text,
|
||||
'url' => $status['url'],
|
||||
'picture' => '',
|
||||
'tweetid' => $tweetid,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $status['nbretweet'],
|
||||
'nblike' => $status['nblike'],
|
||||
'nbreply' => $status['nbreply'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getOrganizer($screen)
|
||||
{
|
||||
$organiser = Organizer::where('screen_name', $screen)->first();
|
||||
|
||||
if ($organiser){
|
||||
return $organiser->id;
|
||||
}else
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
// Création des informations d'authentification
|
||||
$username = 'autokdo';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', 'https://nitter-autokdo.fly.dev/'.$screen);
|
||||
try{
|
||||
$name = $crawler->filterXPath('//*[@class="profile-card-fullname"]')->text();
|
||||
$description = $crawler->filterXPath('//*[@class="profile-bio"]')->text();
|
||||
$profileUrl = $crawler->getUri();
|
||||
$parsedUrl = parse_url($profileUrl);
|
||||
$baseTwitterUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
|
||||
|
||||
|
||||
$image = $crawler->filterXPath('//meta[@property="og:image"]')->attr('content');
|
||||
$url = str_replace("http://nitter-autokdo.fly.dev/pic/", "", $image);
|
||||
$url = urldecode($url);
|
||||
$url = 'https://'.$url;
|
||||
$response = Http::get($url);
|
||||
$contents = $response->body();
|
||||
|
||||
// Utilisation de getimagesize pour obtenir les informations sur l'image
|
||||
$imageInfo = getimagesizefromstring($contents);
|
||||
|
||||
if ($imageInfo === false) {
|
||||
$filename = 'icon-96x96.png';
|
||||
}
|
||||
|
||||
$format = image_type_to_extension($imageInfo[2], false);
|
||||
$filename = uniqid() . '.' . $format;
|
||||
|
||||
// Stocker l'image dans le répertoire 'ads' du stockage
|
||||
Storage::put('/public/logo/'.$filename, $contents);
|
||||
|
||||
$organiser = Organizer::create([
|
||||
'name' => $name,
|
||||
'screen_name' => $screen,
|
||||
'description' => $description,
|
||||
'logo' => $filename,
|
||||
'url' => 'https://twitter.com/'.$screen,
|
||||
]);
|
||||
|
||||
return $organiser->id;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dd($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function getCategorie($data)
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
$client->request('GET', 'https://api.uclassify.com/v1/twittercontests/categories/classify/?readKey=c7ivTcoN2ycU&text='.$data);
|
||||
|
||||
$json = $client->getResponse()->getContent();
|
||||
|
||||
$array = json_decode($json,true);
|
||||
|
||||
$laravelArray = collect($array);
|
||||
|
||||
$laravelArray = $laravelArray->sortDesc();
|
||||
|
||||
$value = $laravelArray->first();
|
||||
|
||||
if($value < '0.5'){
|
||||
$categorie = '20';
|
||||
}
|
||||
else{
|
||||
|
||||
$cat = $laravelArray->keys()->first();
|
||||
|
||||
if($cat == 'argent'){
|
||||
$categorie = '1';
|
||||
}elseif($cat == 'beaute'){
|
||||
$categorie = '2';
|
||||
}elseif($cat == 'console'){
|
||||
$categorie = '3';
|
||||
}elseif($cat == 'cuisine'){
|
||||
$categorie = '4';
|
||||
}elseif($cat == 'dvd'){
|
||||
$categorie = '5';
|
||||
}elseif($cat == 'enfant'){
|
||||
$categorie = '6';
|
||||
}elseif($cat == 'goodies'){
|
||||
$categorie = '7';
|
||||
}elseif($cat == 'invitation'){
|
||||
$categorie = '8';
|
||||
}elseif($cat == 'livre'){
|
||||
$categorie = '9';
|
||||
}elseif($cat == 'maison'){
|
||||
$categorie = '10';
|
||||
}elseif($cat == 'mode'){
|
||||
$categorie = '11';
|
||||
}elseif($cat == 'pc'){
|
||||
$categorie = '12';
|
||||
}elseif($cat == 'sport'){
|
||||
$categorie = '13';
|
||||
}elseif($cat == 'telephone'){
|
||||
$categorie = '14';
|
||||
}elseif($cat == 'voiture'){
|
||||
$categorie = '15';
|
||||
}elseif($cat == 'voyage'){
|
||||
$categorie = '16';
|
||||
}else{
|
||||
$categorie = '20';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $categorie;
|
||||
|
||||
}
|
||||
|
||||
private function getDate($string) {
|
||||
// Pattern pour détecter les dates au format JJ/MM ou JJ.MM
|
||||
$pattern_jjmm = '/\b(\d{1,2})(\/|\.)\d{1,2}\b/';
|
||||
|
||||
// Pattern pour détecter les dates du style "1 août" (ou autre mois en français)
|
||||
$mois_fr = array(
|
||||
'janvier', 'février', 'mars', 'avril', 'mai', 'juin',
|
||||
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'
|
||||
);
|
||||
$pattern_jj_mois_fr = '/\b(\d{1,2}) (' . implode('|', $mois_fr) . ')\b/i';
|
||||
|
||||
// Stocker les correspondances dans un tableau
|
||||
$correspondances = [];
|
||||
|
||||
// Chercher les dates au format JJ/MM ou JJ.MM
|
||||
if (preg_match_all($pattern_jjmm, $string, $matches)) {
|
||||
$correspondances = array_merge($correspondances, $matches[0]);
|
||||
}
|
||||
|
||||
// Chercher les dates du style "1 août" (ou autre mois en français)
|
||||
if (preg_match_all($pattern_jj_mois_fr, $string, $matches)) {
|
||||
// Convertir le mois en format numérique (1 pour janvier, 2 pour février, etc.)
|
||||
$mois_numerique = array_flip($mois_fr);
|
||||
foreach ($matches[2] as $index => $mois) {
|
||||
$matches[0][$index] = $matches[1][$index] . '/' . str_pad($mois_numerique[strtolower($mois)] + 1, 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$correspondances = array_merge($correspondances, $matches[0]);
|
||||
}
|
||||
|
||||
// Vérifier s'il y a des dates détectées
|
||||
if (empty($correspondances)) {
|
||||
return ""; // Retourne une chaîne vide si aucune date n'est trouvée
|
||||
}
|
||||
|
||||
// Récupérer la dernière date détectée
|
||||
$derniere_date = end($correspondances);
|
||||
|
||||
// Convertir la dernière date au format "Y-m-d" (année-mois-jour)
|
||||
if (strpos($derniere_date, '/') !== false) {
|
||||
// Format JJ/MM
|
||||
list($jour, $mois) = explode('/', $derniere_date);
|
||||
$annee = date('Y');
|
||||
} elseif (strpos($derniere_date, '.') !== false) {
|
||||
// Format JJ.MM
|
||||
list($jour, $mois) = explode('.', $derniere_date);
|
||||
$annee = date('Y');
|
||||
} else {
|
||||
return ""; // Cas inattendu (ne devrait pas se produire)
|
||||
}
|
||||
|
||||
// Convertir en date avec gestion des erreurs (ex. : février 30)
|
||||
try {
|
||||
$date_convertie = date('Y-m-d', strtotime("$annee-$mois-$jour"));
|
||||
} catch (Exception $e) {
|
||||
return ""; // Retourne une chaîne vide si la conversion échoue
|
||||
}
|
||||
|
||||
return $date_convertie;
|
||||
}
|
||||
|
||||
private function getTwitterDate($text)
|
||||
{
|
||||
// Utilisez une expression régulière pour extraire toutes les dates
|
||||
$pattern = '/(\w{3} \d{1,2}, \d{4})/';
|
||||
preg_match_all($pattern, $text, $matches);
|
||||
|
||||
if (!empty($matches[1])) {
|
||||
// Récupérer la dernière date trouvée
|
||||
$lastDateString = end($matches[1]);
|
||||
|
||||
// Analyse de la date
|
||||
$date = Carbon::createFromFormat('M d, Y', $lastDateString);
|
||||
|
||||
// Obtenez la date au format Y-m-d
|
||||
$formattedDate = $date->addDays(1)->format('Y-m-d');
|
||||
|
||||
return $formattedDate;
|
||||
} else {
|
||||
// Retourne la date actuelle +1 jour si aucune date n'est trouvée
|
||||
return Carbon::now()->addDays(1)->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
}
|
||||
27
app/Http/Controllers/HomeController.php
Normal file
27
app/Http/Controllers/HomeController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contest;
|
||||
use Artesaos\SEOTools\Facades\SEOTools;
|
||||
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
SEOTools::setTitle('Liste des concours');
|
||||
|
||||
return view('index');
|
||||
}
|
||||
|
||||
public function history()
|
||||
{
|
||||
|
||||
$contests = Contest::where('participated',true)->orderby('updated_at','desc')->paginate(20);
|
||||
|
||||
SEOTools::setTitle('Mon historique');
|
||||
|
||||
return view('history', compact('contests'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user