11package org.jetbrains.kotlinconf.backend.services
22
33import io.ktor.client.HttpClient
4- import io.ktor.client.call.body
5- import io.ktor.client.request.get
6- import io.ktor.client.request.headers
74import io.ktor.utils.io.core.Closeable
8- import kotlinx.coroutines.Dispatchers
9- import kotlinx.coroutines.GlobalScope
10- import kotlinx.coroutines.delay
11- import kotlinx.coroutines.flow.MutableSharedFlow
12- import kotlinx.coroutines.flow.first
13- import kotlinx.coroutines.launch
145import org.jetbrains.kotlinconf.SessionId
15- import org.jetbrains.kotlinconf.backend.model.GitHubItem
166import org.jetbrains.kotlinconf.backend.utils.ConferenceConfig
177import org.slf4j.LoggerFactory
188
@@ -23,74 +13,87 @@ class VideoUrlService(private val client: HttpClient, config: ConferenceConfig)
2313 private val folder: String = config.videosFolder
2414 private val updateInterval = config.sessionizeInterval
2515
26- private val videoUrls = MutableSharedFlow <Map <SessionId , String >>(replay = 1 )
16+ private val videoUrls: Map <SessionId , String > = mapOf (
17+ SessionId (" 857088" ) to " https://www.youtube.com/watch?v=F5NaqGF9oT4" ,
18+ SessionId (" 857092" ) to " https://www.youtube.com/watch?v=E4f5PyNmGLo" ,
19+ SessionId (" 814508" ) to " https://www.youtube.com/watch?v=NcAW-FZtpzk" ,
20+ SessionId (" 814689" ) to " https://www.youtube.com/watch?v=WTWW7OOHQIw" ,
21+ SessionId (" 793515" ) to " https://www.youtube.com/watch?v=5lkZj4v4-ks" ,
22+ SessionId (" 793888" ) to " https://www.youtube.com/watch?v=mQhtLCMiUMA" ,
23+ SessionId (" 795861" ) to " https://www.youtube.com/watch?v=bkd6EAPIVe0" ,
24+ SessionId (" 786515" ) to " https://www.youtube.com/watch?v=kIEBQ_czdxs" ,
25+ SessionId (" 762779" ) to " https://www.youtube.com/watch?v=IUrA3mDSWZQ" ,
26+ SessionId (" 794504" ) to " https://www.youtube.com/watch?v=Hy5TOyDDics" ,
27+ SessionId (" 795179" ) to " https://www.youtube.com/watch?v=QExksqeNWbY" ,
28+ SessionId (" 800713" ) to " https://www.youtube.com/watch?v=9KdP2idt6LE" ,
29+ SessionId (" 867231" ) to " https://www.youtube.com/watch?v=D3hCBrxJHLo" ,
30+ SessionId (" 812350" ) to " https://www.youtube.com/watch?v=434WFSiYj9k" ,
31+ SessionId (" 792910" ) to " https://www.youtube.com/watch?v=zBgb0z1pQkM" ,
32+ SessionId (" 795318" ) to " https://www.youtube.com/watch?v=ufQvrZmQw_I" ,
33+ SessionId (" 793244" ) to " https://www.youtube.com/watch?v=qpM3_ymNkP8" ,
34+ SessionId (" 779171" ) to " https://www.youtube.com/watch?v=JKLqQiYh8GQ" ,
35+ SessionId (" 793302" ) to " https://www.youtube.com/watch?v=z-u99yZFn5o" ,
36+ SessionId (" 796310" ) to " https://www.youtube.com/watch?v=M9Nni0Qywyo" ,
37+ SessionId (" 800297" ) to " https://www.youtube.com/watch?v=YKTlW8Qkj0w" ,
38+ SessionId (" 774874" ) to " https://www.youtube.com/watch?v=XcxqhmG_bdg" ,
39+ SessionId (" 795195" ) to " https://www.youtube.com/watch?v=bKwdgMKyFOY" ,
40+ SessionId (" 816767" ) to " https://www.youtube.com/watch?v=a8uMQk4R6jQ" ,
41+ SessionId (" 779829" ) to " https://www.youtube.com/watch?v=Q4oj9fkaDCs" ,
42+ SessionId (" 836755" ) to " https://www.youtube.com/watch?v=Zw7eJFciwXg" ,
43+ SessionId (" 856501" ) to " https://www.youtube.com/watch?v=O8WQCrdza8E" ,
44+ SessionId (" 795897" ) to " https://www.youtube.com/watch?v=PW_qc6EUBQE" ,
45+ SessionId (" 794336" ) to " https://www.youtube.com/watch?v=fv-vw1huJ-4" ,
46+ SessionId (" 783886" ) to " https://www.youtube.com/watch?v=UebhKUdO2sQ" ,
47+ SessionId (" 793235" ) to " https://www.youtube.com/watch?v=3vaAVtnrzAM" ,
48+ SessionId (" 885501" ) to " https://www.youtube.com/watch?v=JxTIZAEos8Y" ,
49+ SessionId (" 793709" ) to " https://www.youtube.com/watch?v=vewgb-vyJME" ,
50+ SessionId (" 795839" ) to " https://www.youtube.com/watch?v=vMNCAryfJys" ,
51+ SessionId (" 800068" ) to " https://www.youtube.com/watch?v=57Ed70ROmm4" ,
52+ SessionId (" 795976" ) to " https://www.youtube.com/watch?v=hxEM5J6QfLY" ,
53+ SessionId (" 812314" ) to " https://www.youtube.com/watch?v=2Vp2QeBZkfo" ,
54+ SessionId (" 812209" ) to " https://www.youtube.com/watch?v=ojuBhKRzyL8" ,
55+ SessionId (" 796169" ) to " https://www.youtube.com/watch?v=FXGT6HbBXNw" ,
56+ SessionId (" 779345" ) to " https://www.youtube.com/watch?v=4A6aLK2KznU" ,
57+ SessionId (" 858141" ) to " https://www.youtube.com/watch?v=5Sc3Qdb0XoQ" ,
58+ SessionId (" 781372" ) to " https://www.youtube.com/watch?v=9P7qUGi5_gc" ,
59+ SessionId (" 797367" ) to " https://www.youtube.com/watch?v=dcgwPpVT74g" ,
60+ SessionId (" 795941" ) to " https://www.youtube.com/watch?v=sDA28kH6AIc" ,
61+ SessionId (" 795620" ) to " https://www.youtube.com/watch?v=n0LpCCv3VEY" ,
62+ SessionId (" 788999" ) to " https://www.youtube.com/watch?v=qJB5iX2cOu0" ,
63+ SessionId (" 799261" ) to " https://www.youtube.com/watch?v=QTX5_JV4TVU" ,
64+ SessionId (" 779451" ) to " https://www.youtube.com/watch?v=HSIhkB5bGJs" ,
65+ SessionId (" 759131" ) to " https://www.youtube.com/watch?v=OuX5325yq_I" ,
66+ SessionId (" 788419" ) to " https://www.youtube.com/watch?v=P0mo8Tzrapo" ,
67+ SessionId (" 774286" ) to " https://www.youtube.com/watch?v=vWIDRH6aQfI" ,
68+ SessionId (" 812400" ) to " https://www.youtube.com/watch?v=RJtiFt5pbfs" ,
69+ SessionId (" 794830" ) to " https://www.youtube.com/watch?v=xgfeqj8UyVA" ,
70+ SessionId (" 795546" ) to " https://www.youtube.com/watch?v=QSoG8OaCSgw" ,
71+ SessionId (" 857571" ) to " https://www.youtube.com/watch?v=bC_grxuSO08" ,
72+ SessionId (" 811578" ) to " https://www.youtube.com/watch?v=clDGqPfaIto" ,
73+ SessionId (" 795023" ) to " https://www.youtube.com/watch?v=lcqtRQ5Fou8" ,
74+ SessionId (" 787545" ) to " https://www.youtube.com/watch?v=OyEfB6Q4Y0s" ,
75+ SessionId (" 795778" ) to " https://www.youtube.com/watch?v=2Eyq1VhBxUg" ,
76+ SessionId (" 856531" ) to " https://www.youtube.com/watch?v=-CznWwKD-WE" ,
77+ SessionId (" 793518" ) to " https://www.youtube.com/watch?v=z_IO2_XeW2Q" ,
78+ SessionId (" 811915" ) to " https://www.youtube.com/watch?v=K2PN03AepC0" ,
79+ SessionId (" 796359" ) to " https://www.youtube.com/watch?v=n6egwuOnGuk" ,
80+ SessionId (" 786540" ) to " https://www.youtube.com/watch?v=AlGWsTXnWsY" ,
81+ SessionId (" 798313" ) to " https://www.youtube.com/watch?v=KEsVNrzPf24" ,
82+ SessionId (" 792693" ) to " https://www.youtube.com/watch?v=l7alNC819MU" ,
83+ SessionId (" 800400" ) to " https://www.youtube.com/watch?v=rKbM3e0OidI" ,
84+ SessionId (" 784566" ) to " https://www.youtube.com/watch?v=O0BqoLcRuJI" ,
85+ SessionId (" 796464" ) to " https://www.youtube.com/watch?v=eryPIdJjBgk" ,
86+ SessionId (" 811421" ) to " https://www.youtube.com/watch?v=jDz_yNZkEzk" ,
87+ SessionId (" 774210" ) to " https://www.youtube.com/watch?v=6jZa4B-If-I" ,
88+ SessionId (" 904371" ) to " https://www.youtube.com/watch?v=Jyj4kdK8a6o" ,
89+ SessionId (" 791121" ) to " https://www.youtube.com/watch?v=SwNTpgp262o" ,
90+ SessionId (" 787342" ) to " https://www.youtube.com/watch?v=uGgK0F3cLEI" ,
91+ SessionId (" 792742" ) to " https://www.youtube.com/watch?v=PY7eOmnOK3s" ,
92+ SessionId (" 782203" ) to " https://www.youtube.com/watch?v=oRKytkr2FOY" ,
93+ )
2794
28- val syncJob = GlobalScope .launch(Dispatchers .IO ) {
29- while (true ) {
30- runCatching { updateVideoUrls() }.onFailure {
31- log.error(" Failed to update video URLs" , it)
32- }
33-
34- delay(updateInterval * 1000 )
35- }
36- }
37-
38- suspend fun getVideoUrls (): Map <SessionId , String > = videoUrls.first()
39-
40- suspend fun updateVideoUrls () {
41- videoUrls.emit(downloadVideoUrls())
42- }
43-
44- private suspend fun downloadVideoUrls (): Map <SessionId , String > {
45- val url = " https://api.github.com/repos/$repo /contents/$folder ?ref=$branch "
46-
47- val contents: List <GitHubItem > = try {
48- client.get(url) {
49- headers {
50- append(" Accept" , " application/vnd.github.v3+json" )
51- }
52- }.body()
53- } catch (cause: Throwable ) {
54- log.warn(" Error fetching repository contents: ${cause.message} " )
55- return emptyMap()
56- }
57-
58- val urlsFile = contents
59- .find { it.type == " file" && it.name == " urls.csv" }
60- ?.download_url ? : run {
61- log.warn(" urls.csv file not found in $folder " )
62- return emptyMap()
63- }
64-
65- return try {
66- val content = client.get(urlsFile).body<String >()
67- parseVideoUrls(content)
68- } catch (cause: Throwable ) {
69- log.warn(" Error downloading $urlsFile : ${cause.message} " )
70- emptyMap()
71- }
72- }
73-
74- internal fun parseVideoUrls (csvContent : String ): Map <SessionId , String > {
75- val result = mutableMapOf<SessionId , String >()
76-
77- csvContent.lineSequence()
78- .filter { it.isNotBlank() }
79- .forEach { line ->
80- val parts = line.split(" ;" , limit = 2 )
81- if (parts.size == 2 ) {
82- val sessionId = parts[0 ].trim()
83- val videoUrl = parts[1 ].trim()
84- if (sessionId.isNotEmpty() && videoUrl.isNotEmpty()) {
85- result[SessionId (sessionId)] = videoUrl
86- }
87- }
88- }
89-
90- return result
91- }
95+ suspend fun getVideoUrls (): Map <SessionId , String > = videoUrls
9296
9397 override fun close () {
94- syncJob.cancel()
9598 }
9699}
0 commit comments