-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathutils.py
More file actions
232 lines (203 loc) · 7.42 KB
/
Copy pathutils.py
File metadata and controls
232 lines (203 loc) · 7.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#MIT License
#Copyright (c) 2021 SUBIN 老房东
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#The above copyright notice and this permission notice shall be included in all
#copies or substantial portions of the Software.
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.
import os
import asyncio
from pyrogram.types import InlineKeyboardButton,InlineKeyboardMarkup
from config import Config
import ffmpeg
from pyrogram import emoji
from pyrogram.utils import MAX_CHANNEL_ID
from pyrogram.methods.messages.download_media import DEFAULT_DOWNLOAD_DIR
from pytgcalls import GroupCallFactory
from util.AudioFileFifo import AudioFileFifo
import signal
import wget
from asyncio import sleep
from pyrogram import Client
from youtube_dl import YoutubeDL
from util.youtube import youtube_downaudio
from os import path
bot = Client(
"Musicplayervc",
Config.API_ID,
Config.API_HASH,
workdir=Config.WORKDIR,
bot_token=Config.BOT_TOKEN
)
bot.start()
e=bot.get_me()
USERNAME=e.username
from user import USER
STREAM_URL=Config.STREAM_URL
CHAT=Config.CHAT
GROUP_CALLS = {}
FFMPEG_PROCESSES = {}
RADIO={6}
LOG_GROUP=Config.LOG_GROUP
DURATION_LIMIT=Config.DURATION_LIMIT
DELAY=Config.DELAY
playlist=Config.playlist
msg=Config.msg
class MusicPlayer(object):
CLIENT_TYPE = GroupCallFactory.MTPROTO_CLIENT_TYPE.PYROGRAM
audio_task = None
def __init__(self):
self.audio_fifo = AudioFileFifo()
self.audio_fifo.loop = asyncio.get_event_loop()
self.audio_fifo.on_playout_ended(self.playout_ended_handler)
self.group_call = GroupCallFactory(USER,self.CLIENT_TYPE).get_raw_group_call(on_played_data = self.audio_fifo.on_played_data)
self.chat_id = None
async def send_playlist(self):
if not playlist:
pl = f"{emoji.NO_ENTRY} Playlist is empty!!\n{emoji.NO_ENTRY} 播放列表里嘛都木有啦"
else:
pl = f"{emoji.PLAY_BUTTON} **Playlist**:\n" + "\n".join([
f"**{i}**. **🎸{x[1]}**\n 👤**Requested by:** {x[4].split('(tg://user?id=')[0]}\n"
for i, x in enumerate(playlist)
])
if msg.get('playlist') is not None:
await msg['playlist'].delete()
msg['playlist'] = await self.send_text(pl)
async def skip_current_playing(self):
if not playlist:
return
if len(playlist) == 1:
playlist.clear()
await self.start_radio()
return
afile = playlist[1][7]
await self.play_file(afile) # TODO 如果文件不存在其实就会出问题,这里需要修复
# remove old track from playlist
old_track = playlist.pop(0)
print(f"- START PLAYING: {playlist[0][1]}")
await self.send_photo(playlist[0])
if LOG_GROUP:
await self.send_playlist()
# 缓存所有已经下载过的文件
# os.remove(os.path.join(
# download_dir,
# f"{old_track[5]}.m4a")
# )
if len(playlist) == 1:
return
await self.download_audio(playlist[1])
async def send_text(self, text):
group_call = self.group_call
client = group_call.client
chat_id = LOG_GROUP
message = await bot.send_message(
chat_id,
text,
disable_web_page_preview=True,
disable_notification=True
)
return message
async def send_photo(self,track):
if LOG_GROUP:
chat_id = LOG_GROUP
buttons = [[
InlineKeyboardButton('再次点播', callback_data=f'research={track[2]}'),
InlineKeyboardButton('加入我的收藏', callback_data=f'addme={track[2]}'),
],[
InlineKeyboardButton('来源',url=track[2])
]]
reply_markup = InlineKeyboardMarkup(buttons)
phtoturl = track[6].split('?')[0]
message = await bot.send_photo(
chat_id,
photo=phtoturl,
caption=f"`{track[1]}`\n点播者: {track[4]} ",
reply_markup=reply_markup,
disable_notification=True
)
return message
return None
async def download_audio(self, song):
original_file = None
if song[3] == "youtube":
original_file = await youtube_downaudio(song[2])
print(f"download {original_file} finish")
song[7]=original_file
else:
original_file=wget.download(song[2])
return original_file
async def play_file(self, file):
if self.audio_task is not None:
self.audio_task.cancel()
try:
await self.audio_task
except asyncio.CancelledError:
print(f"cancel old task run new {file} task")
self.audio_task = asyncio.create_task(self.audio_fifo.avdecode(file))
return self.audio_task
async def start_radio(self):
group_call = self.group_call
if not group_call.is_connected:
await self.start_call()
afile = await youtube_downaudio(STREAM_URL) # TODO 应该对下载失败做出一些操作
if os.path.isfile(afile):
await self.play_file(afile)
try:
RADIO.remove(0)
except:
pass
try:
RADIO.add(1)
except:
pass
else:
print("No File Found\nSleeping...\n\n文件没找到\n晚安...")
async def stop_radio(self):
group_call = self.group_call
if group_call:
playlist.clear()
self.audio_task.cancel()
try:
RADIO.remove(1)
except:
pass
try:
RADIO.add(0)
except:
pass
async def start_call(self):
group_call = self.group_call
await group_call.start(CHAT)
# while not group_call.is_connected:
# print("wait connect")
# await asyncio.sleep(1)
async def delete(self, message):
if message.chat.type == "supergroup":
await sleep(DELAY)
try:
await message.delete()
except:
pass
async def playout_ended_handler(self):
if not playlist:
await self.start_radio()
else:
await self.skip_current_playing()
mp = MusicPlayer()
# pytgcalls handlers
@mp.group_call.on_network_status_changed
async def network_status_changed_handler(context, is_connected: bool):
if is_connected:
mp.chat_id = MAX_CHANNEL_ID - context.full_chat.id
else:
mp.chat_id = None