@@ -17,6 +17,7 @@ import org.schabi.newpipe.database.subscription.NotificationMode
1717import org.schabi.newpipe.database.subscription.SubscriptionEntity
1818import org.schabi.newpipe.extractor.Info
1919import org.schabi.newpipe.extractor.NewPipe
20+ import org.schabi.newpipe.extractor.ServiceList
2021import org.schabi.newpipe.extractor.feed.FeedInfo
2122import org.schabi.newpipe.extractor.stream.StreamInfoItem
2223import org.schabi.newpipe.ktx.getStringSafe
@@ -90,6 +91,10 @@ class FeedLoadManager(private val context: Context) {
9091 else -> feedDatabaseManager.outdatedSubscriptionsForGroup(groupId, outdatedThreshold)
9192 }
9293
94+ // like `currentProgress`, but counts the number of YouTube extractions that have begun, so
95+ // they can be properly throttled every once in a while (see doOnNext below)
96+ val youtubeExtractionCount = AtomicInteger ()
97+
9398 return outdatedSubscriptions
9499 .take(1 )
95100 .doOnNext {
@@ -105,6 +110,15 @@ class FeedLoadManager(private val context: Context) {
105110 .observeOn(Schedulers .io())
106111 .flatMap { Flowable .fromIterable(it) }
107112 .takeWhile { ! cancelSignal.get() }
113+ .doOnNext { subscriptionEntity ->
114+ // throttle YouTube extractions once every BATCH_SIZE to avoid being rate limited
115+ if (subscriptionEntity.serviceId == ServiceList .YouTube .serviceId) {
116+ val previousCount = youtubeExtractionCount.getAndIncrement()
117+ if (previousCount != 0 && previousCount % BATCH_SIZE == 0 ) {
118+ Thread .sleep(DELAY_BETWEEN_BATCHES_MILLIS .random())
119+ }
120+ }
121+ }
108122 .parallel(PARALLEL_EXTRACTIONS , PARALLEL_EXTRACTIONS * 2 )
109123 .runOn(Schedulers .io(), PARALLEL_EXTRACTIONS * 2 )
110124 .filter { ! cancelSignal.get() }
@@ -328,7 +342,19 @@ class FeedLoadManager(private val context: Context) {
328342 /* *
329343 * How many extractions will be running in parallel.
330344 */
331- private const val PARALLEL_EXTRACTIONS = 6
345+ private const val PARALLEL_EXTRACTIONS = 3
346+
347+ /* *
348+ * How many YouTube extractions to perform before waiting [DELAY_BETWEEN_BATCHES_MILLIS]
349+ * to avoid being rate limited
350+ */
351+ private const val BATCH_SIZE = 50
352+
353+ /* *
354+ * Wait a random delay in this range once every [BATCH_SIZE] YouTube extractions to avoid
355+ * being rate limited
356+ */
357+ private val DELAY_BETWEEN_BATCHES_MILLIS = (6000L .. 12000L )
332358
333359 /* *
334360 * Number of items to buffer to mass-insert in the database.
0 commit comments