diff --git a/extension_add_support_to_live_photo.php b/extension_add_support_to_live_photo.php
new file mode 100644
index 0000000..6fc74a9
--- /dev/null
+++ b/extension_add_support_to_live_photo.php
@@ -0,0 +1,280 @@
+registerHook('entry_before_display', [self::class, 'content_modification_hook']);
+ $this->registerHook('entry_before_insert', [self::class, 'image_upload_hook']);
+ // Defaults
+ $save = false;
+ if (is_null(FreshRSS_Context::userConf()->image_cache_url)) {
+ FreshRSS_Context::userConf()->image_cache_url = self::CACHE_URL;
+ $save = true;
+ }
+ if (is_null(FreshRSS_Context::userConf()->image_cache_post_url)) {
+ FreshRSS_Context::userConf()->image_cache_post_url = self::CACHE_POST_URL;
+ $save = true;
+ }
+ if (is_null(FreshRSS_Context::userConf()->image_cache_access_token)) {
+ FreshRSS_Context::userConf()->image_cache_access_token = self::CACHE_ACCESS_TOKEN;
+ $save = true;
+ }
+ if (is_null(FreshRSS_Context::userConf()->image_cache_post_enabled)) {
+ FreshRSS_Context::userConf()->image_cache_post_enabled = self::CACHE_POST_ENABLED;
+ $save = true;
+ }
+ if ($save) {
+ FreshRSS_Context::userConf()->save();
+ }
+ }
+
+ #[\Override]
+ public function handleConfigureAction(): void
+ {
+ $this->registerTranslates();
+ if (Minz_Request::isPost()) {
+ FreshRSS_Context::userConf()->image_cache_url = Minz_Request::paramString('image_cache_url');
+ FreshRSS_Context::userConf()->image_cache_post_url = Minz_Request::paramString('image_cache_post_url');
+ FreshRSS_Context::userConf()->image_cache_access_token = Minz_Request::paramString('image_cache_access_token');
+ FreshRSS_Context::userConf()->image_cache_post_enabled = Minz_Request::paramString('image_cache_post_enabled');
+ FreshRSS_Context::userConf()->save();
+ }
+ }
+
+ public static function curlPostRequest(string $url, array $data): bool
+ {
+ $data = json_encode($data);
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($curl, CURLOPT_HEADER, true);
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array(
+ "Content-Type: application/json;charset='utf-8'",
+ 'Content-Length: ' . strlen($data),
+ "Accept: application/json")
+ );
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
+ curl_setopt($curl, CURLOPT_TIMEOUT, 10);
+ $output = curl_exec($curl);
+ curl_close($curl);
+ if ($output === false) {
+ return false;
+ }
+ return true;
+ }
+
+ public static function is_remote_url(string $url): bool
+ {
+ return strcmp(substr(strtolower($url), 0, 5), "data:") != 0;
+ }
+
+ public static function send_proactive_cache_request(string $url): bool
+ {
+ if (FreshRSS_Context::userConf()->image_cache_post_enabled && self::is_remote_url($url)) {
+ $post_url = FreshRSS_Context::userConf()->image_cache_post_url;
+ return self::curlPostRequest($post_url, array("access_token" => FreshRSS_Context::userConf()->image_cache_access_token, "url" => $url));
+ }
+ return false;
+ }
+
+ public static function getCacheImageUri(string $url): string
+ {
+ if (!self::is_remote_url($url)) {
+ return $url;
+ }
+ $url = rawurlencode($url);
+ return FreshRSS_Context::userConf()->image_cache_url . $url;
+ }
+
+ /**
+ * 仅缓存资源(发送缓存请求),不替换 URL
+ */
+ public static function cache_images(string $content): string
+ {
+ if (empty($content)) {
+ return $content;
+ }
+ $doc = new DOMDocument();
+ libxml_use_internal_errors(true);
+ $encoding = mb_detect_encoding($content);
+ $doc->loadHTML(''.$content);
+
+ // 处理
标签
+ $imgs = $doc->getElementsByTagName('img');
+ foreach ($imgs as $img) {
+ if ($img->hasAttribute('src')) {
+ self::send_proactive_cache_request($img->getAttribute('src'));
+ }
+ if ($img->hasAttribute('srcset')) {
+ preg_replace_callback('/(?:([^\s,]+)(\s*(?:\s+\d+[wx])(?:,\s*)?))/',
+ function (array $matches): string {
+ self::send_proactive_cache_request($matches[1]);
+ return '';
+ },
+ $img->getAttribute('srcset'));
+ }
+ // 处理 Live Photo
+ if ($img->hasAttribute('data-livephoto')) {
+ self::send_proactive_cache_request($img->getAttribute('data-livephoto'));
+ }
+ }
+
+ // 处理