diff --git a/build.gradle b/build.gradle index 8989a27..cb422ba 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group = 'com.hiczp' -version = '0.0.10' +version = '0.0.11' description = 'Bilibili android client API library written in Java' apply plugin: 'idea' diff --git a/src/main/java/com/hiczp/bilibili/api/BilibiliAPI.java b/src/main/java/com/hiczp/bilibili/api/BilibiliAPI.java index febcb21..cbf9c83 100644 --- a/src/main/java/com/hiczp/bilibili/api/BilibiliAPI.java +++ b/src/main/java/com/hiczp/bilibili/api/BilibiliAPI.java @@ -393,11 +393,19 @@ public class BilibiliAPI implements BilibiliServiceProvider, BilibiliCaptchaProv return infoEntity; } + /** + * 2018-05-11 现在用假的房间 Id 也能正常连接弹幕推送服务器 + * + * @param eventLoopGroup + * @param roomId + * @param isRealRoomId + * @return + */ @Override - public LiveClient getLiveClient(EventLoopGroup eventLoopGroup, long showRoomId) { + public LiveClient getLiveClient(EventLoopGroup eventLoopGroup, long roomId, boolean isRealRoomId) { return bilibiliAccount.getUserId() == null ? - new LiveClient(this, eventLoopGroup, showRoomId) : - new LiveClient(this, eventLoopGroup, showRoomId, bilibiliAccount.getUserId()); + new LiveClient(this, eventLoopGroup, roomId, isRealRoomId) : + new LiveClient(this, eventLoopGroup, roomId, isRealRoomId, bilibiliAccount.getUserId()); } private void markCurrentTokenAndRefreshTokenInvalid() { diff --git a/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java b/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java index 632ee55..e7d2f2f 100644 --- a/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java +++ b/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java @@ -99,6 +99,11 @@ public class ServerErrorCode { * "请先登录" */ public static final int NO_LOGIN = -101; + /** + * 访问的房间号不存在 + * "message": "Document is not exists." + */ + public static final int DOCUMENT_IS_NOT_EXISTS = -404; /** * 搜索时, 关键字字数过少或过多 * "关键字不能小于2个字节或大于50字节" diff --git a/src/main/java/com/hiczp/bilibili/api/live/LiveService.java b/src/main/java/com/hiczp/bilibili/api/live/LiveService.java index 66696b8..368deb9 100644 --- a/src/main/java/com/hiczp/bilibili/api/live/LiveService.java +++ b/src/main/java/com/hiczp/bilibili/api/live/LiveService.java @@ -38,6 +38,8 @@ public interface LiveService { * 获取直播间信息 * 登录后访问该 API 将在服务器新增一条直播间观看历史 * + * 2018-05-11 现在用假的房间 ID 也能获得正确的信息 + * * @param roomId 房间号 */ @GET("AppRoom/index") diff --git a/src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java b/src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java index 28438b3..000363e 100644 --- a/src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java +++ b/src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java @@ -24,35 +24,51 @@ import retrofit2.Call; import javax.annotation.Nonnull; import java.io.IOException; -import java.util.Optional; +import java.util.concurrent.*; public class LiveClient { private static final Logger LOGGER = LoggerFactory.getLogger(LiveClient.class); + private static final String DEFAULT_SERVER_ADDRESS = "livecmt-2.bilibili.com"; + private static final int DEFAULT_SERVER_PORT = 2243; + private final BilibiliServiceProvider bilibiliServiceProvider; private final EventLoopGroup eventLoopGroup; - private final long showRoomId; private final long userId; private final EventBus eventBus = new EventBus("BilibiliLiveClientEventBus"); + private Long showRoomId; + private Long realRoomId; private LiveRoomInfoEntity.LiveRoom liveRoom; private Channel channel; - public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, EventLoopGroup eventLoopGroup, long showRoomId, long userId) { + public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, @Nonnull EventLoopGroup eventLoopGroup, long roomId, boolean isRealRoomId, long userId) { this.bilibiliServiceProvider = bilibiliServiceProvider; this.eventLoopGroup = eventLoopGroup; - this.showRoomId = showRoomId; + if (isRealRoomId) { + realRoomId = roomId; + } else { + showRoomId = roomId; + } this.userId = userId; } - public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, EventLoopGroup eventLoopGroup, long showRoomId) { - this(bilibiliServiceProvider, eventLoopGroup, showRoomId, 0); + public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, @Nonnull EventLoopGroup eventLoopGroup, long showRoomId, long userId) { + this(bilibiliServiceProvider, eventLoopGroup, showRoomId, false, userId); + } + + public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, @Nonnull EventLoopGroup eventLoopGroup, long roomId, boolean isRealRoomId) { + this(bilibiliServiceProvider, eventLoopGroup, roomId, isRealRoomId, 0); + } + + public LiveClient(@Nonnull BilibiliServiceProvider bilibiliServiceProvider, @Nonnull EventLoopGroup eventLoopGroup, long showRoomId) { + this(bilibiliServiceProvider, eventLoopGroup, showRoomId, false, 0); } public Call fetchRoomInfoAsync() { return bilibiliServiceProvider.getLiveService() - .getRoomInfo(showRoomId); + .getRoomInfo(getShowRoomIdOrRoomId()); } public LiveRoomInfoEntity.LiveRoom fetchRoomInfo() throws IOException { @@ -61,60 +77,75 @@ public class LiveClient { .execute() .body() .getData(); + //此时 code 为 -404 if (liveRoom != null) { return liveRoom; } else { - throw new IllegalArgumentException("Target room " + showRoomId + " not exists"); + throw new IllegalArgumentException("Target room " + getShowRoomIdOrRoomId() + " not exists"); } } - public synchronized LiveClient connect() throws IOException { - if (channel != null && channel.isActive()) { - LOGGER.warn("Already connected to server, connect method can not be invoked twice"); + public Callable connectAsync() { + return () -> { + if (channel != null && channel.isActive()) { + LOGGER.warn("Already connected to server, connect method can not be invoked twice"); + return this; + } + if (realRoomId == null) { + if (liveRoom == null) { + LOGGER.info("Fetching info of live room {}", showRoomId); + liveRoom = fetchRoomInfo(); + LOGGER.info("Get actual room id {}", liveRoom.getRoomId()); + } + realRoomId = liveRoom.getRoomId(); + } + + LOGGER.debug("Init SocketChannel Bootstrap"); + Bootstrap bootstrap = new Bootstrap() + .group(eventLoopGroup) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel socketChannel) throws Exception { + socketChannel.pipeline() + .addLast(new LengthFieldBasedFrameDecoder( + Integer.MAX_VALUE, + 0, + Package.LENGTH_FIELD_LENGTH, + -Package.LENGTH_FIELD_LENGTH, + 0 + )) + .addLast(new IdleStateHandler(40, 0, 0)) + .addLast(new PackageEncoder()) + .addLast(new PackageDecoder()) + .addLast(new LiveClientHandler(self(), realRoomId, userId)); + } + }); + + String address = liveRoom != null ? liveRoom.getCmt() : DEFAULT_SERVER_ADDRESS; + int port = liveRoom != null ? liveRoom.getCmtPortGoim() : DEFAULT_SERVER_PORT; + LOGGER.info("Connecting to Bullet Screen server {}:{}", address, port); + try { + channel = bootstrap.connect(address, port) + .sync() + .channel(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (Exception e) { //有可能在此时出现网络错误 + throw new IOException(e); + } + return this; - } + }; + } - LOGGER.info("Fetching info of live room {}", showRoomId); - liveRoom = fetchRoomInfo(); - long roomId = liveRoom.getRoomId(); - LOGGER.info("Get actual room id {}", roomId); + public LiveClient connect(ExecutorService executorService) throws InterruptedException, ExecutionException { + Future future = executorService.submit(connectAsync()); + return future.get(); + } - LOGGER.debug("Init SocketChannel Bootstrap"); - Bootstrap bootstrap = new Bootstrap() - .group(eventLoopGroup) - .channel(NioSocketChannel.class) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(SocketChannel socketChannel) throws Exception { - socketChannel.pipeline() - .addLast(new LengthFieldBasedFrameDecoder( - Integer.MAX_VALUE, - 0, - Package.LENGTH_FIELD_LENGTH, - -Package.LENGTH_FIELD_LENGTH, - 0 - )) - .addLast(new IdleStateHandler(40, 0, 0)) - .addLast(new PackageEncoder()) - .addLast(new PackageDecoder()) - .addLast(new LiveClientHandler(self(), roomId, userId)); - } - }); - - String address = liveRoom.getCmt(); - int port = liveRoom.getCmtPortGoim(); - LOGGER.info("Connecting to Bullet Screen server {}:{}", address, port); - try { - channel = bootstrap.connect(address, port) - .sync() - .channel(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (Exception e) { //有可能在此时出现网络错误 - throw new IOException(e); - } - - return this; + public LiveClient connect() throws InterruptedException, ExecutionException { + return connect(Executors.newSingleThreadExecutor()); } public synchronized ChannelFuture closeChannelAsync() { @@ -149,6 +180,8 @@ public class LiveClient { return this; } + //TODO 弹幕发送队列 + public Call sendBulletScreenAsync(@Nonnull String message) { return bilibiliServiceProvider.getLiveService() .sendBulletScreen(createBulletScreenEntity(message)); @@ -160,12 +193,6 @@ public class LiveClient { .body(); } - private LiveClient self() { - return this; - } - - //TODO 弹幕发送队列 - private BulletScreenEntity createBulletScreenEntity(String message) { return new BulletScreenEntity( getRoomIdOrShowRoomId(), @@ -174,34 +201,27 @@ public class LiveClient { ); } - public long getShowRoomId() { - return showRoomId; - } - public long getUserId() { return userId; } - public Optional getRoomInfo() { - if (liveRoom == null) { - try { - liveRoom = fetchRoomInfo(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return Optional.of(liveRoom); + public long getRoomIdOrShowRoomId() { + return realRoomId != null ? realRoomId : showRoomId; } - public long getRoomIdOrShowRoomId() { - return getRoomInfo().map(LiveRoomInfoEntity.LiveRoom::getRoomId).orElse(showRoomId); + public long getShowRoomIdOrRoomId() { + return showRoomId != null ? showRoomId : realRoomId; } public int getBulletScreenLengthLimitOrDefaultLengthLimit() { - return getRoomInfo().map(LiveRoomInfoEntity.LiveRoom::getMsgLength).orElse(BulletScreenConstDefinition.DEFAULT_MESSAGE_LENGTH_LIMIT); + return liveRoom != null ? liveRoom.getMsgLength() : BulletScreenConstDefinition.DEFAULT_MESSAGE_LENGTH_LIMIT; } public Channel getChannel() { return channel; } + + private LiveClient self() { + return this; + } } diff --git a/src/main/java/com/hiczp/bilibili/api/provider/LiveClientProvider.java b/src/main/java/com/hiczp/bilibili/api/provider/LiveClientProvider.java index 4404484..cc26664 100644 --- a/src/main/java/com/hiczp/bilibili/api/provider/LiveClientProvider.java +++ b/src/main/java/com/hiczp/bilibili/api/provider/LiveClientProvider.java @@ -4,5 +4,9 @@ import com.hiczp.bilibili.api.live.socket.LiveClient; import io.netty.channel.EventLoopGroup; public interface LiveClientProvider { - LiveClient getLiveClient(EventLoopGroup eventLoopGroup, long showRoomId); + LiveClient getLiveClient(EventLoopGroup eventLoopGroup, long roomId, boolean isRealRoomId); + + default LiveClient getLiveClient(EventLoopGroup eventLoopGroup, long showRoomId) { + return getLiveClient(eventLoopGroup, showRoomId, false); + } } diff --git a/src/test/java/com/hiczp/bilibili/api/test/LiveClientTest.java b/src/test/java/com/hiczp/bilibili/api/test/LiveClientTest.java index 1403ef3..80e3b71 100644 --- a/src/test/java/com/hiczp/bilibili/api/test/LiveClientTest.java +++ b/src/test/java/com/hiczp/bilibili/api/test/LiveClientTest.java @@ -20,7 +20,7 @@ import java.util.List; public class LiveClientTest { private static final Logger LOGGER = LoggerFactory.getLogger(LiveClientTest.class); private static final BilibiliAPI BILIBILI_API = Config.getBilibiliAPI(); - private static final long ROOM_ID = 102; + private static final Config CONFIG = Config.getInstance(); private static final long TEST_TIME = 70 * 1000; @Ignore @@ -28,7 +28,7 @@ public class LiveClientTest { public void _0_duplicateConnectAndCloseTest() throws Exception { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); LiveClient liveClient = BILIBILI_API - .getLiveClient(eventLoopGroup, ROOM_ID); + .getLiveClient(eventLoopGroup, CONFIG.getRoomId()); LOGGER.debug("Connecting!"); liveClient.connect(); Thread.sleep(5000); @@ -55,7 +55,7 @@ public class LiveClientTest { public void _1_longTimeTest() throws Exception { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); LiveClient liveClient = BILIBILI_API - .getLiveClient(eventLoopGroup, ROOM_ID) + .getLiveClient(eventLoopGroup, CONFIG.getRoomId()) .registerListener(new Listener()); LOGGER.debug("Start long-time test"); LOGGER.debug("Connecting!");