156 lines
6.4 KiB
PHP
156 lines
6.4 KiB
PHP
<?php
|
|
// WEVIA LinkedIn Posts API + collecteur
|
|
// Endpoint: /api/linkedin-posts.php
|
|
// GET ?action=list → all posts from DB
|
|
// GET ?action=sync → collecte LinkedIn + update stats
|
|
// POST ?action=add → add new post manually
|
|
|
|
header('Content-Type: application/json');
|
|
header('Access-Control-Allow-Origin: *');
|
|
|
|
$action = $_GET['action'] ?? 'list';
|
|
$pdo = new PDO("pgsql:host=127.0.0.1;dbname=wevia_db", "postgres", "");
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
// === LIST POSTS ===
|
|
if ($action === 'list') {
|
|
$posts = $pdo->query("SELECT id,post_date,title,excerpt,likes,comments,reposts,views,image,source,linkedin_url,status,auto_synced,updated_at FROM admin.linkedin_posts WHERE status='published' ORDER BY post_date DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['posts' => $posts, 'count' => count($posts), 'updated' => date('c')]);
|
|
exit;
|
|
}
|
|
|
|
// === SYNC FROM LINKEDIN ===
|
|
if ($action === 'sync') {
|
|
require_once '/opt/wevads/vault/credentials.php';
|
|
$results = ['fetched' => 0, 'updated' => 0, 'new' => 0, 'errors' => []];
|
|
|
|
// LinkedIn company page: https://www.linkedin.com/company/69533182/
|
|
// Strategy: fetch the public company page and extract post data
|
|
// LinkedIn blocks most collecteurs, so we use multiple fallback methods
|
|
|
|
// Method 1: LinkedIn public RSS/feed (if available)
|
|
$company_id = '69533182';
|
|
$company_url = "https://www.linkedin.com/company/$company_id/posts/";
|
|
|
|
// Method 2: Use a headless approach via S204
|
|
$ch = curl_init($company_url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 15,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
CURLOPT_HTTPHEADER => ['Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7'],
|
|
]);
|
|
$html = curl_exec($ch);
|
|
$hc = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$results['http_code'] = $hc;
|
|
$results['html_size'] = strlen($html ?? '');
|
|
|
|
if ($html && $hc === 200) {
|
|
// Parse LinkedIn page for post data
|
|
// LinkedIn embeds post data in JSON-LD or script tags
|
|
if (preg_match_all('/"numLikes":(\d+)/', $html, $likes_matches)) {
|
|
$results['likes_found'] = count($likes_matches[1]);
|
|
}
|
|
if (preg_match_all('/"numComments":(\d+)/', $html, $comment_matches)) {
|
|
$results['comments_found'] = count($comment_matches[1]);
|
|
}
|
|
|
|
// Try to extract post titles and stats from the page
|
|
// LinkedIn public pages have limited data without auth
|
|
$results['method'] = 'public_page';
|
|
}
|
|
|
|
// Method 3: Use Groq to analyze the page content and extract stats
|
|
if ($html && strlen($html) > 1000) {
|
|
// Extract visible text
|
|
$text = strip_tags($html);
|
|
$text = preg_replace('/\s+/', ' ', $text);
|
|
$text = mb_substr($text, 0, 3000);
|
|
|
|
$ch2 = curl_init('https://api.groq.com/openai/v1/chat/completions');
|
|
curl_setopt_array($ch2, [
|
|
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . GROQ_KEY, 'Content-Type: application/json'],
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'llama-3.1-8b-instant',
|
|
'messages' => [
|
|
['role' => 'system', 'content' => 'Extract LinkedIn post stats from this page. Return JSON array: [{"title":"...","likes":N,"comments":N,"views":N}]. If no data found, return []'],
|
|
['role' => 'user', 'content' => $text]
|
|
],
|
|
'temperature' => 0.1,
|
|
'max_tokens' => 500,
|
|
'response_format' => ['type' => 'json_object']
|
|
]),
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 15
|
|
]);
|
|
$gr = curl_exec($ch2);
|
|
$ghc = curl_getinfo($ch2, CURLINFO_HTTP_CODE);
|
|
curl_close($ch2);
|
|
|
|
if ($ghc === 200) {
|
|
$gd = json_decode($gr, true);
|
|
$extracted = json_decode($gd['choices'][0]['message']['content'] ?? '{}', true);
|
|
$results['ai_extracted'] = $extracted;
|
|
}
|
|
}
|
|
|
|
// Update DB with any extracted stats
|
|
// For now, just bump the updated_at timestamp to track sync attempts
|
|
$pdo->exec("UPDATE admin.linkedin_posts SET updated_at = NOW() WHERE status = 'published'");
|
|
$results['db_updated'] = true;
|
|
|
|
echo json_encode($results);
|
|
exit;
|
|
}
|
|
|
|
// === ADD POST ===
|
|
if ($action === 'add' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
if (!$input || !$input['title']) { echo json_encode(['error' => 'title required']); exit; }
|
|
|
|
$ins = $pdo->prepare("INSERT INTO admin.linkedin_posts (post_date,title,excerpt,likes,comments,reposts,views,image,source,linkedin_url) VALUES (?,?,?,?,?,?,?,?,?,?) ON CONFLICT(title,post_date) DO UPDATE SET likes=EXCLUDED.likes,comments=EXCLUDED.comments,reposts=EXCLUDED.reposts,views=EXCLUDED.views,updated_at=NOW() RETURNING id");
|
|
$ins->execute([
|
|
$input['date'] ?? date('Y-m-d'),
|
|
$input['title'],
|
|
$input['excerpt'] ?? '',
|
|
$input['likes'] ?? 0,
|
|
$input['comments'] ?? 0,
|
|
$input['reposts'] ?? 0,
|
|
$input['views'] ?? 0,
|
|
$input['image'] ?? '',
|
|
$input['source'] ?? 'W',
|
|
$input['linkedin_url'] ?? ''
|
|
]);
|
|
$id = $ins->fetchColumn();
|
|
echo json_encode(['ok' => true, 'id' => $id]);
|
|
exit;
|
|
}
|
|
|
|
// === UPDATE STATS ===
|
|
if ($action === 'update' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
if (!$input || !$input['id']) { echo json_encode(['error' => 'id required']); exit; }
|
|
|
|
$sets = [];
|
|
$params = [];
|
|
foreach (['likes', 'comments', 'reposts', 'views', 'linkedin_url', 'image'] as $field) {
|
|
if (isset($input[$field])) {
|
|
$sets[] = "$field = ?";
|
|
$params[] = $input[$field];
|
|
}
|
|
}
|
|
if ($sets) {
|
|
$sets[] = "updated_at = NOW()";
|
|
$params[] = $input['id'];
|
|
$pdo->prepare("UPDATE admin.linkedin_posts SET " . implode(', ', $sets) . " WHERE id = ?")->execute($params);
|
|
}
|
|
echo json_encode(['ok' => true]);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['error' => 'unknown action', 'actions' => ['list', 'sync', 'add', 'update']]);
|