-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
340 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,140 @@ | ||
# soop | ||
|
||
[![npm version](https://img.shields.io/npm/v/soop-extension.svg?style=for-the-badge)](https://www.npmjs.com/package/soop-extension) | ||
[![npm downloads](https://img.shields.io/npm/dm/soop-extension.svg?style=for-the-badge)](http://npm-stat.com/charts.html?package=soop-extension) | ||
[![license](https://img.shields.io/github/license/maro5397/soop?style=for-the-badge)](https://github.com/maro5397/soop/blob/main/LICENSE) | ||
|
||
![createAt](https://img.shields.io/github/created-at/maro5397/soop?style=for-the-badge) | ||
![language](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white) | ||
|
||
라이브 스트리밍 서비스 숲(soop)의 비공식 API 라이브러리 | ||
|
||
라이브 스트리밍 서비스 SOOP의 비공식 API 라이브러리입니다. | ||
|
||
현재 구현된 기능은 다음과 같습니다. | ||
|
||
- 방송 상태 및 상세 정보 조회 | ||
- 채팅 | ||
|
||
## 설치 | ||
|
||
> Node 20.17.0 버전에서 개발되었습니다. | ||
```bash | ||
npm install soop-extension | ||
``` | ||
|
||
## 예시 | ||
|
||
```ts | ||
const streamerId = "cotton1217" | ||
const client = new SoopClient(); | ||
|
||
// 라이브 세부정보 | ||
const liveDetail = await client.live.detail(streamerId); | ||
console.log(liveDetail) | ||
|
||
// 채널 정보 | ||
const stationInfo = await client.channel.station(streamerId); | ||
console.log(stationInfo) | ||
|
||
const soopChat = client.chat({ | ||
streamerId: streamerId | ||
}) | ||
|
||
// 연결 성공 | ||
soopChat.on('connect', response => { | ||
console.log(`[${response.receivedTime}] Connected to ${response.streamerId}`) | ||
}) | ||
|
||
// 채팅방 입장 | ||
soopChat.on('enterChatRoom', response => { | ||
console.log(`[${response.receivedTime}] Enter to ${response.streamerId}'s chat room`) | ||
}) | ||
|
||
// 채팅방 공지 | ||
soopChat.on('notification', response => { | ||
console.log('-'.repeat(50)) | ||
console.log(`[${response.receivedTime}]`) | ||
console.log(response.notification.replace(/\r\n/g, '\n')) | ||
console.log('-'.repeat(50)) | ||
}) | ||
|
||
// 일반 채팅 | ||
soopChat.on('chat', response => { | ||
console.log(`[${response.receivedTime}] ${response.username}(${response.userId}): ${response.comment}`) | ||
}) | ||
|
||
// 이모티콘 채팅 | ||
soopChat.on('emoticon', response => { | ||
console.log(`[${response.receivedTime}] ${response.username}(${response.userId}): ${response.emoticonId}`) | ||
}) | ||
|
||
// 텍스트/음성 후원 채팅 | ||
soopChat.on('textDonation', response => { | ||
console.log(`\n[${response.receivedTime}] ${response.fromUsername}(${response.from})님이 ${response.to}님에게 ${response.amount}개 후원`) | ||
if (Number(response.fanClubOrdinal) !== 0) { | ||
console.log(`[${response.receivedTime}] ${response.fanClubOrdinal}번째 팬클럽 가입을 환영합니다.\n`) | ||
} else { | ||
console.log(`[${response.receivedTime}] 이미 팬클럽에 가입된 사용자입니다.\n`) | ||
} | ||
}) | ||
|
||
// 영상 후원 채팅 | ||
soopChat.on('videoDonation', response => { | ||
console.log(`\n[${response.receivedTime}] ${response.fromUsername}(${response.from})님이 ${response.to}님에게 ${response.amount}개 후원`) | ||
if (Number(response.fanClubOrdinal) !== 0) { | ||
console.log(`[${response.receivedTime}] ${response.fanClubOrdinal}번째 팬클럽 가입을 환영합니다.\n`) | ||
} else { | ||
console.log(`[${response.receivedTime}] 이미 팬클럽에 가입된 사용자입니다.\n`) | ||
} | ||
}) | ||
|
||
// 애드벌룬 후원 채팅 | ||
soopChat.on('adBalloonDonation', response => { | ||
console.log(`\n[${response.receivedTime}] ${response.fromUsername}(${response.from})님이 ${response.to}님에게 ${response.amount}개 후원`) | ||
if (Number(response.fanClubOrdinal) !== 0) { | ||
console.log(`[${response.receivedTime}] ${response.fanClubOrdinal}번째 팬클럽 가입을 환영합니다.\n`) | ||
} else { | ||
console.log(`[${response.receivedTime}] 이미 팬클럽에 가입된 사용자입니다.\n`) | ||
} | ||
}) | ||
|
||
// 구독 채팅 | ||
soopChat.on('subscribe', response => { | ||
console.log(`\n[${response.receivedTime}] ${response.fromUsername}(${response.from})님이 ${response.to}님을 구독하셨습니다.`) | ||
console.log(`[${response.receivedTime}] ${response.monthCount}개월, ${response.tier}티어\n`) | ||
}) | ||
|
||
// 퇴장 정보 | ||
soopChat.on('exit', response => { | ||
console.log(`\n[${response.receivedTime}] ${response.username}(${response.userId})이/가 퇴장하셨습니다\n`) | ||
}) | ||
|
||
// 입장 정보 | ||
soopChat.on('viewer', response => { | ||
if(response.userId.length > 1) { | ||
console.log(`[${response.receivedTime}] 수신한 채팅방 사용자는 ${response.userId.length}명 입니다.`) | ||
} else { | ||
console.log(`[${response.receivedTime}] ${response.userId[0]}이/가 입장하셨습니다`) | ||
} | ||
}) | ||
|
||
// 방송 종료 | ||
soopChat.on('disconnect', response => { | ||
console.log(`[${response.receivedTime}] ${response.streamerId}의 방송이 종료됨`) | ||
}) | ||
|
||
// 특정하지 못한 패킷 | ||
soopChat.on('unknown', packet => { | ||
console.log(packet) | ||
}) | ||
|
||
// 패킷을 바이너리 형태로 확인 | ||
soopChat.on('raw', packet => { | ||
console.log(packet) | ||
}) | ||
|
||
// 채팅 연결 | ||
await soopChat.connect() | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import {SoopClient} from "../client" | ||
import {DEFAULT_BASE_URLS} from "../const" | ||
|
||
interface StationInfo { | ||
profile_image: string; | ||
station: Station; | ||
broad: Broad; | ||
starballoon_top: StarBalloonTop[]; | ||
sticker_top: StickerTop[]; | ||
subscription: Subscription; | ||
is_best_bj: boolean; | ||
is_partner_bj: boolean; | ||
is_ppv_bj: boolean; | ||
is_af_supporters_bj: boolean; | ||
is_shopfreeca_bj: boolean; | ||
is_favorite: boolean; | ||
is_subscription: boolean; | ||
is_owner: boolean; | ||
is_manager: boolean; | ||
is_notice: boolean; | ||
is_adsence: boolean; | ||
is_mobile_push: boolean; | ||
subscribe_visible: string; | ||
country: string; | ||
current_timestamp: string; | ||
} | ||
|
||
interface Station { | ||
display: Display; | ||
groups: Group[]; | ||
menus: Menu[]; | ||
upd: Upd; | ||
vods: Vod[]; | ||
broad_start: string; | ||
grade: number; | ||
jointime: string; | ||
station_name: string; | ||
station_no: number; | ||
station_title: string; | ||
total_broad_time: number; | ||
user_id: string; | ||
user_nick: string; | ||
active_no: number; | ||
} | ||
|
||
interface Display { | ||
main_type: string; | ||
title_type: string; | ||
title_text: string; | ||
profile_text: string; | ||
skin_type: number; | ||
skin_no: number; | ||
title_skin_image: string; | ||
} | ||
|
||
interface Group { | ||
idx: number; | ||
group_no: number; | ||
priority: number; | ||
info: { | ||
group_name: string; | ||
group_class_name: string; | ||
group_background_color: string; | ||
}; | ||
} | ||
|
||
interface Menu { | ||
bbs_no: number; | ||
station_no: number; | ||
auth_no: number; | ||
w_auth_no: number; | ||
display_type: number; | ||
rnum: number; | ||
line: number; | ||
indention: number; | ||
name: string; | ||
name_font: number; | ||
main_view_yn: number; | ||
view_type: number; | ||
} | ||
|
||
interface Upd { | ||
station_no: number; | ||
user_id: string; | ||
asp_code: number; | ||
fan_cnt: number; | ||
today0_visit_cnt: number; | ||
today1_visit_cnt: number; | ||
total_visit_cnt: number; | ||
today0_ok_cnt: number; | ||
today1_ok_cnt: number; | ||
today0_fav_cnt: number; | ||
today1_fav_cnt: number; | ||
total_ok_cnt: number; | ||
total_view_cnt: number; | ||
} | ||
|
||
interface Vod { | ||
bbs_no: number; | ||
station_no: number; | ||
auth_no: number; | ||
w_auth_no: number; | ||
display_type: number; | ||
rnum: number; | ||
line: number; | ||
indention: number; | ||
name: string; | ||
name_font: number; | ||
main_view_yn: number; | ||
view_type: number; | ||
} | ||
|
||
interface Broad { | ||
user_id: string; | ||
broad_no: number; | ||
broad_title: string; | ||
current_sum_viewer: number; | ||
broad_grade: number; | ||
is_password: boolean; | ||
} | ||
|
||
interface StarBalloonTop { | ||
user_id: string; | ||
user_nick: string; | ||
profile_image: string; | ||
} | ||
|
||
interface StickerTop { | ||
user_id: string; | ||
user_nick: string; | ||
profile_image: string; | ||
} | ||
|
||
interface Subscription { | ||
total: number; | ||
tier1: number; | ||
tier2: number; | ||
} | ||
|
||
export class SoopChannel { | ||
private client: SoopClient | ||
|
||
constructor(client: SoopClient) { | ||
this.client = client | ||
} | ||
|
||
async station(streamerId: string, baseUrl: string = DEFAULT_BASE_URLS.soopChannelBaseUrl): Promise<StationInfo> { | ||
return this.client.fetch(`${baseUrl}/api/${streamerId}/station`, { | ||
method: "GET", | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
return { | ||
profile_image: data["profile_image"], | ||
station: data["station"], | ||
broad: data["broad"], | ||
starballoon_top: data["starballoon_top"], | ||
sticker_top: data["sticker_top"], | ||
subscription: data["subscription"], | ||
is_best_bj: data["is_best_bj"], | ||
is_partner_bj: data["is_partner_bj"], | ||
is_ppv_bj: data["is_ppv_bj"], | ||
is_af_supporters_bj: data["is_af_supporters_bj"], | ||
is_shopfreeca_bj: data["is_shopfreeca_bj"], | ||
is_favorite: data["is_favorite"], | ||
is_subscription: data["is_subscription"], | ||
is_owner: data["is_owner"], | ||
is_manager: data["is_manager"], | ||
is_notice: data["is_notice"], | ||
is_adsence: data["is_adsence"], | ||
is_mobile_push: data["is_mobile_push"], | ||
subscribe_visible: data["subscribe_visible"], | ||
country: data["country"], | ||
current_timestamp: data["current_timestamp"] | ||
}; | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.