Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

自定义 Miniflux 以添加自定义排序

Posted on 2025-01-04

我使用Miniflux作为我的 feed 阅读器已经有几年了。它是有意简约的,因此缺乏某些功能。我非常怀念的一件事是能够按照条目阅读时间等各种标准对提要条目进行排序。值得庆幸的是,Miniflux 允许用户通过设置注入自定义 JavaScript 代码来自定义 UI。所以我把这个掌握在自己手中:

Screenshot of the Miniflux reader showing my custom sorting options Miniflux 阅读器的屏幕截图显示了我的自定义排序选项

以下是不同排序选项的含义:

默认
未应用自定义排序。默认为 Miniflux 设置中指定的排序顺序。
随机的
随机排序。每次刷新都会发生变化。
网址
按条目 URL 的字母顺序排序。对于查找重复条目很有用。
最古老的
按条目发布日期排序,最旧的排在前面。
最新
按条目发布日期排序,最新的排在前面。
最长
按条目预计阅读时间排序,最长的排在前面。阅读时间未知的条目排序在最后。
最短
按条目预计阅读时间排序,最短的排在前面。阅读时间未知的条目排序在最后。
最少
按 Feed 名称分组,按 Feed 中的条目数排序,最少的在前。条目按默认排序顺序排序。
最多
按 Feed 名称分组,按 Feed 中的条目数排序,最先排序。条目按默认排序顺序排序。
喂养
按 Feed 名称分组和排序,条目按默认排序顺序排序。
类别
按类别名称然后提要名称进行分组和排序,条目按默认排序顺序排序。

排序选项不会出现在“历史记录”页面上。按提要和类别排序的选项不会出现在提要特定页面上。按类别排序的选项不会出现在类别特定页面上。

此外,为任何页面选择的选项都会记住在浏览器的本地存储中,因此当您返回页面时,您会发现它按您上次选择的相同选项排序。

这是自定义 JavaScript:

 ( function () { " use strict " ; function entryFeed ( e ) { return e . querySelector ( " .item-meta-info-title a " ). getAttribute ( " title " ); } function entryCategory ( e ) { return e . querySelector ( " .category " ). innerText ; } function entryTime ( e ) { return e . querySelector ( " .item-meta-info-timestamp time " ). dateTime ; } function entryUrl ( e ) { return e . querySelector ( " .item-meta-icons-external-url a " ) . href . split ( " :// " )[ 1 ]; } function entryReadingTime ( e ) { const ertE = e . querySelector ( " .item-meta-info-reading-time " ); return ertE == null ? null : parseInt ( ertE . innerText ); } function sortEntriesBy ( entries , f , comparator ) { return entries . map (( e ) => [ f ( e ), e ]) . sort ( comparator ) . map (([ _ , e ]) => e ); } function sortEntries ( entries , sortMode ) { if ( entries . length < 2 ) { return entries ; } switch ( sortMode ) { case " random " : return sortEntriesBy ( entries , ( _ ) => Math . random ()); case " url " : return sortEntriesBy ( entries , entryUrl ); case " fewest " : return Array . from ( Map . groupBy ( entries , entryFeed ). values ()) . sort (( a , b ) => a . length > b . length ) . flat (); case " most " : return Array . from ( Map . groupBy ( entries , entryFeed ). values ()) . sort (( a , b ) => a . length < b . length ) . flat (); case " oldest " : return sortEntriesBy ( entries , entryTime ); case " newest " : return sortEntriesBy ( entries , entryTime ). reverse (); case " shortest " : return sortEntriesBy ( entries , entryReadingTime , ([ a ], [ b ]) => a == null ? 1 : b == null ? - 1 : a - b , ); case " longest " : return sortEntriesBy ( entries , entryReadingTime , ([ a ], [ b ]) => a == null ? 1 : b == null ? - 1 : b - a , ); case " feed " : return sortEntriesBy ( entries , entryFeed ); case " category " : return sortEntriesBy ( entries , ( e ) => entryCategory ( e ) + " - " + entryFeed ( e ), ); default : return entries ; } } function setupSortModeSelector () { const entries = Array . from ( document . querySelectorAll ( " .items .entry-item:not(:has(.item-title a[href^='/history'])) " , ), ); if ( entries . length < 2 ) { return ; } const path = window . location . pathname ; const lsKey = path + " -sortmode " ; const sortMode = localStorage . getItem ( lsKey ); const ph = document . querySelector ( " .page-header " ); const sortOpts = document . createElement ( " select " ); sortOpts . id = " sortmode " ; const options = [ " Default " , " Random " , " URL " , " Oldest " , " Newest " , " Longest " , " Shortest " , ]; if ( path . startsWith ( " /unread " )) { options . push ( " Fewest " , " Most " , " Feed " , " Category " ); } else if ( path . startsWith ( " /category " )) { options . push ( " Fewest " , " Most " , " Feed " ); } for ( const opt of options ) { const optE = document . createElement ( " option " ); optE . text = opt ; optE . value = opt . toLowerCase (); if ( optE . value === sortMode ) { optE . selected = true ; } sortOpts . appendChild ( optE ); } ph . insertBefore ( sortOpts , ph . querySelector ( " #page-header-title " )); sortOpts . onchange = function ( event ) { const sortMode = event . target . value ; sortEntries ( entries , sortMode ). forEach (( e , i ) => ( e . style . order = i )); localStorage . setItem ( lsKey , sortMode ); }; if ( sortMode != null ) { sortEntries ( entries , sortMode ). forEach (( e , i ) => ( e . style . order = i )); } } document . addEventListener ( " DOMContentLoaded " , function () { setupSortModeSelector (); }); })();

就是这样!这对我来说非常有效,我希望这对其他人也有帮助。

点赞、分享或评论Mastodon上的这篇文章。

原文: https://notes.abhinavsarkar.net/2025/customizing-miniflux

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme