beatmaps-io / beatsaver-main

https://beatsaver.com
GNU General Public License v3.0
73 stars 24 forks source link

[Request] Add API for retrieving mapDetails by mapIdList #202

Closed ktKongTong closed 1 year ago

ktKongTong commented 1 year ago

I'm working on a local playlist management program that may require data synchronization. There can be more than 100 beatmaps in a single folder. If it is possible to add an API that allows batch retrieval of beatmap details by providing a mapIdList.

Top-Cat commented 1 year ago

Do you have or can you calculate the map hashes? If yes, you can already do this in batches of 50 on the map by hash endpoint

ktKongTong commented 1 year ago

Do you have or can you calculate the map hashes? If yes, you can already do this in batches of 50 on the map by hash endpoint

I can't get or calculate the map hash because the maps I'm handling are uncompressed folders, not zip files.🥲

Top-Cat commented 1 year ago

That sounds like you don't know how map hashes work because them being uncompressed makes no difference

ktKongTong commented 1 year ago

oh, sorry. I mistakenly assumed that map hash was calculated for the entire zipfile. I took a look at the relevant code, and it seems that map hashes is calculated based on the content written to 'Info.dat'. Is that correct?

  val info by lazy {
      infoPath.inputStream().use {
          val byteArrayOutputStream = ByteArrayOutputStream()
          it.copyTo(byteArrayOutputStream, sizeLimit = 50 * 1024 * 1024)
          jackson.readValue<MapInfo>(byteArrayOutputStream.toByteArray())
      }
  }

https://github.com/beatmaps-io/beatsaver-main/blob/60e7537843816984b9ba7e4ba3c0cc3e7b2b07cb/src/jvmMain/kotlin/io/beatmaps/controllers/upload.kt#L343-L356

I tried to calculate it in same way but didn't get the same hash.here is the code.

   val jackson: ObjectMapper = jacksonObjectMapper()
       .enable(SerializationFeature.INDENT_OUTPUT)
       .disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
       .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
       .setSerializationInclusion(JsonInclude.Include.NON_NULL)
       .registerModule(KotlinTimeModule())
       .registerModule(JavaTimeModule())
       .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
   val jsonWriter: ObjectWriter = jackson.writer(BSPrettyPrinter())
   val md = MessageDigest.getInstance("SHA1")

   val info = File("src/main/resources/Info.dat").inputStream().use {
       val byteArrayOutputStream = ByteArrayOutputStream()
       it.copyTo(byteArrayOutputStream, sizeLimit = 50 * 1024 * 1024)
       jackson.readValue<MapInfo>(byteArrayOutputStream.toByteArray())
   }
   DigestOutputStream(OutputStream.nullOutputStream(), md).use { dos ->
       jsonWriter.writeValue(dos, info)
   }
  val fx = "%0" + md.digestLength * 2 + "x"
  val digest = String.format(fx, BigInteger(1, md.digest()))
  println(digest)
Top-Cat commented 1 year ago

Not quite, it's a little hard to follow in this repo. SongCore's implementation may be clearer:

https://github.com/Kylemc1413/SongCore/blob/fbb0684f8bca7a8f7bd482cb623e530d185ca78f/source/SongCore/Utilities/Hashing.cs#L137-L162

ktKongTong commented 1 year ago

Not quite, it's a little hard to follow in this repo. SongCore's implementation may be clearer:

https://github.com/Kylemc1413/SongCore/blob/fbb0684f8bca7a8f7bd482cb623e530d185ca78f/source/SongCore/Utilities/Hashing.cs#L137-L162

It's work. thanks!