Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,18 @@ import dev.typetype.server.cache.DragonflyService
import dev.typetype.server.services.HomeRecommendationPoolResolver
import dev.typetype.server.services.HomeRecommendationPoolResolverDependencies
import dev.typetype.server.services.HomeRecommendationService
import dev.typetype.server.services.RecommendationFeedHistoryService
import dev.typetype.server.services.RecommendationPrivacyService

data class HomeRecommendationServices(
val feedHistoryService: RecommendationFeedHistoryService,
val recommendationService: HomeRecommendationService,
)

fun createHomeRecommendationServices(
cache: DragonflyService,
deps: HomeRecommendationPoolResolverDependencies,
privacyService: RecommendationPrivacyService,
): HomeRecommendationServices {
val feedHistoryService = RecommendationFeedHistoryService()
val resolverDeps = deps.copy(cache = cache, feedHistoryService = feedHistoryService)
val resolverDeps = deps.copy(cache = cache)
val recommendationService = HomeRecommendationService(
poolResolver = HomeRecommendationPoolResolver(resolverDeps),
feedHistoryService = feedHistoryService,
privacyService = privacyService,
)
return HomeRecommendationServices(feedHistoryService, recommendationService)
return HomeRecommendationServices(recommendationService)
}
30 changes: 6 additions & 24 deletions src/main/kotlin/dev/typetype/server/ServiceRegistry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,13 @@ import dev.typetype.server.services.PipePipeSuggestionService
import dev.typetype.server.services.PipePipeTrendingService
import dev.typetype.server.services.PlaylistService
import dev.typetype.server.services.ProgressService
import dev.typetype.server.services.RecommendationEventService
import dev.typetype.server.services.RecommendationFeedbackService
import dev.typetype.server.services.RecommendationInterestService
import dev.typetype.server.services.RecommendationOnboardingService
import dev.typetype.server.services.RecommendationPrivacyService
import dev.typetype.server.services.HomeRecommendationSignalContextService
import dev.typetype.server.services.SearchHistoryService
import dev.typetype.server.services.SettingsService
import dev.typetype.server.services.HomeRecommendationPoolResolverDependencies
import dev.typetype.server.services.SubscriptionFeedService
import dev.typetype.server.services.SubscriptionShortsBlendService
import dev.typetype.server.services.SubscriptionShortsFeedService
import dev.typetype.server.services.SubscriptionShortsSignalService
import dev.typetype.server.services.SubscriptionsService
import dev.typetype.server.services.SubscriptionFeedCacheInvalidation
import dev.typetype.server.services.SubscriptionFeedCacheInvalidator
Expand Down Expand Up @@ -71,50 +65,38 @@ internal class ServiceRegistry(cache: DragonflyService, subtitleServiceUrl: Stri
val nativeManifestService = CachedNativeManifestService(NativeManifestService(), cache)
val hlsManifestService = HlsManifestService(streamService, proxyHttpClient)
val suggestionService = CachedSuggestionService(PipePipeSuggestionService(), cache)
val recommendationPrivacyService = RecommendationPrivacyService(SettingsService())
val recommendationInterestService = RecommendationInterestService()
val recommendationEventService = RecommendationEventService(recommendationInterestService, recommendationPrivacyService)
val historyService = HistoryService(recommendationEventService)
val historyService = HistoryService()
val subscriptionsService = SubscriptionsService()
val subscriptionFeedService = SubscriptionFeedService(subscriptionsService, channelService, cache)
val subscriptionShortsFeedService = SubscriptionShortsFeedService(
subscriptionsService,
channelService,
SubscriptionShortsBlendService(trendingService, SubscriptionShortsSignalService(recommendationEventService)),
SubscriptionShortsBlendService(trendingService),
cache,
)
val notificationsService = NotificationsService(subscriptionFeedService)
val playlistService = PlaylistService()
val watchLaterService = WatchLaterService(recommendationEventService)
val watchLaterService = WatchLaterService()
val progressService = ProgressService()
val favoritesService = FavoritesService(recommendationEventService)
val favoritesService = FavoritesService()
val settingsService = SettingsService()
val searchHistoryService = SearchHistoryService()
val blockedService = BlockedService(recommendationEventService)
val blockedService = BlockedService()
val bugReportService = BugReportService()
val recommendationFeedbackService = RecommendationFeedbackService(recommendationEventService)
val recommendationOnboardingService = RecommendationOnboardingService()
val recommendationSignalContextService = HomeRecommendationSignalContextService(subscriptionsService, historyService, favoritesService)
val youtubeTakeoutImportService = YoutubeTakeoutFactory.create(subscriptionsService, playlistService, historyService, favoritesService, watchLaterService)
val recommendationPoolResolverDependencies = HomeRecommendationPoolResolverDependencies(
subscriptionsService = subscriptionsService,
subscriptionFeedService = subscriptionFeedService,
subscriptionShortsFeedService = subscriptionShortsFeedService,
historyService = historyService,
playlistService = playlistService,
favoritesService = favoritesService,
watchLaterService = watchLaterService,
blockedService = blockedService,
feedbackService = recommendationFeedbackService,
eventService = recommendationEventService,
feedHistoryService = dev.typetype.server.services.RecommendationFeedHistoryService(),
signalContextService = recommendationSignalContextService,
trendingService = trendingService,
searchService = searchService,
streamService = streamService,
cache = cache,
)
private val homeRecommendationServices = createHomeRecommendationServices(cache, recommendationPoolResolverDependencies, recommendationPrivacyService)
val recommendationFeedHistoryService = homeRecommendationServices.feedHistoryService
private val homeRecommendationServices = createHomeRecommendationServices(cache, recommendationPoolResolverDependencies)
val homeRecommendationService = homeRecommendationServices.recommendationService
}
17 changes: 0 additions & 17 deletions src/main/kotlin/dev/typetype/server/db/DatabaseFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ import dev.typetype.server.db.tables.WatchLaterTable
import dev.typetype.server.db.tables.AdminSettingsTable
import dev.typetype.server.db.tables.PasswordResetTable
import dev.typetype.server.db.tables.NotificationStatesTable
import dev.typetype.server.db.tables.RecommendationEventsTable
import dev.typetype.server.db.tables.RecommendationFeedbackTable
import dev.typetype.server.db.tables.RecommendationFeedHistoryTable
import dev.typetype.server.db.tables.RecommendationOnboardingPreferencesTable
import dev.typetype.server.db.tables.RecommendationOnboardingStateTable
import dev.typetype.server.db.tables.UserChannelInterestTable
import dev.typetype.server.db.tables.UserTopicInterestTable
import dev.typetype.server.db.tables.YoutubeTakeoutImportJobsTable
import dev.typetype.server.db.tables.YoutubeTakeoutPlaylistKeysTable
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -64,13 +57,6 @@ object DatabaseFactory {
BlockedChannelsTable,
BlockedVideosTable,
PasswordResetTable,
RecommendationFeedbackTable,
RecommendationEventsTable,
RecommendationFeedHistoryTable,
RecommendationOnboardingStateTable,
RecommendationOnboardingPreferencesTable,
UserChannelInterestTable,
UserTopicInterestTable,
YoutubeTakeoutImportJobsTable,
YoutubeTakeoutPlaylistKeysTable,
BugReportsTable,
Expand All @@ -82,7 +68,6 @@ object DatabaseFactory {
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS default_subtitle_language TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS default_audio_language TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS prefer_original_language BOOLEAN NOT NULL DEFAULT false")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS recommendation_personalization_enabled BOOLEAN NOT NULL DEFAULT true")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS subscription_sync_interval INTEGER NOT NULL DEFAULT 0")
exec("ALTER TABLE history ADD COLUMN IF NOT EXISTS channel_avatar TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE history ADD COLUMN IF NOT EXISTS user_id TEXT NOT NULL DEFAULT ''")
Expand All @@ -103,8 +88,6 @@ object DatabaseFactory {
exec("ALTER TABLE users ADD COLUMN IF NOT EXISTS avatar_code TEXT")
exec("ALTER TABLE users ADD COLUMN IF NOT EXISTS public_username TEXT")
exec("ALTER TABLE users ADD COLUMN IF NOT EXISTS bio TEXT")
exec("ALTER TABLE recommendation_events ADD COLUMN IF NOT EXISTS watch_duration_ms BIGINT")
exec("ALTER TABLE recommendation_events ADD COLUMN IF NOT EXISTS context_key TEXT")
exec("ALTER TABLE youtube_takeout_import_jobs ADD COLUMN IF NOT EXISTS preview_json TEXT")
exec("ALTER TABLE bug_reports ALTER COLUMN github_issue_url TYPE TEXT")
DatabaseSessionAuthMigration.apply()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ object DatabaseIndexMigrations {
exec("CREATE INDEX IF NOT EXISTS idx_watch_later_user_added_at ON watch_later (user_id, added_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_search_history_user_searched_at ON search_history (user_id, searched_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_playlists_user_created_at ON playlists (user_id, created_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_reco_feedback_user_created_at ON recommendation_feedback (user_id, created_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_reco_events_user_event_occurred ON recommendation_events (user_id, event_type, occurred_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_reco_events_user_occurred ON recommendation_events (user_id, occurred_at DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_reco_feed_history_user_last_shown ON recommendation_feed_history (user_id, last_shown DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_user_channel_interest_user_score ON user_channel_interest (user_id, score DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_user_topic_interest_user_score ON user_topic_interest (user_id, score DESC)")
exec("CREATE INDEX IF NOT EXISTS idx_history_title_trgm ON history USING gin (lower(title) gin_trgm_ops)")
exec("CREATE INDEX IF NOT EXISTS idx_history_channel_name_trgm ON history USING gin (lower(channel_name) gin_trgm_ops)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ object SettingsTable : Table("settings") {
val defaultSubtitleLanguage = text("default_subtitle_language").default("")
val defaultAudioLanguage = text("default_audio_language").default("")
val preferOriginalLanguage = bool("prefer_original_language").default(false)
val recommendationPersonalizationEnabled = bool("recommendation_personalization_enabled").default(true)
override val primaryKey = PrimaryKey(userId)
}
1 change: 0 additions & 1 deletion src/main/kotlin/dev/typetype/server/models/SettingsItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ data class SettingsItem(
val defaultSubtitleLanguage: String = "",
val defaultAudioLanguage: String = "",
val preferOriginalLanguage: Boolean = false,
val recommendationPersonalizationEnabled: Boolean = true,
)
4 changes: 0 additions & 4 deletions src/main/kotlin/dev/typetype/server/routes/UserDataRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,11 @@ internal fun Route.userDataRoutes(
settingsRoutes(svc.settingsService, authService)
searchHistoryRoutes(svc.searchHistoryService, authService)
blockedRoutes(svc.blockedService, authService)
recommendationEventsRoutes(svc.recommendationEventService, authService)
recommendationFeedbackRoutes(svc.recommendationFeedbackService, authService)
recommendationOnboardingRoutes(svc.recommendationOnboardingService, authService)
notificationsRoutes(svc.notificationsService, authService)
youtubeTakeoutImportRoutes(svc.youtubeTakeoutImportService, authService)
profileRoutes(profileService, avatarService, authService)
bugReportRoutes(bugReportService, authService)
restoreRoutes(restoreService, authService)
homeRecommendationRoutes(svc.homeRecommendationService, authService)
homeRecommendationShortsRoutes(svc.homeRecommendationService, authService)
homeRecommendationMetricsRoutes(svc.homeRecommendationService, authService)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import org.jetbrains.exposed.v1.jdbc.selectAll
private const val SCOPE_USER = "user"
private const val SCOPE_GLOBAL = "global"

class BlockedService(private val eventService: RecommendationEventService? = null) {
class BlockedService {
suspend fun getChannels(userId: String): List<BlockedItem> = DatabaseFactory.query {
BlockedChannelsTable.selectAll()
.where { (BlockedChannelsTable.userId eq userId) or (BlockedChannelsTable.scope eq SCOPE_GLOBAL) }
Expand Down Expand Up @@ -55,7 +55,6 @@ class BlockedService(private val eventService: RecommendationEventService? = nul
it[blockedAt] = now
}
}
eventService?.add(userId, "block_channel", null, url, name, null, null)
return BlockedItem(url = url, name = name, thumbnailUrl = thumbnailUrl, blockedAt = now)
}

Expand All @@ -69,7 +68,6 @@ class BlockedService(private val eventService: RecommendationEventService? = nul
it[blockedAt] = now
}
}
eventService?.add(userId, "block_video", url, null, null, null, null)
return BlockedItem(url = url, blockedAt = now)
}

Expand Down
16 changes: 1 addition & 15 deletions src/main/kotlin/dev/typetype/server/services/FavoritesService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.selectAll

class FavoritesService(
private val eventService: RecommendationEventService? = null,
private val privacyService: RecommendationPrivacyService = RecommendationPrivacyService(SettingsService()),
) {
class FavoritesService {

suspend fun getAll(userId: String): List<FavoriteItem> = DatabaseFactory.query {
FavoritesTable.selectAll()
Expand All @@ -32,17 +29,6 @@ class FavoritesService(
it[favoritedAt] = now
}
}
if (privacyService.isPersonalizationEnabled(userId)) {
eventService?.add(
userId = userId,
eventType = "favorite",
videoUrl = videoUrl,
uploaderUrl = null,
title = null,
watchRatio = null,
watchDurationMs = null,
)
}
return FavoriteItem(videoUrl = videoUrl, favoritedAt = now)
}

Expand Down
17 changes: 1 addition & 16 deletions src/main/kotlin/dev/typetype/server/services/HistoryService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import org.jetbrains.exposed.v1.jdbc.batchInsert
import org.jetbrains.exposed.v1.jdbc.selectAll
import java.util.UUID

class HistoryService(
private val eventService: RecommendationEventService? = null,
private val privacyService: RecommendationPrivacyService = RecommendationPrivacyService(SettingsService()),
) {
class HistoryService {
suspend fun search(userId: String, q: String?, from: Long?, to: Long?, limit: Int, offset: Int): Pair<List<HistoryItem>, Long> = DatabaseFactory.query {
val query = HistoryTable.selectAll().where { HistoryTable.userId eq userId }
if (!q.isNullOrBlank()) {
Expand Down Expand Up @@ -90,18 +87,6 @@ class HistoryService(
it[HistoryTable.watchedAt] = watchedAt
}
}
val ratio = if (item.duration > 0) progress.toDouble() / item.duration.toDouble() else 0.0
if (privacyService.isPersonalizationEnabled(userId)) {
eventService?.add(
userId = userId,
eventType = "watch",
videoUrl = item.url,
uploaderUrl = item.channelUrl,
title = item.title,
watchRatio = ratio.coerceIn(0.0, 1.0),
watchDurationMs = progress * 1_000L,
)
}
return item.copy(id = id, progress = progress, watchedAt = watchedAt)
}
}
Loading