refactor the image provider

This commit is contained in:
frederik
2025-08-16 11:41:36 +02:00
committed by Nachtzuster
parent c6cb753e25
commit ae72399c43
+152 -60
View File
@@ -188,30 +188,107 @@ function fetch_all_detections($sci_name, $sort_by, $date=null) {
return $result;
}
define('DB', './scripts/flickr.db');
class Flickr {
class ImageProvider {
protected $db = null;
protected $db_path = null;
protected $db_reset = false;
protected $context = null;
public function __construct() {
$this->set_db();
$opts = ['http' => ['header' => "User-Agent: BirdNET-Pi"]];
$this->context = stream_context_create($opts);
}
public function get_image($sci_name) {
$image = $this->get_image_from_db($sci_name);
if ($image !== false) {
$now = new DateTime();
$datetime = DateTime::createFromFormat("Y-m-d", $image['date_created']);
$interval = $now->diff($datetime);
$expire_days = rand(15, 25);
if ($interval->days > $expire_days) {
$image = false;
}
}
if ($image === false) {
$this->get_from_source($sci_name);
$image = $this->get_image_from_db($sci_name);
}
return $image;
}
public function is_reset() {
return $this->db_reset;
}
protected function get_json($url) {
return json_decode(file_get_contents($url, false, $this->context), true);
}
protected function set_db() {
try {
if ($this->db === null) {
$db = new SQLite3($this->db_path, SQLITE3_OPEN_READWRITE);
$this->db = $db;
}
} catch (Exception $ex) {
$this->create_tables();
}
$this->db->busyTimeout(1000);
}
protected function create_tables() {
$tbl_def = "CREATE TABLE images (sci_name VARCHAR(63) NOT NULL PRIMARY KEY, com_en_name VARCHAR(63) NOT NULL, image_url TEXT NOT NULL, title TEXT NOT NULL, id TEXT NOT NULL UNIQUE, author_url TEXT NOT NULL, license_url TEXT NOT NULL, date_created DATE)";
$db = new SQLite3($this->db_path);
$db->exec($tbl_def);
$db->exec('CREATE TABLE source (ID INTEGER PRIMARY KEY, email VARCHAR(63), uid VARCHAR(63), date_created DATE)');
$this->db_reset = true;
$this->db = $db;
}
protected function delete_image_from_db($sci_name) {
$statement0 = $this->db->prepare('DELETE FROM images WHERE sci_name == :sci_name');
$statement0->bindValue(':sci_name', $sci_name);
$statement0->execute();
}
protected function get_image_from_db($sci_name) {
$statement0 = $this->db->prepare('SELECT sci_name, com_en_name, image_url, title, id, author_url, license_url, date_created FROM images WHERE sci_name == :sci_name');
$statement0->bindValue(':sci_name', $sci_name);
$result = $statement0->execute();
$row = $result->fetchArray(SQLITE3_ASSOC);
return $row;
}
protected function set_image_in_db($sci_name, $com_en_name, $image_url, $title, $id, $author_url, $license_url) {
$statement0 = $this->db->prepare("INSERT OR REPLACE INTO images VALUES (:sci_name, :com_en_name, :image_url, :title, :id, :author_url, :license_url, DATE(\"now\"))");
$statement0->bindValue(':sci_name', $sci_name);
$statement0->bindValue(':com_en_name', $com_en_name);
$statement0->bindValue(':image_url', $image_url);
$statement0->bindValue(':title', $title);
$statement0->bindValue(':id', $id);
$statement0->bindValue(':author_url', $author_url);
$statement0->bindValue(':license_url', $license_url);
$statement0->execute();
}
}
class Flickr extends ImageProvider {
protected $db_path = './scripts/flickr.db';
private $flickr_api_key = null;
private $args = "&license=2%2C3%2C4%2C5%2C6%2C9&orientation=square,portrait";
private $blacklisted_ids = [];
private $db = null;
private $licenses_urls = [];
private $labels_flickr = null;
private $flickr_email = null;
private $comnameprefix = "%20bird";
public function __construct() {
$tbl_def = "CREATE TABLE images (sci_name VARCHAR(63) NOT NULL PRIMARY KEY, com_en_name VARCHAR(63) NOT NULL, image_url VARCHAR(63) NOT NULL, title VARCHAR(31) NOT NULL, id VARCHAR(31) NOT NULL UNIQUE, author_url VARCHAR(63) NOT NULL, license_url VARCHAR(63) NOT NULL, date_created DATE)";
try {
$db = new SQLite3(DB, SQLITE3_OPEN_READWRITE);
} catch (Exception $ex) {
$db = new SQLite3(DB);
$db->exec($tbl_def);
$db->exec('CREATE TABLE source (ID INTEGER PRIMARY KEY, email VARCHAR(63), uid VARCHAR(63), date_created DATE)');
}
$db->busyTimeout(1000);
$this->db = $db;
$this->set_db();
$blacklisted = get_home() . "/BirdNET-Pi/scripts/blacklisted_images.txt";
if (file_exists($blacklisted)) {
@@ -225,7 +302,8 @@ class Flickr {
$source = $this->get_uid_from_db();
if ($source['email'] !== $this->flickr_email) {
// reset the DB
$this->db->exec("DROP TABLE images; " . $tbl_def);
$this->db->exec("DROP TABLE images;");
$this->create_tables();
if (!empty($this->flickr_email)) {
$source = $this->get_uid_from_db();
if ($source['email'] !== $this->flickr_email) {
@@ -243,57 +321,24 @@ class Flickr {
}
public function get_image($sci_name) {
$image = $this->get_image_from_db($sci_name);
$image = parent::get_image_from_db($sci_name);
if ($image !== false && in_array($image['id'], $this->blacklisted_ids)) {
$image = false;
$this->delete_image_from_db($sci_name);
}
if ($image !== false) {
$now = new DateTime();
$datetime = DateTime::createFromFormat("Y-m-d", $image['date_created']);
$interval = $now->diff($datetime);
// use the last digit of the id as a semi random number, so not all entries expire at the same time
$expire_days = 15 + intval($image['id'][-1]);
if ($interval->days > $expire_days) {
$image = false;
}
}
if ($image === false) {
$this->get_from_flickr($sci_name);
$this->get_from_source($sci_name);
$image = $this->get_image_from_db($sci_name);
}
if ($image === false)
return false;
// external link to photo
$photos_url = str_replace('/people/', '/photos/', $image['author_url'] . '/' . $image['id']);
$image['photos_url'] = $photos_url;
return $image;
}
private function delete_image_from_db($sci_name) {
$statement0 = $this->db->prepare('DELETE FROM images WHERE sci_name == :sci_name');
$statement0->bindValue(':sci_name', $sci_name);
$statement0->execute();
}
private function get_image_from_db($sci_name) {
$statement0 = $this->db->prepare('SELECT sci_name, com_en_name, image_url, title, id, author_url, license_url, date_created FROM images WHERE sci_name == :sci_name');
$statement0->bindValue(':sci_name', $sci_name);
$result = $statement0->execute();
$row = $result->fetchArray(SQLITE3_ASSOC);
return $row;
}
private function set_image_in_db($sci_name, $com_en_name, $image_url, $title, $id, $author_url, $license_url) {
$statement0 = $this->db->prepare("INSERT OR REPLACE INTO images VALUES (:sci_name, :com_en_name, :image_url, :title, :id, :author_url, :license_url, DATE(\"now\"))");
$statement0->bindValue(':sci_name', $sci_name);
$statement0->bindValue(':com_en_name', $com_en_name);
$statement0->bindValue(':image_url', $image_url);
$statement0->bindValue(':title', $title);
$statement0->bindValue(':id', $id);
$statement0->bindValue(':author_url', $author_url);
$statement0->bindValue(':license_url', $license_url);
$statement0->execute();
}
private function get_from_flickr($sci_name) {
private function get_from_source($sci_name) {
$engname = get_com_en_name($sci_name);
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=" . $this->flickr_api_key . "&text=" . str_replace(" ", "%20", $engname) . $this->comnameprefix . "&sort=relevance" . $this->args . "&per_page=5&media=photos&format=json&nojsoncallback=1"), true)["photos"]["photo"];
@@ -307,11 +352,11 @@ class Flickr {
}
}
if ($photo === null) return;
if ($photo === null)
return;
$license_url = "https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&api_key=" . $this->flickr_api_key . "&photo_id=" . $photo["id"] . "&format=json&nojsoncallback=1";
$license_response = file_get_contents($license_url);
$license_id = json_decode($license_response, true)["photo"]["license"];
$license_response = $this->get_json("https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&api_key=" . $this->flickr_api_key . "&photo_id=" . $photo["id"] . "&format=json&nojsoncallback=1");
$license_id = $license_response["photo"]["license"];
$license_url = $this->get_license_url($license_id);
$authorlink = "https://flickr.com/people/" . $photo["owner"];
@@ -323,8 +368,8 @@ class Flickr {
private function get_license_url($id) {
if (empty($this->licenses_urls)) {
$licenses_url = "https://api.flickr.com/services/rest/?method=flickr.photos.licenses.getInfo&api_key=" . $this->flickr_api_key . "&format=json&nojsoncallback=1";
$licenses_response = file_get_contents($licenses_url);
$licenses_data = json_decode($licenses_response, true)["licenses"]["license"];
$licenses_response = $this->get_json($licenses_url);
$licenses_data = $licenses_response["licenses"]["license"];
foreach ($licenses_data as $license) {
$license_id = $license["id"];
$license_url = $license["url"];
@@ -354,7 +399,54 @@ class Flickr {
$uid = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.people.findByEmail&api_key=" . $this->flickr_api_key . "&find_email=" . $this->flickr_email . "&format=json&nojsoncallback=1"), true)["user"]["nsid"];
$this->set_uid_in_db($uid);
}
}
class Wikipedia extends ImageProvider {
protected $db_path = './scripts/wikipedia.db';
protected function get_from_source($sci_name) {
$title = str_replace(' ', '_', $sci_name);
$data = $this->get_json("https://en.wikipedia.org/api/rest_v1/page/summary/$title");
if ($data == false or !isset($data['originalimage']))
return;
$image_name = substr($data['originalimage']['source'], strrpos($data['originalimage']['source'], '/') + 1);
$metadata = $this->get_json("https://commons.wikimedia.org/w/api.php?action=query&titles=Image:$image_name&prop=imageinfo&iiprop=extmetadata&format=json");
if ($metadata == false or !isset($metadata['query']['pages']))
return;
foreach ($metadata['query']['pages'] as $page) {
$details = $page['imageinfo']['0']['extmetadata'];
$author = $details['Artist']['value'];
$matches = [];
if (preg_match('/href="(http\S*)"/', $author, $matches)) {
$author_url = $matches[1];
} else {
$author_url = "https://en.wikipedia.org/wiki/File:$image_name";
}
$license_url = $details['LicenseUrl']['value'];
}
$engname = get_com_en_name($sci_name);
$image_url = $data['originalimage']['source'];
$title = $data['description'];
// $sci_name, $com_en_name, $image_url, $title, $id, $author_url, $license_url
$this->set_image_in_db($sci_name, $engname, $image_url, $title, $sci_name, $author_url, $license_url);
}
public function get_image($sci_name) {
$image = parent::get_image($sci_name);
if ($image === false)
return false;
$image_name = substr($image['image_url'], strrpos($image['image_url'], '/') + 1);
// external link to photo
$photos_url = "https://en.wikipedia.org/wiki/File:$image_name";
$image['photos_url'] = $photos_url;
return $image;
}
}
function get_info_url($sciname){