Просмотр исходного кода

Support RSS feeds for custom searches

Fixes #45
Zed 7 лет назад
Родитель
Сommit
61991a9b56
3 измененных файлов с 69 добавлено и 37 удалено
  1. 11 0
      src/routes/rss.nim
  2. 4 2
      src/routes/search.nim
  3. 54 35
      src/views/rss.nimf

+ 11 - 0
src/routes/rss.nim

@@ -19,6 +19,17 @@ template respRss*(rss: typed) =
 
 
 proc createRssRouter*(cfg: Config) =
 proc createRssRouter*(cfg: Config) =
   router rss:
   router rss:
+    get "/search/rss":
+      if @"text".len > 200:
+        resp Http400, showError("Search input too long.", cfg.title)
+
+      let query = initQuery(params(request))
+      if query.kind != custom:
+        resp Http400, showError("Only Tweet searches are allowed for RSS feeds.", cfg.title)
+
+      let tweets = await getSearch[Tweet](query, "", getAgent())
+      respRss(renderSearchRss(tweets.content, query.text, genQueryUrl(query)))
+
     get "/@name/rss":
     get "/@name/rss":
       cond '.' notin @"name"
       cond '.' notin @"name"
       respRss(await showRss(@"name", Query()))
       respRss(await showRss(@"name", Query()))

+ 4 - 2
src/routes/search.nim

@@ -10,7 +10,7 @@ export search
 
 
 proc createSearchRouter*(cfg: Config) =
 proc createSearchRouter*(cfg: Config) =
   router search:
   router search:
-    get "/search":
+    get "/search/?":
       if @"text".len > 200:
       if @"text".len > 200:
         resp Http400, showError("Search input too long.", cfg.title)
         resp Http400, showError("Search input too long.", cfg.title)
 
 
@@ -25,7 +25,9 @@ proc createSearchRouter*(cfg: Config) =
         resp renderMain(renderUserSearch(users, prefs), request, cfg.title)
         resp renderMain(renderUserSearch(users, prefs), request, cfg.title)
       of custom:
       of custom:
         let tweets = await getSearch[Tweet](query, @"after", getAgent())
         let tweets = await getSearch[Tweet](query, @"after", getAgent())
-        resp renderMain(renderTweetSearch(tweets, prefs, getPath()), request, cfg.title)
+        let rss = "/search/rss?" & genQueryUrl(query)
+        resp renderMain(renderTweetSearch(tweets, prefs, getPath()), request,
+                        cfg.title, rss=rss)
       else:
       else:
         resp Http404, showError("Invalid search.", cfg.title)
         resp Http404, showError("Invalid search.", cfg.title)
 
 

+ 54 - 35
src/views/rss.nimf

@@ -3,6 +3,22 @@
 #import ../types, ../utils, ../formatters
 #import ../types, ../utils, ../formatters
 #const hostname {.strdefine.} = "nitter.net"
 #const hostname {.strdefine.} = "nitter.net"
 #
 #
+#proc getTitle(tweet: Tweet; prefs: Prefs): string =
+#if tweet.pinned: result = "Pinned: "
+#elif tweet.retweet.isSome: result = "RT: "
+#end if
+#result &= xmltree.escape(replaceUrl(tweet.text, prefs))
+#if result.len > 0: return
+#end if
+#if tweet.photos.len > 0:
+#  result &= "Image"
+#elif tweet.video.isSome:
+#  result &= "Video"
+#elif tweet.gif.isSome:
+#  result &= "Gif"
+#end if
+#end proc
+#
 #proc renderRssTweet(tweet: Tweet; prefs: Prefs): string =
 #proc renderRssTweet(tweet: Tweet; prefs: Prefs): string =
 #let text = linkifyText(tweet.text, prefs, rss=true)
 #let text = linkifyText(tweet.text, prefs, rss=true)
 #if tweet.quote.isSome and get(tweet.quote).available:
 #if tweet.quote.isSome and get(tweet.quote).available:
@@ -23,20 +39,22 @@
 #end if
 #end if
 #end proc
 #end proc
 #
 #
-#proc getTitle(tweet: Tweet; prefs: Prefs): string =
-#if tweet.pinned: result = "Pinned: "
-#elif tweet.retweet.isSome: result = "RT: "
-#end if
-#result &= xmltree.escape(replaceUrl(tweet.text, prefs))
-#if result.len > 0: return
-#end if
-#if tweet.photos.len > 0:
-#  result &= "Image"
-#elif tweet.video.isSome:
-#  result &= "Video"
-#elif tweet.gif.isSome:
-#  result &= "Gif"
+#proc renderRssTweets(tweets: seq[Tweet]; prefs: Prefs): string =
+#var links: seq[string]
+#for tweet in tweets:
+#let link = getLink(tweet)
+#if link in links: continue
 #end if
 #end if
+#links.add link
+<item>
+  <title>${getTitle(tweet, prefs)}</title>
+  <dc:creator>@${tweet.profile.username}</dc:creator>
+  <description><![CDATA[${renderRssTweet(tweet, prefs).strip(chars={'\n'})}]]></description>
+  <pubDate>${getRfc822Time(tweet)}</pubDate>
+  <guid>https://${hostname & link}</guid>
+  <link>https://${hostname & link}</link>
+</item>
+#end for
 #end proc
 #end proc
 #
 #
 #proc renderTimelineRss*(tweets: seq[Tweet]; profile: Profile): string =
 #proc renderTimelineRss*(tweets: seq[Tweet]; profile: Profile): string =
@@ -58,42 +76,43 @@
       <width>128</width>
       <width>128</width>
       <height>128</height>
       <height>128</height>
     </image>
     </image>
-    #for tweet in tweets:
-    <item>
-      <title>${getTitle(tweet, prefs)}</title>
-      <dc:creator>@${tweet.profile.username}</dc:creator>
-      <description><![CDATA[${renderRssTweet(tweet, prefs).strip(chars={'\n'})}]]></description>
-      <pubDate>${getRfc822Time(tweet)}</pubDate>
-      <guid>https://${hostname}${getLink(tweet)}</guid>
-      <link>https://${hostname}${getLink(tweet)}</link>
-    </item>
-    #end for
+    ${renderRssTweets(tweets, prefs)}
   </channel>
   </channel>
 </rss>
 </rss>
 #end proc
 #end proc
 #
 #
 #proc renderListRss*(tweets: seq[Tweet]; name, list: string): string =
 #proc renderListRss*(tweets: seq[Tweet]; name, list: string): string =
 #let prefs = Prefs(replaceTwitter: hostname)
 #let prefs = Prefs(replaceTwitter: hostname)
+#let link = &"https://{hostname}/{name}/lists/{list}"
 #result = ""
 #result = ""
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
 <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
   <channel>
   <channel>
-    <atom:link href="https://${hostname}/${name}/lists/${list}/rss" rel="self" type="application/rss+xml" />
+    <atom:link href="${link}" rel="self" type="application/rss+xml" />
     <title>${list} / @${name}</title>
     <title>${list} / @${name}</title>
-    <link>https://${hostname}/${name}/lists/${list}</link>
+    <link>${link}</link>
     <description>Twitter feed for: ${list} by @${name}. Generated by ${hostname}</description>
     <description>Twitter feed for: ${list} by @${name}. Generated by ${hostname}</description>
     <language>en-us</language>
     <language>en-us</language>
     <ttl>40</ttl>
     <ttl>40</ttl>
-    #for tweet in tweets:
-    <item>
-      <title>${getTitle(tweet, prefs)}</title>
-      <dc:creator>@${tweet.profile.username}</dc:creator>
-      <description><![CDATA[${renderRssTweet(tweet, prefs).strip(chars={'\n'})}]]></description>
-      <pubDate>${getRfc822Time(tweet)}</pubDate>
-      <guid>https://${hostname}${getLink(tweet)}</guid>
-      <link>https://${hostname}${getLink(tweet)}</link>
-    </item>
-    #end for
+    ${renderRssTweets(tweets, prefs)}
+ </channel>
+</rss>
+#end proc
+#
+#proc renderSearchRss*(tweets: seq[Tweet]; name, param: string): string =
+#let prefs = Prefs(replaceTwitter: hostname)
+#let link = &"https://{hostname}/search"
+#result = ""
+<?xml version="1.0" encoding="UTF-8"?>
+<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
+  <channel>
+    <atom:link href="${link}" rel="self" type="application/rss+xml" />
+    <title>Search results for "${name}"</title>
+    <link>${link}</link>
+    <description>Twitter feed for search "${name}". Generated by ${hostname}</description>
+    <language>en-us</language>
+    <ttl>40</ttl>
+    ${renderRssTweets(tweets, prefs)}
   </channel>
   </channel>
 </rss>
 </rss>
 #end proc
 #end proc