116 lines
3.9 kB
1
defmodule BlogWeb.RedditLinksLive do
2
use BlogWeb, :live_view
3
require Logger
4
5
@max_skeets 50
6
# Extract YouTube video ID from various YouTube URL formats
7
8
def mount(_params, _session, socket) do
9
# Load existing skeets from ETS
10
initial_skeets =
11
BlueskyHose.get_reddit_links(@max_skeets)
12
13
if connected?(socket) do
14
# Subscribe to the reddit links feed
15
Phoenix.PubSub.subscribe(Blog.PubSub, "reddit_links")
16
end
17
18
{:ok,
19
assign(socket,
20
page_title: "Reddit Links from Bluesky",
21
skeets: initial_skeets,
22
filtered_skeets: initial_skeets,
23
max_skeets: @max_skeets,
24
meta_attrs: [
25
%{name: "description", content: "Bluesky posts containing Reddit links"},
26
%{property: "og:title", content: "Reddit Links from Bluesky"},
27
%{property: "og:description", content: "Bluesky posts containing Reddit links"},
28
%{property: "og:type", content: "website"}
29
]
30
)}
31
end
32
33
def handle_info({:reddit_link, skeet}, socket) do
34
# Add the new skeet to the list and trim to max size
35
updated_skeets =
36
[skeet | socket.assigns.skeets]
37
|> Enum.take(socket.assigns.max_skeets)
38
39
{:noreply, assign(socket, skeets: updated_skeets)}
40
end
41
42
43
def render(assigns) do
44
~H"""
45
<div class="max-w-4xl mx-auto py-8">
46
<h1 class="text-3xl font-bold mb-6">Youtube Links from Bluesky</h1>
47
48
<div class="mb-8 p-4 bg-blue-50 rounded-lg border border-blue-200">
49
<p class="text-blue-800">
50
This page shows Bluesky posts that contain youtube links. New posts will appear automatically.
51
</p>
52
</div>
53
54
<div class="space-y-6">
55
<%= if Enum.empty?(@skeets) do %>
56
<div class="p-8 text-center bg-gray-50 rounded-lg border border-gray-200">
57
<p class="text-gray-500">Waiting for posts with Reddit links to appear...</p>
58
<p class="text-sm text-gray-400 mt-2">
59
This could take some time depending on Bluesky activity.
60
</p>
61
</div>
62
<% end %>
63
64
<%= for skeet <- @skeets do %>
65
<div class="p-4 bg-white rounded-lg shadow-md border border-gray-200 transition-all hover:shadow-lg">
66
<div class="prose prose-sm max-w-none">
67
<%= if youtube_id = extract_youtube_id(skeet) do %>
68
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
69
<div class="aspect-w-16 aspect-h-9 w-full">
70
<iframe
71
src={"https://www.youtube.com/embed/#{youtube_id}"}
72
frameborder="0"
73
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
74
allowfullscreen
75
class="w-full h-full rounded-lg"
76
>
77
</iframe>
78
</div>
79
</div>
80
<% end %>
81
</div>
82
</div>
83
<% end %>
84
</div>
85
</div>
86
"""
87
end
88
89
defp extract_youtube_id(url) do
90
cond do
91
# youtu.be format
92
String.match?(url, ~r/youtu\.be\/([a-zA-Z0-9_-]+)/) ->
93
[[_, id]] = Regex.scan(~r/youtu\.be\/([a-zA-Z0-9_-]+)/, url)
94
id
95
96
# youtube.com/watch?v= format
97
String.match?(url, ~r/youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)/) ->
98
[[_, id]] = Regex.scan(~r/v=([a-zA-Z0-9_-]+)/, url)
99
id
100
101
# youtube.com/v/ format
102
String.match?(url, ~r/youtube\.com\/v\/([a-zA-Z0-9_-]+)/) ->
103
[[_, id]] = Regex.scan(~r/youtube\.com\/v\/([a-zA-Z0-9_-]+)/, url)
104
id
105
106
# youtube.com/embed/ format
107
String.match?(url, ~r/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/) ->
108
[[_, id]] = Regex.scan(~r/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/, url)
109
id
110
111
true ->
112
nil
113
end
114
end
115
116
end
117