示例#1
0
    def asyncGet(self):
        statusCode = 400
        data = {"message": "unknown error"}
        try:
            # Check arguments
            if not requestsManager.checkArguments(self.request.arguments,
                                                  ["b"]):
                raise exceptions.invalidArgumentsException(MODULE_NAME)

            # Get beatmap ID and make sure it's a valid number
            beatmapID = self.get_argument("b")
            if not beatmapID.isdigit():
                raise exceptions.invalidArgumentsException(MODULE_NAME)

            # Get mods
            if "m" in self.request.arguments:
                modsEnum = self.get_argument("m")
                if not modsEnum.isdigit():
                    raise exceptions.invalidArgumentsException(MODULE_NAME)
                modsEnum = int(modsEnum)
            else:
                modsEnum = 0

            # Get game mode
            if "g" in self.request.arguments:
                gameMode = self.get_argument("g")
                if not gameMode.isdigit():
                    raise exceptions.invalidArgumentsException(MODULE_NAME)
                gameMode = int(gameMode)
            else:
                gameMode = 0

            # Get acc
            if "a" in self.request.arguments:
                accuracy = self.get_argument("a")
                try:
                    accuracy = float(accuracy)
                except ValueError:
                    raise exceptions.invalidArgumentsException(MODULE_NAME)
            else:
                accuracy = None

            # Print message
            log.info("Requested pp for beatmap {}".format(beatmapID))

            # Get beatmap md5 from osuapi
            # TODO: Move this to beatmap object
            osuapiData = osuapiHelper.osuApiRequest("get_beatmaps",
                                                    "b={}".format(beatmapID))
            if int(beatmapID) > 100000000:
                raise exceptions.ppCustomBeatmap(MODULE_NAME)
            if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData:
                raise exceptions.invalidBeatmapException(MODULE_NAME)
            beatmapMd5 = osuapiData["file_md5"]
            beatmapSetID = osuapiData["beatmapset_id"]

            # Create beatmap object
            bmap = beatmap.beatmap(beatmapMd5, beatmapSetID)

            # Check beatmap length
            if bmap.hitLength > 900:
                raise exceptions.beatmapTooLongException(MODULE_NAME)

            returnPP = []
            if gameMode == gameModes.STD and bmap.starsStd == 0:
                # Mode Specific beatmap, auto detect game mode
                if bmap.starsTaiko > 0:
                    gameMode = gameModes.TAIKO
                if bmap.starsCtb > 0:
                    gameMode = gameModes.CTB
                if bmap.starsMania > 0:
                    gameMode = gameModes.MANIA

            # Calculate pp
            if gameMode in (gameModes.STD, gameModes.TAIKO):
                # Std pp
                if accuracy is None and modsEnum == 0:
                    # Generic acc/nomod
                    # Get cached pp values
                    cachedPP = bmap.getCachedTillerinoPP()
                    if (modsEnum & mods.RELAX):
                        cachedPP = [0, 0, 0, 0]
                    elif (modsEnum & mods.RELAX2):
                        cachedPP = [0, 0, 0, 0]

                    if cachedPP != [0, 0, 0, 0]:
                        log.debug("Got cached pp.")
                        returnPP = cachedPP
                    else:
                        log.debug(
                            "Cached pp not found. Calculating pp with oppai..."
                        )
                        # Cached pp not found, calculate them
                        if gameMode == gameModes.STD and (modsEnum
                                                          & mods.RELAX):
                            oppai = relaxoppai.oppai(bmap,
                                                     mods=modsEnum,
                                                     tillerino=True)
                        elif gameMode == gameModes.STD and (modsEnum
                                                            & mods.RELAX2):
                            oppai = relax2oppai.oppai(bmap,
                                                      mods=modsEnum,
                                                      tillerino=True)
                        else:
                            oppai = rippoppai.oppai(bmap,
                                                    mods=modsEnum,
                                                    tillerino=True)
                        returnPP = oppai.pp
                        bmap.starsStd = oppai.stars

                        if not (modsEnum & mods.RELAX) or (modsEnum
                                                           & mods.RELAX2):
                            # Cache values in DB
                            log.debug("Saving cached pp...")
                            if type(returnPP) == list and len(returnPP) == 4:
                                bmap.saveCachedTillerinoPP(returnPP)
                else:
                    # Specific accuracy/mods, calculate pp
                    # Create oppai instance
                    log.debug(
                        "Specific request ({}%/{}). Calculating pp with oppai..."
                        .format(accuracy, modsEnum))
                    if gameMode == gameModes.STD and (modsEnum & mods.RELAX):
                        oppai = relaxoppai.oppai(bmap,
                                                 mods=modsEnum,
                                                 tillerino=True)
                    elif gameMode == gameModes.STD and (modsEnum
                                                        & mods.RELAX2):
                        oppai = relax2oppai.oppai(bmap,
                                                  mods=modsEnum,
                                                  tillerino=True)
                    else:
                        oppai = rippoppai.oppai(bmap,
                                                mods=modsEnum,
                                                tillerino=True)
                    bmap.starsStd = oppai.stars
                    if accuracy is not None:
                        returnPP = calculatePPFromAcc(oppai, accuracy)
                    else:
                        returnPP = oppai.pp
            else:
                raise exceptions.unsupportedGameModeException()

            # Data to return
            data = {
                "song_name": bmap.songName,
                "pp":
                [x for x in returnPP] if type(returnPP) is list else returnPP,
                "length": bmap.hitLength,
                "stars": bmap.starsStd,
                "ar": bmap.AR,
                "bpm": bmap.bpm,
            }

            # Set status code and message
            statusCode = 200
            data["message"] = "ok"
        except exceptions.invalidArgumentsException:
            # Set error and message
            statusCode = 400
            data["message"] = "missing required arguments"
        except exceptions.ppCustomBeatmap:
            statusCode = 400
            data[
                "message"] = "Custom map does not supported pp calculating yet"
        except exceptions.invalidBeatmapException:
            statusCode = 400
            data["message"] = "beatmap not found"
        except exceptions.beatmapTooLongException:
            statusCode = 400
            data["message"] = "requested beatmap is too long"
        except exceptions.unsupportedGameModeException:
            statusCode = 400
            data["message"] = "Unsupported gamemode"
        finally:
            # Add status code to data
            data["status"] = statusCode

            # Debug output
            log.debug(str(data))

            # Send response
            #self.clear()
            self.write(json.dumps(data))
            self.set_header("Content-Type", "application/json")
            self.set_status(statusCode)
示例#2
0
	def asyncGet(self):
		statusCode = 400
		data = {"message": "unknown error"}
		try:
			# Check arguments
			if not requestsManager.checkArguments(self.request.arguments, ["b"]):
				raise exceptions.invalidArgumentsException(MODULE_NAME)

			# Get beatmap ID and make sure it's a valid number
			beatmapID = self.get_argument("b")
			if not beatmapID.isdigit():
				raise exceptions.invalidArgumentsException(MODULE_NAME)

			# Get mods
			if "m" in self.request.arguments:
				modsEnum = self.get_argument("m")
				if not modsEnum.isdigit():
					raise exceptions.invalidArgumentsException(MODULE_NAME)
				modsEnum = int(modsEnum)
			else:
				modsEnum = 0

			# Get game mode
			if "g" in self.request.arguments:
				gameMode = self.get_argument("g")
				if not gameMode.isdigit():
					raise exceptions.invalidArgumentsException(MODULE_NAME)
				gameMode = int(gameMode)
			else:
				gameMode = 0

			# Get acc
			if "a" in self.request.arguments:
				accuracy = self.get_argument("a")
				try:
					accuracy = float(accuracy)
					if math.isnan(accuracy):
						accuracy = -1.0
				except ValueError:
					raise exceptions.invalidArgumentsException(MODULE_NAME)
			else:
				accuracy = -1.0

			if "x" in self.request.arguments:
				misses = self.get_argument("x")
				try:
					misses = int(misses)
				except ValueError:
					raise exceptions.invalidArgumentsException(MODULE_NAME)
			else:
				misses = 0

			if "c" in self.request.arguments:
				combo = self.get_argument("c")
				if not combo.isdigit():
					raise exceptions.invalidArgumentsException(MODULE_NAME)
				combo = int(combo)
			else:
				combo = 0


			# Print message
			log.info("Requested pp for beatmap {}".format(beatmapID))

			# Get beatmap md5 from osuapi
			# TODO: Move this to beatmap object
			"""osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapID))
			if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData:
				raise exceptions.invalidBeatmapException(MODULE_NAME)
			beatmapMd5 = osuapiData["file_md5"]
			beatmapSetID = osuapiData["beatmapset_id"]"""
			dbData = glob.db.fetch("SELECT beatmap_md5, beatmapset_id, mode FROM beatmaps WHERE beatmap_id = {}".format(beatmapID))
			if dbData is None:
				raise exceptions.invalidBeatmapException(MODULE_NAME)

			beatmapMd5 = dbData["beatmap_md5"]
			beatmapSetID = dbData["beatmapset_id"]

			# Create beatmap object
			bmap = beatmap.beatmap(beatmapMd5, beatmapSetID)
			stars = 0
			# Check beatmap length
			if bmap.hitLength > 900:
				raise exceptions.beatmapTooLongException(MODULE_NAME)

			returnPP = []
			if gameMode == gameModes.STD and bmap.starsStd == 0:
				gameMode = dbData["mode"]
				if(gameMode == 2):
					raise exceptions.unsupportedGameModeException
			if accuracy > 100 or combo > bmap.maxCombo or misses < 0 or math.isnan(accuracy):
				raise exceptions.invalidArgumentsException(MODULE_NAME)
			# Calculate pp
			if gameMode != 2:
				# Std pp
				if accuracy < 0 and combo == 0 and misses == 0 and gameMode == dbData["mode"]:
					# Generic acc
					# Get cached pp values
					cachedPP = bmap.getCachedTillerinoPP()
					if(modsEnum == 0 and cachedPP != [0,0,0,0]):
						log.debug("Got cached pp.")
						returnPP = cachedPP
						stars = bmap.starsStd
					else:
						log.debug("Cached pp not found. Calculating pp with oppai...")
						# Cached pp not found, calculate them
						if(gameMode == 1 or gameMode == 0):
							oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=True, stars=True)
							returnPP = oppai.pp
							stars = oppai.stars
						else:
							xeno = omppcPy.piano(bmap, mods=modsEnum, tillerino=True, stars=True)
							returnPP = xeno.pp
							stars = xeno.stars

						# Cache values in DB
						log.debug("Saving cached pp...")
						if(modsEnum == 0 and type(returnPP) != int and len(returnPP) == 4):
							bmap.saveCachedTillerinoPP(returnPP)
				else:
					# Specific accuracy, calculate
					# Create oppai instance
					if(gameMode == 3):
							log.info("Specific request ({}%/{}). Calculating pp with omppc...".format(accuracy, modsEnum))
							xeno = omppcPy.piano(bmap, acc=accuracy, mods=modsEnum, tillerino=False, stars=True)
							returnPP.append(xeno.pp)
							stars = xeno.stars	
					else:
						if(gameMode != 0 and gameMode != 1):
							raise exceptions.unsupportedGameModeException
						log.debug("Specific request ({}%/{}). Calculating pp with oppai...".format(accuracy, modsEnum))
						oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=False, stars=True)
						stars = oppai.stars
						if accuracy > 0:
							oppai.acc = accuracy
						if combo > 0:
							oppai.combo = combo
						if misses > 0:
							oppai.misses = misses	
						oppai.getPP()
						returnPP.append(oppai.pp)
			else:
				raise exceptions.unsupportedGameModeException

			# Data to return
			data = {
				"song_name": bmap.songName,
				"pp": returnPP,
				"length": round(bmap.hitLength*0.75) if modsEnum & mods.DOUBLETIME > 0 else bmap.hitLength if modsEnum & mods.HALFTIME < 1 else round(bmap.hitLength*1.50),
				"stars": stars,
				"ar": round(min(10, bmap.AR * 1.4),1) if modsEnum & mods.HARDROCK > 0 else bmap.AR if modsEnum & mods.EASY < 1 else round(max(0, bmap.AR / 2),1),
				"od": round(min(10, bmap.OD * 1.4),1) if modsEnum & mods.HARDROCK > 0 else bmap.OD if modsEnum & mods.EASY < 1 else round(max(0, bmap.OD / 2),1),
				"bpm": round(bmap.bpm*1.5) if modsEnum & mods.DOUBLETIME > 0 else bmap.bpm if modsEnum & mods.HALFTIME < 1 else round(bmap.bpm*0.75),
			}
			# Set status code and message
			statusCode = 200
			data["message"] = "ok"
		except exceptions.invalidArgumentsException:
			# Set error and message
			statusCode = 400
			data["message"] = "missing required arguments"
		except exceptions.invalidBeatmapException:
			statusCode = 400
			data["message"] = "beatmap not found"
		except exceptions.beatmapTooLongException:
			statusCode = 400
			data["message"] = "requested beatmap is too long"
		except exceptions.unsupportedGameModeException:
			statusCode = 400
			data["message"] = "Unsupported gamemode"
		finally:
			# Add status code to data
			data["status"] = statusCode

			# Debug output
			log.debug(str(data))

			# Send response
			#self.clear()
			self.write(json.dumps(data))
			self.set_header("Content-Type", "application/json")
			self.set_status(statusCode)