Skip to content

Commit 93a91d5

Browse files
authored
Merge pull request #32 from kdroidFilter/dev
Enhance `SqliteStoreBuilder` with app policy loading and `isRecommendedInStore` processing
2 parents 8554af8 + db7d312 commit 93a91d5

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

generators/store/src/jvmMain/kotlin/SqliteStoreBuilder.kt

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import co.touchlab.kermit.Logger
33
import com.kdroid.gplayscrapper.core.model.GooglePlayApplicationInfo
44
import com.kdroid.gplayscrapper.services.getGooglePlayApplicationInfo
55
import io.github.kdroidfilter.database.core.AppCategory
6+
import io.github.kdroidfilter.database.core.policies.AppPolicy
67
import io.github.kdroidfilter.database.downloader.DatabaseDownloader
78
import io.github.kdroidfilter.database.store.*
89
import kotlinx.coroutines.runBlocking
10+
import kotlinx.serialization.json.Json
911
import java.nio.file.Files
1012
import java.nio.file.Path
1113
import java.time.LocalDateTime
@@ -14,6 +16,12 @@ import java.time.format.DateTimeFormatter
1416
object 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,

generators/store/src/jvmMain/kotlin/SqliteStoreExtractor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ fun main(args: Array<String>) {
2828
} else {
2929
println("Building or updating databases (downloading existing ones if available)...")
3030
}
31-
SqliteStoreBuilder.buildOrUpdateMultiLanguageDatabases(policiesDir, baseDbPath, forceFromScratch)
31+
SqliteStoreBuilder.buildOrUpdateMultiLanguageDatabases(policiesDir, baseDbPath, true)
3232
}
3333
}

0 commit comments

Comments
 (0)