Skip to content

Commit a4831e1

Browse files
committed
Create a youtube item only if content is inside media group
1 parent 8ba2f85 commit a4831e1

File tree

8 files changed

+189
-33
lines changed

8 files changed

+189
-33
lines changed

.github/workflows/pr-checks.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ jobs:
309309
key: ${{ runner.os }}-v1-${{ hashFiles('**/libs.versions.toml') }}
310310

311311
- name: Build watchOS Sample
312-
run: set -o pipefail && xcodebuild -project samples/multiplatform/iosApp/iosApp.xcodeproj -scheme 'RssParserDemo Watch App' -destination "platform=watchOS Simulator,name=Apple Watch SE (40mm) (2nd generation),OS=11.5" -configuration Debug CODE_SIGNING_ALLOWED=NO build | xcbeautify --renderer github-actions
312+
run: set -o pipefail && xcodebuild -project samples/multiplatform/iosApp/iosApp.xcodeproj -scheme 'RssParserDemo Watch App' -destination 'generic/platform=watchOS Simulator' -configuration Debug CODE_SIGNING_ALLOWED=NO build | xcbeautify --renderer github-actions
313313

314314
build-wasm-sample:
315315
name: Build Wasm Sample

rssparser/src/androidMain/kotlin/com/prof18/rssparser/internal/atom/AtomParser.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ internal fun CoroutineScope.extractAtomContent(
3838
// A flag just to be sure of the correct parsing
3939
var insideItem = false
4040
var insideChannel = false
41+
var insideYoutubeMediaGroup = false
4142

4243
var eventType = xmlPullParser.eventType
4344

@@ -54,6 +55,12 @@ internal fun CoroutineScope.extractAtomContent(
5455
xmlPullParser.contains(AtomKeyword.ENTRY_ITEM) -> {
5556
insideItem = true
5657
}
58+
59+
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP) -> {
60+
if (insideItem) {
61+
insideYoutubeMediaGroup = true
62+
}
63+
}
5764
//endregion
5865

5966
//region Channel tags
@@ -185,19 +192,19 @@ internal fun CoroutineScope.extractAtomContent(
185192
}
186193

187194
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP_TITLE) -> {
188-
if (insideItem) {
195+
if (insideItem && insideYoutubeMediaGroup) {
189196
channelFactory.youtubeItemDataBuilder.title(xmlPullParser.nextTrimmedText())
190197
}
191198
}
192199

193200
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP_DESCRIPTION) -> {
194-
if (insideItem) {
201+
if (insideItem && insideYoutubeMediaGroup) {
195202
channelFactory.youtubeItemDataBuilder.description(xmlPullParser.nextTrimmedText())
196203
}
197204
}
198205

199206
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP_CONTENT) -> {
200-
if (insideItem) {
207+
if (insideItem && insideYoutubeMediaGroup) {
201208
val videoUrl = xmlPullParser.attributeValue(AtomKeyword.YOUTUBE_MEDIA_GROUP_CONTENT_URL)
202209
channelFactory.youtubeItemDataBuilder.videoUrl(videoUrl)
203210
}
@@ -208,12 +215,16 @@ internal fun CoroutineScope.extractAtomContent(
208215
val thumbnailUrl = xmlPullParser.attributeValue(
209216
AtomKeyword.YOUTUBE_MEDIA_GROUP_THUMBNAIL_URL
210217
)
211-
channelFactory.youtubeItemDataBuilder.thumbnailUrl(thumbnailUrl)
218+
if (insideYoutubeMediaGroup) {
219+
channelFactory.youtubeItemDataBuilder.thumbnailUrl(thumbnailUrl)
220+
} else {
221+
channelFactory.articleBuilder.image(thumbnailUrl)
222+
}
212223
}
213224
}
214225

215226
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STATISTICS) -> {
216-
if (insideItem) {
227+
if (insideItem && insideYoutubeMediaGroup) {
217228
val views = xmlPullParser.attributeValue(
218229
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STATISTICS_VIEWS
219230
)
@@ -222,7 +233,7 @@ internal fun CoroutineScope.extractAtomContent(
222233
}
223234

224235
xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STAR_RATING) -> {
225-
if (insideItem) {
236+
if (insideItem && insideYoutubeMediaGroup) {
226237
val count = xmlPullParser.attributeValue(
227238
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STAR_RATING_COUNT
228239
)
@@ -232,9 +243,14 @@ internal fun CoroutineScope.extractAtomContent(
232243
}
233244

234245
// Exit conditions
246+
eventType == XmlPullParser.END_TAG && xmlPullParser.contains(AtomKeyword.YOUTUBE_MEDIA_GROUP) -> {
247+
insideYoutubeMediaGroup = false
248+
}
249+
235250
eventType == XmlPullParser.END_TAG && xmlPullParser.contains(AtomKeyword.ENTRY_ITEM) -> {
236251
// The item is correctly parsed
237252
insideItem = false
253+
insideYoutubeMediaGroup = false
238254
channelFactory.buildArticle()
239255
}
240256

rssparser/src/appleMain/kotlin/com/prof18/rssparser/internal/atom/AtomFeedHandler.kt

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@ internal class AtomFeedHandler(
1414

1515
private var isInsideItem = false
1616
private var isInsideChannel = true
17+
private var isInsideYoutubeMediaGroup = false
1718

1819
override fun didStartElement(startElement: String, attributes: Map<Any?, *>) {
1920
when (startElement) {
2021
AtomKeyword.ATOM.value -> isInsideChannel = true
2122
AtomKeyword.ENTRY_ITEM.value -> isInsideItem = true
2223

24+
AtomKeyword.YOUTUBE_MEDIA_GROUP.value -> {
25+
if (isInsideItem) {
26+
isInsideYoutubeMediaGroup = true
27+
}
28+
}
29+
2330
AtomKeyword.ENTRY_CATEGORY.value -> {
2431
if (isInsideItem) {
2532
val category = attributes.getValueOrNull(
@@ -56,27 +63,39 @@ internal class AtomFeedHandler(
5663
}
5764

5865
AtomKeyword.YOUTUBE_MEDIA_GROUP_CONTENT.value -> {
59-
val url = attributes.getValueOrNull(AtomKeyword.YOUTUBE_MEDIA_GROUP_CONTENT_URL.value) as? String
60-
channelFactory.youtubeItemDataBuilder.videoUrl(url)
66+
if (isInsideItem && isInsideYoutubeMediaGroup) {
67+
val url = attributes.getValueOrNull(AtomKeyword.YOUTUBE_MEDIA_GROUP_CONTENT_URL.value) as? String
68+
channelFactory.youtubeItemDataBuilder.videoUrl(url)
69+
}
6170
}
6271

6372
AtomKeyword.YOUTUBE_MEDIA_GROUP_THUMBNAIL.value -> {
6473
val url = attributes.getValueOrNull(AtomKeyword.YOUTUBE_MEDIA_GROUP_THUMBNAIL_URL.value) as? String
65-
channelFactory.youtubeItemDataBuilder.thumbnailUrl(url)
74+
if (isInsideItem) {
75+
if (isInsideYoutubeMediaGroup) {
76+
channelFactory.youtubeItemDataBuilder.thumbnailUrl(url)
77+
} else {
78+
channelFactory.articleBuilder.image(url)
79+
}
80+
}
6681
}
6782

6883
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STATISTICS.value -> {
69-
val views = attributes.getValueOrNull(
70-
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STATISTICS_VIEWS.value,
71-
) as? String
72-
channelFactory.youtubeItemDataBuilder.viewsCount(views?.toIntOrNull())
84+
if (isInsideItem && isInsideYoutubeMediaGroup) {
85+
val views = attributes.getValueOrNull(
86+
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STATISTICS_VIEWS.value,
87+
) as? String
88+
channelFactory.youtubeItemDataBuilder.viewsCount(views?.toIntOrNull())
89+
}
7390
}
7491

7592
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STAR_RATING.value -> {
76-
val count = attributes.getValueOrNull(
77-
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STAR_RATING_COUNT.value,
78-
) as? String
79-
channelFactory.youtubeItemDataBuilder.likesCount(count?.toIntOrNull())
93+
if (isInsideItem && isInsideYoutubeMediaGroup) {
94+
val count = attributes.getValueOrNull(
95+
AtomKeyword.YOUTUBE_MEDIA_GROUP_COMMUNITY_STAR_RATING_COUNT.value,
96+
) as? String
97+
channelFactory.youtubeItemDataBuilder.likesCount(count?.toIntOrNull())
98+
}
8099
}
81100
}
82101
}
@@ -87,9 +106,14 @@ internal class AtomFeedHandler(
87106
isInsideChannel = false
88107
}
89108

109+
AtomKeyword.YOUTUBE_MEDIA_GROUP.value -> {
110+
isInsideYoutubeMediaGroup = false
111+
}
112+
90113
AtomKeyword.ENTRY_ITEM.value -> {
91114
channelFactory.buildArticle()
92115
isInsideItem = false
116+
isInsideYoutubeMediaGroup = false
93117
}
94118

95119
AtomKeyword.ICON.value -> {
@@ -167,13 +191,13 @@ internal class AtomFeedHandler(
167191
}
168192

169193
AtomKeyword.YOUTUBE_MEDIA_GROUP_TITLE.value -> {
170-
if (isInsideItem) {
194+
if (isInsideItem && isInsideYoutubeMediaGroup) {
171195
channelFactory.youtubeItemDataBuilder.title(text)
172196
}
173197
}
174198

175199
AtomKeyword.YOUTUBE_MEDIA_GROUP_DESCRIPTION.value -> {
176-
if (isInsideItem) {
200+
if (isInsideItem && isInsideYoutubeMediaGroup) {
177201
channelFactory.youtubeItemDataBuilder.description(text)
178202
}
179203
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.prof18.rssparser.atom
2+
3+
import com.prof18.rssparser.XmlParserTestExecutor
4+
import com.prof18.rssparser.model.RssChannel
5+
import com.prof18.rssparser.model.RssItem
6+
import com.prof18.rssparser.parseFeed
7+
import kotlinx.coroutines.test.runTest
8+
import kotlin.test.Test
9+
import kotlin.test.assertEquals
10+
11+
class XmlParserAtomIdeaRicirTest : XmlParserTestExecutor() {
12+
13+
private val expectedChannel = RssChannel(
14+
title = "IDEA - scintille informatiche",
15+
link = "https://idea.ricir.net/",
16+
description = "Un piccolo blog dove condivido qualche IDEA per facilitare il mio, e vostro, uso delle tecnologie informatiche, e magari (se avrò tempo) qualche spunto di riflessione.",
17+
image = null,
18+
lastBuildDate = "2025-12-31T18:28:09+01:00",
19+
updatePeriod = null,
20+
itunesChannelData = null,
21+
youtubeChannelData = null,
22+
items = listOf(
23+
RssItem(
24+
guid = "https://idea.ricir.net/Ricevere-notifiche-per-nuovi-articoli",
25+
title = "Avvisi automatici: scopri i nuovi articoli in tempo reale",
26+
author = "Riccardo",
27+
link = "https://idea.ricir.net/Ricevere-notifiche-per-nuovi-articoli/",
28+
pubDate = "2025-12-31T00:00:00+01:00",
29+
description = "Dopo tanti mesi di pausa, torno ad aggiornare il sito con un articolo dedicato proprio all’uscita di nuovi contenuti. Ti spiego qui sotto come puoi restare aggiornato su nuovi articoli dei siti che ti interessano, usando una semplice app, e - solo per il mio sito - un canale Telegram. Per il mio sito Come avrai visto, non ti chiedo l’indirizzo e-mail per avvisarti dei nuovi articoli: desidero però che tu possa seguire le nuove uscite con facilità, e per questo ti propongo due soluzioni semplici. Prima soluzione - canale La soluzione più veloce, se hai un utente su Telegram, è iscriverti al mio canale. Basta che clicchi qua a fianco: Canale Telegram Il mio canale si aggiungerà ai canali che segui. E riceverai una notifica di Telegram quando pubblicherò un articolo. Seconda soluzione - App FeedFlow La seconda soluzione è l’app FeedFlow. La trovi su Google Play (se invece hai un iPhone, su Apple Store) cercando “Feedflow”: Una volta installata, torna qui e clicca qui a fianco Clicca a lungo (su cellulare) Segui poi questi passaggi sulla App (vedi figura sotto): clicca Condividi Link clicca su FeedFlow (può essere che devi scorrere a destra per trovarlo) ti arriva un breve messaggio: Feed IDEA - scintille informatiche aggiunto → Fatto! Ma cosa vuol dire Feed? Un Feed non è altro che un collegamento alla lista degli articoli di un sito.",
30+
content = "content",
31+
image = "https://idea.ricir.net/assets/ComeSeguireAggiornamenti-social.png",
32+
audio = null,
33+
video = null,
34+
sourceName = null,
35+
sourceUrl = null,
36+
categories = emptyList(),
37+
commentsUrl = null,
38+
itunesItemData = null,
39+
youtubeItemData = null,
40+
rawEnclosure = null,
41+
)
42+
),
43+
)
44+
45+
@Test
46+
fun channelIsParsedCorrectly() = runTest {
47+
val channel = parseFeed("atom-feed-idea-ricir.xml")
48+
assertEquals(expectedChannel, channel)
49+
}
50+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<feed
3+
xmlns="http://www.w3.org/2005/Atom" xml:lang="it">
4+
<generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator>
5+
<link href="https://idea.ricir.net/feed.xml" rel="self" type="application/atom+xml" />
6+
<link href="https://idea.ricir.net/" rel="alternate" type="text/html" hreflang="it" />
7+
<updated>2025-12-31T18:28:09+01:00</updated>
8+
<id>https://idea.ricir.net/feed.xml</id>
9+
<title type="html">IDEA - scintille informatiche</title>
10+
<subtitle>Un piccolo blog dove condivido qualche IDEA per facilitare il mio, e vostro, uso delle tecnologie informatiche, e magari (se avrò tempo) qualche spunto di riflessione.</subtitle>
11+
<entry>
12+
<title type="html">Avvisi automatici: scopri i nuovi articoli in tempo reale</title>
13+
<link href="https://idea.ricir.net/Ricevere-notifiche-per-nuovi-articoli/" rel="alternate" type="text/html" title="Avvisi automatici: scopri i nuovi articoli in tempo reale" />
14+
<published>2025-12-31T00:00:00+01:00</published>
15+
<updated>2025-12-31T00:00:00+01:00</updated>
16+
<id>https://idea.ricir.net/Ricevere-notifiche-per-nuovi-articoli</id>
17+
<content type="html" xml:base="https://idea.ricir.net/Ricevere-notifiche-per-nuovi-articoli/">
18+
<![CDATA[content]]>
19+
</content>
20+
<author>
21+
<name>Riccardo</name>
22+
</author>
23+
<summary type="html">
24+
<![CDATA[Dopo tanti mesi di pausa, torno ad aggiornare il sito con un articolo dedicato proprio all’uscita di nuovi contenuti. Ti spiego qui sotto come puoi restare aggiornato su nuovi articoli dei siti che ti interessano, usando una semplice app, e - solo per il mio sito - un canale Telegram. Per il mio sito Come avrai visto, non ti chiedo l’indirizzo e-mail per avvisarti dei nuovi articoli: desidero però che tu possa seguire le nuove uscite con facilità, e per questo ti propongo due soluzioni semplici. Prima soluzione - canale La soluzione più veloce, se hai un utente su Telegram, è iscriverti al mio canale. Basta che clicchi qua a fianco: Canale Telegram Il mio canale si aggiungerà ai canali che segui. E riceverai una notifica di Telegram quando pubblicherò un articolo. Seconda soluzione - App FeedFlow La seconda soluzione è l’app FeedFlow. La trovi su Google Play (se invece hai un iPhone, su Apple Store) cercando “Feedflow”: Una volta installata, torna qui e clicca qui a fianco Clicca a lungo (su cellulare) Segui poi questi passaggi sulla App (vedi figura sotto): clicca Condividi Link clicca su FeedFlow (può essere che devi scorrere a destra per trovarlo) ti arriva un breve messaggio: Feed IDEA - scintille informatiche aggiunto → Fatto! Ma cosa vuol dire Feed? Un Feed non è altro che un collegamento alla lista degli articoli di un sito.]]>
25+
</summary>
26+
<media:thumbnail
27+
xmlns:media="http://search.yahoo.com/mrss/" url="https://idea.ricir.net/assets/ComeSeguireAggiornamenti-social.png" />
28+
<media:content medium="image" url="https://idea.ricir.net/assets/ComeSeguireAggiornamenti-social.png"
29+
xmlns:media="http://search.yahoo.com/mrss/" />
30+
</entry>
31+
</feed>

0 commit comments

Comments
 (0)