@@ -3,9 +3,11 @@ import co.touchlab.kermit.Logger
33import com.kdroid.gplayscrapper.core.model.GooglePlayApplicationInfo
44import com.kdroid.gplayscrapper.services.getGooglePlayApplicationInfo
55import io.github.kdroidfilter.database.core.AppCategory
6+ import io.github.kdroidfilter.database.core.policies.AppPolicy
67import io.github.kdroidfilter.database.downloader.DatabaseDownloader
78import io.github.kdroidfilter.database.store.*
89import kotlinx.coroutines.runBlocking
10+ import kotlinx.serialization.json.Json
911import java.nio.file.Files
1012import java.nio.file.Path
1113import java.time.LocalDateTime
@@ -14,6 +16,12 @@ import java.time.format.DateTimeFormatter
1416object SqliteStoreBuilder {
1517 private val logger = Logger .withTag(" SqliteStoreBuilder" )
1618
19+ // Extension function to convert Boolean to Long (1 for true, 0 for false)
20+ private fun Boolean.toSqliteInt (): Long = if (this ) 1L else 0L
21+
22+ // Extension function to convert nullable Boolean to Long (1 for true, 0 for false or null)
23+ private fun Boolean?.toSqliteInt (): Long = if (this == true ) 1L else 0L
24+
1725 fun buildDatabase (
1826 appPoliciesDir : Path ,
1927 outputDbPath : Path ,
@@ -79,17 +87,47 @@ object SqliteStoreBuilder {
7987 logger.i { " ✅ Inserted version info: $releaseName " }
8088 }
8189
90+ private val json = Json {
91+ classDiscriminator = " type"
92+ ignoreUnknownKeys = true
93+ }
94+
95+ private fun loadPolicies (appPoliciesDir : Path ): Map <String , AppPolicy > {
96+ val policies = mutableMapOf<String , AppPolicy >()
97+
98+ Files .walk(appPoliciesDir)
99+ .filter { Files .isRegularFile(it) && it.toString().endsWith(" .json" ) }
100+ .forEach { file ->
101+ try {
102+ val content = Files .readString(file)
103+ val policy = json.decodeFromString(AppPolicy .serializer(), content)
104+ policies[policy.packageName] = policy
105+ logger.d { " Loaded policy for ${policy.packageName} : isRecommendedInStore=${policy.isRecommendedInStore} " }
106+ } catch (e: Exception ) {
107+ logger.w { " Failed to load policy from $file : ${e.message} " }
108+ }
109+ }
110+
111+ logger.i { " ✅ Loaded ${policies.size} policies" }
112+ return policies
113+ }
114+
82115 private fun upsertPackages (dir : Path , outputDbPath : Path , language : String = "en", country : String = "us") {
83116 // Get existing applications to avoid re-fetching
84117 val existingApps = mutableMapOf<String , GooglePlayApplicationInfo ?>()
85118
119+ // Load app policies to get isRecommendedInStore values
120+ val policies = loadPolicies(dir)
121+
86122 var count = 0
87123 Files .walk(dir)
88124 .filter { Files .isRegularFile(it) && it.toString().endsWith(" .json" ) }
89125 .forEach { file ->
90- val packageName = file.fileName.toString().substringBeforeLast(" ." )
91- val categoryName = file.parent.fileName.toString()
92- .uppercase().replace(' -' , ' _' )
126+ // Get policy for this file to extract packageName and category
127+ val content = Files .readString(file)
128+ val policy = json.decodeFromString(AppPolicy .serializer(), content)
129+ val packageName = policy.packageName
130+ val categoryName = policy.category.name
93131
94132 // Get or create the category
95133 val appCategoriesQueries = App_categoriesQueries (createSqlDriver(outputDbPath))
@@ -118,7 +156,8 @@ object SqliteStoreBuilder {
118156 packageName = packageName,
119157 applicationsQueries = applicationsQueries,
120158 developersQueries = developersQueries,
121- categoryId = categoryId
159+ categoryId = categoryId,
160+ policies = policies
122161 )
123162
124163 count++
@@ -151,10 +190,16 @@ object SqliteStoreBuilder {
151190 var processedCount = 0
152191 var addedCount = 0
153192
193+ // Load app policies to get isRecommendedInStore values
194+ val policies = loadPolicies(dir)
195+
154196 Files .walk(dir)
155197 .filter { Files .isRegularFile(it) && it.toString().endsWith(" .json" ) }
156198 .forEach { file ->
157- val packageName = file.fileName.toString().substringBeforeLast(" ." )
199+ // Get policy for this file to extract packageName and category
200+ val content = Files .readString(file)
201+ val policy = json.decodeFromString(AppPolicy .serializer(), content)
202+ val packageName = policy.packageName
158203 processedCount++
159204
160205 // Check if the package already exists in the database
@@ -165,8 +210,7 @@ object SqliteStoreBuilder {
165210
166211 // Only process if the package doesn't exist
167212 if (existingApp == null ) {
168- val categoryName = file.parent.fileName.toString()
169- .uppercase().replace(' -' , ' _' )
213+ val categoryName = policy.category.name
170214
171215 // Get or create the category
172216 val appCategoriesQueries = App_categoriesQueries (createSqlDriver(outputDbPath))
@@ -191,7 +235,8 @@ object SqliteStoreBuilder {
191235 packageName = packageName,
192236 applicationsQueries = applicationsQueries,
193237 developersQueries = developersQueries,
194- categoryId = categoryId
238+ categoryId = categoryId,
239+ policies = policies
195240 )
196241
197242 addedCount++
@@ -238,7 +283,8 @@ object SqliteStoreBuilder {
238283 packageName : String ,
239284 applicationsQueries : ApplicationsQueries ,
240285 developersQueries : DevelopersQueries ,
241- categoryId : Long
286+ categoryId : Long ,
287+ policies : Map <String , AppPolicy > = emptyMap()
242288 ): Long {
243289 // Get or create the developer
244290 val developer = developersQueries
@@ -276,13 +322,13 @@ object SqliteStoreBuilder {
276322 reviews = appInfo.reviews,
277323 histogram = appInfo.histogram.toString(),
278324 price = appInfo.price,
279- free = if ( appInfo.free) 1 else 0 ,
325+ free = appInfo.free.toSqliteInt() ,
280326 currency = appInfo.currency,
281- sale = if ( appInfo.sale) 1 else 0 ,
327+ sale = appInfo.sale.toSqliteInt() ,
282328 sale_time = null ,
283329 original_price = appInfo.originalPrice,
284330 sale_text = appInfo.saleText,
285- offers_iap = if ( appInfo.offersIAP) 1 else 0 ,
331+ offers_iap = appInfo.offersIAP.toSqliteInt() ,
286332 in_app_product_price = appInfo.inAppProductPrice,
287333 developer_id = developer.id,
288334 privacy_policy = appInfo.privacyPolicy,
@@ -295,9 +341,9 @@ object SqliteStoreBuilder {
295341 video_image = appInfo.videoImage,
296342 content_rating = appInfo.contentRating,
297343 content_rating_description = appInfo.contentRatingDescription,
298- ad_supported = if ( appInfo.adSupported) 1 else 0 ,
299- contains_ads = if ( appInfo.containsAds) 1 else 0 ,
300- is_recommended_in_store = 0 ,
344+ ad_supported = appInfo.adSupported.toSqliteInt() ,
345+ contains_ads = appInfo.containsAds.toSqliteInt() ,
346+ is_recommended_in_store = (policies[packageName]?.isRecommendedInStore ? : false ).toSqliteInt() ,
301347 released = appInfo.released,
302348 updated = appInfo.updated,
303349 version = appInfo.version,
0 commit comments