Skip to content

Instantly share code, notes, and snippets.

@g-plane
Last active October 8, 2025 13:19
Show Gist options
  • Select an option

  • Save g-plane/257bb4319ad9a4cd2580a24283674557 to your computer and use it in GitHub Desktop.

Select an option

Save g-plane/257bb4319ad9a4cd2580a24283674557 to your computer and use it in GitHub Desktop.
Filtered Anime RSS Server
黒ネズミたち
Prejudice-Studio
[Pre-S]
GM-Team
夜莺家族
YYQ字幕组
jibaketa
晚街与灯
晚街與燈
幸花壓制
yonzilch
整理搬运
云光字幕组
暗芝居
枫叶字幕组
楓葉字幕組
沸班亚马
SW字幕组
TOC
YYSUB
FSD
丸子家族
肥猫压制
FatCatRAW
风车字幕组
風車字幕組
世界遗产
SUK字幕组
H-Enc
豪盛文化
ZR0零始字幕组
今晚月色真美
package main
import (
"bufio"
"encoding/xml"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
)
type RssXml struct {
XMLName xml.Name `xml:"rss"`
Channel Channel `xml:"channel"`
}
type Channel struct {
Title string `xml:"title"`
Description string `xml:"description"`
Link string `xml:"link"`
LastBuildDate string `xml:"lastBuildDate"`
PubDate string `xml:"pubDate"`
Ttl string `xml:"ttl"`
Items []Item `xml:"item"`
}
type Item struct {
Title string `xml:"title"`
Link string `xml:"link"`
PubDate string `xml:"pubDate"`
GUID string `xml:"guid"`
Enclosure Enclosure `xml:"enclosure"`
}
type Enclosure struct {
URL string `xml:"url,attr"`
Type string `xml:"type,attr"`
Length string `xml:"length,attr"`
}
func fetchBangumi(denylist []string, w io.Writer) {
resp, err := http.Get("https://bangumi.moe/rss/latest")
if err != nil {
panic(err)
}
defer resp.Body.Close()
decoder := xml.NewDecoder(resp.Body)
var rss RssXml
err = decoder.Decode(&rss)
if err != nil {
panic(err)
}
var items []Item
for _, item := range rss.Channel.Items {
if (strings.HasPrefix(item.Title, "[") || strings.HasPrefix(item.Title, "【")) && !isDenied(item, denylist) {
items = append(items, item)
}
}
rss.Channel.Items = items
encoder := xml.NewEncoder(w)
err = encoder.Encode(rss)
if err != nil {
panic(err)
}
}
func isDenied(item Item, denylist []string) bool {
for _, deny := range denylist {
if strings.HasPrefix(deny, "#") || strings.TrimSpace(deny) == "" {
continue
}
if strings.Contains(item.Title, deny) {
return true
}
}
return false
}
func readDenylist() []string {
exe, err := os.Executable()
if err != nil {
panic(err)
}
denylistFile, err := os.ReadFile(filepath.Join(filepath.Dir(exe), "denylist.txt"))
if err != nil {
panic(err)
}
return strings.Split(string(denylistFile), "\n")
}
func main() {
lock := sync.RWMutex{}
denylist := readDenylist()
go func() {
reader := bufio.NewReader(os.Stdin)
for {
b, _ := reader.ReadByte()
switch b {
case 'q', 'Q':
os.Exit(0)
case 'r', 'R':
func() {
lock.Lock()
defer lock.Unlock()
denylist = readDenylist()
fmt.Println("Denylist reloaded")
}()
}
}
}()
http.HandleFunc("/bangumi", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Add("Content-Type", "application/xml")
lock.RLock()
defer lock.RUnlock()
fetchBangumi(denylist, w)
})
log.Fatal(http.ListenAndServe(":5000", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment