diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala index 59469be..1b465b5 100644 --- a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala +++ b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala @@ -113,7 +113,7 @@ object Piece { case "weapon" => Weapon(pieceType, job) case "head" => Head(pieceType, job) case "body" => Body(pieceType, job) - case "hands" => Hands(pieceType, job) + case "hand" | "hands" => Hands(pieceType, job) case "legs" => Legs(pieceType, job) case "feet" => Feet(pieceType, job) case "ears" => Ears(pieceType, job) diff --git a/src/main/scala/me/arcanis/ffxivbis/service/bis/BisProvider.scala b/src/main/scala/me/arcanis/ffxivbis/service/bis/BisProvider.scala index d483026..c2b1717 100644 --- a/src/main/scala/me/arcanis/ffxivbis/service/bis/BisProvider.scala +++ b/src/main/scala/me/arcanis/ffxivbis/service/bis/BisProvider.scala @@ -16,7 +16,7 @@ import com.typesafe.scalalogging.StrictLogging import me.arcanis.ffxivbis.messages.BiSProviderMessage import me.arcanis.ffxivbis.models.{BiS, Job, Piece, PieceType} import me.arcanis.ffxivbis.service.bis.parser.Parser -import me.arcanis.ffxivbis.service.bis.parser.impl.{Ariyala, Etro} +import me.arcanis.ffxivbis.service.bis.parser.impl.{Ariyala, Etro, XIVGear} import spray.json._ import java.nio.file.Paths @@ -50,9 +50,12 @@ class BisProvider(context: ActorContext[BiSProviderMessage]) private def get(link: String, job: Job): Future[Seq[Piece]] = try { val url = Uri(link) - val id = Paths.get(link).normalize.getFileName.toString + val id = Paths.get(link).normalize.getFileName.toString - val parser = if (url.authority.host.address().contains("etro")) Etro else Ariyala + val parser = + if (url.authority.host.address().contains("etro")) Etro + else if (url.authority.host.address().contains("xivgear.app")) XIVGear + else Ariyala val uri = parser.uri(url, id) sendRequest(uri, BisProvider.parseBisJsonToPieces(job, parser, getPieceType)) } catch { @@ -81,12 +84,12 @@ object BisProvider { } } - def remapKey(key: String): Option[String] = key match { - case "mainhand" => Some("weapon") - case "chest" => Some("body") - case "ringLeft" | "fingerL" => Some("left ring") - case "ringRight" | "fingerR" => Some("right ring") - case "weapon" | "head" | "body" | "hands" | "legs" | "feet" | "ears" | "neck" | "wrist" | "wrists" => Some(key) - case _ => None + def remapKey(key: String): Option[String] = Some(key.toLowerCase).collect { + case "mainhand" => "weapon" + case "chest" => "body" + case "ringleft" | "fingerl" => "left ring" + case "ringright" | "fingerr" => "right ring" + case "weapon" | "head" | "body" | "hand" | "hands" | "legs" | "feet" | "ears" | "neck" | "wrist" | "wrists" => key + case "hand" => "hands" } } diff --git a/src/main/scala/me/arcanis/ffxivbis/service/bis/parser/impl/XIVGear.scala b/src/main/scala/me/arcanis/ffxivbis/service/bis/parser/impl/XIVGear.scala new file mode 100644 index 0000000..e8a8e30 --- /dev/null +++ b/src/main/scala/me/arcanis/ffxivbis/service/bis/parser/impl/XIVGear.scala @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2022 Evgeniy Alekseev. + * + * This file is part of ffxivbis + * (see https://github.com/arcan1s/ffxivbis). + * + * License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause + */ +package me.arcanis.ffxivbis.service.bis.parser.impl + +import akka.http.scaladsl.model.Uri +import me.arcanis.ffxivbis.models.Job +import me.arcanis.ffxivbis.service.bis.BisProvider +import me.arcanis.ffxivbis.service.bis.parser.Parser +import spray.json.{deserializationError, JsNumber, JsObject} + +import scala.concurrent.{ExecutionContext, Future} + +object XIVGear extends Parser { + + override def parse(job: Job, js: JsObject)(implicit executionContext: ExecutionContext): Future[Map[String, Long]] = + Future { + val set = js.fields.get("items") match { + case Some(JsObject(items)) => items + case other => throw deserializationError(s"Invalid job name $other") + } + set.foldLeft(Map.empty[String, Long]) { + case (acc, (key, JsObject(properties))) => + val pieceId = properties.get("id").collect { case JsNumber(id) => + id.toLong + } + (for ( + piece <- BisProvider.remapKey(key); + id <- pieceId + ) yield (piece, id)).map(acc + _).getOrElse(acc) + case (acc, _) => acc + } + } + + override def uri(root: Uri, id: String): Uri = { + val gearSet = Uri(id).query().get("page").map(_.replace("sl|", "")).getOrElse(id) + root.withHost(s"api.${root.authority.host.address()}").withPath(Uri.Path / "shortlink" / gearSet) + } +} diff --git a/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala b/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala index 7ae9042..b91d5a8 100644 --- a/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala +++ b/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala @@ -52,12 +52,28 @@ object Fixtures { Piece.Ring(pieceType = PieceType.Tome, Job.SGE, "right ring") ) ) + lazy val bis4: BiS = BiS( + Seq( + Piece.Weapon(pieceType = PieceType.Savage ,Job.VPR), + Piece.Head(pieceType = PieceType.Savage, Job.VPR), + Piece.Body(pieceType = PieceType.Savage, Job.VPR), + Piece.Hands(pieceType = PieceType.Tome, Job.VPR), + Piece.Legs(pieceType = PieceType.Tome, Job.VPR), + Piece.Feet(pieceType = PieceType.Savage, Job.VPR), + Piece.Ears(pieceType = PieceType.Tome, Job.VPR), + Piece.Neck(pieceType = PieceType.Savage, Job.VPR), + Piece.Wrist(pieceType = PieceType.Tome, Job.VPR), + Piece.Ring(pieceType = PieceType.Savage, Job.VPR, "left ring"), + Piece.Ring(pieceType = PieceType.Tome, Job.VPR, "right ring") + ) + ) lazy val link: String = "https://ffxiv.ariyala.com/19V5R" lazy val link2: String = "https://ffxiv.ariyala.com/1A0WM" lazy val link3: String = "https://etro.gg/gearset/26a67536-b4ce-4adc-a46a-f70e348bb138" lazy val link4: String = "https://etro.gg/gearset/865fc886-994f-4c28-8fc1-4379f160a916" lazy val link5: String = "https://ffxiv.ariyala.com/1FGU0" + lazy val link6: String = "https://xivgear.app/?page=sl%7Cd65b4776-01e1-4269-af74-0bc6e01ca2ec" lazy val lootWeapon: Piece = Piece.Weapon(pieceType = PieceType.Tome, Job.AnyJob) lazy val lootBody: Piece = Piece.Body(pieceType = PieceType.Savage, Job.AnyJob) diff --git a/src/test/scala/me/arcanis/ffxivbis/service/bis/BisProviderTest.scala b/src/test/scala/me/arcanis/ffxivbis/service/bis/BisProviderTest.scala index 987cb5c..0358c08 100644 --- a/src/test/scala/me/arcanis/ffxivbis/service/bis/BisProviderTest.scala +++ b/src/test/scala/me/arcanis/ffxivbis/service/bis/BisProviderTest.scala @@ -41,5 +41,11 @@ class BisProviderTest extends ScalaTestWithActorTestKit(Settings.withRandomDatab probe.expectMessage(askTimeout, Fixtures.bis2) } + "get best in slot set (xivgear)" in { + val probe = testKit.createTestProbe[BiS]() + provider ! DownloadBiS(Fixtures.link6, Job.VPR, probe.ref) + probe.expectMessage(askTimeout, Fixtures.bis4) + } + } }