Jelajahi Sumber

added getting weather by location

Vadik Sirekanyan 5 tahun lalu
induk
melakukan
0aafa6870c

+ 5 - 0
build.gradle.kts

@@ -2,6 +2,7 @@ plugins {
     val kotlinVersion = "1.4.10"
     kotlin("jvm") version kotlinVersion
     kotlin("plugin.serialization") version kotlinVersion
+    application
 }
 
 group = "com.sirekanyan"
@@ -20,6 +21,10 @@ dependencies {
     testImplementation("junit:junit:4.13")
 }
 
+application {
+    mainClassName = "com.sirekanyan.andersrobot.Main"
+}
+
 tasks {
     compileKotlin {
         kotlinOptions.jvmTarget = "1.8"

+ 17 - 14
src/main/kotlin/com/sirekanyan/andersrobot/AndersRobot.kt

@@ -19,7 +19,7 @@ val adminId = Config[ADMIN_ID].toLong()
 
 class AndersRobot : DefaultAbsSender(DefaultBotOptions()), LongPollingBot {
 
-    private val weather = WeatherApi()
+    private val api = WeatherApi()
     private val repository = CityRepositoryImpl(Config[DB_URL])
 
     override fun getBotUsername(): String = botName
@@ -46,30 +46,33 @@ class AndersRobot : DefaultAbsSender(DefaultBotOptions()), LongPollingBot {
         val addCityCommand = getAddCityCommand(message.text)
         val delCityCommand = getDelCityCommand(message.text)
         when {
+            message.hasLocation() -> {
+                val weather = api.getWeather(message.location, language)
+                if (weather == null) {
+                    sendText(chatId, "Не знаю такого места")
+                } else {
+                    sendWeather(chatId, weather, accuracy)
+                }
+            }
             !cityCommand.isNullOrEmpty() -> {
-                val temperature = weather.getTemperature(cityCommand, language)
-                if (temperature == null) {
+                val weather = api.getWeather(cityCommand, language)
+                if (weather == null) {
                     sendText(chatId, "Не знаю такого города")
                 } else {
-                    val text = temperature.format(accuracy)
-                    val icon = temperature.findImageFile()
-                    if (icon != null) {
-                        sendSticker(chatId, icon)
-                    }
-                    sendText(chatId, text)
+                    sendWeather(chatId, weather, accuracy)
                 }
             }
             !addCityCommand.isNullOrEmpty() -> {
-                val temperature = weather.getTemperature(addCityCommand, language)
-                if (temperature == null) {
+                val weather = api.getWeather(addCityCommand, language)
+                if (weather == null) {
                     sendText(chatId, "Не знаю такого города")
                 } else {
-                    repository.putCity(chatId, temperature.id)
+                    repository.putCity(chatId, weather.id)
                     showWeather(chatId, accuracy, language)
                 }
             }
             !delCityCommand.isNullOrEmpty() -> {
-                val temperature = weather.getTemperature(delCityCommand, language)
+                val temperature = api.getWeather(delCityCommand, language)
                 when {
                     temperature == null -> sendText(chatId, "Не знаю такого города")
                     repository.deleteCity(chatId, temperature.id) -> sendText(chatId, "Удалено")
@@ -88,7 +91,7 @@ class AndersRobot : DefaultAbsSender(DefaultBotOptions()), LongPollingBot {
     private fun showWeather(chatId: Long, accuracy: Int, language: String?) {
         val dbCities = repository.getCities(chatId)
         val cities = if (dbCities.isEmpty()) listOf(DEFAULT_CITY_ID) else dbCities
-        val temperatures = weather.getTemperatures(cities, language)
+        val temperatures = api.getWeathers(cities, language)
         check(temperatures.isNotEmpty())
         sendText(chatId, temperatures.joinToString("\n") { it.format(accuracy) })
     }

+ 1 - 1
src/main/kotlin/com/sirekanyan/andersrobot/api/Weather.kt

@@ -16,7 +16,7 @@ data class Weather(
     data class MainInfo(val temp: Double)
 
     @Serializable
-    data class System(val country: String)
+    data class System(val country: String = "")
 
     @Serializable
     data class Condition(val id: Int)

+ 11 - 5
src/main/kotlin/com/sirekanyan/andersrobot/api/WeatherApi.kt

@@ -8,6 +8,7 @@ import kotlinx.coroutines.async
 import kotlinx.coroutines.runBlocking
 import kotlinx.serialization.decodeFromString
 import kotlinx.serialization.json.Json
+import org.telegram.telegrambots.meta.api.objects.Location
 
 private const val WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather"
 
@@ -17,19 +18,24 @@ class WeatherApi {
     private val apiKey = Config[WEATHER_API_KEY]
     private val comparator = compareBy<Weather> { it.sys.country.toLowerCase().replace("ru", "aa") }.thenBy { it.name }
 
-    fun getTemperature(city: String, language: String?): Weather? = runBlocking {
+    fun getWeather(city: String, language: String?): Weather? = runBlocking {
         println("getting $city")
-        getWeather("q" to city, "lang" to language)
+        fetchWeather("q" to city, "lang" to language)
     }
 
-    fun getTemperatures(cities: List<Long>, language: String?): List<Weather> = runBlocking {
+    fun getWeather(location: Location, language: String?): Weather? = runBlocking {
+        println("getting $location")
+        fetchWeather("lon" to location.longitude, "lat" to location.latitude, "lang" to language)
+    }
+
+    fun getWeathers(cities: List<Long>, language: String?): List<Weather> = runBlocking {
         println("getting $cities")
-        cities.map { city -> async { getWeather("id" to city, "lang" to language) } }
+        cities.map { city -> async { fetchWeather("id" to city, "lang" to language) } }
             .mapNotNull { it.await() }
             .sortedWith(comparator)
     }
 
-    private suspend fun getWeather(vararg params: Pair<String, Any?>): Weather? =
+    private suspend fun fetchWeather(vararg params: Pair<String, Any?>): Weather? =
         try {
             val response: String = httpClient.get(WEATHER_URL) {
                 params.forEach { (k, v) ->

+ 9 - 1
src/main/kotlin/com/sirekanyan/andersrobot/extensions/AbsSender.kt

@@ -1,5 +1,6 @@
 package com.sirekanyan.andersrobot.extensions
 
+import com.sirekanyan.andersrobot.api.Weather
 import org.telegram.telegrambots.meta.api.methods.send.SendMessage
 import org.telegram.telegrambots.meta.api.methods.send.SendSticker
 import org.telegram.telegrambots.meta.api.objects.InputFile
@@ -13,7 +14,14 @@ private val cachedFileIds: MutableMap<File, String> = ConcurrentHashMap()
 fun AbsSender.sendText(chatId: Long, text: String): Message =
     execute(SendMessage(chatId, text))
 
-fun AbsSender.sendSticker(chatId: Long, file: File) {
+fun AbsSender.sendWeather(chatId: Long, weather: Weather, accuracy: Int) {
+    weather.findImageFile()?.let { icon ->
+        sendSticker(chatId, icon)
+    }
+    sendText(chatId, weather.format(accuracy))
+}
+
+private fun AbsSender.sendSticker(chatId: Long, file: File) {
     fun send(f: InputFile) = execute(SendSticker().setChatId(chatId).setSticker(f))
     val cachedFileId = cachedFileIds[file]
     if (cachedFileId == null) {