Skip to content

Commit

Permalink
Added ability to hide feed from homepage
Browse files Browse the repository at this point in the history
Closes #22
  • Loading branch information
ssddanbrown committed Jul 17, 2023
1 parent 9bf5d33 commit a9feb85
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 19 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The following features are built into the application:
- Every hour by default, configurable down to 5 mins.
- Custom feed names and colors.
- Feed-based tags for categorization.
- Ability to hide feed posts by default.
- 3 different post layout modes (card, list, compact).
- Fetching of page open-graph images.
- Feeds managed via a single plaintext file.
Expand Down Expand Up @@ -131,6 +132,11 @@ https://example.com/feed-b.xml News_Site #news
# Feed color can be set using square brackets after the name.
# The color must be a CSS-compatible color value.
https://example.com/feed-c.xml Blue_News[#0078b9] #news #blue
# Feeds starting with a '-' are flagged as hidden.
# Posts for hidden feeds won't be shown on the homepage
# but can be seen via any type of active filter.
- https://example.com/feed-d.xml Cat_Facts #cats #facts
```

## App Configuration
Expand Down
2 changes: 2 additions & 0 deletions app/Config/ConfiguredFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function __construct(
public string $url,
public string $color,
public array $tags,
public bool $hidden,
) {
}

Expand All @@ -26,6 +27,7 @@ public function jsonSerialize(): mixed
'color' => $this->color,
'url' => $this->url,
'tags' => $this->tags,
'hidden' => $this->hidden,
'reloading' => $this->reloading,
'outdated' => $this->isOutdated(),
];
Expand Down
3 changes: 2 additions & 1 deletion app/Config/ConfiguredFeedList.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Config;

use ArrayIterator;
use IteratorAggregate;
use JsonSerializable;
use Traversable;
Expand Down Expand Up @@ -50,7 +51,7 @@ public function reloadOutdatedFeeds(): int

public function getIterator(): Traversable
{
return $this->feeds;
return new ArrayIterator($this->feeds);
}

public function jsonSerialize(): mixed
Expand Down
15 changes: 13 additions & 2 deletions app/Config/ConfiguredFeedProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ConfiguredFeedProvider
protected RssConfig $config;

/** @var ConfiguredFeed[] */
protected $feeds = [];
protected array $feeds = [];

public function loadFromConfig(): void
{
Expand Down Expand Up @@ -54,7 +54,8 @@ protected function getConfiguredFeeds(): array
$this->config->getName($feedUrl),
$feedUrl,
$this->config->getColor($feedUrl),
$this->config->getTags($feedUrl)
$this->config->getTags($feedUrl),
$this->config->getHidden($feedUrl),
);

$configuredFeeds[] = $configured;
Expand All @@ -78,6 +79,16 @@ public function getAll()
return new ConfiguredFeedList($this->feeds);
}

public function getVisible()
{
$feeds = array_filter($this->feeds, function (ConfiguredFeed $feed) {
return !$feed->hidden;
});

$this->updateLastAccessedForFeeds($feeds);
return new ConfiguredFeedList($feeds);
}

public function get(string $feedUrl): ?ConfiguredFeed
{
foreach ($this->feeds as $feed) {
Expand Down
29 changes: 24 additions & 5 deletions app/Config/RssConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ class RssConfig
* The configured feeds.
* Array keys are the feed URLs and values are arrays of tags as strings.
* Tag strings include their '#' prefix.
* @var array<string, array{name: string, tags: string[], color: string}>
* @var array<string, array{name: string, tags: string[], color: string, hidden: bool}>
*/
protected $feeds = [];
protected array $feeds = [];

/**
* Get all feed URLs
Expand All @@ -24,12 +24,13 @@ public function getFeedUrls(): array
/**
* Add a new feed to the config.
*/
public function addFeed(string $feed, string $name, array $tags = [], string $color = ''): void
public function addFeed(string $feed, string $name, array $tags = [], string $color = '', bool $hidden = false): void
{
$this->feeds[$feed] = [
'name' => $name,
'tags' => $tags,
'color' => $color,
'hidden' => $hidden,
];
}

Expand Down Expand Up @@ -73,6 +74,14 @@ public function getColor(string $feed): string
return $this->feeds[$feed]['color'] ?? '';
}

/**
* Get the hidden status for the given feed.
*/
public function getHidden(string $feed): bool
{
return $this->feeds[$feed]['hidden'] ?? false;
}

/**
* Get the configuration as a string.
*/
Expand All @@ -92,6 +101,10 @@ public function toString(): string
$line .= " {$tag}";
}

if ($details['hidden']) {
$line = '-' . $line;
}

$lines[] = $line;
}

Expand All @@ -107,8 +120,14 @@ public function parseFromString(string $configString): void

foreach ($lines as $line) {
$line = trim($line);
$parts = explode(' ', $line);
$hidden = false;

if (str_starts_with($line, '-')) {
$hidden = true;
$line = ltrim($line, '- ');
}

$parts = explode(' ', $line);
if (empty($line) || str_starts_with($line, '#') || count($parts) < 2) {
continue;
}
Expand All @@ -127,7 +146,7 @@ public function parseFromString(string $configString): void
$tags = array_filter(array_slice($parts, 2), fn ($str) => str_starts_with($str, '#'));

if (str_starts_with($url, 'http://') || str_starts_with($url, 'https://')) {
$this->addFeed($url, $name, $tags, $color);
$this->addFeed($url, $name, $tags, $color, $hidden);
}
}
}
Expand Down
18 changes: 10 additions & 8 deletions app/Http/Controllers/PostViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ public function __construct(

public function home(Request $request)
{
$feeds = $this->feedProvider->getAll();
$feeds->reloadOutdatedFeeds();
$displayFeeds = $this->feedProvider->getAll();
$displayFeeds->reloadOutdatedFeeds();

$postFeeds = $this->feedProvider->getVisible();

return $this->renderPostsView($request, $feeds);
return $this->renderPostsView($request, $displayFeeds, $postFeeds);
}

public function tag(Request $request, string $tag)
{
$feeds = $this->feedProvider->getForTag('#' . $tag);
$feeds->reloadOutdatedFeeds();

return $this->renderPostsView($request, $feeds, ['tag' => $tag]);
return $this->renderPostsView($request, $feeds, $feeds, ['tag' => $tag]);
}

public function feed(Request $request, string $feed)
Expand All @@ -40,10 +42,10 @@ public function feed(Request $request, string $feed)
$feeds = $this->feedProvider->getAsList($feed);
$feeds->reloadOutdatedFeeds();

return $this->renderPostsView($request, $feeds, ['feed' => $feed]);
return $this->renderPostsView($request, $feeds, $feeds, ['feed' => $feed]);
}

protected function renderPostsView(Request $request, ConfiguredFeedList $feeds, array $additionalData = [])
protected function renderPostsView(Request $request, ConfiguredFeedList $displayFeeds, ConfiguredFeedList $postFeeds, array $additionalData = [])
{
$page = max(intval($request->get('page')), 1);
$query = $request->get('query', '');
Expand All @@ -57,14 +59,14 @@ protected function renderPostsView(Request $request, ConfiguredFeedList $feeds,
}

$posts = $this->postProvider->getLatest(
$feeds,
$postFeeds,
100,
$page,
$subFilter
);

$coreData = [
'feeds' => $feeds,
'feeds' => $displayFeeds,
'posts' => $posts,
'page' => $page,
'search' => $query,
Expand Down
7 changes: 7 additions & 0 deletions resources/js/Parts/Feed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
<div class="py-1 my-2">
<h4 class="font-bold text-black dark:text-gray-400" :style="{color: feed.color}">
<Link :href="`f/${encodeURIComponent(encodeURIComponent(feed.url))}`">{{ feed.name }}</Link>
<span v-if="feed.hidden" title="Posts hidden by default" class="text-xs ml-2 text-gray-600">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="inline bi bi-eye-slash" viewBox="0 0 16 16">
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/>
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/>
</svg>
</span>
</h4>
<div class="font-mono text-gray-600 dark:text-gray-500 text-xs my-1 overflow-ellipsis whitespace-nowrap w-full overflow-hidden">{{ feed.url }}</div>
<div class="flex gap-1 text-gray-600 dark:text-gray-500 text-sm flex-wrap">
Expand Down
6 changes: 4 additions & 2 deletions tests/Feature/ConfiguredFeedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public function test_is_outdated_can_be_controlled_by_config(): void
'My great feed',
'https://example.com',
'#fff',
['#a']
['#a'],
false,
);

config()->set('app.feed_update_frequency', 60);
Expand All @@ -45,7 +46,8 @@ public function test_start_reloading_dispatched_refresh_job(): void
'My great feed',
'https://example.com',
'#fff',
['#a']
['#a'],
false,
);
Queue::fake();

Expand Down
8 changes: 7 additions & 1 deletion tests/Unit/RssConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,23 @@ public function test_parse_from_string(): void
# A comment
https://example-C.com/cats?test=abc#okay
-https://example-hidden-a.com Hidden_A #news
- https://example-hidden-b.com/ Hidden_B
http://beans.com/feed.xml#food d_is_cool #cooking
");

$this->assertCount(3, $config->getFeedUrls());
$this->assertCount(5, $config->getFeedUrls());
$this->assertCount(0, $config->getTags('https://example-B.com/cats?test=abc#okay'));
$this->assertEquals(['#dog', '#cat'], $config->getTags('https://example.com'));
$this->assertEquals(['#cooking'], $config->getTags('http://beans.com/feed.xml#food'));
$this->assertEquals('a', $config->getName('https://example-B.com/cats?test=abc#okay'));
$this->assertEquals('b', $config->getName('https://example.com'));
$this->assertEquals('#000', $config->getColor('https://example.com'));
$this->assertEquals('d is cool', $config->getName('http://beans.com/feed.xml#food'));
$this->assertTrue($config->getHidden('https://example-hidden-a.com'));
$this->assertTrue($config->getHidden('https://example-hidden-b.com/'));
$this->assertFalse($config->getHidden('http://beans.com/feed.xml#food'));
}


Expand Down

0 comments on commit a9feb85

Please sign in to comment.