gram-tgcalls
Advanced tools
Comparing version 1.4.0 to 2.0.1
import { TelegramClient, Api } from 'telegram'; | ||
import { JoinVoiceCallCallback } from 'tgcalls/lib/types'; | ||
export declare const calls: Map<number, Api.InputGroupCall>; | ||
export declare function getJoinCall(client: TelegramClient, chatId: number, joinAs?: Api.TypeEntityLike): JoinVoiceCallCallback<any>; | ||
export declare function leaveCall(client: TelegramClient, chatId: number): Promise<boolean>; | ||
import { JoinVoiceCallParams, JoinVoiceCallResponse } from 'tgcalls/lib/types'; | ||
import { JoinParams, EditParams } from './types'; | ||
export declare function join(client: TelegramClient, call: Api.InputGroupCall, payload: JoinVoiceCallParams<any>, params: JoinParams): Promise<JoinVoiceCallResponse>; | ||
export declare function leave(client: TelegramClient, call: Api.TypeInputGroupCall): Promise<Api.TypeUpdates>; | ||
export declare function edit(client: TelegramClient, call: Api.InputGroupCall, participant: Api.TypeEntityLike, params: EditParams): Promise<Api.TypeUpdates>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.leaveCall = exports.getJoinCall = exports.calls = void 0; | ||
exports.edit = exports.leave = exports.join = void 0; | ||
const telegram_1 = require("telegram"); | ||
exports.calls = new Map(); | ||
function getJoinCall(client, chatId, joinAs) { | ||
return async (params) => { | ||
const fullChat = (await client.invoke(new telegram_1.Api.channels.GetFullChannel({ channel: chatId }))).fullChat; | ||
if (!fullChat.call) { | ||
throw new Error('No active group call'); | ||
} | ||
exports.calls.set(chatId, fullChat.call); | ||
const joinGroupCallResult = await client.invoke(new telegram_1.Api.phone.JoinGroupCall({ | ||
muted: false, | ||
call: fullChat.call, | ||
params: new telegram_1.Api.DataJSON({ | ||
data: JSON.stringify({ | ||
ufrag: params.ufrag, | ||
pwd: params.pwd, | ||
fingerprints: [ | ||
{ | ||
hash: params.hash, | ||
setup: params.setup, | ||
fingerprint: params.fingerprint, | ||
}, | ||
], | ||
ssrc: params.source, | ||
}), | ||
async function join(client, call, payload, params) { | ||
// @ts-ignore | ||
const { updates } = await client.invoke(new telegram_1.Api.phone.JoinGroupCall({ | ||
call, | ||
params: new telegram_1.Api.DataJSON({ | ||
data: JSON.stringify({ | ||
ufrag: payload.ufrag, | ||
pwd: payload.pwd, | ||
fingerprints: [ | ||
{ | ||
hash: payload.hash, | ||
setup: payload.setup, | ||
fingerprint: payload.fingerprint, | ||
}, | ||
], | ||
ssrc: payload.source, | ||
}), | ||
joinAs: joinAs || fullChat.groupcallDefaultJoinAs || 'me', | ||
})); | ||
// @ts-ignore | ||
for (let i in joinGroupCallResult.updates) { | ||
// @ts-ignore | ||
const update = joinGroupCallResult.updates[i]; | ||
if (update instanceof telegram_1.Api.UpdateGroupCallConnection) { | ||
return JSON.parse(update.params.data); | ||
} | ||
}), | ||
...params, | ||
})); | ||
for (let i in updates) { | ||
const update = updates[i]; | ||
if (update instanceof telegram_1.Api.UpdateGroupCallConnection) { | ||
return JSON.parse(update.params.data); | ||
} | ||
throw new Error('Could not get connection params'); | ||
}; | ||
} | ||
throw new Error('Could not get transport'); | ||
} | ||
exports.getJoinCall = getJoinCall; | ||
async function leaveCall(client, chatId) { | ||
const call = exports.calls.get(chatId); | ||
if (!call) { | ||
return false; | ||
} | ||
await client.invoke(new telegram_1.Api.phone.LeaveGroupCall({ | ||
call: call, | ||
source: 0, | ||
exports.join = join; | ||
function leave(client, call) { | ||
return client.invoke(new telegram_1.Api.phone.LeaveGroupCall({ call })); | ||
} | ||
exports.leave = leave; | ||
function edit(client, call, participant, params) { | ||
return client.invoke(new telegram_1.Api.phone.EditGroupCallParticipant({ | ||
call, | ||
participant, | ||
...params, | ||
})); | ||
exports.calls.delete(chatId); | ||
return true; | ||
} | ||
exports.leaveCall = leaveCall; | ||
exports.edit = edit; |
/// <reference types="node" /> | ||
import { Readable } from 'stream'; | ||
import { Api, TelegramClient } from 'telegram'; | ||
import { EntityLike } from 'telegram/define'; | ||
export declare class GramTGCalls { | ||
#private; | ||
import { Stream } from 'tgcalls'; | ||
import { JoinParams, MediaParams, EditParams } from './types'; | ||
export default class GramTGCalls { | ||
client: TelegramClient; | ||
constructor(client: TelegramClient); | ||
chat: Api.TypeEntityLike; | ||
private call?; | ||
private tgcalls?; | ||
media?: Stream; | ||
track?: MediaStreamTrack; | ||
constructor(client: TelegramClient, chat: Api.TypeEntityLike); | ||
/** | ||
* Streams the specified audio with the provided options. | ||
* | ||
* Audio properties: | ||
* - Format: s16le | ||
* - Bitrate: 65K or what you provide in options.stream.sampleRate | ||
* - Channels: 2 | ||
* Starts streaming the provided readable. | ||
*/ | ||
stream(chatId: number, readable: Readable, options?: { | ||
onFinish?: (...args: any[]) => void; | ||
joinAs?: Api.TypeEntityLike; | ||
params?: any; | ||
stream?: { | ||
bitsPerSample?: number; | ||
sampleRate?: number; | ||
channelCount?: number; | ||
almostFinishedTrigger?: number; | ||
}; | ||
}): Promise<void>; | ||
stream(readable: Readable, params?: { | ||
join?: JoinParams; | ||
media?: MediaParams; | ||
}): void; | ||
/** | ||
* Pauses the stream. Returns true if successful, false if already paused or null if not in the call of the specified chat. | ||
* Pauses streaming. Returns `null` if not in call, `false` if already paused or `true` if successful. | ||
*/ | ||
pause(chatId: number): boolean | null; | ||
pause(): boolean | null; | ||
/** | ||
* Resumes the stream. Returns true if successful, false if already resumed or null if not in the call of the specified chat. | ||
* Resumes streaming. Returns `null` if not in call, `false` if not paused or `true` if successful. | ||
*/ | ||
resume(chatId: number): boolean | null; | ||
resume(): boolean | null; | ||
/** | ||
* Stops the stream and leaves the call. Returns true if successful or a falsy value if not. | ||
* Mutes the sound. Returns `null` if not in call, `false` if already muted or `true` if successful. | ||
*/ | ||
stop(chatId: number): Promise<boolean | null>; | ||
mute(): boolean | null; | ||
/** | ||
* Returns true if in the call of the specified chat or false if not. | ||
* Unmutes the sound. Returns `null` if not in call, `false` if already muted or `true` if successful. | ||
*/ | ||
connected(chatId: number): boolean; | ||
unmute(): boolean | null; | ||
/** | ||
* Returns true if the stream is finished in the specified chat or false if not. | ||
* Stops the stream, closes the WebRTC connection and sends leave request to Telegram. Returns `false` if not in call or `true` if successful. | ||
*/ | ||
finished(chatId: number): boolean | null; | ||
stop(): Promise<boolean>; | ||
/** | ||
* Sets the volume of self or someone. Returns true if successful or false if not in the call of the specified chat. | ||
* Tells if the provided readable has finished streaming. Returns `null` if not in call, `true` if finished or `false` if not. | ||
*/ | ||
setVolume(chatId: number, volume: number, participant?: EntityLike): Promise<boolean>; | ||
finished(): boolean | null; | ||
/** | ||
* Edits the provided participant. | ||
*/ | ||
edit(participant: Api.TypeEntityLike, params: EditParams): Promise<boolean>; | ||
/** | ||
* Alias for `edit`. | ||
*/ | ||
editParticipant: (participant: Api.TypeEntityLike, params: EditParams) => Promise<boolean>; | ||
/** | ||
* Edits self participant. | ||
*/ | ||
editSelf(params: EditParams): Promise<boolean>; | ||
/** | ||
* Alias for `editSelf`. | ||
*/ | ||
editSelfParticipant: (params: EditParams) => Promise<boolean>; | ||
} |
215
lib/index.js
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _GramTGCalls_connections; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GramTGCalls = void 0; | ||
const tgcalls_1 = require("tgcalls"); | ||
const calls_1 = require("./calls"); | ||
const participants_1 = require("./participants"); | ||
const calls = __importStar(require("./calls")); | ||
const chats = __importStar(require("./chats")); | ||
class GramTGCalls { | ||
constructor(client) { | ||
_GramTGCalls_connections.set(this, void 0); | ||
constructor(client, chat) { | ||
this.client = client; | ||
__classPrivateFieldSet(this, _GramTGCalls_connections, new Map(), "f"); | ||
this.chat = chat; | ||
/** | ||
* Alias for `edit`. | ||
*/ | ||
this.editParticipant = this.edit; | ||
/** | ||
* Alias for `editSelf`. | ||
*/ | ||
this.editSelfParticipant = this.editSelf; | ||
} | ||
/** | ||
* Streams the specified audio with the provided options. | ||
* | ||
* Audio properties: | ||
* - Format: s16le | ||
* - Bitrate: 65K or what you provide in options.stream.sampleRate | ||
* - Channels: 2 | ||
* Starts streaming the provided readable. | ||
*/ | ||
async stream(chatId, readable, options) { | ||
var _a, _b, _c, _d; | ||
const connection = __classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
if (connection) { | ||
connection.stream.setReadable(readable); | ||
stream(readable, params) { | ||
var _a, _b, _c, _d, _e; | ||
if (!this.tgcalls) { | ||
this.tgcalls = new tgcalls_1.TGCalls({}); | ||
this.tgcalls.joinVoiceCall = async (payload) => { | ||
var _a, _b; | ||
const fullChat = await chats.getFull(this.client, this.chat); | ||
if (!fullChat.call) { | ||
throw new Error('No active call'); | ||
} | ||
this.call = fullChat.call; | ||
return await calls.join(this.client, this.call, payload, { | ||
...params === null || params === void 0 ? void 0 : params.join, | ||
muted: ((_a = params === null || params === void 0 ? void 0 : params.join) === null || _a === void 0 ? void 0 : _a.muted) || false, | ||
joinAs: ((_b = params === null || params === void 0 ? void 0 : params.join) === null || _b === void 0 ? void 0 : _b.joinAs) || | ||
fullChat.groupcallDefaultJoinAs || | ||
'me', | ||
}); | ||
}; | ||
} | ||
else { | ||
const connection = { | ||
tgcalls: new tgcalls_1.TGCalls(options === null || options === void 0 ? void 0 : options.params), | ||
stream: new tgcalls_1.Stream(readable, ((_a = options === null || options === void 0 ? void 0 : options.stream) === null || _a === void 0 ? void 0 : _a.bitsPerSample) || 16, ((_b = options === null || options === void 0 ? void 0 : options.stream) === null || _b === void 0 ? void 0 : _b.sampleRate) || 65000, ((_c = options === null || options === void 0 ? void 0 : options.stream) === null || _c === void 0 ? void 0 : _c.channelCount) || 1, ((_d = options === null || options === void 0 ? void 0 : options.stream) === null || _d === void 0 ? void 0 : _d.almostFinishedTrigger) || 20), | ||
}; | ||
connection.tgcalls.joinVoiceCall = calls_1.getJoinCall(this.client, chatId, options === null || options === void 0 ? void 0 : options.joinAs); | ||
if (options === null || options === void 0 ? void 0 : options.onFinish) { | ||
connection.stream.addListener('finish', options.onFinish); | ||
if (!this.media) { | ||
this.media = new tgcalls_1.Stream(readable, (_a = params === null || params === void 0 ? void 0 : params.media) === null || _a === void 0 ? void 0 : _a.bitsPerSample, (_b = params === null || params === void 0 ? void 0 : params.media) === null || _b === void 0 ? void 0 : _b.sampleRate, (_c = params === null || params === void 0 ? void 0 : params.media) === null || _c === void 0 ? void 0 : _c.channelCount, (_d = params === null || params === void 0 ? void 0 : params.media) === null || _d === void 0 ? void 0 : _d.almostFinishedTrigger); | ||
if ((_e = params === null || params === void 0 ? void 0 : params.media) === null || _e === void 0 ? void 0 : _e.onFinish) { | ||
this.media.addListener('finish', params.media.onFinish); | ||
} | ||
__classPrivateFieldGet(this, _GramTGCalls_connections, "f").set(chatId, connection); | ||
try { | ||
await connection.tgcalls.start(connection.stream.createTrack()); | ||
} | ||
catch (error) { | ||
__classPrivateFieldGet(this, _GramTGCalls_connections, "f").delete(chatId); | ||
throw error; | ||
} | ||
} | ||
else { | ||
this.media.setReadable(readable); | ||
return; | ||
} | ||
this.track = this.media.createTrack(); | ||
this.tgcalls.start(this.track); | ||
} | ||
/** | ||
* Pauses the stream. Returns true if successful, false if already paused or null if not in the call of the specified chat. | ||
* Pauses streaming. Returns `null` if not in call, `false` if already paused or `true` if successful. | ||
*/ | ||
pause(chatId) { | ||
const connection = __classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
if (connection) { | ||
if (!connection.stream.paused) { | ||
connection.stream.pause(); | ||
return true; | ||
} | ||
return false; | ||
pause() { | ||
if (!this.media) { | ||
return null; | ||
} | ||
return null; | ||
if (!this.media.paused) { | ||
this.media.pause(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Resumes the stream. Returns true if successful, false if already resumed or null if not in the call of the specified chat. | ||
* Resumes streaming. Returns `null` if not in call, `false` if not paused or `true` if successful. | ||
*/ | ||
resume(chatId) { | ||
const connection = __classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
if (connection) { | ||
if (connection.stream.paused) { | ||
connection.stream.pause(); | ||
return true; | ||
} | ||
return false; | ||
resume() { | ||
if (!this.media) { | ||
return null; | ||
} | ||
return null; | ||
if (this.media.paused) { | ||
this.media.pause(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Stops the stream and leaves the call. Returns true if successful or a falsy value if not. | ||
* Mutes the sound. Returns `null` if not in call, `false` if already muted or `true` if successful. | ||
*/ | ||
async stop(chatId) { | ||
const connection = __classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
if (connection) { | ||
__classPrivateFieldGet(this, _GramTGCalls_connections, "f").delete(chatId); | ||
return calls_1.leaveCall(this.client, chatId); | ||
mute() { | ||
if (!this.track) { | ||
return null; | ||
} | ||
return null; | ||
if (this.track.enabled) { | ||
this.track.enabled = false; | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Returns true if in the call of the specified chat or false if not. | ||
* Unmutes the sound. Returns `null` if not in call, `false` if already muted or `true` if successful. | ||
*/ | ||
connected(chatId) { | ||
return !!__classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
unmute() { | ||
if (!this.track) { | ||
return null; | ||
} | ||
if (!this.track.enabled) { | ||
this.track.enabled = true; | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Returns true if the stream is finished in the specified chat or false if not. | ||
* Stops the stream, closes the WebRTC connection and sends leave request to Telegram. Returns `false` if not in call or `true` if successful. | ||
*/ | ||
finished(chatId) { | ||
const connection = __classPrivateFieldGet(this, _GramTGCalls_connections, "f").get(chatId); | ||
if (connection) { | ||
return connection.stream.finished; | ||
async stop() { | ||
var _a, _b; | ||
if (!this.call) { | ||
return false; | ||
} | ||
return null; | ||
(_a = this.media) === null || _a === void 0 ? void 0 : _a.stop(); | ||
(_b = this.tgcalls) === null || _b === void 0 ? void 0 : _b.close(); | ||
await calls.leave(this.client, this.call); | ||
this.call = this.tgcalls = this.media = this.track = undefined; | ||
return true; | ||
} | ||
/** | ||
* Sets the volume of self or someone. Returns true if successful or false if not in the call of the specified chat. | ||
* Tells if the provided readable has finished streaming. Returns `null` if not in call, `true` if finished or `false` if not. | ||
*/ | ||
setVolume(chatId, volume, participant = 'me') { | ||
return participants_1.setVolume(this.client, chatId, participant, volume); | ||
finished() { | ||
if (!this.media) { | ||
return null; | ||
} | ||
return this.media.finished; | ||
} | ||
/** | ||
* Edits the provided participant. | ||
*/ | ||
async edit(participant, params) { | ||
if (!this.call) { | ||
return false; | ||
} | ||
await calls.edit(this.client, this.call, participant, params); | ||
return true; | ||
} | ||
/** | ||
* Edits self participant. | ||
*/ | ||
editSelf(params) { | ||
return this.edit('me', params); | ||
} | ||
} | ||
exports.GramTGCalls = GramTGCalls; | ||
_GramTGCalls_connections = new WeakMap(); | ||
exports.default = GramTGCalls; |
@@ -1,5 +0,21 @@ | ||
import { Stream, TGCalls } from 'tgcalls'; | ||
export interface Connection { | ||
tgcalls: TGCalls<any>; | ||
stream: Stream; | ||
import { Api } from 'telegram'; | ||
export interface JoinParams { | ||
muted?: boolean; | ||
inviteHash?: string; | ||
joinAs?: Api.TypeEntityLike; | ||
} | ||
export interface MediaParams { | ||
onFinish?: () => void; | ||
bitsPerSample?: number; | ||
sampleRate?: number; | ||
channelCount?: number; | ||
almostFinishedTrigger?: number; | ||
} | ||
export interface EditParams { | ||
muted?: boolean; | ||
volume?: number; | ||
raiseHand?: boolean; | ||
videoStopped?: boolean; | ||
videoPaused?: boolean; | ||
presentationPaused?: boolean; | ||
} |
{ | ||
"name": "gram-tgcalls", | ||
"version": "1.4.0", | ||
"version": "2.0.1", | ||
"main": "lib/index.js", | ||
@@ -27,6 +27,5 @@ "scripts": { | ||
"dependencies": { | ||
"node-pre-gyp": "^0.17.0", | ||
"telegram": "^1.7.23", | ||
"telegram": "^1.8.9", | ||
"tgcalls": "^0.1.4" | ||
} | ||
} |
# Gram TGCalls [![Mentioned in Awesome Telegram Calls](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/tgcalls/awesome-tgcalls) | ||
Gram TGCalls connects tgcallsjs with [GramJS](https://github.com/gram-js/gramjs). It makes it easier for you to use tgcallsjs with its methods and helpers. | ||
An operative library for Telegram calls and a tgcallsjs helper. | ||
## Install | ||
## Features | ||
- Super light & easy-to-use. | ||
- Smart stream function. | ||
- Native controls: pause, resume, mute, unmute. | ||
- Call helpers: join, edit, leave. | ||
## Installation | ||
```shell | ||
@@ -14,1 +21,5 @@ npm i gram-tgcalls | ||
The docs can be found [here](https://tgcallsjs.github.io/gram-tgcalls). | ||
## Credits | ||
- [Telethon bridge](https://github.com/MarshalX/tgcalls/blob/dev/pytgcalls/pytgcalls/mtproto/telethon_bridge.py) by [@MarshalX](https://github.com) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
21570
2
13
340
25
1
- Removednode-pre-gyp@^0.17.0
- Removednode-pre-gyp@0.17.0(transitive)
Updatedtelegram@^1.8.9