commit eecc3178b1881291bcef6e808aafd9c5180f9622
Author: thehrz
Date: Wed Feb 5 18:09:54 2025 +0800
Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..832f841
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+.idea
+.vscode
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..a2694c5
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,42 @@
+plugins {
+ kotlin("jvm") version "2.0.10"
+ id("java")
+ id("com.github.johnrengelman.shadow") version "8.1.1"
+}
+
+group = "io.github.thehrz.allmusicreload"
+version = "1.0.0"
+
+repositories {
+ mavenCentral()
+ maven("https://hub.spigotmc.org/nexus/content/groups/public")
+ maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
+ maven("https://jitpack.io")
+ maven(" https://mvnrepository.com/artifact/mysql/mysql-connector-java")
+ maven("https://maven.citizensnpcs.co/repo")
+ maven("https://nexus.velocitypowered.com/repository/maven-public/")
+}
+
+dependencies {
+ compileOnly("net.md-5:bungeecord-api:1.20-R0.1-SNAPSHOT")
+ compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")
+ compileOnly("com.velocitypowered:velocity-api:3.0.0")
+ compileOnly("me.clip:placeholderapi:2.11.6")
+ implementation("org.xerial:sqlite-jdbc:3.46.0.1")
+ api("com.squareup.okhttp3:okhttp:4.12.0")
+ api("com.google.code.gson:gson:2.11.0")
+ annotationProcessor("com.velocitypowered:velocity-api:3.0.0")
+}
+
+val targetJavaVersion = 17
+kotlin {
+ jvmToolchain(targetJavaVersion)
+}
+
+tasks.shadowJar {
+ exclude("kotlin/**")
+}
+
+tasks.build {
+ dependsOn("shadowJar")
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..249e583
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..dfddb8b
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Feb 03 17:44:49 CST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1b6c787
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..ad923c5
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,2 @@
+rootProject.name = "AllMusicReload"
+
diff --git a/src/main/java/io/github/thehrz/allmusicreload/AllMusicVelocity.java b/src/main/java/io/github/thehrz/allmusicreload/AllMusicVelocity.java
new file mode 100644
index 0000000..7eb7be2
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/AllMusicVelocity.java
@@ -0,0 +1,60 @@
+package io.github.thehrz.allmusicreload;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.velocity.*;
+import com.google.inject.Inject;
+import com.velocitypowered.api.command.CommandMeta;
+import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
+import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
+import com.velocitypowered.api.plugin.Plugin;
+import com.velocitypowered.api.plugin.annotation.DataDirectory;
+import com.velocitypowered.api.proxy.ProxyServer;
+import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
+import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
+import org.slf4j.Logger;
+
+import java.nio.file.Path;
+
+@Plugin(id = "allmusicreload", name = "AllMusicReload", version = AllMusic.version,
+ authors = {"Color_yr", "thehrz"})
+public class AllMusicVelocity {
+ public static AllMusicVelocity plugin;
+ public static ChannelIdentifier channel;
+ public static ChannelIdentifier channelBC;
+ public final ProxyServer server;
+ public final Path dataDirectory;
+ private final Logger logger;
+
+ @Inject
+ public AllMusicVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
+ this.server = server;
+ this.logger = logger;
+ this.dataDirectory = dataDirectory;
+ }
+
+ @Subscribe
+ public void onProxyInitialization(ProxyInitializeEvent event) {
+ plugin = this;
+ AllMusic.log = new LogVelocity(logger);
+ AllMusic.side = new SideVelocity();
+
+ new AllMusic().init(dataDirectory.toFile());
+
+ CommandMeta meta = server.getCommandManager().metaBuilder("music")
+ .build();
+ channel = () -> AllMusic.channel;
+ channelBC = MinecraftChannelIdentifier.from(AllMusic.channelBC);
+
+ server.getChannelRegistrar().register(channelBC);
+ server.getCommandManager().register(meta, new CommandVelocity());
+ server.getEventManager().register(this, new ListenerVelocity());
+
+ AllMusic.start();
+ }
+
+ @Subscribe
+ public void onStop(ProxyShutdownEvent event) {
+ AllMusic.stop();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/codec/PacketCodec.java b/src/main/java/io/github/thehrz/allmusicreload/codec/PacketCodec.java
new file mode 100644
index 0000000..ab9ff82
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/codec/PacketCodec.java
@@ -0,0 +1,51 @@
+package io.github.thehrz.allmusicreload.codec;
+
+import io.github.thehrz.allmusicreload.core.objs.enums.ComType;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+
+import java.nio.charset.StandardCharsets;
+
+public class PacketCodec {
+ public static ByteBuf pack(ComType type, String data, int data1) {
+ ByteBuf buf = Unpooled.buffer(0);
+ buf.writeByte(type.ordinal());
+ switch (type) {
+ case HUD:
+ case LYRIC:
+ case LIST:
+ case INFO:
+ case IMG:
+ case PLAY:
+ writeString(buf, data);
+ break;
+ case POS:
+ buf.writeInt(data1);
+ break;
+ }
+ return buf;
+ }
+
+ public static void pack(ByteBuf buf, ComType type, String data, int data1) {
+ buf.writeByte(type.ordinal());
+ switch (type) {
+ case HUD:
+ case LYRIC:
+ case LIST:
+ case INFO:
+ case IMG:
+ case PLAY:
+ writeString(buf, data);
+ break;
+ case POS:
+ buf.writeInt(data1);
+ break;
+ }
+ }
+
+ private static void writeString(ByteBuf buf, String text) {
+ byte[] temp = text.getBytes(StandardCharsets.UTF_8);
+ buf.writeInt(temp.length);
+ buf.writeBytes(temp);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/AllMusic.java b/src/main/java/io/github/thehrz/allmusicreload/core/AllMusic.java
new file mode 100644
index 0000000..3eecb7c
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/AllMusic.java
@@ -0,0 +1,448 @@
+package io.github.thehrz.allmusicreload.core;
+
+import io.github.thehrz.allmusicreload.core.music.api.APIMain;
+import io.github.thehrz.allmusicreload.core.music.play.MusicSearch;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayRuntime;
+import io.github.thehrz.allmusicreload.core.objs.CookieObj;
+import io.github.thehrz.allmusicreload.core.objs.config.ConfigObj;
+import io.github.thehrz.allmusicreload.core.objs.message.MessageObj;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.side.BaseSide;
+import io.github.thehrz.allmusicreload.core.side.IMyLogger;
+import io.github.thehrz.allmusicreload.core.sql.DataSql;
+import io.github.thehrz.allmusicreload.core.sql.IEconomy;
+import io.github.thehrz.allmusicreload.core.utils.Logs;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.*;
+
+public class AllMusic {
+ public static final Gson gson = new Gson();
+
+ /**
+ * 客户端插件信道名
+ */
+ public static final String channel = "allmusic:channel";
+ /**
+ * BC插件信道名
+ */
+ public static final String channelBC = "allmusic:channelbc";
+ /**
+ * 插件版本号
+ */
+ public static final String version = "1.0.0";
+ /**
+ * 配置文件版本号
+ */
+ public static final String configVersion = "203";
+ /**
+ * 语言文件配置版本号
+ */
+ public static final String messageVersion = "206";
+ /**
+ * 搜歌结果
+ * 玩家名 结果
+ */
+ private static final Map searchSave = new HashMap<>();
+ /**
+ * 正在播放的玩家
+ */
+ private static final Set nowPlayPlayer = new HashSet<>();
+ /**
+ * 日志
+ */
+ public static IMyLogger log;
+ /**
+ * 服务器端操作
+ */
+ public static BaseSide side;
+ /**
+ * 是否在运行
+ */
+ public static boolean isRun;
+ /**
+ * Cookie对象
+ */
+ public static CookieObj cookie;
+ /**
+ * 经济插件对象
+ */
+ public static IEconomy economy;
+ /**
+ * 网易API
+ */
+ private static APIMain apiMusic;
+ /**
+ * 配置对象
+ */
+ private static ConfigObj config;
+ /**
+ * 语言对象
+ */
+ private static MessageObj message;
+ /**
+ * 配置文件
+ */
+ private static File configFile;
+ /**
+ * Cookie文件
+ */
+ private static File cookieFile;
+ /**
+ * 语言文件
+ */
+ private static File messageFile;
+
+ /**
+ * 检查配置文件完整性
+ */
+ public static void configCheck() {
+ if (config == null || config.check()) {
+ config = ConfigObj.make();
+ log.warning("§d[AllMusic3]§c配置文件config.json错误,已覆盖");
+ saveConfig();
+ }
+ }
+
+ /**
+ * 检查语言文件完整性
+ */
+ private static void messageCheck() {
+ if (message == null || message.check()) {
+ message = MessageObj.make();
+ log.warning("§d[AllMusic3]§c配置文件message.json错误,已覆盖");
+ saveMessage();
+ }
+ }
+
+ /**
+ * 检查是否需要
+ *
+ * @param name 用户名
+ * @param server 服务器名
+ * @param checkList 是否检查正在播放的列表
+ * @return 结果
+ */
+ public static boolean isSkip(String name, String server, boolean checkList) {
+ try {
+ name = name.toLowerCase();
+ if (server != null && AllMusic.getConfig().muteServer.contains(server))
+ return true;
+ if (AllMusic.getConfig().mutePlayer.contains(name))
+ return true;
+ if (!checkList)
+ return false;
+ return AllMusic.containNowPlay(name);
+ } catch (NoSuchElementException e) {
+ return true;
+ }
+ }
+
+ /**
+ * 是否存在正在播放的玩家
+ *
+ * @param player 用户名
+ * @return 是否存在
+ */
+ public static boolean containNowPlay(String player) {
+ player = player.toLowerCase();
+ return !nowPlayPlayer.contains(player);
+ }
+
+ /**
+ * 获取配置文件
+ *
+ * @return 配置对象
+ */
+ public static ConfigObj getConfig() {
+ if (config == null) {
+ log.warning("§d[AllMusic3]§c配置文件config.json错误,已使用默认配置文件");
+ config = ConfigObj.make();
+ }
+ return config;
+ }
+
+ /**
+ * 获取语言文件
+ *
+ * @return 语言对象
+ */
+ public static MessageObj getMessage() {
+ if (message == null) {
+ log.warning("§d[AllMusic3]§c配置文件message.json错误,已使用默认配置文件");
+ message = MessageObj.make();
+ }
+ return message;
+ }
+
+ /**
+ * 添加搜歌结果
+ *
+ * @param player 用户名
+ * @param page 结果
+ */
+ public static void addSearch(String player, SearchPageObj page) {
+ player = player.toLowerCase();
+ searchSave.put(player, page);
+ }
+
+ /**
+ * 获取搜歌结果
+ *
+ * @param player 用户名
+ * @return 结果
+ */
+ public static SearchPageObj getSearch(String player) {
+ player = player.toLowerCase();
+ return searchSave.get(player);
+ }
+
+ /**
+ * 删除搜歌结果
+ *
+ * @param player 用户名
+ */
+ public static void removeSearch(String player) {
+ player = player.toLowerCase();
+ searchSave.remove(player);
+ }
+
+ /**
+ * 添加正在播放的玩家
+ *
+ * @param player 用户名
+ */
+ public static void addNowPlayPlayer(String player) {
+ player = player.toLowerCase();
+ nowPlayPlayer.add(player);
+ }
+
+ /**
+ * 删除正在播放的玩家
+ *
+ * @param player 用户名
+ */
+ public static void removeNowPlayPlayer(String player) {
+ player = player.toLowerCase();
+ nowPlayPlayer.remove(player);
+ }
+
+ /**
+ * 清空正在播放玩家的列表
+ */
+ public static void clearNowPlayer() {
+ nowPlayPlayer.clear();
+ }
+
+ /**
+ * 保存配置文件
+ */
+ public static void saveConfig() {
+ try {
+ String data = new GsonBuilder().setPrettyPrinting().create().toJson(config);
+ FileOutputStream out = new FileOutputStream(configFile);
+ OutputStreamWriter write = new OutputStreamWriter(
+ out, StandardCharsets.UTF_8);
+ write.write(data);
+ write.close();
+ out.close();
+ } catch (Exception e) {
+ log.warning("§d[AllMusic3]§c配置文件保存错误");
+ e.printStackTrace();
+ }
+ }
+
+ public static void saveMessage() {
+ try {
+ String data = new GsonBuilder().setPrettyPrinting().create().toJson(message);
+ FileOutputStream out = new FileOutputStream(messageFile);
+ OutputStreamWriter write = new OutputStreamWriter(
+ out, StandardCharsets.UTF_8);
+ write.write(data);
+ write.close();
+ out.close();
+ } catch (Exception e) {
+ log.warning("§d[AllMusic3]§c配置文件保存错误");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 保存Cookie
+ */
+ public static void saveCookie() {
+ try {
+ String data = new GsonBuilder().setPrettyPrinting().create().toJson(cookie);
+ FileOutputStream out = new FileOutputStream(cookieFile);
+ OutputStreamWriter write = new OutputStreamWriter(
+ out, StandardCharsets.UTF_8);
+ write.write(data);
+ write.close();
+ } catch (Exception e) {
+ log.warning("§d[AllMusic3]§c配置文件保存错误");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 启动插件
+ */
+ public static void start() {
+ AllMusic.apiMusic = new APIMain();
+ PlayMusic.start();
+ PlayRuntime.start();
+ MusicSearch.start();
+ DataSql.start();
+
+ log.info("§d[AllMusic3]§e已启动-" + version);
+ }
+
+ /**
+ * 停止插件
+ */
+ public static void stop() {
+ try {
+ PlayMusic.clearVote();
+ PlayMusic.clearPush();
+ Logs.stop();
+ side.sendStop();
+ MusicSearch.stop();
+ PlayMusic.stop();
+ PlayRuntime.stop();
+ DataSql.stop();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ log.info("§d[AllMusic3]§2§e已停止,感谢使用");
+ }
+
+ /**
+ * 获取音乐API
+ *
+ * @return 音乐API
+ */
+ public static APIMain getMusicApi() {
+ return apiMusic;
+ }
+
+ /**
+ * 加载配置文件
+ */
+ private static void loadConfig() {
+ try {
+ InputStreamReader reader = new InputStreamReader(
+ Files.newInputStream(configFile.toPath()), StandardCharsets.UTF_8);
+ BufferedReader bf = new BufferedReader(reader);
+ config = new Gson().fromJson(bf, ConfigObj.class);
+ bf.close();
+ reader.close();
+ configCheck();
+
+ reader = new InputStreamReader(Files.newInputStream(messageFile.toPath()), StandardCharsets.UTF_8);
+ bf = new BufferedReader(reader);
+ message = new Gson().fromJson(bf, MessageObj.class);
+ bf.close();
+ reader.close();
+ messageCheck();
+
+ log.info("§d[AllMusic3]§e当前语言配置文件版本为:" + messageVersion
+ + ",你的语言文件版本为:" + message.version);
+
+ if (!message.version.equalsIgnoreCase(messageVersion)) {
+ log.warning("§d[AllMusic3]§c语言文件版本号错误,运行可能会发生问题,请删除后重载");
+ }
+
+ reader = new InputStreamReader(Files.newInputStream(cookieFile.toPath()), StandardCharsets.UTF_8);
+ bf = new BufferedReader(reader);
+ cookie = new Gson().fromJson(bf, CookieObj.class);
+ bf.close();
+ reader.close();
+ if (cookie == null || cookie.cookieStore == null) {
+ cookie = new CookieObj();
+ saveCookie();
+ }
+
+ log.info("§d[AllMusic3]§e当前插件配置文件版本为:" + configVersion
+ + ",你的配置文件版本为:" + config.version);
+
+ if (!AllMusic.configVersion.equalsIgnoreCase(config.version)) {
+ log.warning("§d[AllMusic3]§c请及时更新配置文件");
+ }
+ } catch (Exception e) {
+ log.warning("§d[AllMusic3]§c读取配置文件错误");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 加入时播放
+ *
+ * @param player 用户名
+ */
+ public static void joinPlay(String player) {
+ player = player.toLowerCase();
+ if (getConfig().mutePlayer.contains(player) || nowPlayPlayer.contains(player)) {
+ return;
+ }
+
+ String finalPlayer = player;
+ AllMusic.side.runTask(() -> {
+ SongInfoObj music = PlayMusic.nowPlayMusic;
+ if (music != null && PlayMusic.url != null) {
+ AllMusic.side.sendHudPos(finalPlayer);
+ AllMusic.side.sendMusic(finalPlayer, PlayMusic.url);
+ if (!music.isUrl()) {
+ AllMusic.side.sendPic(finalPlayer, music.getPicUrl());
+ }
+ AllMusic.side.sendPos(finalPlayer, (int)PlayMusic.musicNowTime);
+ }
+ }, 40);
+ }
+
+ /**
+ * 读取配置文件
+ *
+ * @param file 配置文件文件夹
+ */
+ public void init(File file) {
+ log.info("§d[AllMusic3]§2§e正在启动,感谢使用,本插件交流群:571239090");
+ try {
+ if (!file.exists())
+ file.mkdir();
+ if (configFile == null)
+ configFile = new File(file, "config.json");
+ if (messageFile == null)
+ messageFile = new File(file, "message.json");
+ if (cookieFile == null)
+ cookieFile = new File(file, "cookie.json");
+ if (Logs.file == null)
+ Logs.file = new File(file, "logs.log");
+ if (DataSql.sqlFile == null)
+ DataSql.sqlFile = new File(file, "data.db");
+ if (!configFile.exists()) {
+ configFile.createNewFile();
+ }
+ if (!messageFile.exists()) {
+ messageFile.createNewFile();
+ }
+ if (!cookieFile.exists()) {
+ cookieFile.createNewFile();
+ }
+ if (!Logs.file.exists()) {
+ Logs.file.createNewFile();
+ }
+ loadConfig();
+ isRun = true;
+ } catch (IOException e) {
+ isRun = false;
+ log.warning("§d[AllMusic3]§c启动失败");
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/AllMusicAPI.java b/src/main/java/io/github/thehrz/allmusicreload/core/AllMusicAPI.java
new file mode 100644
index 0000000..a2e00fb
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/AllMusicAPI.java
@@ -0,0 +1,67 @@
+package io.github.thehrz.allmusicreload.core;
+
+import io.github.thehrz.allmusicreload.core.objs.config.SaveObj;
+import io.github.thehrz.allmusicreload.core.objs.enums.HudType;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+
+public class AllMusicAPI {
+ /**
+ * 发送播放音乐
+ *
+ * @param name 用户名
+ * @param url 链接
+ */
+ public static void playMusic(String name, String url) {
+ AllMusic.side.sendMusic(name, url);
+ }
+
+ /**
+ * 更新玩家Hud数据
+ *
+ * @param name 用户名
+ * @param pos 位置
+ * @param data 数据
+ */
+ public static void sendHud(String name, HudType pos, String data) {
+ AllMusic.side.sendHud(name, pos, data);
+ }
+
+ /**
+ * 发送图片
+ *
+ * @param name 用户名
+ * @param url 图片地址
+ */
+ public static void sendPic(String name, String url) {
+ AllMusic.side.sendPic(name, url);
+ }
+
+ /**
+ * 停止播放
+ *
+ * @param name 用户名
+ */
+ public static void sendStop(String name) {
+ AllMusic.side.sendStop(name);
+ }
+
+ /**
+ * 获取玩家Hud信息
+ *
+ * @param player 玩家
+ * @return Hud信息
+ */
+ public static SaveObj getHud(String player) {
+ return HudUtils.get(player);
+ }
+
+ /**
+ * 设置玩家Hud
+ *
+ * @param player 玩家
+ * @param hud Hud信息
+ */
+ public static void setHud(String player, SaveObj hud) {
+ HudUtils.set(player, hud);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/ACommand.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/ACommand.java
new file mode 100644
index 0000000..702c26b
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/ACommand.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import java.util.Collections;
+import java.util.List;
+
+public abstract class ACommand implements ICommand {
+ @Override
+ public List tab(String name, String[] args, int index) {
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/AHudCommand.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/AHudCommand.java
new file mode 100644
index 0000000..2012c9f
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/AHudCommand.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.objs.enums.HudType;
+
+public abstract class AHudCommand extends ACommand {
+ protected final HudType type;
+
+ public AHudCommand(HudType type) {
+ this.type = type;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandAddList.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandAddList.java
new file mode 100644
index 0000000..7906a8b
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandAddList.java
@@ -0,0 +1,31 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+public class CommandAddList extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+
+ String musicID;
+
+ if (args[1].contains("id=") && !args[1].contains("/?userid")) {
+ if (args[1].contains("&user"))
+ musicID = Function.getString(args[1], "id=", "&user");
+ else
+ musicID = Function.getString(args[1], "id=", null);
+ } else
+ musicID = args[1];
+
+ if (Function.isInteger(musicID)) {
+ AllMusic.getMusicApi().setList(musicID, sender);
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2添加空闲音乐列表" + musicID);
+ } else {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2请输入有效的音乐列表ID");
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBan.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBan.java
new file mode 100644
index 0000000..b6519c3
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBan.java
@@ -0,0 +1,43 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CommandBan extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ if (Function.isInteger(args[1])) {
+ AllMusic.getConfig().addBanMusic(args[1]);
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2已禁止点歌" + args[1]);
+ } else {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2请输入有效的ID");
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index || (args.length == index + 1 && args[index].isEmpty())) {
+ List list = new ArrayList<>();
+ if (PlayMusic.nowPlayMusic != null) {
+ list.add(PlayMusic.nowPlayMusic.getID());
+ }
+ for (SongInfoObj item : PlayMusic.getList()) {
+ list.add(item.getID());
+ }
+
+ return list;
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBanPlayer.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBanPlayer.java
new file mode 100644
index 0000000..9b2fc23
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandBanPlayer.java
@@ -0,0 +1,28 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class CommandBanPlayer implements ICommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ AllMusic.getConfig().addBanPlayer(args[1].toLowerCase(Locale.ROOT));
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2已禁止玩家" + args[1] + "点歌");
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index || (args.length == index + 1 && args[index].isEmpty())) {
+ return AllMusic.side.getPlayerList();
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCancel.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCancel.java
new file mode 100644
index 0000000..16e2f13
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCancel.java
@@ -0,0 +1,70 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CommandCancel implements ICommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 1) {
+ SongInfoObj id = PlayMusic.findPlayerMusic(name);
+ if (id == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.err1);
+ return;
+ }
+ if (!id.getCall().equalsIgnoreCase(name)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.err2.replace(PAL.musicName, id.getName())
+ .replace(PAL.musicAuthor, id.getAuthor()));
+ return;
+ }
+ PlayMusic.remove(id);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.done);
+ } else if (args.length == 2) {
+ try {
+ int index = Integer.parseInt(args[1]);
+ SongInfoObj id = PlayMusic.findMusicIndex(index);
+ if (id == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.err3
+ .replace(PAL.index, args[1]));
+ return;
+ }
+ if (!id.getCall().equalsIgnoreCase(name)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.err2.replace(PAL.musicName, id.getName())
+ .replace(PAL.musicAuthor, id.getAuthor()));
+ return;
+ }
+
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.done);
+ } catch (Exception e) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cancel.err4);
+ }
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == 1 || (args.length == 2 && args[1].isEmpty())) {
+ List list = new ArrayList<>();
+ List list1 = PlayMusic.getList();
+ if (list1.size() > 1) {
+ for (int a = 1; a < list1.size(); a++) {
+ SongInfoObj item = list1.get(a);
+ if (item.getCall().equalsIgnoreCase(name)) {
+ list.add(String.valueOf(a));
+ }
+ }
+ }
+ return list;
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandClearList.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandClearList.java
new file mode 100644
index 0000000..6f058ca
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandClearList.java
@@ -0,0 +1,12 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+
+public class CommandClearList extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ PlayMusic.clearIdleList();
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2添加空闲音乐列表已清空");
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCookie.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCookie.java
new file mode 100644
index 0000000..ad55b02
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandCookie.java
@@ -0,0 +1,57 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.UserCookie;
+import com.google.gson.reflect.TypeToken;
+import okhttp3.Cookie;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class CommandCookie extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§c没有Cookie数据");
+ return;
+ }
+ if (AllMusic.side.isPlayer(sender)) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§c请在控制台上操作");
+ return;
+ }
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§d设置网易云账户");
+ try {
+ String cookie = args[1];
+ String[] cookies = cookie.split(";");
+ Map list1 = new HashMap<>();
+ for (String item : cookies) {
+ String[] cookieitem = item.split("=");
+ if (cookieitem.length == 1) {
+ if (list1.containsKey(cookieitem[0])) {
+ continue;
+ }
+ list1.put(cookieitem[0], new Cookie.Builder()
+ .name(cookieitem[0])
+ .domain("163.com")
+ .expiresAt(Long.MAX_VALUE)
+ .build());
+ } else {
+ list1.put(cookieitem[0], new Cookie.Builder()
+ .name(cookieitem[0])
+ .value(cookieitem[1])
+ .domain("163.com")
+ .expiresAt(Long.MAX_VALUE)
+ .build());
+ }
+ }
+ AllMusic.cookie.cookieStore.put("music.163.com", new ArrayList<>(list1.values()));
+
+ AllMusic.saveCookie();
+ } catch (Exception e) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§c错误的cookie");
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandDelete.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandDelete.java
new file mode 100644
index 0000000..6506975
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandDelete.java
@@ -0,0 +1,47 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CommandDelete extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ if (!args[1].isEmpty() && Function.isInteger(args[1])) {
+ int music = Integer.parseInt(args[1]);
+ if (music == 0) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2请输入有效的序列ID");
+ return;
+ }
+ if (music > PlayMusic.getListSize()) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2序列号过大");
+ return;
+ }
+ PlayMusic.remove(music - 1);
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2已删除序列" + music);
+ } else {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2请输入有效的序列ID");
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == 1 || (args.length == 2 && args[1].isEmpty())) {
+ List list = new ArrayList<>();
+ for (int a = 0; a < PlayMusic.getListSize(); a++) {
+ list.add(String.valueOf(a + 1));
+ }
+ return list;
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandEX.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandEX.java
new file mode 100644
index 0000000..6f448c0
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandEX.java
@@ -0,0 +1,303 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.MusicSearch;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.MusicObj;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CommandEX {
+
+ public static final Map commandList = new HashMap<>();
+ public static final Map commandAdminList = new HashMap<>();
+ private static final List normal = new ArrayList() {{
+ this.add("stop");
+ this.add("cancel");
+ this.add("list");
+ this.add("vote");
+ this.add("mute");
+ this.add("search");
+ this.add("hud");
+ this.add("push");
+ }};
+ /**
+ * 管理员的指令
+ */
+ private static final List admin = new ArrayList() {{
+ this.add("reload");
+ this.add("next");
+ this.add("ban");
+ this.add("delete");
+ this.add("addlist");
+ this.add("clearlist");
+ this.add("cookie");
+ this.add("test");
+ }};
+ /**
+ * 搜歌的指令
+ */
+ private static final List search = new ArrayList() {{
+ this.add("select");
+ this.add("nextpage");
+ this.add("lastpage");
+ }};
+
+ static {
+ commandList.put("stop", new CommandStop());
+ commandList.put("help", new CommandHelp());
+ commandList.put("list", new CommandList());
+ commandList.put("vote", new CommandVote());
+ commandList.put("mute", new CommandMute());
+ commandList.put("search", new CommandSearch());
+ commandList.put("select", new CommandSelect());
+ commandList.put("nextpage", new CommandNextPage());
+ commandList.put("lastpage", new CommandLastPage());
+ commandList.put("hud", new CommandHud());
+ commandList.put("reload", new CommandReload());
+ commandList.put("push", new CommandPush());
+ commandList.put("cancel", new CommandCancel());
+
+ commandAdminList.put("next", new CommandNext());
+ commandAdminList.put("ban", new CommandBan());
+ commandAdminList.put("banplayer", new CommandBanPlayer());
+ commandAdminList.put("url", new CommandUrl());
+ commandAdminList.put("delete", new CommandDelete());
+ commandAdminList.put("addlist", new CommandAddList());
+ commandAdminList.put("clearlist", new CommandClearList());
+ commandAdminList.put("cookie", new CommandCookie());
+ commandAdminList.put("test", new CommandTest());
+ }
+
+ /**
+ * 搜索音乐
+ *
+ * @param sender 发送者
+ * @param name 用户名
+ * @param args 参数
+ * @param isDefault 是否是默认点歌方式
+ */
+ public static void searchMusic(Object sender, String name, String[] args, boolean isDefault) {
+ MusicObj obj = new MusicObj();
+ obj.sender = sender;
+ obj.name = name;
+ obj.args = args;
+ obj.isDefault = isDefault;
+
+ if (AllMusic.side.onMusicAdd(sender, obj)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.cancel);
+ return;
+ }
+
+ MusicSearch.addSearch(obj);
+ }
+
+ /**
+ * 检查金额是否够
+ *
+ * @param sender 发送者
+ * @param name 用户名
+ * @param cost 金额
+ * @return 结果
+ */
+ public static boolean checkMoney(Object sender, String name, int cost) {
+ if (!AllMusic.getConfig().cost.useCost || AllMusic.economy == null) {
+ return false;
+ }
+
+ if (!AllMusic.economy.check(name, cost)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cost.noMoney);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 扣钱
+ *
+ * @param sender 发送者
+ * @param name 用户名
+ * @param cost 金额
+ * @param message 结果消息
+ * @return 结果
+ */
+ public static boolean cost(Object sender, String name, int cost, String message) {
+ if (!AllMusic.getConfig().cost.useCost || AllMusic.economy == null) {
+ return false;
+ }
+
+ if (AllMusic.economy.cost(name, cost)) {
+ AllMusic.side.sendMessage(sender, message
+ .replace(PAL.cost, String.valueOf(cost)));
+ return false;
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().cost.costFail);
+ return true;
+ }
+ }
+
+ /**
+ * 添加音乐
+ *
+ * @param sender 发送者
+ * @param name 用户名
+ * @param args 参数
+ */
+ public static void addMusic(Object sender, String name, String[] args) {
+ String musicID;
+ if (args[0].contains("id=") && !args[0].contains("/?userid")) {
+ if (args[0].contains("&uct2")) {
+ musicID = Function.getString(args[0], "id=", "&uct2");
+ }
+ else if (args[0].contains("&user"))
+ musicID = Function.getString(args[0], "id=", "&user");
+ else
+ musicID = Function.getString(args[0], "id=", null);
+ } else if (args[0].contains("song/")) {
+ if (args[0].contains("/?userid"))
+ musicID = Function.getString(args[0], "song/", "/?userid");
+ else
+ musicID = Function.getString(args[0], "song/", null);
+ } else
+ musicID = args[0];
+ if (Function.isInteger(musicID)) {
+ if (PlayMusic.getListSize() >= AllMusic.getConfig().maxPlayList) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.listFull);
+ } else if (AllMusic.getConfig().banMusic.contains(musicID)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.banMusic);
+ } else if (PlayMusic.haveMusic(musicID)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.existMusic);
+ } else if (PlayMusic.isPlayerMax(name)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.playerToMany);
+ } else if (AllMusic.getConfig().banPlayer.contains(name)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.playerBan);
+ } else {
+ if (checkMoney(sender, name, AllMusic.getConfig().cost.addMusicCost)) {
+ return;
+ }
+ if (cost(sender, name, AllMusic.getConfig().cost.addMusicCost,
+ AllMusic.getMessage().cost.addMusic)) {
+ return;
+ }
+ AllMusic.getConfig().removeNoMusicPlayer(name);
+ if (AllMusic.side.needPlay()) {
+ MusicObj obj = new MusicObj();
+ obj.sender = sender;
+ obj.id = musicID;
+ obj.name = name;
+ obj.isDefault = false;
+
+ if (AllMusic.side.onMusicAdd(sender, obj)) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.cancel);
+ return;
+ }
+
+ PlayMusic.addTask(obj);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.success);
+ } else
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.noPlayer);
+ }
+ } else
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.noID);
+ }
+
+ private static boolean isAdmin(String name)
+ {
+ for (String item : AllMusic.getConfig().adminList) {
+ if (item.equalsIgnoreCase(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 执行命令
+ *
+ * @param sender 发送者
+ * @param name 用户名
+ * @param args 参数
+ */
+ public static void execute(Object sender, String name, String[] args) {
+ if (args.length == 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ ICommand command = commandList.get(args[0]);
+ if (command != null) {
+ command.execute(sender, name, args);
+ return;
+ }
+
+ if (isAdmin(name) || AllMusic.side.checkPermission(sender)) {
+ command = commandAdminList.get(args[0]);
+ if (command != null) {
+ command.execute(sender, name, args);
+ return;
+ }
+ }
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(sender, "allmusic.addmusic"))
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.noPer);
+ else {
+ switch (AllMusic.getConfig().defaultAddMusic) {
+ case 1:
+ searchMusic(sender, name, args, true);
+ break;
+ case 0:
+ default:
+ addMusic(sender, name, args);
+ }
+ }
+ }
+
+ /**
+ * 获取Tab指令列表
+ *
+ * @param name 用户名
+ * @param arg 参数
+ * @return 指令列表
+ */
+ public static List getTabList(String name, String[] arg) {
+ List arguments = new ArrayList<>();
+ if (arg.length == 0) {
+ arguments.addAll(normal);
+ if (AllMusic.side.checkPermission(name)) {
+ arguments.addAll(admin);
+ }
+ if (AllMusic.getSearch(name) != null) {
+ return search;
+ }
+ } else {
+ if (arg[0] == null || arg[0].isEmpty() || arg.length == 1) {
+ arguments.addAll(normal);
+ if (AllMusic.side.checkPermission(name)) {
+ arguments.addAll(admin);
+ }
+ if (arg[0] == null || arg[0].isEmpty()) {
+ if (AllMusic.getSearch(name) != null) {
+ return search;
+ }
+ }
+ } else {
+ ICommand command = CommandEX.commandList.get(arg[0]);
+ if (command != null) {
+ arguments.addAll(command.tab(name, arg, 1));
+ }
+ if (AllMusic.side.checkPermission(name)) {
+ command = CommandEX.commandAdminList.get(arg[0]);
+ if (command != null) {
+ arguments.addAll(command.tab(name, arg, 1));
+ }
+ }
+ }
+ }
+
+ return arguments;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHelp.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHelp.java
new file mode 100644
index 0000000..5d6c2ba
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHelp.java
@@ -0,0 +1,78 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+
+public class CommandHelp extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().help.normal.head);
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.base,
+ AllMusic.getMessage().click.clickCheck, "/music ");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.stop,
+ AllMusic.getMessage().click.clickRun, "/music stop");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.list,
+ AllMusic.getMessage().click.clickRun, "/music list");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.cancel,
+ AllMusic.getMessage().click.clickRun, "/music cancel");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.vote,
+ AllMusic.getMessage().click.clickRun, "/music vote");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.vote1,
+ AllMusic.getMessage().click.clickRun, "/music vote cancel");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.push,
+ AllMusic.getMessage().click.clickRun, "/music push");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.push1,
+ AllMusic.getMessage().click.clickRun, "/music push cancel");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.mute,
+ AllMusic.getMessage().click.clickRun, "/music mute");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.search,
+ AllMusic.getMessage().click.clickCheck, "/music search ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.select,
+ AllMusic.getMessage().click.clickCheck, "/music select ");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.nextpage,
+ AllMusic.getMessage().click.clickRun, "/music nextpage");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.lastpage,
+ AllMusic.getMessage().click.clickRun, "/music lastpage");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.hud9,
+ AllMusic.getMessage().click.clickRun, "/music hud enable");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.normal.hud10,
+ AllMusic.getMessage().click.clickRun, "/music hud reset");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud1,
+ AllMusic.getMessage().click.clickCheck, "/music hud ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud2,
+ AllMusic.getMessage().click.clickCheck, "/music hud ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud6,
+ AllMusic.getMessage().click.clickCheck, "/music hud ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud7,
+ AllMusic.getMessage().click.clickCheck, "/music hud ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud8,
+ AllMusic.getMessage().click.clickCheck, "/music hud ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud3,
+ AllMusic.getMessage().click.clickCheck, "/music hud pic size ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud4,
+ AllMusic.getMessage().click.clickCheck, "/music hud pic rotate ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.normal.hud5,
+ AllMusic.getMessage().click.clickCheck, "/music hud pic speed ");
+ if (AllMusic.side.checkPermission(name)) {
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.admin.reload,
+ AllMusic.getMessage().click.clickRun, "/music reload");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.admin.next,
+ AllMusic.getMessage().click.clickRun, "/music next");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.ban,
+ AllMusic.getMessage().click.clickCheck, "/music ban ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.banPlayer,
+ AllMusic.getMessage().click.clickCheck, "/music banplayer ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.url,
+ AllMusic.getMessage().click.clickCheck, "/music url ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.delete,
+ AllMusic.getMessage().click.clickCheck, "/music delete ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.addList,
+ AllMusic.getMessage().click.clickCheck, "/music addlist ");
+ AllMusic.side.sendMessageRun(sender, AllMusic.getMessage().help.admin.clearList,
+ AllMusic.getMessage().click.clickRun, "/music clearlist");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.cookie,
+ AllMusic.getMessage().click.clickCheck, "/music cookie ");
+ AllMusic.side.sendMessageSuggest(sender, AllMusic.getMessage().help.admin.test,
+ AllMusic.getMessage().click.clickCheck, "/music test ");
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHud.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHud.java
new file mode 100644
index 0000000..85e1dd5
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHud.java
@@ -0,0 +1,95 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.enums.HudType;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+
+import java.util.*;
+
+public class CommandHud extends ACommand {
+ /**
+ * Hud的指令
+ */
+ private static final List hudlist = new ArrayList() {{
+ this.add("enable");
+ this.add("reset");
+ this.add("info");
+ this.add("list");
+ this.add("lyric");
+ this.add("pic");
+ }};
+ private final Map commandList = new HashMap<>();
+
+ public CommandHud() {
+ commandList.put("enable", new HudEnable());
+ commandList.put("reset", new HudReset());
+ commandList.put("info", new CommandHudSet(HudType.INFO));
+ commandList.put("list", new CommandHudSet(HudType.LIST));
+ commandList.put("lyric", new CommandHudSet(HudType.LYRIC));
+ commandList.put("pic", new CommandHudSet(HudType.PIC));
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 1) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ } else {
+ ICommand command = commandList.get(args[1]);
+ if (command != null) {
+ command.execute(sender, name, args);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return hudlist;
+ } else {
+ ICommand command = commandList.get(args[index]);
+ if (command != null) {
+ return command.tab(name, args, index + 1);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static class HudEnable extends ACommand {
+ private static final List tf = new ArrayList() {{
+ this.add("true");
+ this.add("false");
+ }};
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 2 || args.length == 3) {
+ boolean temp = HudUtils.setHudEnable(name, null, args.length == 3 ? args[2] : null);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.state
+ .replace(PAL.state, temp ? "启用" : "关闭")
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(null)));
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return tf;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ private static class HudReset extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ HudUtils.reset(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.reset
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(null)));
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHudSet.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHudSet.java
new file mode 100644
index 0000000..7611d21
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandHudSet.java
@@ -0,0 +1,285 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.enums.HudDirType;
+import io.github.thehrz.allmusicreload.core.objs.enums.HudType;
+import io.github.thehrz.allmusicreload.core.objs.hud.PosObj;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+
+import java.util.*;
+
+public class CommandHudSet extends AHudCommand {
+ /**
+ * Hud的指令
+ */
+ private static final List hud = new ArrayList() {{
+ this.add("enable");
+ this.add("pos");
+ this.add("dir");
+ this.add("reset");
+ }};
+ private static final List pic = new ArrayList() {{
+ this.add("size");
+ this.add("rotate");
+ this.add("speed");
+ }};
+ private static final List info = new ArrayList() {{
+ this.add("color");
+ this.add("shadow");
+ }};
+ private static final List tf = new ArrayList() {{
+ this.add("true");
+ this.add("false");
+ }};
+ private final Map commandList = new HashMap<>();
+
+ public CommandHudSet(HudType type) {
+ super(type);
+ commandList.put("enable", new HudEnable(type));
+ commandList.put("reset", new HudReset(type));
+ commandList.put("pos", new HudPos(type));
+ commandList.put("dir", new HudDir(type));
+ if (type == HudType.PIC) {
+ commandList.put("size", new PicSize());
+ commandList.put("rotate", new PicRotate());
+ commandList.put("speed", new PicRotateSpeed());
+ } else {
+ commandList.put("color", new HudColor(type));
+ commandList.put("shadow", new HudShadow(type));
+ }
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ } else {
+ ICommand command = commandList.get(args[2]);
+ if (command != null) {
+ command.execute(sender, name, args);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ List list = new ArrayList<>(hud);
+ if (type == HudType.PIC) {
+ list.addAll(pic);
+ } else {
+ list.addAll(info);
+ }
+
+ return list;
+ } else {
+ ICommand command = commandList.get(args[index]);
+ if (command != null) {
+ return command.tab(name, args, index + 1);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static class HudEnable extends AHudCommand {
+ public HudEnable(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 3 || args.length == 4) {
+ boolean temp = HudUtils.setHudEnable(name, type, args.length == 4 ? args[3] : null);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.state
+ .replace(PAL.state, temp
+ ? AllMusic.getMessage().hudList.enable
+ : AllMusic.getMessage().hudList.disable)
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type)));
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return tf;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ private static class HudReset extends AHudCommand {
+ public HudReset(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ HudUtils.reset(name, type);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.reset
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type)));
+ }
+ }
+
+ private static class HudPos extends AHudCommand {
+ public HudPos(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ try {
+ if (args.length != 5) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ PosObj obj = HudUtils.setHudPos(name, type, args[3], args[4]);
+ if (obj == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.set
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type))
+ .replace(PAL.x, args[3])
+ .replace(PAL.y, args[4]));
+ } catch (Exception e) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+ }
+ }
+
+ private static class HudDir extends AHudCommand {
+ private static final List dir = new ArrayList() {{
+ for (HudDirType type : HudDirType.values()) {
+ this.add(type.name());
+ }
+ }};
+
+ public HudDir(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 4) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ HudDirType type1 = HudUtils.setDir(name, type, args[3]);
+ if (type1 == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.set1
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type))
+ .replace(PAL.dir, AllMusic.getMessage().hudList.getDir(type1)));
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return dir;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ private static class HudColor extends AHudCommand {
+ public HudColor(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 4) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ if (!HudUtils.setColor(name, type, args[3])) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.set2
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type))
+ .replace(PAL.color, args[3]));
+ }
+ }
+
+ private static class HudShadow extends AHudCommand {
+ public HudShadow(HudType type) {
+ super(type);
+ }
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 3 || args.length == 4) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.set3
+ .replace(PAL.hud, AllMusic.getMessage().hudList.getHud(type))
+ .replace(PAL.state, HudUtils.setShadow(name, type, args.length == 4 ? args[3] : null)
+ ? AllMusic.getMessage().hudList.enable
+ : AllMusic.getMessage().hudList.disable));
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return tf;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ private static class PicSize extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 4 || !HudUtils.setPicSize(name, args[3])) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ AllMusic.side.sendMessage(sender,
+ AllMusic.getMessage().hud.picSize.replace(PAL.size, args[2]));
+ }
+ }
+
+ private static class PicRotate extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length == 3 || args.length == 4) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().hud.picRotate
+ .replace(PAL.state, HudUtils.setPicRotate(name, args.length == 4 ? args[3] : null)
+ ? AllMusic.getMessage().hudList.enable
+ : AllMusic.getMessage().hudList.disable));
+ return;
+ }
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == index + 1) {
+ return tf;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ private static class PicRotateSpeed extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 4 || !HudUtils.setPicRotateSpeed(name, args[3])) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ AllMusic.side.sendMessage(sender,
+ AllMusic.getMessage().hud.picSpeed.replace(PAL.size, args[3]));
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandLastPage.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandLastPage.java
new file mode 100644
index 0000000..09af1ba
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandLastPage.java
@@ -0,0 +1,24 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.MusicSearch;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+
+public class CommandLastPage extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.search")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.noPer);
+ return;
+ }
+ SearchPageObj obj = AllMusic.getSearch(name);
+ if (obj == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.emptySearch);
+ } else if (obj.lastPage()) {
+ MusicSearch.showSearch(sender, obj);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.cantLast);
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandList.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandList.java
new file mode 100644
index 0000000..d05444e
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandList.java
@@ -0,0 +1,29 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+
+public class CommandList extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (PlayMusic.nowPlayMusic == null || PlayMusic.nowPlayMusic.isNull()) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.emptyPlayingMusic);
+ } else {
+ String info = AllMusic.getMessage().musicPlay.nowPlay;
+ info = info.replace(PAL.musicName, PlayMusic.nowPlayMusic.getName())
+ .replace(PAL.musicAuthor, PlayMusic.nowPlayMusic.getAuthor())
+ .replace(PAL.musicAl, PlayMusic.nowPlayMusic.getAl())
+ .replace(PAL.musicAlia, PlayMusic.nowPlayMusic.getAlia())
+ .replace(PAL.player, PlayMusic.nowPlayMusic.getCall());
+ AllMusic.side.sendMessage(sender, info);
+ }
+ if (PlayMusic.getListSize() == 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.emptyPlay);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.listMusic.head
+ .replace(PAL.count, "" + PlayMusic.getListSize()));
+ AllMusic.side.sendMessage(sender, PlayMusic.getAllList());
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandMute.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandMute.java
new file mode 100644
index 0000000..d11c610
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandMute.java
@@ -0,0 +1,13 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+
+public class CommandMute extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ AllMusic.side.sendStop(name);
+ AllMusic.side.clearHud(name);
+ AllMusic.getConfig().addNoMusicPlayer(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.mute);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNext.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNext.java
new file mode 100644
index 0000000..2a2b52c
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNext.java
@@ -0,0 +1,14 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+
+public class CommandNext extends ACommand {
+
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ PlayMusic.musicLessTime = 1;
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2已强制切歌");
+ AllMusic.getConfig().removeNoMusicPlayer(name);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNextPage.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNextPage.java
new file mode 100644
index 0000000..3357ca2
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandNextPage.java
@@ -0,0 +1,24 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.MusicSearch;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+
+public class CommandNextPage extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.search")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.noPer);
+ return;
+ }
+ SearchPageObj obj = AllMusic.getSearch(name);
+ if (obj == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.emptySearch);
+ } else if (obj.nextPage()) {
+ MusicSearch.showSearch(sender, obj);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.cantNext);
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandPush.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandPush.java
new file mode 100644
index 0000000..5219843
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandPush.java
@@ -0,0 +1,113 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CommandPush extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.push")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.noPermission);
+ return;
+ }
+ if (PlayMusic.getListSize() == 0 && PlayMusic.getIdleListSize() == 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.emptyPlay);
+ }
+ SongInfoObj music = null;
+ if (args.length == 1) {
+ music = PlayMusic.findPlayerMusic(name);
+ if (music == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.noId);
+ return;
+ }
+ SongInfoObj id1 = PlayMusic.findMusicIndex(1);
+ if (id1 != null && id1.getID().equalsIgnoreCase(music.getID())) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.pushErr);
+ return;
+ }
+ } else if (args.length == 2) {
+ if (args[1].equalsIgnoreCase("cancel")) {
+ if (!name.equalsIgnoreCase(PlayMusic.getPushSender())) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.err1);
+ return;
+ }
+ if (PlayMusic.getPushTime() <= 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.err2);
+ return;
+ }
+ PlayMusic.clearPush();
+ AllMusic.side.broadcast(AllMusic.getMessage().push.cancel);
+ return;
+ } else {
+ try {
+ int index = Integer.parseInt(args[1]);
+ music = PlayMusic.findMusicIndex(index);
+ } catch (Exception e) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.noId);
+ return;
+ }
+ if (music == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.noId1.replace(PAL.index, args[1]));
+ return;
+ }
+ }
+ } else if (args.length > 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ if (PlayMusic.getPushTime() <= 0) {
+ if (music == null) {
+ return;
+ }
+ PlayMusic.startPush(name, music);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.doVote);
+ String data = AllMusic.getMessage().push.bq;
+ AllMusic.side.broadcast(data
+ .replace(PAL.player, name)
+ .replace(PAL.time, String.valueOf(AllMusic.getConfig().voteTime))
+ .replace(PAL.musicName, music.getName())
+ .replace(PAL.musicAuthor, music.getAuthor()));
+ AllMusic.side.broadcastWithRun(AllMusic.getMessage().push.bq1, AllMusic.getMessage().push.bq2, "/music push");
+ } else {
+ if (music != null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.err3);
+ return;
+ }
+ if (!PlayMusic.containPush(name)) {
+ PlayMusic.addPush(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.agree);
+ String data = AllMusic.getMessage().push.bqAgree;
+ data = data.replace(PAL.player, name)
+ .replace(PAL.count, String.valueOf(PlayMusic.getVoteCount()));
+ AllMusic.side.broadcast(data);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().push.arAgree);
+ }
+ }
+ AllMusic.getConfig().removeNoMusicPlayer(name);
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == 1 || (args.length == 2 && args[1].isEmpty())) {
+ List list = new ArrayList<>();
+ List list1 = PlayMusic.getList();
+ for (int a = 1; a < list1.size(); a++) {
+ SongInfoObj item = list1.get(a);
+ if (item.getCall().equalsIgnoreCase(name)) {
+ list.add(String.valueOf(a));
+ }
+ }
+
+ return list;
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandReload.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandReload.java
new file mode 100644
index 0000000..8d690a2
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandReload.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+
+public class CommandReload extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ AllMusic.side.reload();
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2已重读配置文件");
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSearch.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSearch.java
new file mode 100644
index 0000000..2dfbfd6
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSearch.java
@@ -0,0 +1,24 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+
+public class CommandSearch extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.search")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.noPer);
+ return;
+ }
+ if (CommandEX.checkMoney(sender, name, AllMusic.getConfig().cost.searchCost)) {
+ return;
+ }
+ if (CommandEX.cost(sender, name, AllMusic.getConfig().cost.searchCost,
+ AllMusic.getMessage().cost.search)) {
+ return;
+ }
+
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.startSearch);
+ CommandEX.searchMusic(sender, name, args, false);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSelect.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSelect.java
new file mode 100644
index 0000000..56fbfd5
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandSelect.java
@@ -0,0 +1,54 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CommandSelect extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.search")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.noPer);
+ return;
+ }
+ SearchPageObj obj = AllMusic.getSearch(name);
+ if (obj == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.emptySearch);
+ } else if (!args[1].isEmpty() && Function.isInteger(args[1])) {
+ int a = Integer.parseInt(args[1]);
+ if (a == 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.errorNum);
+ return;
+ }
+ String[] ID = new String[1];
+ ID[0] = obj.getSong((obj.getPage() * 10) + (a - 1));
+ AllMusic.side.sendMessage(sender,
+ AllMusic.getMessage().search.choice.replace(PAL.index, "" + a));
+ CommandEX.addMusic(sender, name, ID);
+ AllMusic.removeSearch(name);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().search.errorNum);
+ }
+ }
+
+ @Override
+ public List tab(String name, String[] args, int index) {
+ if (args.length == 1 || (args.length == 2 && args[1].isEmpty())) {
+ List list = new ArrayList<>();
+ SearchPageObj obj = AllMusic.getSearch(name);
+ if (obj != null) {
+ for (int a = 0; a < obj.getIndex(); a++) {
+ list.add(String.valueOf(a));
+ }
+ }
+ return list;
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandStop.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandStop.java
new file mode 100644
index 0000000..61ca565
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandStop.java
@@ -0,0 +1,15 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+
+public class CommandStop extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ AllMusic.side.clearHud(name);
+ AllMusic.side.sendStop(name);
+ HudUtils.clearHud(name);
+ AllMusic.removeNowPlayPlayer(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.stopPlaying);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandTest.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandTest.java
new file mode 100644
index 0000000..8797167
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandTest.java
@@ -0,0 +1,35 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+public class CommandTest extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ if (Function.isInteger(args[1])) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2正在测试解析" + args[1]);
+ try {
+ SongInfoObj info = AllMusic.getMusicApi().getMusic(args[1], "test", false);
+ if (info == null) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2测试解析失败");
+ return;
+ }
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2音乐名称 " + info.getName());
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2音乐作者 " + info.getAuthor());
+ String url = AllMusic.getMusicApi().getPlayUrl(args[1]);
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2播放地址 " + url);
+ } catch (Exception e) {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2测试解析错误");
+ e.printStackTrace();
+ }
+ } else {
+ AllMusic.side.sendMessage(sender, "§d[AllMusic3]§2请输入有效的ID");
+ }
+ }
+}
+
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandUrl.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandUrl.java
new file mode 100644
index 0000000..a6464e4
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandUrl.java
@@ -0,0 +1,21 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.music.MusicObj;
+
+public class CommandUrl extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (args.length != 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ }
+ MusicObj obj = new MusicObj();
+ obj.sender = sender;
+ obj.isUrl = true;
+ obj.url = args[1];
+ PlayMusic.addTask(obj);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().addMusic.success);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandVote.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandVote.java
new file mode 100644
index 0000000..84f3ac9
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/CommandVote.java
@@ -0,0 +1,57 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+
+public class CommandVote extends ACommand {
+ @Override
+ public void execute(Object sender, String name, String[] args) {
+ if (AllMusic.getConfig().needPermission &&
+ !AllMusic.side.checkPermission(name, "allmusic.vote")) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.noPermission);
+ return;
+ } else if (PlayMusic.getListSize() == 0 && PlayMusic.getIdleListSize() == 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.emptyPlay);
+ } else if (PlayMusic.nowPlayMusic == null) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().musicPlay.emptyPlayingMusic);
+ } else if (args.length == 2) {
+ if (args[1].equalsIgnoreCase("cancel")) {
+ if (!name.equalsIgnoreCase(PlayMusic.getVoteSender())) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.err1);
+ return;
+ } else if (PlayMusic.getVoteTime() <= 0) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.err2);
+ return;
+ }
+ AllMusic.side.broadcast(AllMusic.getMessage().vote.cancel);
+ PlayMusic.clearVote();
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ }
+ return;
+ } else if (args.length > 2) {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().command.error);
+ return;
+ } else if (PlayMusic.getVoteTime() <= 0) {
+ PlayMusic.startVote(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.doVote);
+ String data = AllMusic.getMessage().vote.bq;
+ AllMusic.side.broadcast(data.replace(PAL.player, name)
+ .replace(PAL.time, String.valueOf(AllMusic.getConfig().voteTime)));
+ AllMusic.side.broadcastWithRun(AllMusic.getMessage().vote.bq1, AllMusic.getMessage().vote.bq2, "/music vote");
+ } else {
+ if (!PlayMusic.containVote(name)) {
+ PlayMusic.addVote(name);
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.agree);
+ String data = AllMusic.getMessage().vote.bqAgree;
+ data = data.replace(PAL.player, name)
+ .replace(PAL.count, String.valueOf(PlayMusic.getVoteCount()));
+ AllMusic.side.broadcast(data);
+ } else {
+ AllMusic.side.sendMessage(sender, AllMusic.getMessage().vote.arAgree);
+ }
+ }
+ AllMusic.getConfig().removeNoMusicPlayer(name);
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/command/ICommand.java b/src/main/java/io/github/thehrz/allmusicreload/core/command/ICommand.java
new file mode 100644
index 0000000..e877e35
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/command/ICommand.java
@@ -0,0 +1,10 @@
+package io.github.thehrz.allmusicreload.core.command;
+
+import java.util.List;
+
+public interface ICommand {
+
+ void execute(Object sender, String name, String[] args);
+
+ List tab(String name, String[] args, int index);
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Bitstream.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Bitstream.java
new file mode 100644
index 0000000..93ebb42
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Bitstream.java
@@ -0,0 +1,536 @@
+/*
+ * 11/19/04 1.0 moved to LGPL.
+ *
+ * 11/17/04 Uncomplete frames discarded. E.B, javalayer@javazoom.net
+ *
+ * 12/05/03 ID3v2 tag returned. E.B, javalayer@javazoom.net
+ *
+ * 12/12/99 Based on Ibitstream. Exceptions thrown on errors,
+ * Temporary removed seek functionality. mdm@techie.com
+ *
+ * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
+ *
+ * 04/14/97 : Added function prototypes for new syncing and seeking
+ * mechanisms. Also made this file portable. Changes made by Jeff Tsay
+ *
+ * @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34
+ * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
+ * @(#) Berlin University of Technology
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+package io.github.thehrz.allmusicreload.core.decoder;
+
+import java.io.*;
+
+
+/**
+ * The Bistream
class is responsible for parsing
+ * an MPEG audio bitstream.
+ *
+ * REVIEW: much of the parsing currently occurs in the
+ * various decoders. This should be moved into this class and associated
+ * inner classes.
+ */
+public final class Bitstream implements BitstreamErrors {
+ /**
+ * Maximum size of the frame buffer.
+ */
+ private static final int BUFFER_INT_SIZE = 433;
+ /**
+ * Synchronization control constant for the initial
+ * synchronization to the start of a frame.
+ */
+ static byte INITIAL_SYNC = 0;
+
+ // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC
+ /**
+ * Synchronization control constant for non-initial frame
+ * synchronizations.
+ */
+ static byte STRICT_SYNC = 1;
+ /**
+ * The frame buffer that holds the data for the current frame.
+ */
+ private final int[] framebuffer = new int[BUFFER_INT_SIZE];
+ private final int[] bitmask = {0, // dummy
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+ 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+ 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+ 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+ 0x0001FFFF};
+ private final PushbackInputStream source;
+ private final Header header = new Header();
+ private final byte[] syncbuf = new byte[4];
+ /**
+ * The bytes read from the stream.
+ */
+ private final byte[] frame_bytes = new byte[BUFFER_INT_SIZE * 4];
+ private final Crc16[] crc = new Crc16[1];
+ /**
+ * Number of valid bytes in the frame buffer.
+ */
+ private int framesize;
+ //private int current_frame_number;
+ //private int last_frame_number;
+ /**
+ * Index into framebuffer
where the next bits are
+ * retrieved.
+ */
+ private int wordpointer;
+ /**
+ * Number (0-31, from MSB to LSB) of next bit for get_bits()
+ */
+ private int bitindex;
+ /**
+ * The current specified syncword
+ */
+ private int syncword;
+ /**
+ * Audio header position in stream.
+ */
+ private int header_pos = 0;
+ /**
+ *
+ */
+ private boolean single_ch_mode;
+ private byte[] rawid3v2 = null;
+
+ private boolean firstframe = true;
+
+
+ /**
+ * Construct a IBitstream that reads data from a
+ * given InputStream.
+ *
+ * @param in The InputStream to read from.
+ */
+ public Bitstream(InputStream in) {
+ if (in == null) throw new NullPointerException("in");
+ in = new BufferedInputStream(in);
+ loadID3v2(in);
+ firstframe = true;
+ //source = new PushbackInputStream(in, 1024);
+ source = new PushbackInputStream(in, BUFFER_INT_SIZE * 4);
+
+ closeFrame();
+ //current_frame_number = -1;
+ //last_frame_number = -1;
+ }
+
+ /**
+ * Return position of the first audio header.
+ *
+ * @return size of ID3v2 tag frames.
+ */
+ public int header_pos() {
+ return header_pos;
+ }
+
+ /**
+ * Load ID3v2 frames.
+ *
+ * @param in MP3 InputStream.
+ * @author JavaZOOM
+ */
+ private void loadID3v2(InputStream in) {
+ int size = -1;
+ try {
+ // Read ID3v2 header (10 bytes).
+ in.mark(10);
+ size = readID3v2Header(in);
+ header_pos = size;
+ } catch (IOException e) {
+ } finally {
+ try {
+ // Unread ID3v2 header (10 bytes).
+ in.reset();
+ } catch (IOException e) {
+ }
+ }
+ // Load ID3v2 tags.
+ try {
+ if (size > 0) {
+ rawid3v2 = new byte[size];
+ in.read(rawid3v2, 0, rawid3v2.length);
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Parse ID3v2 tag header to find out size of ID3v2 frames.
+ *
+ * @param in MP3 InputStream
+ * @return size of ID3v2 frames + header
+ * @throws IOException
+ * @author JavaZOOM
+ */
+ private int readID3v2Header(InputStream in) throws IOException {
+ byte[] id3header = new byte[4];
+ int size = -10;
+ in.read(id3header, 0, 3);
+ // Look for ID3v2
+ if ((id3header[0] == 'I') && (id3header[1] == 'D') && (id3header[2] == '3')) {
+ in.read(id3header, 0, 3);
+ int majorVersion = id3header[0];
+ int revision = id3header[1];
+ in.read(id3header, 0, 4);
+ size = (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
+ }
+ return (size + 10);
+ }
+
+ /**
+ * Return raw ID3v2 frames + header.
+ *
+ * @return ID3v2 InputStream or null if ID3v2 frames are not available.
+ */
+ public InputStream getRawID3v2() {
+ if (rawid3v2 == null) return null;
+ else {
+ return new ByteArrayInputStream(rawid3v2);
+ }
+ }
+
+ /**
+ * Close the Bitstream.
+ *
+ * @throws BitstreamException
+ */
+ public void close() throws BitstreamException {
+ try {
+ source.close();
+ } catch (IOException ex) {
+ throw newBitstreamException(STREAM_ERROR, ex);
+ }
+ }
+
+ /**
+ * Reads and parses the next frame from the input source.
+ *
+ * @return the Header describing details of the frame read,
+ * or null if the end of the stream has been reached.
+ */
+ public Header readFrame() throws BitstreamException {
+ Header result = null;
+ try {
+ result = readNextFrame();
+ // E.B, Parse VBR (if any) first frame.
+ if (firstframe) {
+ result.parseVBR(frame_bytes);
+ firstframe = false;
+ }
+ } catch (BitstreamException ex) {
+ if ((ex.getErrorCode() == INVALIDFRAME)) {
+ // Try to skip this frame.
+ //System.out.println("INVALIDFRAME");
+ try {
+ closeFrame();
+ result = readNextFrame();
+ } catch (BitstreamException e) {
+ if ((e.getErrorCode() != STREAM_EOF)) {
+ // wrap original exception so stack trace is maintained.
+ throw newBitstreamException(e.getErrorCode(), e);
+ }
+ }
+ } else if ((ex.getErrorCode() != STREAM_EOF)) {
+ // wrap original exception so stack trace is maintained.
+ throw newBitstreamException(ex.getErrorCode(), ex);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Read next MP3 frame.
+ *
+ * @return MP3 frame header.
+ * @throws BitstreamException
+ */
+ private Header readNextFrame() throws BitstreamException {
+ if (framesize == -1) {
+ nextFrame();
+ }
+ return header;
+ }
+
+
+ /**
+ * Read next MP3 frame.
+ *
+ * @throws BitstreamException
+ */
+ private void nextFrame() throws BitstreamException {
+ // entire frame is read by the header class.
+ header.read_header(this, crc);
+ }
+
+ /**
+ * Unreads the bytes read from the frame.
+ *
+ * @throws BitstreamException
+ */
+ // REVIEW: add new error codes for this.
+ public void unreadFrame() throws BitstreamException {
+ if (wordpointer == -1 && bitindex == -1 && (framesize > 0)) {
+ try {
+ source.unread(frame_bytes, 0, framesize);
+ } catch (IOException ex) {
+ throw newBitstreamException(STREAM_ERROR);
+ }
+ }
+ }
+
+ /**
+ * Close MP3 frame.
+ */
+ public void closeFrame() {
+ framesize = -1;
+ wordpointer = -1;
+ bitindex = -1;
+ }
+
+ /**
+ * Determines if the next 4 bytes of the stream represent a
+ * frame header.
+ */
+ public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException {
+ int read = readBytes(syncbuf, 0, 4);
+ int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);
+
+ try {
+ source.unread(syncbuf, 0, read);
+ } catch (IOException ex) {
+ }
+
+ boolean sync = false;
+ switch (read) {
+ case 0:
+ sync = true;
+ break;
+ case 4:
+ sync = isSyncMark(headerstring, syncmode, syncword);
+ break;
+ }
+
+ return sync;
+ }
+
+ BitstreamException newBitstreamException(int errorcode) {
+ return new BitstreamException(errorcode, null);
+ }
+
+ private BitstreamException newBitstreamException(int errorcode, Throwable throwable) {
+ return new BitstreamException(errorcode, throwable);
+ }
+
+ /**
+ * Get next 32 bits from bitstream.
+ * They are stored in the headerstring.
+ * syncmod allows Synchro flag ID
+ * The returned value is False at the end of stream.
+ */
+
+ int syncHeader(byte syncmode) throws BitstreamException {
+ boolean sync;
+ int headerstring;
+ // read additional 2 bytes
+ int bytesRead = readBytes(syncbuf, 0, 3);
+
+ if (bytesRead != 3) throw newBitstreamException(STREAM_EOF, null);
+
+ headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2]) & 0x000000FF);
+
+ do {
+ headerstring <<= 8;
+
+ if (readBytes(syncbuf, 3, 1) != 1)
+ throw newBitstreamException(STREAM_EOF, null);
+
+ headerstring |= (syncbuf[3] & 0x000000FF);
+
+ sync = isSyncMark(headerstring, syncmode, syncword);
+ }
+ while (!sync);
+
+ return headerstring;
+ }
+
+ public boolean isSyncMark(int headerstring, int syncmode, int word) {
+ boolean sync = false;
+
+ if (syncmode == INITIAL_SYNC) {
+ sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5
+ } else {
+ sync = ((headerstring & 0xFFF80C00) == word) &&
+ (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
+ }
+
+ // filter out invalid sample rate
+ if (sync)
+ sync = (((headerstring >>> 10) & 3) != 3);
+ // filter out invalid layer
+ if (sync)
+ sync = (((headerstring >>> 17) & 3) != 0);
+ // filter out invalid version
+ if (sync)
+ sync = (((headerstring >>> 19) & 3) != 1);
+
+ return sync;
+ }
+
+ /**
+ * Reads the data for the next frame. The frame is not parsed
+ * until parse frame is called.
+ */
+ int read_frame_data(int bytesize) throws BitstreamException {
+ int numread = readFully(frame_bytes, 0, bytesize);
+ framesize = bytesize;
+ wordpointer = -1;
+ bitindex = -1;
+ return numread;
+ }
+
+ /**
+ * Parses the data previously read with read_frame_data().
+ */
+ void parse_frame() throws BitstreamException {
+ // Convert Bytes read to int
+ int b = 0;
+ byte[] byteread = frame_bytes;
+ int bytesize = framesize;
+
+ for (int k = 0; k < bytesize; k = k + 4) {
+ int convert = 0;
+ byte b0 = 0;
+ byte b1 = 0;
+ byte b2 = 0;
+ byte b3 = 0;
+ b0 = byteread[k];
+ if (k + 1 < bytesize) b1 = byteread[k + 1];
+ if (k + 2 < bytesize) b2 = byteread[k + 2];
+ if (k + 3 < bytesize) b3 = byteread[k + 3];
+ framebuffer[b++] = ((b0 << 24) & 0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);
+ }
+ wordpointer = 0;
+ bitindex = 0;
+ }
+
+ /**
+ * Read bits from buffer into the lower bits of an unsigned int.
+ * The LSB contains the latest read bit of the stream.
+ * (1 <= number_of_bits <= 16)
+ */
+ public int get_bits(int number_of_bits) {
+ int returnvalue = 0;
+ int sum = bitindex + number_of_bits;
+
+ // E.B
+ // There is a problem here, wordpointer could be -1 ?!
+ if (wordpointer < 0) wordpointer = 0;
+ // E.B : End.
+
+ if (sum <= 32) {
+ // all bits contained in *wordpointer
+ returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];
+ // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];
+ if ((bitindex += number_of_bits) == 32) {
+ bitindex = 0;
+ wordpointer++; // added by me!
+ }
+ return returnvalue;
+ }
+
+ int Right = (framebuffer[wordpointer] & 0x0000FFFF);
+ wordpointer++;
+ int Left = (framebuffer[wordpointer] & 0xFFFF0000);
+ returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16) & 0x0000FFFF);
+
+ returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))
+ returnvalue &= bitmask[number_of_bits];
+ bitindex = sum - 32;
+ return returnvalue;
+ }
+
+ /**
+ * Set the word we want to sync the header to.
+ * In Big-Endian byte order
+ */
+ void set_syncword(int syncword0) {
+ syncword = syncword0 & 0xFFFFFF3F;
+ single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
+ }
+
+ /**
+ * Reads the exact number of bytes from the source
+ * input stream into a byte array.
+ *
+ * @param b The byte array to read the specified number
+ * of bytes into.
+ * @param offs The index in the array where the first byte
+ * read should be stored.
+ * @param len the number of bytes to read.
+ * @throws BitstreamException is thrown if the specified
+ * number of bytes could not be read from the stream.
+ */
+ private int readFully(byte[] b, int offs, int len)
+ throws BitstreamException {
+ int nRead = 0;
+ try {
+ while (len > 0) {
+ int bytesread = source.read(b, offs, len);
+ if (bytesread == -1) {
+ while (len-- > 0) {
+ b[offs++] = 0;
+ }
+ break;
+ //throw newBitstreamException(UNEXPECTED_EOF, new EOFException());
+ }
+ nRead = nRead + bytesread;
+ offs += bytesread;
+ len -= bytesread;
+ }
+ } catch (IOException ex) {
+ throw newBitstreamException(STREAM_ERROR, ex);
+ }
+ return nRead;
+ }
+
+ /**
+ * Simlar to readFully, but doesn't throw exception when
+ * EOF is reached.
+ */
+ private int readBytes(byte[] b, int offs, int len)
+ throws BitstreamException {
+ int totalBytesRead = 0;
+ try {
+ while (len > 0) {
+ int bytesread = source.read(b, offs, len);
+ if (bytesread == -1) {
+ break;
+ }
+ totalBytesRead += bytesread;
+ offs += bytesread;
+ len -= bytesread;
+ }
+ } catch (IOException ex) {
+ throw newBitstreamException(STREAM_ERROR, ex);
+ }
+ return totalBytesRead;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamErrors.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamErrors.java
new file mode 100644
index 0000000..ffe44df
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamErrors.java
@@ -0,0 +1,55 @@
+/*
+ * 11/19/04 1.0 moved to LGPL.
+ * 11/17/04 INVALIDFRAME code added. javalayer@javazoom.net
+ * 12/12/99 Initial version. mdm@techie.com
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+package io.github.thehrz.allmusicreload.core.decoder;
+
+/**
+ * This interface describes all error codes that can be thrown
+ * in BistreamException
s.
+ *
+ * @author MDM 12/12/99
+ * @see BitstreamException
+ * @since 0.0.6
+ */
+
+public interface BitstreamErrors extends JavaLayerErrors {
+
+ /**
+ * An undeterminable error occurred.
+ */
+ int UNKNOWN_ERROR = BITSTREAM_ERROR;
+
+ /**
+ * A problem occurred reading from the stream.
+ */
+ int STREAM_ERROR = BITSTREAM_ERROR + 2;
+
+ /**
+ * The end of the stream was reached.
+ */
+ int STREAM_EOF = BITSTREAM_ERROR + 4;
+
+ /**
+ * Frame data are missing.
+ */
+ int INVALIDFRAME = BITSTREAM_ERROR + 5;
+
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamException.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamException.java
new file mode 100644
index 0000000..21b24a0
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/BitstreamException.java
@@ -0,0 +1,65 @@
+/*
+ * 11/19/04 1.0 moved to LGPL.
+ * 12/12/99 Initial version. mdm@techie.com
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+package io.github.thehrz.allmusicreload.core.decoder;
+
+/**
+ * Instances of BitstreamException
are thrown
+ * when operations on a Bitstream
fail.
+ *
+ * The exception provides details of the exception condition
+ * in two ways:
+ *
-
+ * as an error-code describing the nature of the error
+ *
-
+ * as the
Throwable
instance, if any, that was thrown
+ * indicating that an exceptional condition has occurred.
+ *
+ *
+ * @author MDM 12/12/99
+ * @since 0.0.6
+ */
+
+public class BitstreamException extends JavaLayerException
+ implements BitstreamErrors {
+ private int errorcode = UNKNOWN_ERROR;
+
+ public BitstreamException(String msg, Throwable t) {
+ super(msg, t);
+ }
+
+ public BitstreamException(int errorcode, Throwable t) {
+ this(getErrorString(errorcode), t);
+ this.errorcode = errorcode;
+ }
+
+ static public String getErrorString(int errorcode) {
+ // REVIEW: use resource bundle to map error codes
+ // to locale-sensitive strings.
+
+ return "Bitstream errorcode " + Integer.toHexString(errorcode);
+ }
+
+ public int getErrorCode() {
+ return errorcode;
+ }
+
+
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Crc16.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Crc16.java
new file mode 100644
index 0000000..10503ba
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Crc16.java
@@ -0,0 +1,64 @@
+/*
+ * 11/19/04 : 1.0 moved to LGPL.
+ *
+ * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
+ *
+ * @(#) crc.h 1.5, last edit: 6/15/94 16:55:32
+ * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
+ * @(#) Berlin University of Technology
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package io.github.thehrz.allmusicreload.core.decoder;
+
+/**
+ * 16-Bit CRC checksum
+ */
+public final class Crc16 {
+ private short crc;
+
+ /**
+ * Dummy Constructor
+ */
+ public Crc16() {
+ crc = (short) 0xFFFF;
+ }
+
+ /**
+ * Feed a bitstring to the crc calculation (0 < length <= 32).
+ */
+ public void add_bits(int bitstring, int length) {
+ int bitmask = 1 << (length - 1);
+ do
+ if (((crc & 0x8000) == 0) ^ ((bitstring & bitmask) == 0)) {
+ crc <<= 1;
+ short polynomial = (short) 0x8005;
+ crc ^= polynomial;
+ } else
+ crc <<= 1;
+ while ((bitmask >>>= 1) != 0);
+ }
+
+ /**
+ * Return the calculated checksum.
+ * Erase it for next calls to add_bits().
+ */
+ public short checksum() {
+ short sum = crc;
+ crc = (short) 0xFFFF;
+ return sum;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Header.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Header.java
new file mode 100644
index 0000000..c9ebf04
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/Header.java
@@ -0,0 +1,618 @@
+/*
+ * 11/19/04 : 1.0 moved to LGPL.
+ * VBRI header support added, E.B javalayer@javazoom.net
+ *
+ * 12/04/03 : VBR (XING) header support added, E.B javalayer@javazoom.net
+ *
+ * 02/13/99 : Java Conversion by JavaZOOM , E.B javalayer@javazoom.net
+ *
+ * Declarations for MPEG header class
+ * A few layer III, MPEG-2 LSF, and seeking modifications made by Jeff Tsay.
+ * Last modified : 04/19/97
+ *
+ * @(#) header.h 1.7, last edit: 6/15/94 16:55:33
+ * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
+ * @(#) Berlin University of Technology
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package io.github.thehrz.allmusicreload.core.decoder;
+
+/**
+ * Class for extracting information from a frame header.
+ */
+public final class Header {
+ public static final int[][] frequencies =
+ {{22050, 24000, 16000, 1},
+ {44100, 48000, 32000, 1},
+ {11025, 12000, 8000, 1}}; // SZD: MPEG25
+
+ /**
+ * Constant for MPEG-2 LSF version
+ */
+ public static final int MPEG2_LSF = 0;
+ public static final int MPEG25_LSF = 2; // SZD
+
+ /**
+ * Constant for MPEG-1 version
+ */
+ public static final int MPEG1 = 1;
+
+ public static final int STEREO = 0;
+ public static final int JOINT_STEREO = 1;
+ public static final int DUAL_CHANNEL = 2;
+ public static final int SINGLE_CHANNEL = 3;
+ public static final int FOURTYFOUR_POINT_ONE = 0;
+ public static final int FOURTYEIGHT = 1;
+ public static final int THIRTYTWO = 2;
+ // E.B -> private to public
+ public static final int[][][] bitrates = {
+ {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
+ 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, 0},
+ {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
+ 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
+ {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
+ 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
+
+ {{0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000,
+ 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0},
+ {0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
+ 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0},
+ {0 /*free format*/, 32000, 40000, 48000, 56000, 64000, 80000,
+ 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0}},
+ // SZD: MPEG2.5
+ {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
+ 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, 0},
+ {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
+ 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},
+ {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,
+ 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},
+
+ };
+ // E.B -> private to public
+ public static final String[][][] bitrate_str = {
+ {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
+ "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
+ "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
+ "forbidden"},
+ {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
+ "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
+ "forbidden"},
+ {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
+ "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
+ "forbidden"}},
+
+ {{"free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s",
+ "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s",
+ "320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s", "448 kbit/s",
+ "forbidden"},
+ {"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
+ "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s",
+ "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", "384 kbit/s",
+ "forbidden"},
+ {"free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s",
+ "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s",
+ "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s",
+ "forbidden"}},
+ // SZD: MPEG2.5
+ {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",
+ "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",
+ "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
+ "forbidden"},
+ {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
+ "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
+ "forbidden"},
+ {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",
+ "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
+ "forbidden"}},
+ };
+ // VBR support added by E.B
+ private final double[] h_vbr_time_per_frame = {-1, 384, 1152, 1152};
+ public short checksum;
+ public int framesize;
+ public int nSlots;
+ private int h_layer, h_protection_bit, h_bitrate_index,
+ h_padding_bit, h_mode_extension;
+ private int h_version;
+ private int h_mode;
+ private int h_sample_frequency;
+ private int h_number_of_subbands, h_intensity_stereo_bound;
+ private boolean h_vbr;
+ private int h_vbr_frames;
+ private int h_vbr_bytes;
+ private byte syncmode = Bitstream.INITIAL_SYNC;
+ private Crc16 crc;
+
+ Header() {
+ }
+
+ /**
+ * Returns total ms.
+ *
+ * @param streamsize
+ * @return total milliseconds
+ */
+ public float total_ms(int streamsize) {
+ return (max_number_of_frames(streamsize) * ms_per_frame());
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder(200);
+ buffer.append("Layer ");
+ buffer.append(layer_string());
+ buffer.append(" frame ");
+ buffer.append(mode_string());
+ buffer.append(' ');
+ buffer.append(version_string());
+ if (!checksums())
+ buffer.append(" no");
+ buffer.append(" checksums");
+ buffer.append(' ');
+ buffer.append(sample_frequency_string());
+ buffer.append(',');
+ buffer.append(' ');
+ buffer.append(bitrate_string());
+
+ return buffer.toString();
+ }
+
+ // Functions to query header contents:
+
+ /**
+ * Read a 32-bit header from the bitstream.
+ */
+ void read_header(Bitstream stream, Crc16[] crcp) throws BitstreamException {
+ int headerstring;
+ int channel_bitrate;
+ boolean sync = false;
+ do {
+ headerstring = stream.syncHeader(syncmode);
+ if (syncmode == Bitstream.INITIAL_SYNC) {
+ h_version = ((headerstring >>> 19) & 1);
+ if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection
+ if (h_version == MPEG2_LSF)
+ h_version = MPEG25_LSF;
+ else
+ throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
+ if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3) {
+ throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
+ }
+ }
+ h_layer = 4 - (headerstring >>> 17) & 3;
+ h_protection_bit = (headerstring >>> 16) & 1;
+ h_bitrate_index = (headerstring >>> 12) & 0xF;
+ h_padding_bit = (headerstring >>> 9) & 1;
+ h_mode = ((headerstring >>> 6) & 3);
+ h_mode_extension = (headerstring >>> 4) & 3;
+ if (h_mode == JOINT_STEREO)
+ h_intensity_stereo_bound = (h_mode_extension << 2) + 4;
+ else
+ h_intensity_stereo_bound = 0; // should never be used
+ // calculate number of subbands:
+ if (h_layer == 1)
+ h_number_of_subbands = 32;
+ else {
+ channel_bitrate = h_bitrate_index;
+ // calculate bitrate per channel:
+ if (h_mode != SINGLE_CHANNEL)
+ if (channel_bitrate == 4)
+ channel_bitrate = 1;
+ else
+ channel_bitrate -= 4;
+ if ((channel_bitrate == 1) || (channel_bitrate == 2))
+ if (h_sample_frequency == THIRTYTWO)
+ h_number_of_subbands = 12;
+ else
+ h_number_of_subbands = 8;
+ else if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))
+ h_number_of_subbands = 27;
+ else
+ h_number_of_subbands = 30;
+ }
+ if (h_intensity_stereo_bound > h_number_of_subbands)
+ h_intensity_stereo_bound = h_number_of_subbands;
+ // calculate framesize and nSlots
+ calculate_framesize();
+ // read framedata:
+ int framesizeloaded = stream.read_frame_data(framesize);
+ if ((framesize >= 0) && (framesizeloaded != framesize)) {
+ // Data loaded does not match to expected framesize,
+ // it might be an ID3v1 TAG. (Fix 11/17/04).
+ throw stream.newBitstreamException(Bitstream.INVALIDFRAME);
+ }
+ if (stream.isSyncCurrentPosition(syncmode)) {
+ if (syncmode == Bitstream.INITIAL_SYNC) {
+ syncmode = Bitstream.STRICT_SYNC;
+ stream.set_syncword(headerstring & 0xFFF80CC0);
+ }
+ sync = true;
+ } else {
+ stream.unreadFrame();
+ }
+ }
+ while (!sync);
+ stream.parse_frame();
+ if (h_protection_bit == 0) {
+ // frame contains a crc checksum
+ checksum = (short) stream.get_bits(16);
+ if (crc == null)
+ crc = new Crc16();
+ crc.add_bits(headerstring, 16);
+ crcp[0] = crc;
+ } else
+ crcp[0] = null;
+ }
+
+ /**
+ * Parse frame to extract optionnal VBR frame.
+ *
+ * @param firstframe
+ * @author E.B (javalayer@javazoom.net)
+ */
+ void parseVBR(byte[] firstframe) throws BitstreamException {
+ // Trying Xing header.
+ String xing = "Xing";
+ byte[] tmp = new byte[4];
+ int offset = 0;
+ // Compute "Xing" offset depending on MPEG version and channels.
+ if (h_version == MPEG1) {
+ if (h_mode == SINGLE_CHANNEL) offset = 21 - 4;
+ else offset = 36 - 4;
+ } else {
+ if (h_mode == SINGLE_CHANNEL) offset = 13 - 4;
+ else offset = 21 - 4;
+ }
+ byte[] h_vbr_toc;
+ try {
+ System.arraycopy(firstframe, offset, tmp, 0, 4);
+ // Is "Xing" ?
+ if (xing.equals(new String(tmp))) {
+ //Yes.
+ h_vbr = true;
+ h_vbr_frames = -1;
+ h_vbr_bytes = -1;
+ h_vbr_toc = new byte[100];
+
+ int length = 4;
+ // Read flags.
+ byte[] flags = new byte[4];
+ System.arraycopy(firstframe, offset + length, flags, 0, flags.length);
+ length += flags.length;
+ // Read number of frames (if available).
+ if ((flags[3] & (byte) (1)) != 0) {
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
+ h_vbr_frames = (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00 | tmp[3] & 0x000000FF;
+ length += 4;
+ }
+ // Read size (if available).
+ if ((flags[3] & (byte) (1 << 1)) != 0) {
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
+ h_vbr_bytes = (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00 | tmp[3] & 0x000000FF;
+ length += 4;
+ }
+ // Read TOC (if available).
+ if ((flags[3] & (byte) (1 << 2)) != 0) {
+ System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length);
+ length += h_vbr_toc.length;
+ }
+ // Read scale (if available).
+ if ((flags[3] & (byte) (1 << 3)) != 0) {
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new BitstreamException("XingVBRHeader Corrupted", e);
+ }
+
+ // Trying VBRI header.
+ String vbri = "VBRI";
+ offset = 36 - 4;
+ try {
+ System.arraycopy(firstframe, offset, tmp, 0, 4);
+ // Is "VBRI" ?
+ if (vbri.equals(new String(tmp))) {
+ //Yes.
+ h_vbr = true;
+ h_vbr_frames = -1;
+ h_vbr_bytes = -1;
+ // Bytes.
+ int length = 4 + 6;
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
+ h_vbr_bytes = (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00 | tmp[3] & 0x000000FF;
+ length += 4;
+ // Frames.
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);
+ h_vbr_frames = (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00 | tmp[3] & 0x000000FF;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new BitstreamException("VBRIVBRHeader Corrupted", e);
+ }
+ }
+
+ /**
+ * Returns version.
+ */
+ public int version() {
+ return h_version;
+ }
+
+ /**
+ * Returns Layer ID.
+ */
+ public int layer() {
+ return h_layer;
+ }
+
+ /**
+ * Returns bitrate index.
+ */
+ public int bitrate_index() {
+ return h_bitrate_index;
+ }
+
+ /**
+ * Returns Sample Frequency.
+ */
+ public int sample_frequency() {
+ return h_sample_frequency;
+ }
+
+ /**
+ * Returns Frequency.
+ */
+ public int frequency() {
+ return frequencies[h_version][h_sample_frequency];
+ }
+
+ /**
+ * Returns Mode.
+ */
+ public int mode() {
+ return h_mode;
+ }
+
+ /**
+ * Returns Protection bit.
+ */
+ public boolean checksums() {
+ return h_protection_bit == 0;
+ }
+
+ // Seeking and layer III stuff
+
+ /**
+ * Returns Checksum flag.
+ * Compares computed checksum with stream checksum.
+ */
+ public boolean checksum_ok() {
+ return (checksum == crc.checksum());
+ }
+
+ /**
+ * Returns Slots.
+ */
+ public int slots() {
+ return nSlots;
+ }
+
+ // E.B -> private to public
+
+ /**
+ * Returns Mode Extension.
+ */
+ public int mode_extension() {
+ return h_mode_extension;
+ }
+
+ /**
+ * Calculate Frame size.
+ * Calculates framesize in bytes excluding header size.
+ */
+ public void calculate_framesize() {
+
+ if (h_layer == 1) {
+ framesize = (12 * bitrates[h_version][0][h_bitrate_index]) /
+ frequencies[h_version][h_sample_frequency];
+ if (h_padding_bit != 0) framesize++;
+ framesize <<= 2; // one slot is 4 bytes long
+ nSlots = 0;
+ } else {
+ framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index]) /
+ frequencies[h_version][h_sample_frequency];
+ if (h_version == MPEG2_LSF || h_version == MPEG25_LSF) framesize >>= 1; // SZD
+ if (h_padding_bit != 0) framesize++;
+ // Layer III slots
+ if (h_layer == 3) {
+ if (h_version == MPEG1) {
+ nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side info size
+ - ((h_protection_bit != 0) ? 0 : 2) // CRC size
+ - 4; // header size
+ } else { // MPEG-2 LSF, SZD: MPEG-2.5 LSF
+ nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side info size
+ - ((h_protection_bit != 0) ? 0 : 2) // CRC size
+ - 4; // header size
+ }
+ } else {
+ nSlots = 0;
+ }
+ }
+ framesize -= 4; // subtract header size
+ }
+
+ /**
+ * Returns the maximum number of frames in the stream.
+ *
+ * @param streamsize
+ * @return number of frames
+ */
+ public int max_number_of_frames(int streamsize) // E.B
+ {
+ if (h_vbr) return h_vbr_frames;
+ else {
+ if ((framesize + 4 - h_padding_bit) == 0) return 0;
+ else return (streamsize / (framesize + 4 - h_padding_bit));
+ }
+ }
+
+ /**
+ * Returns ms/frame.
+ *
+ * @return milliseconds per frame
+ */
+ public float ms_per_frame() // E.B
+ {
+ if (h_vbr) {
+ double tpf = h_vbr_time_per_frame[layer()] / frequency();
+ if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF)) tpf /= 2;
+ return ((float) (tpf * 1000));
+ } else {
+ float[][] ms_per_frame_array = {{8.707483f, 8.0f, 12.0f},
+ {26.12245f, 24.0f, 36.0f},
+ {26.12245f, 24.0f, 36.0f}};
+ return (ms_per_frame_array[h_layer - 1][h_sample_frequency]);
+ }
+ }
+
+ // functions which return header informations as strings:
+
+ /**
+ * Return Layer version.
+ */
+ public String layer_string() {
+ switch (h_layer) {
+ case 1:
+ return "I";
+ case 2:
+ return "II";
+ case 3:
+ return "III";
+ }
+ return null;
+ }
+
+ /**
+ * Return Bitrate.
+ *
+ * @return bitrate in bps
+ */
+ public String bitrate_string() {
+ if (h_vbr) {
+ return bitrate() / 1000 + " kb/s";
+ } else return bitrate_str[h_version][h_layer - 1][h_bitrate_index];
+ }
+
+ /**
+ * Return Bitrate.
+ *
+ * @return bitrate in bps and average bitrate for VBR header
+ */
+ public int bitrate() {
+ if (h_vbr) {
+ return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames))) * 1000;
+ } else return bitrates[h_version][h_layer - 1][h_bitrate_index];
+ }
+
+ /**
+ * Returns Frequency
+ *
+ * @return frequency string in kHz
+ */
+ public String sample_frequency_string() {
+ switch (h_sample_frequency) {
+ case THIRTYTWO:
+ if (h_version == MPEG1)
+ return "32 kHz";
+ else if (h_version == MPEG2_LSF)
+ return "16 kHz";
+ else // SZD
+ return "8 kHz";
+ case FOURTYFOUR_POINT_ONE:
+ if (h_version == MPEG1)
+ return "44.1 kHz";
+ else if (h_version == MPEG2_LSF)
+ return "22.05 kHz";
+ else // SZD
+ return "11.025 kHz";
+ case FOURTYEIGHT:
+ if (h_version == MPEG1)
+ return "48 kHz";
+ else if (h_version == MPEG2_LSF)
+ return "24 kHz";
+ else // SZD
+ return "12 kHz";
+ }
+ return (null);
+ }
+
+ /**
+ * Returns Mode.
+ */
+ public String mode_string() {
+ switch (h_mode) {
+ case STEREO:
+ return "Stereo";
+ case JOINT_STEREO:
+ return "Joint stereo";
+ case DUAL_CHANNEL:
+ return "Dual channel";
+ case SINGLE_CHANNEL:
+ return "Single channel";
+ }
+ return null;
+ }
+
+ /**
+ * Returns Version.
+ *
+ * @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF
+ */
+ public String version_string() {
+ switch (h_version) {
+ case MPEG1:
+ return "MPEG-1";
+ case MPEG2_LSF:
+ return "MPEG-2 LSF";
+ case MPEG25_LSF: // SZD
+ return "MPEG-2.5 LSF";
+ }
+ return (null);
+ }
+
+ /**
+ * Returns the number of subbands in the current frame.
+ *
+ * @return number of subbands
+ */
+ public int number_of_subbands() {
+ return h_number_of_subbands;
+ }
+
+ /**
+ * Returns Intensity Stereo.
+ * (Layer II joint stereo only).
+ * Returns the number of subbands which are in stereo mode,
+ * subbands above that limit are in intensity stereo mode.
+ *
+ * @return intensity
+ */
+ public int intensity_stereo_bound() {
+ return h_intensity_stereo_bound;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerErrors.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerErrors.java
new file mode 100644
index 0000000..a59f5ef
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerErrors.java
@@ -0,0 +1,39 @@
+/*
+ * 11/19/04 1.0 moved to LGPL.
+ * 12/12/99 Initial version. mdm@techie.com
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+package io.github.thehrz.allmusicreload.core.decoder;
+
+/**
+ * Exception erorr codes for components of the JavaLayer API.
+ */
+public interface JavaLayerErrors {
+ /**
+ * The first bitstream error code. See the {@link DecoderErrors DecoderErrors}
+ * interface for other bitstream error codes.
+ */
+ int BITSTREAM_ERROR = 0x100;
+
+ /**
+ * The first decoder error code. See the {@link DecoderErrors DecoderErrors}
+ * interface for other decoder error codes.
+ */
+ int DECODER_ERROR = 0x200;
+
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerException.java b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerException.java
new file mode 100644
index 0000000..802ae92
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/decoder/JavaLayerException.java
@@ -0,0 +1,61 @@
+/*
+ * 11/19/04 1.0 moved to LGPL.
+ * 12/12/99 Initial version. mdm@techie.com
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+package io.github.thehrz.allmusicreload.core.decoder;
+
+import java.io.PrintStream;
+
+
+/**
+ * The JavaLayerException is the base class for all API-level
+ * exceptions thrown by JavaLayer. To facilitate conversion and
+ * common handling of exceptions from other domains, the class
+ * can delegate some functionality to a contained Throwable instance.
+ *
+ *
+ * @author MDM
+ */
+public class JavaLayerException extends Exception {
+
+ private Throwable exception;
+
+ public JavaLayerException(String msg) {
+ super(msg);
+ }
+
+ public JavaLayerException(String msg, Throwable t) {
+ super(msg);
+ exception = t;
+ }
+
+ public void printStackTrace() {
+ printStackTrace(System.err);
+ }
+
+ public void printStackTrace(PrintStream ps) {
+ if (this.exception == null) {
+ super.printStackTrace(ps);
+ } else {
+ exception.printStackTrace();
+ }
+ }
+
+
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/api/APIMain.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/APIMain.java
new file mode 100644
index 0000000..f267fa0
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/APIMain.java
@@ -0,0 +1,251 @@
+package io.github.thehrz.allmusicreload.core.music.api;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.music.play.LyricDo;
+import io.github.thehrz.allmusicreload.core.music.play.LyricSave;
+import io.github.thehrz.allmusicreload.core.music.play.PlayMusic;
+import io.github.thehrz.allmusicreload.core.objs.HttpResObj;
+import io.github.thehrz.allmusicreload.core.objs.SearchMusicObj;
+import io.github.thehrz.allmusicreload.core.objs.api.music.info.InfoObj;
+import io.github.thehrz.allmusicreload.core.objs.api.music.list.DataObj;
+import io.github.thehrz.allmusicreload.core.objs.api.music.lyric.WLyricObj;
+import io.github.thehrz.allmusicreload.core.objs.api.music.search.SearchDataObj;
+import io.github.thehrz.allmusicreload.core.objs.api.music.search.songs;
+import io.github.thehrz.allmusicreload.core.objs.api.music.trialinfo.TrialInfoObj;
+import io.github.thehrz.allmusicreload.core.objs.api.program.info.PrInfoObj;
+import io.github.thehrz.allmusicreload.core.objs.enums.EncryptType;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.sql.DataSql;
+import io.github.thehrz.allmusicreload.core.utils.Logs;
+import com.google.gson.JsonObject;
+import okhttp3.Cookie;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class APIMain {
+
+ private boolean isUpdate;
+
+ public APIMain() {
+ AllMusic.log.info("§d[AllMusic3]§e正在初始化网络爬虫");
+ HttpClientUtil.init();
+ HttpResObj res = HttpClientUtil.get("https://music.163.com", "");
+ if (res == null || !res.ok) {
+ AllMusic.log.info("§d[AllMusic3]§c初始化网络爬虫连接失败");
+ }
+ }
+
+ public boolean isUpdate() {
+ return isUpdate;
+ }
+
+ /**
+ * 获取音乐详情
+ *
+ * @param id 音乐ID
+ * @param player 用户名
+ * @param isList 是否是空闲列表
+ * @return 结果
+ */
+ private SongInfoObj getMusicDetail(String id, String player, boolean isList) {
+ JsonObject params = new JsonObject();
+ params.addProperty("c", "[{\"id\":" + id + "}]");
+
+ HttpResObj res = HttpClientUtil.post("https://music.163.com/api/v3/song/detail", params, EncryptType.WEAPI, null);
+ if (res != null && res.ok) {
+ InfoObj temp = AllMusic.gson.fromJson(res.data, InfoObj.class);
+ if (temp.isOk()) {
+ params = new JsonObject();
+ params.addProperty("ids", "[" + id + "]");
+ params.addProperty("br", "320000");
+ res = HttpClientUtil.post("https://music.163.com/weapi/song/enhance/player/url", params, EncryptType.WEAPI, null);
+ if (res == null || !res.ok) {
+ AllMusic.log.warning("§d[AllMusic3]§c版权检索失败");
+ return null;
+ }
+ TrialInfoObj obj = AllMusic.gson.fromJson(res.data, TrialInfoObj.class);
+ return new SongInfoObj(temp.getAuthor(), temp.getName(),
+ id, temp.getAlia(), player, temp.getAl(), isList, temp.getLength(),
+ temp.getPicUrl(), obj.isTrial(), obj.getFreeTrialInfo());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 获取音乐数据
+ *
+ * @param id 音乐ID
+ * @param player 用户名
+ * @param isList 是否是空闲列表
+ * @return 结果
+ */
+ public SongInfoObj getMusic(String id, String player, boolean isList) {
+ SongInfoObj info = getMusicDetail(id, player, isList);
+ if (info != null)
+ return info;
+ JsonObject params = new JsonObject();
+ params.addProperty("id", id);
+ HttpResObj res = HttpClientUtil.post("https://music.163.com/api/dj/program/detail", params, EncryptType.WEAPI, null);
+ if (res != null && res.ok) {
+ PrInfoObj temp = AllMusic.gson.fromJson(res.data, PrInfoObj.class);
+ if (temp.isOk()) {
+ return new SongInfoObj(temp.getAuthor(), temp.getName(),
+ temp.getId(), temp.getAlia(), player, "电台", isList, temp.getLength(),
+ null, false, null);
+ } else {
+ AllMusic.log.warning("§d[AllMusic3]§c歌曲信息获取为空");
+ }
+ }
+ return info;
+ }
+
+ /**
+ * 获取播放链接
+ *
+ * @param id 音乐ID
+ * @return 结果
+ */
+ public String getPlayUrl(String id) {
+ JsonObject params = new JsonObject();
+ params.addProperty("ids", "[" + id + "]");
+ params.addProperty("br", AllMusic.getConfig().musicBR);
+ HttpResObj res = HttpClientUtil.post("https://music.163.com/weapi/song/enhance/player/url", params, EncryptType.WEAPI, null);
+ if (res != null && res.ok) {
+ try {
+ TrialInfoObj obj = AllMusic.gson.fromJson(res.data, TrialInfoObj.class);
+ return obj.getUrl();
+ } catch (Exception e) {
+ Logs.logWrite(res.data);
+ AllMusic.log.warning("§d[AllMusic3]§c播放连接解析错误");
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 添加空闲歌单
+ *
+ * @param id 歌单id
+ * @param sender 发送者
+ */
+ public void setList(String id, Object sender) {
+ final Thread thread = new Thread(() -> {
+ JsonObject params = new JsonObject();
+ params.addProperty("id", id);
+ params.addProperty("n", 100000);
+ params.addProperty("s", 8);
+ HttpResObj res = HttpClientUtil.post("https://music.163.com/api/v6/playlist/detail", params, EncryptType.API, null);
+ if (res != null && res.ok)
+ try {
+ isUpdate = true;
+ DataObj obj = AllMusic.gson.fromJson(res.data, DataObj.class);
+ DataSql.addIdleList(obj.getPlaylist());
+ PlayMusic.addIdleList(obj.getPlaylist());
+ AllMusic.side.sendMessageTask(sender, AllMusic.getMessage().musicPlay.listMusic.get.replace(PAL.name, obj.getName()));
+ } catch (Exception e) {
+ AllMusic.log.warning("§d[AllMusic3]§c歌曲列表获取错误");
+ e.printStackTrace();
+ }
+ isUpdate = false;
+ }, "AllMusic_setList");
+ thread.start();
+ }
+
+ /**
+ * 获取歌词
+ *
+ * @param id 歌曲id
+ * @return 结果
+ */
+ public LyricSave getLyric(String id) {
+ LyricSave lyric = new LyricSave();
+ JsonObject params = new JsonObject();
+ params.addProperty("id", id);
+ params.addProperty("cp", false);
+ params.addProperty("tv", 0);
+ params.addProperty("lv", 0);
+ params.addProperty("rv", 0);
+ params.addProperty("kv", 0);
+ params.addProperty("yv", 0);
+ params.addProperty("ytv", 0);
+ params.addProperty("rtv", 0);
+ HttpResObj res = HttpClientUtil.post("https://interface3.music.163.com/eapi/song/lyric/v1",
+ params, EncryptType.EAPI, "/api/song/lyric/v1");
+ if (res != null && res.ok) {
+ try {
+ WLyricObj obj = AllMusic.gson.fromJson(res.data, WLyricObj.class);
+ LyricDo temp = new LyricDo();
+ for (int times = 0; times < 3; times++) {
+ if (temp.check(obj)) {
+ AllMusic.log.warning("§d[AllMusic3]§c歌词解析错误,正在进行第" + times + "重试");
+ } else {
+ if (temp.isHave) {
+ lyric.setHaveLyric(AllMusic.getConfig().sendLyric);
+ lyric.setLyric(temp.getTemp());
+ if (temp.isHaveK) {
+ lyric.setKlyric(temp.getKLyric());
+ }
+ }
+ return lyric;
+ }
+ Thread.sleep(1000);
+ }
+ AllMusic.log.warning("§d[AllMusic3]§c歌词解析失败");
+ } catch (Exception e) {
+ AllMusic.log.warning("§d[AllMusic3]§c歌词解析错误");
+ e.printStackTrace();
+ }
+ }
+ return lyric;
+ }
+
+ /**
+ * 搜歌
+ *
+ * @param name 关键字
+ * @param isDefault 是否是默认方式
+ * @return 结果
+ */
+ public SearchPageObj search(String[] name, boolean isDefault) {
+ List resData = new ArrayList<>();
+ int maxpage;
+
+ StringBuilder name1 = new StringBuilder();
+ for (int a = isDefault ? 0 : 1; a < name.length; a++) {
+ name1.append(name[a]).append(" ");
+ }
+ String MusicName = name1.toString();
+ MusicName = MusicName.substring(0, MusicName.length() - 1);
+
+ JsonObject params = new JsonObject();
+ params.addProperty("s", MusicName);
+ params.addProperty("type", 1);
+ params.addProperty("limit", 30);
+ params.addProperty("offset", 0);
+
+ HttpResObj res = HttpClientUtil.post("https://music.163.com/weapi/search/get", params, EncryptType.WEAPI, null);
+ if (res != null && res.ok) {
+ SearchDataObj obj = AllMusic.gson.fromJson(res.data, SearchDataObj.class);
+ if (obj != null && obj.isOk()) {
+ List res1 = obj.getResult();
+ SearchMusicObj item;
+ for (songs temp : res1) {
+ item = new SearchMusicObj(String.valueOf(temp.getId()), temp.getName(),
+ temp.getArtists(), temp.getAlbum());
+ resData.add(item);
+ }
+ maxpage = res1.size() / 10;
+ return new SearchPageObj(resData, maxpage);
+ } else {
+ AllMusic.log.warning("§d[AllMusic3]§c歌曲搜索出现错误");
+
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/api/CryptoUtil.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/CryptoUtil.java
new file mode 100644
index 0000000..b9fd20e
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/CryptoUtil.java
@@ -0,0 +1,137 @@
+package io.github.thehrz.allmusicreload.core.music.api;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.api.EncResObj;
+import com.google.gson.JsonObject;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+public class CryptoUtil {
+
+ private static final String presetKey = "0CoJUm6Qyw8W8jud";
+ private static final String iv = "0102030405060708";
+ private static final String base62 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
+ private static final String eapiKey = "e82ckenh8dichen8";
+
+ private static String createSecretKey(int size) {
+ StringBuilder key = new StringBuilder();
+ for (int i = 0; i < size; i++) {
+ double index = Math.floor(Math.random() * base62.length());
+ key.append(base62.charAt((int) index));
+ }
+ return key.toString();
+ }
+
+ public static String byteArrToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ private static String aesEncrypt(String content, String key, String iv) {
+ String result = null;
+ if (content == null || key == null)
+ return result;
+ try {
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
+ byte[] keys = key.getBytes(StandardCharsets.UTF_8);
+ byte[] ivs = iv.getBytes(StandardCharsets.UTF_8);
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keys, "AES"),
+ new IvParameterSpec(ivs));
+ bytes = cipher.doFinal(bytes);
+ result = Base64.getEncoder().encodeToString(bytes);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ private static String aesEncrypt(String content, String key) {
+ String result = null;
+ if (content == null || key == null)
+ return result;
+ try {
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+ byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
+ byte[] keys = key.getBytes(StandardCharsets.UTF_8);
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keys, "AES"));
+ bytes = cipher.doFinal(bytes);
+ result = byteArrToHex(bytes).toUpperCase();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ private static String zFill(String str) {
+ StringBuilder strBuilder = new StringBuilder(str);
+ while (strBuilder.length() < 256) {
+ strBuilder.insert(0, "0");
+ }
+ str = strBuilder.toString();
+ return str;
+ }
+
+ private static String rsaEncrypt(String text) {
+ text = new StringBuffer(text).reverse().toString();
+
+ BigInteger biText = new BigInteger(strToHex(text), 16);
+ BigInteger biEx = new BigInteger("010001", 16);
+ BigInteger biMod = new BigInteger("00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7", 16);
+ BigInteger biRet = biText.modPow(biEx, biMod);
+
+ return zFill(biRet.toString(16));
+ }
+
+ private static String strToHex(String s) {
+ StringBuilder str = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ int ch = s.charAt(i);
+ String s4 = Integer.toHexString(ch);
+ str.append(s4);
+ }
+ return str.toString();
+ }
+
+ public static EncResObj weapiEncrypt(String content) {
+ String key = createSecretKey(16);
+ String encText = aesEncrypt(aesEncrypt(content, presetKey, iv), key, iv);
+ String encSecKey = rsaEncrypt(key);
+ return new EncResObj(encText, encSecKey);
+ }
+
+ public static EncResObj eapi(String url, JsonObject object) {
+ String text = AllMusic.gson.toJson(object);
+ String message = "nobody" + url + "use" + text + "md5forencrypt";
+ String digest = getMd5(message);
+ String data = url + "-36cd479b6b5-" + text + "-36cd479b6b5-" + digest;
+ return new EncResObj(aesEncrypt(data, eapiKey), "");
+ }
+
+ public static String getMd5(String plainText) {
+ byte[] secretBytes;
+ try {
+ MessageDigest digest = MessageDigest.getInstance("md5");
+ digest.update(plainText.getBytes(StandardCharsets.UTF_8));
+ secretBytes = digest.digest();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("没有这个md5算法!");
+ }
+ return byteArrToHex(secretBytes);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/api/HttpClientUtil.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/HttpClientUtil.java
new file mode 100644
index 0000000..9608ea0
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/HttpClientUtil.java
@@ -0,0 +1,179 @@
+package io.github.thehrz.allmusicreload.core.music.api;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.HttpResObj;
+import io.github.thehrz.allmusicreload.core.objs.api.EncResObj;
+import io.github.thehrz.allmusicreload.core.objs.enums.EncryptType;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import okhttp3.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class HttpClientUtil {
+
+ private static final int CONNECT_TIMEOUT = 5;
+ private static final int READ_TIMEOUT = 7;
+ private static OkHttpClient client;
+
+ private static final String UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0";
+
+ public static void init() {
+ try {
+ synchronized (OkHttpClient.class) {
+ client = new OkHttpClient.Builder().cookieJar(new MyCookieJar())
+ .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
+ .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
+ .build();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static HttpResObj get(String path, String data) {
+ try {
+ data = URLEncoder.encode(data, StandardCharsets.UTF_8.toString());
+ Request request = new Request.Builder().url(path + data)
+ .addHeader("referer", "https://music.163.com")
+ .addHeader("content-type", "application/json;charset=UTF-8")
+ .addHeader("user-agent", UserAgent)
+ .get()
+ .build();
+ Response response = client.newCall(request).execute();
+ int httpCode = response.code();
+ ResponseBody body = response.body();
+ if (body == null) {
+ AllMusic.log.warning("§d[AllMusic3]§c获取网页错误");
+ return null;
+ }
+ InputStream inputStream = body.byteStream();
+ boolean ok = httpCode == 200;
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+ String data1 = result.toString(StandardCharsets.UTF_8.toString());
+ if (!ok) {
+ AllMusic.log.warning("§d[AllMusic3]§c服务器返回错误:" + data1);
+ }
+ return new HttpResObj(data1, ok);
+ } catch (Exception e) {
+ AllMusic.log.warning("§d[AllMusic3]§c获取网页错误");
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static HttpResObj post(String url, JsonObject data, EncryptType type, String ourl) {
+ try {
+ RequestBody formBody;
+ Request.Builder request = new Request.Builder();
+ request = request.addHeader("Content-Type", "application/x-www-form-urlencoded");
+ request = request.addHeader("Referer", "https://music.163.com");
+ EncResObj res;
+ List cookies = AllMusic.cookie.cookieStore.get("music.163.com");
+ if (cookies == null) {
+ cookies = new ArrayList<>();
+ }
+// StringBuilder cookie = new StringBuilder();
+// for (Cookie item : cookies) {
+// cookie.append(item.name()).append("=").append(item.value()).append(";");
+// }
+// cookie.append("cookie=");
+// request.header("Cookie", cookie.toString());
+ if (type == EncryptType.WEAPI) {
+ request = request.addHeader("User-Agent", UserAgent);
+ String csrfToken = "";
+ for (Cookie item : cookies) {
+ if (item.name().equalsIgnoreCase("__csrf")) {
+ csrfToken = item.value();
+ }
+ }
+ data.addProperty("csrf_token", csrfToken);
+ res = CryptoUtil.weapiEncrypt(AllMusic.gson.toJson(data));
+ url = url.replaceFirst("\\w*api", "weapi");
+ request = request.url(url);
+ formBody = new FormBody.Builder()
+ .add("params", res.params)
+ .add("encSecKey", res.encSecKey)
+ .build();
+ } else if (type == EncryptType.EAPI) {
+ request = request.addHeader("User-Agent", "Mozilla/5.0 (Linux; Android 9; PCT-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 HuaweiBrowser/10.0.3.311 Mobile Safari/537.36");
+ JsonObject header = new JsonObject();
+ header.addProperty("appver", "8.10.90");
+ header.addProperty("versioncode", "140");
+ header.addProperty("buildver", new Date().toString().substring(0, 10));
+ header.addProperty("resolution", "1920x1080");
+ header.addProperty("os", "android");
+ String requestId = "0000" + (new Date() + "_" + Math.floor(Math.random() * 1000));
+ header.addProperty("requestId", requestId);
+ for (Cookie item : cookies) {
+ if (item.name().equalsIgnoreCase("MUSIC_U")) {
+ header.addProperty("MUSIC_U", item.value());
+ } else if (item.name().equalsIgnoreCase("MUSIC_A")) {
+ header.addProperty("MUSIC_A", item.value());
+ } else if (item.name().equalsIgnoreCase("channel")) {
+ header.addProperty("channel", item.value());
+ } else if (item.name().equalsIgnoreCase("mobilename")) {
+ header.addProperty("mobilename", item.value());
+ } else if (item.name().equalsIgnoreCase("osver")) {
+ header.addProperty("osver", item.value());
+ } else if (item.name().equalsIgnoreCase("__csrf")) {
+ header.addProperty("__csrf", item.value());
+ }
+ }
+
+ data.add("header", header);
+ res = CryptoUtil.eapi(ourl, data);
+ url = url.replaceFirst("\\w*api", "eapi");
+ request = request.url(url);
+ formBody = new FormBody.Builder()
+ .add("params", res.params)
+ .build();
+ } else {
+ request = request.url(url);
+ FormBody.Builder builder = new FormBody.Builder();
+ for (Map.Entry item : data.entrySet()) {
+ builder = builder.add(item.getKey(), item.getValue().getAsString());
+ }
+ formBody = builder.build();
+ }
+ request = request.post(formBody);
+ Response response = client.newCall(request.build()).execute();
+ int httpCode = response.code();
+ ResponseBody body = response.body();
+ if (body == null) {
+ AllMusic.log.warning("§d[AllMusic3]§c获取网页错误");
+ return null;
+ }
+ InputStream inputStream = body.byteStream();
+ boolean ok = httpCode == 200;
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+ String data1 = result.toString(StandardCharsets.UTF_8.toString());
+ if (!ok) {
+ AllMusic.log.warning("§d[AllMusic3]§c服务器返回错误:" + data1);
+ }
+ return new HttpResObj(data1, ok);
+ } catch (Exception e) {
+ AllMusic.log.warning("§d[AllMusic3]§c获取网页错误");
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/api/MyCookieJar.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/MyCookieJar.java
new file mode 100644
index 0000000..286b7ec
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/api/MyCookieJar.java
@@ -0,0 +1,37 @@
+package io.github.thehrz.allmusicreload.core.music.api;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import okhttp3.Cookie;
+import okhttp3.CookieJar;
+import okhttp3.HttpUrl;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MyCookieJar implements CookieJar {
+ @Override
+ public void saveFromResponse(HttpUrl httpUrl, @NotNull List list) {
+ ArrayList cookies = AllMusic.cookie.cookieStore.get("music.163.com");
+ if (cookies == null) {
+ cookies = new ArrayList<>();
+ }
+ for (Cookie item : list) {
+ for (Cookie item1 : cookies) {
+ if (item.name().equalsIgnoreCase(item1.name())) {
+ cookies.remove(item1);
+ break;
+ }
+ }
+ cookies.add(item);
+ }
+ AllMusic.cookie.cookieStore.put("music.163.com", cookies);
+ AllMusic.saveCookie();
+ }
+
+ @Override
+ public @NotNull List loadForRequest(HttpUrl httpUrl) {
+ List cookies = AllMusic.cookie.cookieStore.get("music.163.com");
+ return cookies != null ? cookies : new ArrayList<>();
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricDo.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricDo.java
new file mode 100644
index 0000000..8d851ca
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricDo.java
@@ -0,0 +1,171 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.api.music.lyric.WLyricObj;
+import io.github.thehrz.allmusicreload.core.objs.music.LyricItemObj;
+import io.github.thehrz.allmusicreload.core.utils.Function;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LyricDo {
+ private static final Pattern p = Pattern.compile("\\(([0-9]+),[0-9]+.[0-9]\\)");
+ private final Map temp = new LinkedHashMap<>();
+ public boolean isHave = false;
+ public boolean isHaveK = false;
+ public Map kly = new LinkedHashMap<>();
+
+ public Map getTemp() {
+ return temp;
+ }
+
+ public Map getKLyric() {
+ return kly;
+ }
+
+ /**
+ * 检查歌词
+ *
+ * @param obj 歌词
+ * @return 结果
+ */
+ public boolean check(WLyricObj obj) {
+ String[] lyric;
+
+ boolean haveT = false;
+ if (!obj.isOk())
+ return true;
+ else if (obj.isNone())
+ return false;
+ lyric = obj.getLyric().split("\n");
+
+ Map temp = getTime(Arrays.asList(lyric));
+ Map temp1 = new HashMap<>();
+
+ if (obj.getTlyric() != null) {
+ List tlyric = Arrays.asList(obj.getTlyric().split("\n"));
+ haveT = true;
+ temp1 = getTime(tlyric);
+ }
+
+ String temp2 = obj.getYrc() == null ? obj.getKlyric() : obj.getYrc();
+
+ if (temp2 != null && !temp2.isEmpty()) {
+ String[] klyric = temp2.split("\n");
+ for (String item : klyric) {
+ Map temp4 = getKTime(item, obj.getVersion());
+ if (temp4 != null) {
+ kly.putAll(temp4);
+ }
+ }
+ isHaveK = true;
+ }
+
+ for (Map.Entry item : temp.entrySet()) {
+ this.temp.put(item.getKey(), new LyricItemObj(item.getValue(),
+ haveT ? temp1.get(item.getKey()) : null));
+ }
+
+
+ isHave = true;
+ return false;
+ }
+
+ /**
+ * 将歌词转换成时间 字
+ *
+ * @param lyric 歌词
+ * @return 结果
+ */
+ private Map getTime(List lyric) {
+ Map res = new LinkedHashMap<>();
+ String min;
+ String sec;
+ String mil;
+ long time;
+ long milt;
+ for (String s : lyric) {
+ if (!s.startsWith("["))
+ continue;
+ String temp = Function.getString(s, "[", "]");
+ if (!temp.contains(".") || !temp.contains(":"))
+ continue;
+ if (Function.countChar(temp, ':') > 1) {
+ String[] a = s.split(":");
+ min = a[0].substring(1);
+ sec = a[1];
+ mil = a[2];
+ } else {
+ min = Function.getString(s, "[", ":");
+ sec = Function.getString(s, ":", ".");
+ mil = Function.getString(s, ".", "]");
+ }
+ if (!Function.isInteger(min))
+ continue;
+ if (!Function.isInteger(sec))
+ continue;
+ if (!Function.isInteger(mil))
+ continue;
+ if (min.isEmpty() || sec.isEmpty() || mil.isEmpty())
+ continue;
+ milt = Long.parseLong(mil);
+ if (mil.length() == 3) {
+ milt /= 10;
+ }
+ time = Long.parseLong(min) * 60 * 1000 + Long.parseLong(sec) * 1000 + milt * 10;
+ if (time > 0 && time + AllMusic.getConfig().lyricDelay > 0)
+ time += AllMusic.getConfig().lyricDelay / 10 * 10;
+ res.put(time, Function.getString(s, "]", null));
+ }
+ return res;
+ }
+
+ private Map getKTime(String lyric, boolean yrc) {
+ Map res = new LinkedHashMap<>();
+ if (!lyric.startsWith("[") || !lyric.contains("]("))
+ return null;
+
+ String[] datas = lyric.split("\\(([0-9]+),[0-9]+.[0-9]\\)");
+ Matcher m = p.matcher(lyric);
+ List temp1111 = new ArrayList<>();
+ while (m.find()) {
+ temp1111.add(m.group()
+ .replace("(", "")
+ .replace(")", ""));
+ }
+ if (datas.length == 1)
+ return null;
+
+ String temp = Function.getString(lyric, "[", "]");
+ String[] temp11 = temp.split(",");
+ long now = Integer.parseInt(temp11[0]) / 10 * 10;
+ for (int a = 1; a < datas.length; a++) {
+ String data = datas[a];
+ String temp3 = temp1111.get(a - 1);
+ String[] temp8 = temp3.split(",");
+ long temp5;
+ if (yrc) {
+ temp5 = (Integer.parseInt(temp8[0]) / 10 * 10);
+ if (temp5 > 0 && temp5 + AllMusic.getConfig().ktvLyricDelay > 0)
+ temp5 += (AllMusic.getConfig().ktvLyricDelay / 10 * 10);
+ res.put(temp5, data);
+ } else {
+ try {
+ temp5 = (Integer.parseInt(temp8[1]) / 10 * 10);
+ } catch (Exception e) {
+ AllMusic.log.warning("不支持的Ktv歌词");
+ AllMusic.log.warning("请带上音乐ID联系开发者");
+ return null;
+ }
+
+ if (temp5 > 0 && temp5 + AllMusic.getConfig().ktvLyricDelay > 0)
+ temp5 += (AllMusic.getConfig().ktvLyricDelay / 10 * 10);
+ res.put(now, data);
+ now += temp5;
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricSave.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricSave.java
new file mode 100644
index 0000000..d44bb15
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/LyricSave.java
@@ -0,0 +1,112 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+import io.github.thehrz.allmusicreload.core.objs.music.LyricItemObj;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class LyricSave {
+ public int lastIndex = 0;
+ protected boolean haveLyric;
+ protected String lly = "";
+ protected String kly = "";
+ protected String tly = "";
+ private Map lyric;
+ private Map klyric;
+ private LyricItemObj now;
+ private long last;
+ private String kNow;
+
+ public LyricSave() {
+ haveLyric = false;
+ lyric = new HashMap<>();
+ }
+
+ public void setKlyric(Map klyric) {
+ this.klyric = klyric;
+ }
+
+ public boolean isHaveLyric() {
+ return haveLyric;
+ }
+
+ public void setHaveLyric(boolean haveLyric) {
+ this.haveLyric = haveLyric;
+ }
+
+ public String getLyric() {
+ return lly;
+ }
+
+ public void setLyric(Map lyric) {
+ this.lyric = lyric;
+ }
+
+ public String getTlyric() {
+ return tly;
+ }
+
+ public String getKly() {
+ return kly;
+ }
+
+ public boolean kUpdate() {
+ if (lastIndex >= now.lyric.length()) {
+ kly = now.lyric;
+ lly = "";
+ } else if (kNow != null) {
+ int index = now.lyric.toLowerCase(Locale.ROOT).indexOf(kNow, lastIndex);
+ if (index != -1) {
+ lastIndex = index + kNow.length();
+
+ kly = now.lyric.substring(0, lastIndex);
+ lly = now.lyric.substring(lastIndex);
+ return true;
+ }
+ } else {
+ kly = "";
+ }
+
+ return false;
+ }
+
+ public boolean ktv(long time) {
+ if (last == time || klyric == null)
+ return false;
+
+ String temp = klyric.get(time);
+ if (temp != null) {
+ kNow = temp.toLowerCase(Locale.ROOT);
+ last = time;
+ return kUpdate();
+ }
+
+ return false;
+ }
+
+ public boolean checkTime(long playNow, boolean ktv) {
+ if (lyric == null)
+ return false;
+
+ boolean res = false;
+ LyricItemObj temp = lyric.get(playNow);
+ if (temp != null) {
+ now = temp;
+ lly = now.lyric;
+ tly = now.tlyric;
+ if (tly == null)
+ tly = "";
+ kly = null;
+ lastIndex = 0;
+ kUpdate();
+ return true;
+ }
+
+ if (ktv && now != null) {
+ res = ktv(playNow);
+ }
+
+ return res;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/MusicSearch.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/MusicSearch.java
new file mode 100644
index 0000000..fffe2c7
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/MusicSearch.java
@@ -0,0 +1,84 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.SearchMusicObj;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.MusicObj;
+import io.github.thehrz.allmusicreload.core.objs.music.SearchPageObj;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class MusicSearch {
+ private static final Queue tasks = new ConcurrentLinkedQueue<>();
+ private static boolean isRun;
+
+ private static void task() {
+ while (isRun) {
+ try {
+ MusicObj obj = tasks.poll();
+ if (obj != null) {
+ SearchPageObj search = AllMusic.getMusicApi().search(obj.args, obj.isDefault);
+ if (search == null)
+ AllMusic.side.sendMessageTask(obj.sender, AllMusic.getMessage().search
+ .cantSearch.replace(PAL.name, obj.isDefault ? obj.args[0] : obj.args[1]));
+ else {
+ AllMusic.side.sendMessageTask(obj.sender, AllMusic.getMessage().search.res);
+ AllMusic.addSearch(obj.name, search);
+ AllMusic.side.runTask(() -> showSearch(obj.sender, search));
+ }
+ }
+ Thread.sleep(100);
+ } catch (Exception e) {
+ AllMusic.log.warning("搜歌出现问题");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void start() {
+ Thread taskT = new Thread(MusicSearch::task, "AllMusic_search");
+ isRun = true;
+ taskT.start();
+ }
+
+ public static void stop() {
+ isRun = false;
+ }
+
+ public static void addSearch(MusicObj obj) {
+ tasks.add(obj);
+ }
+
+ /**
+ * 展示搜歌结果
+ *
+ * @param sender 发送者
+ * @param search 搜歌结果
+ */
+ public static void showSearch(Object sender, SearchPageObj search) {
+ int index = search.getIndex();
+ SearchMusicObj item;
+ String info;
+ AllMusic.side.sendMessage(sender, "");
+ if (search.haveLastPage()) {
+ AllMusic.side.sendMessageRun(sender, "§d[AllMusic3]§2输入/music lastpage上一页",
+ AllMusic.getMessage().page.last, "/music lastpage");
+ }
+ for (int a = 0; a < index; a++) {
+ item = search.getRes(a + search.getPage() * 10);
+ info = AllMusic.getMessage().page.choice;
+ info = info.replace(PAL.index, "" + (a + 1))
+ .replace(PAL.musicName, item.name)
+ .replace(PAL.musicAuthor, item.author)
+ .replace(PAL.musicAl, item.al);
+ AllMusic.side.sendMessageRun(sender, info,
+ AllMusic.getMessage().click.clickRun, "/music select " + (a + 1));
+ }
+ if (search.haveNextPage()) {
+ AllMusic.side.sendMessageRun(sender, "§d[AllMusic3]§2输入/music nextpage下一页",
+ AllMusic.getMessage().page.next, "/music nextpage");
+ }
+ AllMusic.side.sendMessage(sender, "");
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayMusic.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayMusic.java
new file mode 100644
index 0000000..4b2e54d
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayMusic.java
@@ -0,0 +1,548 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.decoder.Bitstream;
+import io.github.thehrz.allmusicreload.core.decoder.Header;
+import io.github.thehrz.allmusicreload.core.objs.config.LimitObj;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.MusicObj;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.sql.DataSql;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+import io.github.thehrz.allmusicreload.core.utils.Logs;
+
+import java.io.BufferedInputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class PlayMusic {
+
+ /**
+ * 播放列表
+ */
+ private static final List playList = new ArrayList<>();
+ private static final Queue tasks = new ConcurrentLinkedQueue<>();
+ private static final List playIdleList = new ArrayList<>();
+ private static final Queue deep = new PriorityQueue<>();
+ /**
+ * 切歌投票时间
+ */
+ private static int voteTime = 0;
+ /**
+ * 切歌发起人
+ */
+ private static String voteSender;
+ /**
+ * 切歌投票的玩家
+ */
+ private static final Set votePlayer = new HashSet<>();
+ /**
+ * 插歌投票时间
+ */
+ private static int pushTime = 0;
+ /**
+ * 插歌发起人
+ */
+ private static String pushSender;
+ /**
+ * 插歌投票的玩家
+ */
+ private static final Set pushPlayer = new HashSet<>();
+ /**
+ * 插歌目标
+ */
+ private static SongInfoObj push;
+ /**
+ * 总歌曲长度
+ */
+ public static long musicAllTime = 0;
+ /**
+ * 剩余歌曲长度
+ */
+ public static long musicLessTime = 0;
+ /**
+ * 歌曲现在位置
+ */
+ public static long musicNowTime = 0;
+ /**
+ * 当前歌曲信息
+ */
+ public static SongInfoObj nowPlayMusic;
+ /**
+ * 当前歌词信息
+ */
+ public static LyricSave lyric;
+ /**
+ * 播放链接
+ */
+ public static String url;
+ /**
+ * 错误次数
+ */
+ public static int error;
+ private static boolean isRun;
+ private static int idleNow;
+
+ /**
+ * 停止歌曲逻辑
+ */
+ public static void stop() {
+ PlayMusic.clear();
+ isRun = false;
+ }
+
+ /**
+ * 开始歌曲逻辑
+ */
+ public static void start() {
+ Thread addT = new Thread(PlayMusic::task, "AllMusicList");
+ isRun = true;
+ addT.start();
+ }
+
+ /**
+ * 添加投票的玩家
+ *
+ * @param player 用户名
+ */
+ public static void addVote(String player) {
+ player = player.toLowerCase();
+ votePlayer.add(player);
+ }
+
+ public static void startVote(String player) {
+ player = player.toLowerCase();
+ voteSender = player;
+ votePlayer.add(player);
+ voteTime = AllMusic.getConfig().voteTime;
+ }
+
+ /**
+ * 添加投票的玩家
+ *
+ * @param player 用户名
+ */
+ public static void addPush(String player) {
+ player = player.toLowerCase();
+ pushPlayer.add(player);
+ }
+
+ public static void startPush(String player, SongInfoObj music) {
+ player = player.toLowerCase();
+ push = music;
+ pushSender = player;
+ pushPlayer.add(player);
+ pushTime = AllMusic.getConfig().voteTime;
+ }
+
+ public static void pushTick() {
+ pushTime--;
+ }
+
+ public static void voteTick() {
+ voteTime--;
+ }
+
+ public static SongInfoObj getPush() {
+ return push;
+ }
+
+ public static int getPushTime() {
+ return pushTime;
+ }
+
+ public static String getPushSender() {
+ return pushSender;
+ }
+
+ public static int getVoteTime() {
+ return voteTime;
+ }
+
+ public static String getVoteSender() {
+ return voteSender;
+ }
+
+ /**
+ * 获取投票数量
+ *
+ * @return 数量
+ */
+ public static int getVoteCount() {
+ return votePlayer.size();
+ }
+
+ public static int getPushCount() {
+ return pushPlayer.size();
+ }
+
+ /**
+ * 清空投票
+ */
+ public static void clearVote() {
+ voteTime = -1;
+ voteSender = null;
+ votePlayer.clear();
+ }
+
+ /**
+ * 清空插歌
+ */
+ public static void clearPush() {
+ pushTime = -1;
+ push = null;
+ pushSender = null;
+ pushPlayer.clear();
+ }
+
+ /**
+ * 是否已经投票了
+ *
+ * @param player 用户名
+ * @return 结果
+ */
+ public static boolean containVote(String player) {
+ player = player.toLowerCase();
+ return votePlayer.contains(player);
+ }
+
+ public static boolean containPush(String player) {
+ player = player.toLowerCase();
+ return pushPlayer.contains(player);
+ };
+
+ /**
+ * 添加点歌任务
+ *
+ * @param obj 歌曲
+ */
+ public static void addTask(MusicObj obj) {
+ tasks.add(obj);
+ }
+
+ private static void task() {
+ while (isRun) {
+ try {
+ MusicObj obj = tasks.poll();
+ if (obj != null) {
+ if (obj.isUrl) {
+ addUrl(obj.url);
+ } else {
+ addMusic(obj.sender, obj.id, obj.name, obj.isDefault);
+ }
+ }
+ Thread.sleep(10);
+ } catch (Exception e) {
+ AllMusic.log.warning("歌曲处理出现问题");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * 添加歌曲
+ *
+ * @param sender 发送者
+ * @param id 歌曲ID
+ * @param player 用户名
+ * @param isList 是否是空闲歌单
+ */
+ public static void addMusic(Object sender, String id, String player, boolean isList) {
+ if (haveMusic(id))
+ return;
+ if (sender != null) {
+ String text = AllMusic.getMessage().musicPlay.checkMusic
+ .replace(PAL.musicId, id);
+ AllMusic.side.sendMessageTask(sender, text);
+ }
+ Logs.logWrite("player:" + player + " add:" + id);
+ try {
+ SongInfoObj info = AllMusic.getMusicApi().getMusic(id, player, isList);
+ if (info == null) {
+ if (sender != null) {
+ String data = AllMusic.getMessage().musicPlay.emptyCanPlay;
+ AllMusic.side.sendMessageTask(sender, data.replace(PAL.musicId, id));
+ }
+ return;
+ }
+ LimitObj limit = AllMusic.getConfig().limit;
+ if (limit.musicTimeLimit && info.getLength() / 1000 > limit.maxMusicTime) {
+ if (sender != null) {
+ AllMusic.side.sendMessageTask(sender, AllMusic.getMessage().addMusic.timeOut);
+ }
+ return;
+ }
+ playList.add(info);
+ if (!AllMusic.getConfig().muteAddMessage) {
+ if (AllMusic.getConfig().showInBar) {
+ String data = AllMusic.getMessage().musicPlay.addMusic
+ .replace(PAL.musicName, HudUtils.messageLimit(info.getName()))
+ .replace(PAL.musicAuthor, HudUtils.messageLimit(info.getAuthor()))
+ .replace(PAL.musicAl, HudUtils.messageLimit(info.getAl()))
+ .replace(PAL.musicAlia, HudUtils.messageLimit(info.getAlia()))
+ .replace(PAL.player, info.getCall());
+ AllMusic.side.sendBar(data);
+ } else {
+ String data = AllMusic.getMessage().musicPlay.addMusic
+ .replace(PAL.musicName, info.getName())
+ .replace(PAL.musicAuthor, info.getAuthor())
+ .replace(PAL.musicAl, info.getAl())
+ .replace(PAL.musicAlia, info.getAlia())
+ .replace(PAL.player, info.getCall());
+ AllMusic.side.broadcastInTask(data);
+ }
+ }
+ if (AllMusic.getConfig().playListSwitch
+ && (PlayMusic.nowPlayMusic != null && PlayMusic.nowPlayMusic.isList())) {
+ PlayMusic.musicLessTime = 1;
+ if (!isList) {
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().musicPlay.switchMusic);
+ }
+ }
+ error = 0;
+ } catch (Exception e) {
+ if (isList) {
+ error++;
+ }
+ AllMusic.log.warning("§d[AllMusic3]§c歌曲信息解析错误");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 将歌曲移动到队列头
+ */
+ public static void pushMusic() {
+ SongInfoObj obj = push;
+ synchronized (playList) {
+ playList.remove(obj);
+ playList.add(0, obj);
+ }
+ }
+
+ /**
+ * 获取播放列表长度
+ *
+ * @return 长度
+ */
+ public static int getListSize() {
+ synchronized (playList) {
+ return playList.size();
+ }
+ }
+
+ /**
+ * 获取当前播放列表
+ *
+ * @return 播放列表
+ */
+ public static List getList() {
+ synchronized (playList) {
+ return new ArrayList<>(playList);
+ }
+ }
+
+ /**
+ * 清理播放列表
+ */
+ public static void clear() {
+ synchronized (playList) {
+ playList.clear();
+ }
+ }
+
+ /**
+ * 从播放列表删除
+ *
+ * @param index 标号
+ * @return 结果
+ */
+ public static SongInfoObj remove(int index) {
+ synchronized (playList) {
+ return playList.remove(index);
+ }
+ }
+
+ /**
+ * 从播放列表删除
+ *
+ * @param index
+ */
+ public static void remove(SongInfoObj index) {
+ synchronized (playList) {
+ playList.remove(index);
+ }
+ }
+
+ /**
+ * 获取播放列表所有信息
+ *
+ * @return 信息
+ */
+ public static String getAllList() {
+ StringBuilder list = new StringBuilder();
+ String a;
+
+ SongInfoObj info;
+ for (int i = 0; i < playList.size(); i++) {
+ info = playList.get(i);
+ a = AllMusic.getMessage().musicPlay.listMusic.item;
+ a = a.replace(PAL.index, String.valueOf(i + 1))
+ .replace(PAL.musicName, info.getName())
+ .replace(PAL.musicAuthor, info.getAuthor())
+ .replace(PAL.musicAl, info.getAl())
+ .replace(PAL.musicAlia, info.getAlia());
+ list.append(a).append("\n");
+ }
+ String temp = list.toString();
+ if (temp.isEmpty())
+ return "";
+ return temp.substring(0, temp.length() - 1);
+ }
+
+ /**
+ * 是否在播放列表中
+ *
+ * @param id 音乐ID
+ * @return 结果
+ */
+ public static boolean haveMusic(String id) {
+ if (nowPlayMusic != null && nowPlayMusic.getID().equalsIgnoreCase(id))
+ return true;
+ for (SongInfoObj item : playList) {
+ if (item.getID().equalsIgnoreCase(id))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 添加Url歌曲
+ *
+ * @param url 链接
+ */
+ private static void addUrl(String url) {
+ try {
+ URL urlfile = new URL(url);
+ URLConnection con = urlfile.openConnection();
+ int b = con.getContentLength();// 得到音乐文件的总长度
+ BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
+ Bitstream bt = new Bitstream(bis);
+ Header h = bt.readFrame();
+ int le = 6000000;
+ if (h == null) {
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().musicPlay.error1);
+ } else {
+ le = (int) h.total_ms(b);
+ }
+ SongInfoObj info = new SongInfoObj(AllMusic.getMessage().custom.info, url, le);
+ playList.add(info);
+ } catch (Exception e) {
+ AllMusic.log.warning("§d[AllMusic3]§c歌曲信息解析错误");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 判断玩家点歌数量是否超上限
+ *
+ * @param name 玩家名
+ * @return
+ */
+ public static boolean isPlayerMax(String name) {
+ int list = AllMusic.getConfig().maxPlayerList;
+ if (list == 0) {
+ return false;
+ }
+ int count = 0;
+ for (MusicObj obj : tasks) {
+ if (obj.name.equalsIgnoreCase(name)) {
+ count++;
+ }
+ }
+
+ return list <= count;
+ }
+
+ public static void addIdleList(List list) {
+ playIdleList.addAll(list);
+ }
+
+ public static void clearIdleList() {
+ playIdleList.clear();
+ DataSql.clearIdleList();
+ }
+
+ public static int getIdleListSize() {
+ return playIdleList.size();
+ }
+
+ /**
+ * 获取空闲歌单的一首歌
+ *
+ * @return 结果
+ */
+ public static String getIdleMusic() {
+ if (AllMusic.getMusicApi().isUpdate()) {
+ return null;
+ }
+ String id;
+ if (playIdleList.isEmpty())
+ return null;
+ if (AllMusic.getConfig().playListRandom) {
+ if (playIdleList.size() == 1)
+ return playIdleList.get(0);
+ if (playIdleList.size() > 10) {
+ int size = AllMusic.getConfig().playListEscapeDeep;
+ if (size > playIdleList.size() / 2) {
+ size = playIdleList.size() / 2;
+ }
+ if (deep.size() >= size) {
+ deep.poll();
+ }
+ do {
+ id = playIdleList.get(new Random().nextInt(playIdleList.size()));
+ }
+ while (deep.contains(id));
+ deep.add(id);
+ } else {
+ id = playIdleList.get(new Random().nextInt(playIdleList.size()));
+ }
+ } else {
+ id = playIdleList.get(idleNow);
+ idleNow++;
+ if (idleNow >= playIdleList.size()) {
+ idleNow = 0;
+ }
+ }
+ return id;
+ }
+
+ public static SongInfoObj findPlayerMusic(String name) {
+ List list1 = getList();
+ for (int a = 0; a < playList.size(); a++) {
+ SongInfoObj item = list1.get(a);
+ if (name.equalsIgnoreCase(item.getCall())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ public static SongInfoObj findMusicIndex(int index) {
+ List list1 = getList();
+ index--;
+ if (index <= 0) {
+ return null;
+ }
+ if (list1.size() <= index) {
+ return null;
+ }
+
+ return list1.get(index);
+ }
+}
+
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayRuntime.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayRuntime.java
new file mode 100644
index 0000000..29557e7
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/PlayRuntime.java
@@ -0,0 +1,310 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+import io.github.thehrz.allmusicreload.core.AllMusic;
+import io.github.thehrz.allmusicreload.core.objs.message.PAL;
+import io.github.thehrz.allmusicreload.core.objs.music.SongInfoObj;
+import io.github.thehrz.allmusicreload.core.utils.HudUtils;
+
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class PlayRuntime {
+ /**
+ * 倒数计数器
+ */
+ private static int count = 0;
+ private static int ping = 0;
+ private static boolean isRun;
+ /**
+ * 歌曲更新计数器
+ */
+ private static int times = 0;
+ /**
+ * 歌曲定时器
+ */
+ private static ScheduledExecutorService service;
+ /**
+ * 歌词定时器
+ */
+ private static ScheduledExecutorService service1;
+ /**
+ * 事务定时器
+ */
+ private static ScheduledExecutorService service2;
+
+ /**
+ * 启动歌曲工作
+ */
+ public static void start() {
+ Thread taskT = new Thread(PlayRuntime::task, "AllMusicPlay");
+ isRun = true;
+ taskT.start();
+
+ service2 = Executors.newSingleThreadScheduledExecutor();
+ service2.scheduleAtFixedRate(PlayRuntime::time3, 0, 1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 停止歌曲工作
+ */
+ public static void stop() {
+ closeTimer();
+ if (service2 != null) {
+ service2.shutdown();
+ service2 = null;
+ }
+ isRun = false;
+ PlayMusic.musicLessTime = 0;
+ }
+
+ private static void closeTimer() {
+ if (service != null) {
+ service.shutdown();
+ service = null;
+ }
+ if (service1 != null) {
+ service1.shutdown();
+ service1 = null;
+ }
+ }
+
+ private static void startTimer() {
+ service = Executors.newSingleThreadScheduledExecutor();
+ service.scheduleAtFixedRate(PlayRuntime::time1, 0, 10, TimeUnit.MILLISECONDS);
+ if (PlayMusic.lyric != null && PlayMusic.lyric.isHaveLyric()) {
+ service1 = Executors.newSingleThreadScheduledExecutor();
+ service1.scheduleAtFixedRate(PlayRuntime::time2, 0, 2, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ /**
+ * 清空歌曲数据
+ */
+ private static void clear() {
+ closeTimer();
+ PlayMusic.musicNowTime = 0;
+ PlayMusic.musicAllTime = 0;
+ PlayMusic.musicLessTime = 0;
+ PlayMusic.lyric = null;
+ PlayMusic.nowPlayMusic = null;
+ AllMusic.side.updateInfo();
+ HudUtils.clearHud();
+ HudUtils.sendHudNowData();
+ HudUtils.sendHudLyricData();
+ HudUtils.sendHudListData();
+ }
+
+ /**
+ * 歌曲时间定时器
+ */
+ private static void time1() {
+ PlayMusic.musicNowTime += 10;
+ count++;
+ if (count == 100) {
+ PlayMusic.musicLessTime--;
+ count = 0;
+ }
+ }
+
+ /**
+ * 歌词更新
+ */
+ private static void time2() {
+ try {
+ if (PlayMusic.lyric == null)
+ return;
+ boolean res = PlayMusic.lyric
+ .checkTime(PlayMusic.musicNowTime, AllMusic.getConfig().ktvMode);
+ if (res) {
+ times = 0;
+ HudUtils.sendHudLyricData();
+ AllMusic.side.updateLyric();
+ } else {
+ times++;
+ if (times == AllMusic.getConfig().sendDelay / 2 && PlayMusic.lyric != null) {
+ times = 0;
+ HudUtils.sendHudLyricData();
+ AllMusic.side.updateLyric();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static boolean checkPush() {
+ SongInfoObj music = PlayMusic.getPush();
+ if (music != null) {
+ if (PlayMusic.nowPlayMusic.getID().equalsIgnoreCase(music.getID())) {
+ return false;
+ }
+ List list = PlayMusic.getList();
+ if (list.isEmpty()) {
+ return false;
+ }
+ SongInfoObj id1 = list.get(0);
+ if (id1 != null && id1.getID().equalsIgnoreCase(music.getID())) {
+ return false;
+ }
+ for (int a = 1; a < list.size(); a++) {
+ id1 = list.get(a);
+ if (id1.getID().equalsIgnoreCase(music.getID()))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 事务定时器
+ */
+ private static void time3() {
+ try {
+ ping++;
+ if (ping >= 10) {
+ AllMusic.side.ping();
+ }
+ if (PlayMusic.getPushTime() > 0) {
+ if (!checkPush()) {
+ PlayMusic.clearPush();
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().push.cancel);
+ } else {
+ PlayMusic.pushTick();
+ if (PlayMusic.getPushTime() == 0) {
+ PlayMusic.clearPush();
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().push.timeOut);
+ } else {
+ int players = AllMusic.side.getPlayerSize();
+ if (PlayMusic.getPushCount() >= AllMusic.getConfig().minVote
+ || (players <= AllMusic.getConfig().minVote
+ && players <= PlayMusic.getPushCount())) {
+ PlayMusic.pushMusic();
+ PlayMusic.clearPush();
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().push.doPush);
+ }
+ }
+ }
+ }
+
+ if (PlayMusic.getVoteTime() > 0) {
+ PlayMusic.voteTick();
+ if (PlayMusic.getVoteTime() == 0) {
+ PlayMusic.clearVote();
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().vote.timeOut);
+ } else {
+ int players = AllMusic.side.getPlayerSize();
+ if (PlayMusic.getVoteCount() >= AllMusic.getConfig().minVote
+ || (players <= AllMusic.getConfig().minVote
+ && players <= PlayMusic.getVoteCount())) {
+ PlayMusic.musicLessTime = 0;
+ PlayMusic.clearVote();
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().vote.voteDone);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void task() {
+ while (isRun) {
+ try {
+ if (PlayMusic.getListSize() == 0) {
+ if (PlayMusic.error >= 10) {
+ Thread.sleep(1000);
+ } else if (PlayMusic.getIdleListSize() > 0) {
+ if (AllMusic.side.needPlay()) {
+ String id = PlayMusic.getIdleMusic();
+ if (id != null) {
+ PlayMusic.addMusic(null, id, AllMusic.getMessage().custom.idle, true);
+ }
+ }
+ }
+ Thread.sleep(1000);
+ } else {
+ HudUtils.sendHudNowData();
+ HudUtils.sendHudLyricData();
+ HudUtils.sendHudListData();
+ AllMusic.side.sendHudUtilsAll();
+ PlayMusic.nowPlayMusic = PlayMusic.remove(0);
+ if (AllMusic.side.onMusicPlay(PlayMusic.nowPlayMusic)) {
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().musicPlay.cancel);
+ continue;
+ }
+
+ PlayMusic.url = PlayMusic.nowPlayMusic.getPlayerUrl() == null ?
+ AllMusic.getMusicApi().getPlayUrl(PlayMusic.nowPlayMusic.getID()) :
+ PlayMusic.nowPlayMusic.getPlayerUrl();
+ if (PlayMusic.url == null) {
+ String data = AllMusic.getMessage().musicPlay.emptyCanPlay;
+ AllMusic.side.broadcastInTask(data.replace(PAL.musicId, PlayMusic.nowPlayMusic.getID()));
+ PlayMusic.nowPlayMusic = null;
+ continue;
+ }
+
+ if (PlayMusic.nowPlayMusic.getPlayerUrl() == null)
+ PlayMusic.lyric = AllMusic.getMusicApi().getLyric(PlayMusic.nowPlayMusic.getID());
+ else
+ PlayMusic.lyric = new LyricSave();
+
+ if (PlayMusic.nowPlayMusic.getLength() != 0) {
+ PlayMusic.musicAllTime = PlayMusic.musicLessTime = (PlayMusic.nowPlayMusic.getLength() / 1000) + 3;
+ startTimer();
+ AllMusic.side.sendMusic(PlayMusic.url);
+ if (!AllMusic.getConfig().mutePlayMessage) {
+ SongInfoObj music = PlayMusic.nowPlayMusic;
+ if (AllMusic.getConfig().showInBar) {
+ String info = AllMusic.getMessage().musicPlay.nowPlay
+ .replace(PAL.musicName, HudUtils.messageLimit(music.getName()))
+ .replace(PAL.musicAuthor, HudUtils.messageLimit(music.getAuthor()))
+ .replace(PAL.musicAl, HudUtils.messageLimit(music.getAl()))
+ .replace(PAL.musicAlia, HudUtils.messageLimit(music.getAlia()))
+ .replace(PAL.player, music.getCall());
+ AllMusic.side.sendBar(info);
+ } else {
+ String info = AllMusic.getMessage().musicPlay.nowPlay
+ .replace(PAL.musicName, music.getName())
+ .replace(PAL.musicAuthor, music.getAuthor())
+ .replace(PAL.musicAl, music.getAl())
+ .replace(PAL.musicAlia, music.getAlia())
+ .replace(PAL.player, music.getCall());
+ AllMusic.side.broadcastInTask(info);
+ }
+ }
+ if (!PlayMusic.nowPlayMusic.isUrl() && PlayMusic.nowPlayMusic.getPicUrl() != null) {
+ AllMusic.side.sendPic(PlayMusic.nowPlayMusic.getPicUrl());
+ }
+ if (PlayMusic.nowPlayMusic.isTrial()) {
+ AllMusic.side.broadcastInTask(AllMusic.getMessage().musicPlay.trail);
+ PlayMusic.musicLessTime = PlayMusic.nowPlayMusic.getTrialInfo().getEnd();
+ PlayMusic.musicNowTime = PlayMusic.nowPlayMusic.getTrialInfo().getStart();
+ }
+
+ AllMusic.side.updateInfo();
+
+ while (PlayMusic.musicLessTime > 0) {
+ HudUtils.sendHudNowData();
+ HudUtils.sendHudListData();
+ if (!AllMusic.side.needPlay()) {
+ PlayMusic.musicLessTime = 1;
+ }
+ Thread.sleep(AllMusic.getConfig().sendDelay);
+ }
+ AllMusic.side.sendStop();
+ } else {
+ String data = AllMusic.getMessage().musicPlay.emptyCanPlay;
+ AllMusic.side.broadcastInTask(data.replace(PAL.musicId, PlayMusic.nowPlayMusic.getID()));
+ }
+ clear();
+ }
+ } catch (Exception e) {
+ AllMusic.log.warning("§c歌曲播放出现错误");
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/music/play/TopLyricSave.java b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/TopLyricSave.java
new file mode 100644
index 0000000..3c26ea3
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/music/play/TopLyricSave.java
@@ -0,0 +1,28 @@
+package io.github.thehrz.allmusicreload.core.music.play;
+
+public class TopLyricSave extends LyricSave {
+
+ public void setTlyric(String data) {
+ tly = data;
+ }
+
+ public void setLyric(String data) {
+ lly = data;
+ }
+
+ public void setKly(String data) {
+ kly = data;
+ }
+
+ public void setHaveK(boolean data) {
+ if (!data) {
+ kly = null;
+ }
+ }
+
+ public void setHaveT(boolean data) {
+ if (!data) {
+ tly = null;
+ }
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/CookieObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/CookieObj.java
new file mode 100644
index 0000000..ea3a7e4
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/CookieObj.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.objs;
+
+import okhttp3.Cookie;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class CookieObj {
+ public HashMap> cookieStore = new HashMap<>();
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/HttpResObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/HttpResObj.java
new file mode 100644
index 0000000..4c8c5cc
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/HttpResObj.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.objs;
+
+public class HttpResObj {
+ public final String data;
+ public final boolean ok;
+
+ public HttpResObj(String data, boolean ok) {
+ this.data = data;
+ this.ok = ok;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/SearchMusicObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/SearchMusicObj.java
new file mode 100644
index 0000000..aa03c1f
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/SearchMusicObj.java
@@ -0,0 +1,15 @@
+package io.github.thehrz.allmusicreload.core.objs;
+
+public class SearchMusicObj {
+ public final String id;
+ public final String name;
+ public final String author;
+ public final String al;
+
+ public SearchMusicObj(String ID, String Name, String Author, String Al) {
+ this.id = ID;
+ this.name = Name;
+ this.author = Author;
+ this.al = Al;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/UserCookie.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/UserCookie.java
new file mode 100644
index 0000000..161629c
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/UserCookie.java
@@ -0,0 +1,12 @@
+package io.github.thehrz.allmusicreload.core.objs;
+
+public class UserCookie {
+ public String domain;
+ public double expires;
+ public String name;
+ public boolean partitioned;
+ public String path;
+ public String sameSite;
+ public boolean secure;
+ public String value;
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/EncResObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/EncResObj.java
new file mode 100644
index 0000000..7701d8a
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/EncResObj.java
@@ -0,0 +1,11 @@
+package io.github.thehrz.allmusicreload.core.objs.api;
+
+public class EncResObj {
+ public String params;
+ public String encSecKey;
+
+ public EncResObj(String params, String encSecKey) {
+ this.encSecKey = encSecKey;
+ this.params = params;
+ }
+}
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/InfoObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/InfoObj.java
new file mode 100644
index 0000000..2c0e462
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/InfoObj.java
@@ -0,0 +1,127 @@
+package io.github.thehrz.allmusicreload.core.objs.api.music.info;
+
+import java.util.List;
+
+public class InfoObj {
+ private List songs;
+
+ public boolean isOk() {
+ return (songs != null && !songs.isEmpty());
+ }
+
+ public String getName() {
+ if (songs == null || songs.isEmpty())
+ return "";
+ return songs.get(0).getName();
+ }
+
+ public String getAuthor() {
+ StringBuilder Author = new StringBuilder();
+ if (songs.isEmpty())
+ return "";
+ for (ar ar : songs.get(0).getAr()) {
+ Author.append(ar.getName()).append(",");
+ }
+ if (Author.length() != 0) {
+ Author = new StringBuilder(Author.substring(0, Author.length() - 1));
+ }
+ return Author.toString();
+ }
+
+ public String getAlia() {
+ StringBuilder Alia = new StringBuilder();
+ for (String alia : songs.get(0).getAlia()) {
+ Alia.append(alia).append(",");
+ }
+ if (Alia.length() != 0) {
+ Alia = new StringBuilder(Alia.substring(0, Alia.length() - 1));
+ }
+ return Alia.toString();
+ }
+
+ public String getAl() {
+ return songs.get(0).getAl();
+ }
+
+ public long getLength() {
+ if (songs == null)
+ return 0;
+ return songs.get(0).getLength();
+ }
+
+ public String getPicUrl() {
+ if (songs == null)
+ return null;
+ return songs.get(0).getPicUrl();
+ }
+}
+
+class Songs {
+ private String name;
+ private List ar;
+ private List alia;
+ private al al;
+ private h l;
+ private h m;
+ private h h;
+
+ public long getLength() {
+ if (l != null)
+ return l.getLength();
+ if (m != null)
+ return m.getLength();
+ if (h != null)
+ return h.getLength();
+ return 0;
+ }
+
+ public String getName() {
+ return name == null ? "" : name;
+ }
+
+ public List getAr() {
+ return ar;
+ }
+
+ public List getAlia() {
+ return alia;
+ }
+
+ public String getAl() {
+ return al.getName() == null ? "" : al.getName();
+ }
+
+ public String getPicUrl() {
+ return al.getPicUrl();
+ }
+}
+
+class ar {
+ private String name;
+
+ public String getName() {
+ return name == null ? "" : name;
+ }
+}
+
+class al {
+ private String name;
+ private String picUrl;
+
+ public String getName() {
+ return name == null ? "" : name;
+ }
+
+ public String getPicUrl() {
+ return picUrl == null ? "" : picUrl;
+ }
+}
+
+class h {
+ private long br;
+ private long size;
+
+ public long getLength() {
+ return size / br * 8000;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/PlayObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/PlayObj.java
new file mode 100644
index 0000000..88c2a43
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/info/PlayObj.java
@@ -0,0 +1,30 @@
+package io.github.thehrz.allmusicreload.core.objs.api.music.info;
+
+import java.util.List;
+
+public class PlayObj {
+ private List data;
+ private int code;
+
+ public String getData() {
+ if (data == null)
+ return null;
+ if (data.size() == 0)
+ return null;
+ obj obj = data.get(0);
+ return obj.getUrl();
+ }
+
+ public int getCode() {
+ return code;
+ }
+}
+
+class obj {
+ private String url;
+
+ public String getUrl() {
+ return url;
+ }
+}
+
diff --git a/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/list/DataObj.java b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/list/DataObj.java
new file mode 100644
index 0000000..009c575
--- /dev/null
+++ b/src/main/java/io/github/thehrz/allmusicreload/core/objs/api/music/list/DataObj.java
@@ -0,0 +1,41 @@
+package io.github.thehrz.allmusicreload.core.objs.api.music.list;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DataObj {
+ private playlist playlist;
+
+ public List getPlaylist() {
+ List list = new ArrayList<>();
+ for (track item : playlist.getTracks()) {
+ list.add(item.getId());
+ }
+ return list;
+ }
+
+ public String getName() {
+ return playlist.getName();
+ }
+}
+
+class track {
+ private long id;
+
+ public String getId() {
+ return String.valueOf(id);
+ }
+}
+
+class playlist {
+ private List