Moves discovery and video lists to Outbox when Follows or relay lists are selected

This commit is contained in:
Vitor Pamplona 2024-08-07 16:39:24 -04:00
parent a1aaec0b7d
commit b026bffe4a
3 changed files with 52 additions and 72 deletions

View File

@ -108,7 +108,6 @@ import com.vitorpamplona.quartz.signers.NostrSigner
import com.vitorpamplona.quartz.signers.NostrSignerExternal
import com.vitorpamplona.quartz.signers.NostrSignerInternal
import com.vitorpamplona.quartz.utils.DualCase
import com.vitorpamplona.quartz.utils.RelayListRecommendationProcessor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@ -504,6 +503,8 @@ class Account(
userList: Map<HexKey, List<String>>,
hasOnionConnection: Boolean = false,
): Map<String, List<HexKey>> {
checkNotInMainThread()
val authorsPerRelayUrl = mutableMapOf<String, MutableSet<HexKey>>()
val relayUrlsPerAuthor = mutableMapOf<HexKey, MutableSet<String>>()
@ -585,53 +586,6 @@ class Account(
liveHomeListAuthorsPerRelayFlow.stateIn(scope, SharingStarted.Eagerly, emptyMap())
}
fun relaysFromPeopleListFlows(
currentFollowList: LiveFollowLists,
relayUrlsToIgnore: Set<String>,
): Flow<List<RelayListRecommendationProcessor.RelayRecommendation>> =
combine(
currentFollowList.users.map {
getNIP65RelayListFlow(it)
},
) { followsNIP65RelayLists ->
RelayListRecommendationProcessor
.reliableRelaySetFor(
followsNIP65RelayLists.mapNotNull {
(it.note.event as? AdvertisedRelayListEvent)
},
relayUrlsToIgnore,
hasOnionConnection = proxy != null,
).sortedByDescending { it.users.size }
}
@OptIn(ExperimentalCoroutinesApi::class)
val liveHomeFollowRelayFlow: Flow<List<RelayListRecommendationProcessor.RelayRecommendation>> by lazy {
combineTransform(liveHomeFollowListFlow, connectToRelaysFlow) { followList, existing ->
if (followList != null) {
emit(
relaysFromPeopleListFlows(
followList,
existing.mapNotNullTo(HashSet()) {
if (it.read && FeedType.FOLLOWS in it.feedTypes) {
it.url
} else {
null
}
},
),
)
} else {
emit(MutableStateFlow(emptyList()))
}
}.flatMapLatest {
it
}
}
val liveHomeFollowRelays: StateFlow<List<RelayListRecommendationProcessor.RelayRecommendation>> by lazy {
liveHomeFollowRelayFlow.stateIn(scope, SharingStarted.Eagerly, emptyList())
}
@OptIn(ExperimentalCoroutinesApi::class)
private val liveNotificationList: Flow<ListNameNotePair> by lazy {
defaultNotificationFollowList.flatMapLatest { listName ->
@ -656,6 +610,23 @@ class Account(
.stateIn(scope, SharingStarted.Eagerly, LiveFollowLists(usersPlusMe = setOf(keyPair.pubKeyHex)))
}
@OptIn(ExperimentalCoroutinesApi::class)
val liveStoriesListAuthorsPerRelayFlow: Flow<Map<String, List<String>>?> by lazy {
combineTransform(liveStoriesFollowLists, connectToRelaysFlow) { followList, existing ->
if (followList != null) {
emit(authorsPerRelay(followList.usersPlusMe, existing.filter { it.feedTypes.contains(FeedType.FOLLOWS) && it.read }.map { it.url }))
} else {
emit(MutableStateFlow(null))
}
}.flatMapLatest {
it
}
}
val liveStoriesListAuthorsPerRelay: StateFlow<Map<String, List<String>>?> by lazy {
liveStoriesListAuthorsPerRelayFlow.stateIn(scope, SharingStarted.Eagerly, emptyMap())
}
@OptIn(ExperimentalCoroutinesApi::class)
private val liveDiscoveryList: Flow<ListNameNotePair> by lazy {
defaultDiscoveryFollowList.flatMapLatest { listName ->
@ -668,6 +639,23 @@ class Account(
.stateIn(scope, SharingStarted.Eagerly, LiveFollowLists(usersPlusMe = setOf(keyPair.pubKeyHex)))
}
@OptIn(ExperimentalCoroutinesApi::class)
val liveDiscoveryListAuthorsPerRelayFlow: Flow<Map<String, List<String>>?> by lazy {
combineTransform(liveDiscoveryFollowLists, connectToRelaysFlow) { followList, existing ->
if (followList != null) {
emit(authorsPerRelay(followList.usersPlusMe, existing.filter { it.read }.map { it.url }))
} else {
emit(MutableStateFlow(null))
}
}.flatMapLatest {
it
}
}
val liveDiscoveryListAuthorsPerRelay: StateFlow<Map<String, List<String>>?> by lazy {
liveDiscoveryListAuthorsPerRelayFlow.stateIn(scope, SharingStarted.Eagerly, emptyMap())
}
private fun decryptLiveFollows(
listEvent: GeneralListEvent,
onReady: (LiveFollowLists) -> Unit,

View File

@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.SinceAuthorPerRelayFilter
import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.ChannelCreateEvent
@ -66,10 +67,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
}
fun createMarketplaceFilter(): List<TypedFilter> {
val follows =
account.liveDiscoveryFollowLists.value
?.users
?.toList()
val follows = account.liveDiscoveryListAuthorsPerRelay.value
val hashToLoad =
account.liveDiscoveryFollowLists.value
?.hashtags
@ -81,9 +79,9 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return listOfNotNull(
TypedFilter(
types = setOf(FeedType.GLOBAL),
types = if (follows == null) setOf(FeedType.GLOBAL) else setOf(FeedType.FOLLOWS),
filter =
SincePerRelayFilter(
SinceAuthorPerRelayFilter(
authors = follows,
kinds = listOf(ClassifiedsEvent.KIND),
limit = 300,
@ -165,12 +163,14 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
?.users
?.toList()
val followsRelays = account.liveDiscoveryListAuthorsPerRelay.value
return listOfNotNull(
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
SincePerRelayFilter(
authors = follows,
SinceAuthorPerRelayFilter(
authors = followsRelays,
kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND),
limit = 300,
since =
@ -200,17 +200,14 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
}
fun createPublicChatFilter(): List<TypedFilter> {
val follows =
account.liveDiscoveryFollowLists.value
?.users
?.toList()
val follows = account.liveDiscoveryListAuthorsPerRelay.value
val followChats = account.selectedChatsFollowList().toList()
return listOfNotNull(
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
SincePerRelayFilter(
SinceAuthorPerRelayFilter(
authors = follows,
kinds = listOf(ChannelMessageEvent.KIND),
limit = 500,
@ -243,15 +240,12 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
}
fun createCommunitiesFilter(): TypedFilter {
val follows =
account.liveDiscoveryFollowLists.value
?.users
?.toList()
val follows = account.liveDiscoveryListAuthorsPerRelay.value
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
SincePerRelayFilter(
SinceAuthorPerRelayFilter(
authors = follows,
kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND),
limit = 300,

View File

@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.SinceAuthorPerRelayFilter
import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter
import com.vitorpamplona.quartz.events.FileHeaderEvent
import com.vitorpamplona.quartz.events.FileStorageHeaderEvent
@ -64,15 +65,12 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") {
}
fun createContextualFilter(): TypedFilter {
val follows =
account.liveStoriesFollowLists.value
?.users
?.toList()
val follows = account.liveStoriesListAuthorsPerRelay.value
return TypedFilter(
types = setOf(FeedType.GLOBAL),
types = if (follows == null) setOf(FeedType.GLOBAL) else setOf(FeedType.FOLLOWS),
filter =
SincePerRelayFilter(
SinceAuthorPerRelayFilter(
authors = follows,
kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND),
limit = 200,