generated from halo-dev/plugin-starter
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: restructure RSS generation to support extension by other plugins
- Loading branch information
Showing
40 changed files
with
1,448 additions
and
825 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,3 +16,4 @@ jobs: | |
with: | ||
app-id: app-KhIVw | ||
skip-node-setup: true | ||
artifacts-path: 'app/build/libs' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,3 +72,4 @@ application-local.properties | |
|
||
/admin-frontend/node_modules/ | ||
/workplace/ | ||
*/workplace/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
plugins { | ||
id 'java-library' | ||
id 'maven-publish' | ||
id "io.freefair.lombok" version "8.0.0-rc2" | ||
} | ||
|
||
group = 'run.halo.feed' | ||
version = rootProject.version | ||
|
||
java { | ||
sourceCompatibility = JavaVersion.VERSION_17 | ||
targetCompatibility = JavaVersion.VERSION_17 | ||
} | ||
|
||
compileJava.options.encoding = "UTF-8" | ||
compileTestJava.options.encoding = "UTF-8" | ||
javadoc.options.encoding = "UTF-8" | ||
|
||
dependencies { | ||
api platform('run.halo.tools.platform:plugin:2.20.11-SNAPSHOT') | ||
compileOnly 'run.halo.app:api' | ||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
} | ||
|
||
publishing { | ||
publications { | ||
mavenJava(MavenPublication) { | ||
from components.java | ||
artifactId = 'api' | ||
version = project.hasProperty('version') ? project.property('version') : 'unspecified' | ||
|
||
pom { | ||
name = 'RSS' | ||
description = '为站点生成 RSS 订阅链接' | ||
url = 'https://www.halo.run/store/apps/app-KhIVw' | ||
|
||
licenses { | ||
license { | ||
name = 'GPL-3.0' | ||
url = 'https://github.com/halo-dev/plugin-feed/blob/main/LICENSE' | ||
} | ||
} | ||
|
||
developers { | ||
developer { | ||
id = 'guqing' | ||
name = 'guqing' | ||
email = '[email protected]' | ||
} | ||
} | ||
|
||
scm { | ||
connection = 'scm:git:[email protected]:halo-dev/plugin-feed.git' | ||
developerConnection = 'scm:git:[email protected]:halo-dev/plugin-feed.git' | ||
url = 'https://github.com/halo-dev/plugin-feed' | ||
} | ||
} | ||
} | ||
} | ||
repositories { | ||
maven { | ||
url = version.endsWith('-SNAPSHOT') ? 'https://s01.oss.sonatype.org/content/repositories/snapshots/' : | ||
'https://s01.oss.sonatype.org/content/repositories/releases/' | ||
credentials { | ||
username = project.findProperty("ossr.user") ?: System.getenv("OSSR_USERNAME") | ||
password = project.findProperty("ossr.password") ?: System.getenv("OSSR_PASSWORD") | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package run.halo.feed; | ||
|
||
import org.springframework.util.Assert; | ||
|
||
public record CacheClearRule(Type type, String value) { | ||
public CacheClearRule { | ||
Assert.notNull(type, "Type cannot be null"); | ||
Assert.notNull(value, "Value cannot be null"); | ||
if (type == Type.EXACT && !value.startsWith("/")) { | ||
throw new IllegalArgumentException("Exact value must start with /"); | ||
} | ||
} | ||
|
||
public static CacheClearRule forPrefix(String prefix) { | ||
return new CacheClearRule(Type.PREFIX, prefix); | ||
} | ||
|
||
public static CacheClearRule forExact(String exact) { | ||
return new CacheClearRule(Type.EXACT, exact); | ||
} | ||
|
||
public static CacheClearRule forContains(String contains) { | ||
return new CacheClearRule(Type.CONTAINS, contains); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "CacheClearRule{" + | ||
"type=" + type + | ||
", value='" + value + '\'' + | ||
'}'; | ||
} | ||
|
||
public enum Type { | ||
PREFIX, | ||
EXACT, | ||
CONTAINS | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package run.halo.feed; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import java.time.Instant; | ||
import java.util.List; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.Singular; | ||
|
||
@Data | ||
@Builder | ||
public class RSS2 { | ||
/** | ||
* (Recommended) The name of the feed, which should be plain text only | ||
*/ | ||
@NotBlank | ||
private String title; | ||
|
||
/** | ||
* (Recommended) The URL of the website associated with the feed, which should link to a | ||
* human-readable website | ||
*/ | ||
@NotBlank | ||
private String link; | ||
|
||
/** | ||
* (Optional) The summary of the feed, which should be plain text only | ||
*/ | ||
private String description; | ||
|
||
/** | ||
* The primary language of the feed, which should be a value from | ||
* <a href="https://www.rssboard.org/rss-language-codes">RSS Language Codes</a> or ISO | ||
* 639 language codes | ||
*/ | ||
private String language; | ||
|
||
/** | ||
* (Recommended) The URL of the image that represents the channel, which should be relatively | ||
* large and square | ||
*/ | ||
private String image; | ||
|
||
@Singular | ||
private List<Item> items; | ||
|
||
@Data | ||
@Builder | ||
public static class Item { | ||
/** | ||
* (Required) The title of the item, which should be plain text only | ||
*/ | ||
@NotBlank | ||
private String title; | ||
|
||
/** | ||
* (Recommended) The URL of the item, which should link to a human-readable website | ||
*/ | ||
@NotBlank | ||
private String link; | ||
|
||
/** | ||
* <p>(Recommended) The content of the item. For an Atom feed, it's the atom:content | ||
* element.</p> | ||
* <p>For a JSON feed, it's the content_html field.</p> | ||
*/ | ||
@NotBlank | ||
private String description; | ||
|
||
/** | ||
* (Optional) The author of the item | ||
*/ | ||
private String author; | ||
|
||
/** | ||
* (Optional) The category of the item. You can use a plain string or an array of strings | ||
*/ | ||
@Singular | ||
private List<String> categories; | ||
|
||
/** | ||
* (Recommended) The publication | ||
* <a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date">date </a> of the item, which should be a Date object | ||
* following <a href="https://docs.rsshub.app/joinus/advanced/pub-date">the standard</a> | ||
*/ | ||
private Instant pubDate; | ||
|
||
/** | ||
* (Optional) The unique identifier of the item | ||
*/ | ||
private String guid; | ||
|
||
/** | ||
* (Optional) The URL of an enclosure associated with the item | ||
*/ | ||
private String enclosureUrl; | ||
|
||
/** | ||
* (Optional) The size of the enclosure file in byte, which should be a number | ||
*/ | ||
private String enclosureLength; | ||
|
||
/** | ||
* (Optional) The MIME type of the enclosure file, which should be a string | ||
*/ | ||
private String enclosureType; | ||
|
||
/** | ||
* (Optional) Media content, represented by the <media:content> element. | ||
*/ | ||
@Singular | ||
private List<MediaContent> mediaContents; | ||
} | ||
|
||
@Data | ||
@Builder | ||
public static class MediaContent { | ||
/** | ||
* URL of the media object. | ||
*/ | ||
private String url; | ||
|
||
/** | ||
* Type of the media, such as "image/jpeg", "audio/mpeg", "video/mp4". | ||
*/ | ||
private String type; | ||
|
||
/** | ||
* The general type of media: image, audio, video. | ||
*/ | ||
private MediaType mediaType; | ||
|
||
/** | ||
* File size of the media object in bytes. | ||
*/ | ||
private String fileSize; | ||
|
||
/** | ||
* Duration of the media object in seconds (for audio and video). | ||
*/ | ||
private String duration; | ||
|
||
/** | ||
* Height of the media object in pixels (for image and video). | ||
*/ | ||
private String height; | ||
|
||
/** | ||
* Width of the media object in pixels (for image and video). | ||
*/ | ||
private String width; | ||
|
||
/** | ||
* Bitrate of the media (for audio and video). | ||
*/ | ||
private String bitrate; | ||
|
||
/** | ||
* Thumbnail associated with this media content. | ||
*/ | ||
private MediaThumbnail thumbnail; | ||
|
||
public enum MediaType { | ||
IMAGE, AUDIO, VIDEO, DOCUMENT | ||
} | ||
} | ||
|
||
@Data | ||
@Builder | ||
public static class MediaThumbnail { | ||
/** | ||
* URL of the thumbnail. | ||
*/ | ||
private String url; | ||
|
||
/** | ||
* Height of the thumbnail in pixels. | ||
*/ | ||
private String height; | ||
|
||
/** | ||
* Width of the thumbnail in pixels. | ||
*/ | ||
private String width; | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
api/src/main/java/run/halo/feed/RssCacheClearRequested.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package run.halo.feed; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lombok.Getter; | ||
import org.springframework.context.ApplicationEvent; | ||
import run.halo.app.plugin.SharedEvent; | ||
|
||
/** | ||
* Represents an event to request the clearing of RSS cache with flexible rules. | ||
* This event allows specifying multiple strategies for cache invalidation, including | ||
* prefix matching, exact route matching, and keyword containment. | ||
* | ||
* <p>Attributes:</p> | ||
* <ul> | ||
* <li>rules (required, List): | ||
* A list of rules defining the cache clearing strategy. Each rule includes: | ||
* <ul> | ||
* <li>type (required, String): The type of matching rule. Supported values are: | ||
* <ul> | ||
* <li>prefix: Matches cache entries with keys that start with the specified prefix.</li> | ||
* <li>exact: Matches cache entries with keys that exactly match the specified value.</li> | ||
* <li>contains: Matches cache entries with keys that contain the specified substring | ||
* .</li> | ||
* </ul> | ||
* </li> | ||
* <li>value (required, String): The matching value for the rule. | ||
* <ul> | ||
* <li>For type "prefix", the value is the prefix path (e.g., "/feed/").</li> | ||
* <li>For type "exact", the value is the exact route (e.g., "/feed/moments/rss.xml") | ||
* .</li> | ||
* <li>For type "contains", the value is a substring to search for (e.g., "moments").</li> | ||
* </ul> | ||
* </li> | ||
* </ul> | ||
* </li> | ||
* <li>applyToAll (optional, boolean, default: false): | ||
* Indicates whether to clear all cache entries. If true, all rules in the "rules" list are | ||
* ignored, | ||
* and the entire cache is cleared.</li> | ||
* </ul> | ||
*/ | ||
@SharedEvent | ||
@Getter | ||
public class RssCacheClearRequested extends ApplicationEvent { | ||
private final List<CacheClearRule> rules; | ||
private final boolean applyToAll; | ||
|
||
public RssCacheClearRequested(Object source, List<CacheClearRule> rules, boolean applyToAll) { | ||
super(source); | ||
this.rules = (rules == null ? List.of() : new ArrayList<>(rules)); | ||
this.applyToAll = applyToAll; | ||
} | ||
|
||
public static RssCacheClearRequested forAll(Object source) { | ||
return new RssCacheClearRequested(source, null, true); | ||
} | ||
|
||
public static RssCacheClearRequested forRules(Object source, List<CacheClearRule> rules) { | ||
return new RssCacheClearRequested(source, rules, false); | ||
} | ||
|
||
public static RssCacheClearRequested forRule(Object source, CacheClearRule rule) { | ||
List<CacheClearRule> rules = new ArrayList<>(); | ||
rules.add(rule); | ||
return new RssCacheClearRequested(source, rules, false); | ||
} | ||
} |
Oops, something went wrong.