├── .dockerignore
├── .github
└── workflows
│ ├── main.yml
│ └── python-app.yml
├── .gitignore
├── Dockerfile
├── GeezProject
├── __main__.py
├── config.py
├── function
│ ├── __init__.py
│ └── admins.py
├── helpers
│ ├── __init__.py
│ ├── admins.py
│ ├── channelmusic.py
│ ├── decorators.py
│ ├── errors.py
│ ├── filters.py
│ └── gets.py
├── modules
│ ├── __init__.py
│ ├── admins.py
│ ├── channeladmin.py
│ ├── channelplay.py
│ ├── chat_member_updated.py
│ ├── gcast.py
│ ├── inline.py
│ ├── msg.py
│ ├── play.py
│ ├── pmpermit.py
│ ├── private.py
│ ├── song.py
│ ├── userbotjoin.py
│ └── ytsearch.py
└── services
│ ├── __init__.py
│ ├── callsmusic
│ ├── __init__.py
│ └── callsmusic.py
│ ├── converter
│ ├── __init__.py
│ └── converter.py
│ ├── downloaders
│ ├── __init__.py
│ └── youtube.py
│ └── queues
│ ├── __init__.py
│ └── queues.py
├── LICENSE
├── README.md
├── app.json
├── etc
└── font.otf
├── example.env
├── heroku.yml
├── requirements.txt
└── str.py
/.dockerignore:
--------------------------------------------------------------------------------
1 | LICENSE
2 | README.md
3 |
4 | .env
5 | .gitignore
6 |
7 | .git/
8 | __pycache__/
9 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the Geez-Userbot branch
8 | push:
9 | branches: [ master]
10 | pull_request:
11 | branches: [ master]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17 | jobs:
18 | # This workflow contains a single job called "build"
19 | build:
20 | # The type of runner that the job will run on
21 | runs-on: ubuntu-latest
22 |
23 | # Steps represent a sequence of tasks that will be executed as part of the job
24 | steps:
25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26 | - uses: actions/checkout@v2
27 |
28 | # Runs a single command using the runners shell
29 | - name: Run a one-line script
30 | run: echo Hello, world!
31 |
32 | # Runs a set of commands using the runners shell
33 | - name: Run a multi-line script
34 | run: |
35 | echo Add other actions to build,
36 | echo test, and deploy your project.
37 |
--------------------------------------------------------------------------------
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | name: FailCheck
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 | strategy:
10 | max-parallel: 5
11 | matrix:
12 | python-version: [3.9]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Set up Python ${{ matrix.python-version }}
17 | uses: actions/setup-python@v1
18 | with:
19 | python-version: ${{ matrix.python-version }}
20 | - name: Install dependencies
21 | run: |
22 | sudo apt-get install libpq-dev
23 | python -m pip install --upgrade pip
24 | pip install -r requirements.txt
25 | pip install flake8 flake8-print flake8-quotes
26 | - name: Check for showstoppers
27 | run: |
28 | flake8 . --count --select=E999 --show-source --statistics
29 | shellcheck:
30 |
31 | runs-on: ubuntu-latest
32 |
33 | steps:
34 | - uses: actions/checkout@v1
35 | - name: Check for install script errors
36 | uses: ludeeus/action-shellcheck@0.1.0
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.session
2 | *.session-journal
3 | .env
4 | __pycache__
5 | .idea
6 | .vscode
7 | raw_files
8 | downloads
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:latest
2 | FROM python:3.9.6-slim-buster
3 | RUN apt update && apt upgrade -y
4 | RUN apt install git curl python3-pip ffmpeg -y
5 | RUN pip3 install -U pip
6 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -
7 | RUN apt-get install -y nodejs
8 | RUN npm i -g npm
9 | RUN mkdir /app/
10 | WORKDIR /app/
11 | COPY . /app/
12 | RUN pip3 install -U -r requirements.txt
13 | CMD python3 -m GeezProject
14 |
--------------------------------------------------------------------------------
/GeezProject/__main__.py:
--------------------------------------------------------------------------------
1 | # DaisyXMusic (Telegram bot project)
2 | # Copyright (C) 2021 Inuka Asith & Rojserbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | import requests
19 | from pyrogram import Client as Bot
20 |
21 | from GeezProject.config import API_HASH, API_ID, BG_IMAGE, BOT_TOKEN
22 | from GeezProject.services.callsmusic import run
23 |
24 | response = requests.get(BG_IMAGE)
25 | with open("./etc/foreground.png", "wb") as file:
26 | file.write(response.content)
27 | bot = Bot(
28 | ":memory:",
29 | API_ID,
30 | API_HASH,
31 | bot_token=BOT_TOKEN,
32 | plugins=dict(root="GeezProject.modules"),
33 | )
34 |
35 | bot.start()
36 | run()
37 |
--------------------------------------------------------------------------------
/GeezProject/config.py:
--------------------------------------------------------------------------------
1 | # DAISYXMUSIC- Telegram bot project
2 | # Copyright (C) 2021 Roj Serbest
3 | # Copyright (C) 2021 Inuka Asith
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 | # Modified by Inukaasith
17 |
18 | import os
19 | from os import getenv
20 |
21 | from dotenv import load_dotenv
22 |
23 | if os.path.exists("local.env"):
24 | load_dotenv("local.env")
25 |
26 | que = {}
27 | SESSION_NAME = getenv("SESSION_NAME", "session")
28 | BOT_TOKEN = getenv("BOT_TOKEN")
29 | BOT_NAME = getenv("BOT_NAME")
30 | UPDATES_CHANNEL = getenv("UPDATES_CHANNEL", "GeezProjects")
31 | BG_IMAGE = getenv("BG_IMAGE", "https://telegra.ph/file/22d1625c6910bdb0dac66.png")
32 | admins = {}
33 | API_ID = int(getenv("API_ID"))
34 | API_HASH = getenv("API_HASH")
35 | BOT_USERNAME = getenv("BOT_USERNAME")
36 | ASSISTANT_NAME = getenv("ASSISTANT_NAME", "GeezMusicBot")
37 | SUPPORT_GROUP = getenv("SUPPORT_GROUP", "GeezSupportGroup")
38 | PROJECT_NAME = getenv("PROJECT_NAME", "Geez Music Project")
39 | OWNER = getenv("OWNER", "@VckyouuBitch")
40 | SOURCE_CODE = getenv("SOURCE_CODE", "github.com/Vckyou/Geez-MusicProject")
41 | DURATION_LIMIT = int(getenv("DURATION_LIMIT", "15"))
42 | ARQ_API_KEY = getenv("ARQ_API_KEY", None)
43 | PMPERMIT = getenv("PMPERMIT", None)
44 | LOG_GRP = getenv("LOG_GRP", None)
45 | COMMAND_PREFIXES = list(getenv("COMMAND_PREFIXES", "/ !").split())
46 |
47 | SUDO_USERS = list(map(int, getenv("SUDO_USERS").split()))
48 |
--------------------------------------------------------------------------------
/GeezProject/function/__init__.py:
--------------------------------------------------------------------------------
1 | from GeezProject.function.admins import admins, get, set
2 |
3 | __all__ = ["set", "get", "admins"]
4 |
--------------------------------------------------------------------------------
/GeezProject/function/admins.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Union
2 |
3 | admins: Dict[int, List[int]] = {}
4 |
5 |
6 | def set(chat_id: int, admins_: List[int]):
7 | admins[chat_id] = admins_
8 |
9 |
10 | def get(chat_id: int) -> Union[List[int], bool]:
11 | if chat_id in admins:
12 | return admins[chat_id]
13 |
14 | return False
15 |
--------------------------------------------------------------------------------
/GeezProject/helpers/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/GeezProject/helpers/admins.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from typing import List
19 |
20 | from pyrogram.types import Chat
21 |
22 | from GeezProject.function.admins import get as gett
23 | from GeezProject.function.admins import set
24 |
25 |
26 | async def get_administrators(chat: Chat) -> List[int]:
27 | get = gett(chat.id)
28 |
29 | if get:
30 | return get
31 | else:
32 | administrators = await chat.get_members(filter="administrators")
33 | to_set = []
34 |
35 | for administrator in administrators:
36 | if administrator.can_manage_voice_chats:
37 | to_set.append(administrator.user.id)
38 |
39 | set(chat.id, to_set)
40 | return await get_administrators(chat)
41 |
--------------------------------------------------------------------------------
/GeezProject/helpers/channelmusic.py:
--------------------------------------------------------------------------------
1 | from pyrogram.types import Chat
2 |
3 |
4 | def get_chat_id(chat: Chat):
5 | if chat.title.startswith("Channel Music: ") and chat.title[16:].isnumeric():
6 | return int(chat.title[15:])
7 | return chat.id
8 |
--------------------------------------------------------------------------------
/GeezProject/helpers/decorators.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from typing import Callable
19 |
20 | from pyrogram import Client
21 | from pyrogram.types import Message
22 |
23 | from GeezProject.config import SUDO_USERS
24 | from GeezProject.helpers.admins import get_administrators
25 |
26 |
27 | def errors(func: Callable) -> Callable:
28 | async def decorator(client: Client, message: Message):
29 | try:
30 | return await func(client, message)
31 | except Exception as e:
32 | await message.reply(f"{type(e).__name__}: {e}")
33 |
34 | return decorator
35 |
36 |
37 | def authorized_users_only(func: Callable) -> Callable:
38 | async def decorator(client: Client, message: Message):
39 | if message.from_user.id in SUDO_USERS:
40 | return await func(client, message)
41 |
42 | administrators = await get_administrators(message.chat)
43 |
44 | for administrator in administrators:
45 | if administrator == message.from_user.id:
46 | return await func(client, message)
47 |
48 | return decorator
49 |
--------------------------------------------------------------------------------
/GeezProject/helpers/errors.py:
--------------------------------------------------------------------------------
1 | class DurationLimitError(Exception):
2 | pass
3 |
4 |
5 | class FFmpegReturnCodeError(Exception):
6 | pass
7 |
--------------------------------------------------------------------------------
/GeezProject/helpers/filters.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from typing import List, Union
19 |
20 | from pyrogram import filters
21 |
22 | from GeezProject.config import COMMAND_PREFIXES
23 |
24 | other_filters = filters.group & ~filters.edited & ~filters.via_bot & ~filters.forwarded
25 | other_filters2 = (
26 | filters.private & ~filters.edited & ~filters.via_bot & ~filters.forwarded
27 | )
28 |
29 |
30 | def command(commands: Union[str, List[str]]):
31 | return filters.command(commands, COMMAND_PREFIXES)
32 |
--------------------------------------------------------------------------------
/GeezProject/helpers/gets.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from typing import Union
19 |
20 | from pyrogram.types import Audio, Message, Voice
21 |
22 |
23 | def get_url(message_1: Message) -> Union[str, None]:
24 | messages = [message_1]
25 |
26 | if message_1.reply_to_message:
27 | messages.append(message_1.reply_to_message)
28 |
29 | text = ""
30 | offset = None
31 | length = None
32 |
33 | for message in messages:
34 | if offset:
35 | break
36 |
37 | if message.entities:
38 | for entity in message.entities:
39 | if entity.type == "url":
40 | text = message.text or message.caption
41 | offset, length = entity.offset, entity.length
42 | break
43 |
44 | if offset in (None,):
45 | return None
46 |
47 | return text[offset : offset + length]
48 |
49 |
50 | def get_file_name(audio: Union[Audio, Voice]):
51 | return f'{audio.file_unique_id}.{audio.file_name.split(".")[-1] if not isinstance(audio, Voice) else "ogg"}'
52 |
--------------------------------------------------------------------------------
/GeezProject/modules/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/GeezProject/modules/admins.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 VckyouuBitch
3 | # Recode By VICKY From Geez-MusicProject
4 |
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU Affero General Public License as
7 | # published by the Free Software Foundation, either version 3 of the
8 | # License, or (at your option) any later version.
9 |
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU Affero General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Affero General Public License
16 | # along with this program. If not, see .
17 |
18 |
19 | from asyncio import QueueEmpty
20 | from GeezProject.config import que
21 | from pyrogram import Client, filters
22 | from pyrogram.types import Message
23 |
24 | from GeezProject.function.admins import set
25 | from GeezProject.helpers.channelmusic import get_chat_id
26 | from GeezProject.helpers.decorators import authorized_users_only, errors
27 | from GeezProject.helpers.filters import command, other_filters
28 | from GeezProject.services.callsmusic import callsmusic
29 | from GeezProject.services.queues import queues
30 |
31 |
32 | @Client.on_message(filters.command("adminreset"))
33 | async def update_admin(client, message: Message):
34 | chat_id = get_chat_id(message.chat)
35 | set(
36 | chat_id,
37 | [
38 | member.user
39 | for member in await message.chat.get_members(filter="administrators")
40 | ],
41 | )
42 | await message.reply_text("❇️ Admin cache refreshed!")
43 |
44 |
45 | @Client.on_message(command("pause") & other_filters)
46 | @errors
47 | @authorized_users_only
48 | async def pause(_, message: Message):
49 | chat_id = get_chat_id(message.chat)
50 | if (chat_id not in callsmusic.pytgcalls.active_calls) or (
51 | callsmusic.pytgcalls.active_calls[chat_id] == "paused"
52 | ):
53 | await message.reply_text("❗ Nothing is playing!")
54 | else:
55 | callsmusic.pytgcalls.pause_stream(chat_id)
56 | await message.reply_text("▶️ Paused!")
57 |
58 |
59 | @Client.on_message(command("resume") & other_filters)
60 | @errors
61 | @authorized_users_only
62 | async def resume(_, message: Message):
63 | chat_id = get_chat_id(message.chat)
64 | if (chat_id not in callsmusic.pytgcalls.active_calls) or (
65 | callsmusic.pytgcalls.active_calls[chat_id] == "playing"
66 | ):
67 | await message.reply_text("❗ Nothing is paused!")
68 | else:
69 | callsmusic.pytgcalls.resume_stream(chat_id)
70 | await message.reply_text("⏸ Resumed!")
71 |
72 |
73 | @Client.on_message(command("end") & other_filters)
74 | @errors
75 | @authorized_users_only
76 | async def stop(_, message: Message):
77 | chat_id = get_chat_id(message.chat)
78 | if chat_id not in callsmusic.pytgcalls.active_calls:
79 | await message.reply_text("❗ Nothing is streaming!")
80 | else:
81 | try:
82 | callsmusic.queues.clear(chat_id)
83 | except QueueEmpty:
84 | pass
85 |
86 | callsmusic.pytgcalls.leave_group_call(chat_id)
87 | await message.reply_text("❌ Stopped streaming!")
88 |
89 |
90 | @Client.on_message(command("skip") & other_filters)
91 | @errors
92 | @authorized_users_only
93 | async def skip(_, message: Message):
94 | global que
95 | chat_id = get_chat_id(message.chat)
96 | if chat_id not in callsmusic.pytgcalls.active_calls:
97 | await message.reply_text("❗ Nothing is playing to skip!")
98 | else:
99 | callsmusic.queues.task_done(chat_id)
100 |
101 | if callsmusic.queues.is_empty(chat_id):
102 | callsmusic.pytgcalls.leave_group_call(chat_id)
103 | else:
104 | callsmusic.pytgcalls.change_stream(
105 | chat_id, callsmusic.queues.get(chat_id)["file"]
106 | )
107 |
108 | qeue = que.get(chat_id)
109 | if qeue:
110 | skip = qeue.pop(0)
111 | if not qeue:
112 | return
113 | await message.reply_text(f"- Skipped **{skip[0]}**\n- Now Playing **{qeue[0][0]}**")
114 |
115 |
116 | @Client.on_message(filters.command("admincache"))
117 | @errors
118 | async def admincache(client, message: Message):
119 | set(
120 | message.chat.id,
121 | [
122 | member.user
123 | for member in await message.chat.get_members(filter="administrators")
124 | ],
125 | )
126 | await message.reply_text("✅️ **Daftar admin** telah **diperbarui**")
127 |
--------------------------------------------------------------------------------
/GeezProject/modules/channeladmin.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from asyncio import QueueEmpty
19 | from GeezProject.config import que
20 | from pyrogram import Client, filters
21 | from pyrogram.types import Message
22 |
23 | from GeezProject.function.admins import set
24 | from GeezProject.helpers.channelmusic import get_chat_id
25 | from GeezProject.helpers.decorators import authorized_users_only, errors
26 | from GeezProject.helpers.filters import command, other_filters
27 | from GeezProject.services.callsmusic import callsmusic
28 | from GeezProject.services.queues import queues
29 |
30 |
31 | @Client.on_message(filters.command(["channelpause","cpause"]) & filters.group & ~filters.edited)
32 | @errors
33 | @authorized_users_only
34 | async def pause(_, message: Message):
35 | try:
36 | conchat = await _.get_chat(message.chat.id)
37 | conid = conchat.linked_chat.id
38 | chid = conid
39 | except:
40 | await message.reply("Is chat even linked")
41 | return
42 | chat_id = chid
43 | if (chat_id not in callsmusic.pytgcalls.active_calls) or (
44 | callsmusic.pytgcalls.active_calls[chat_id] == "paused"
45 | ):
46 | await message.reply_text("❗ Nothing is playing!")
47 | else:
48 | callsmusic.pytgcalls.pause_stream(chat_id)
49 | await message.reply_text("▶️ Paused!")
50 |
51 |
52 | @Client.on_message(filters.command(["channelresume","cresume"]) & filters.group & ~filters.edited)
53 | @errors
54 | @authorized_users_only
55 | async def resume(_, message: Message):
56 | try:
57 | conchat = await _.get_chat(message.chat.id)
58 | conid = conchat.linked_chat.id
59 | chid = conid
60 | except:
61 | await message.reply("Is chat even linked")
62 | return
63 | chat_id = chid
64 | if (chat_id not in callsmusic.pytgcalls.active_calls) or (
65 | callsmusic.pytgcalls.active_calls[chat_id] == "playing"
66 | ):
67 | await message.reply_text("❗ Nothing is paused!")
68 | else:
69 | callsmusic.pytgcalls.resume_stream(chat_id)
70 | await message.reply_text("⏸ Resumed!")
71 |
72 |
73 | @Client.on_message(filters.command(["channelend","cend"]) & filters.group & ~filters.edited)
74 | @errors
75 | @authorized_users_only
76 | async def stop(_, message: Message):
77 | try:
78 | conchat = await _.get_chat(message.chat.id)
79 | conid = conchat.linked_chat.id
80 | chid = conid
81 | except:
82 | await message.reply("Is chat even linked")
83 | return
84 | chat_id = chid
85 | if chat_id not in callsmusic.pytgcalls.active_calls:
86 | await message.reply_text("❗ Nothing is streaming!")
87 | else:
88 | try:
89 | callsmusic.queues.clear(chat_id)
90 | except QueueEmpty:
91 | pass
92 |
93 | callsmusic.pytgcalls.leave_group_call(chat_id)
94 | await message.reply_text("❌ Stopped streaming!")
95 |
96 |
97 | @Client.on_message(filters.command(["channelskip","cskip"]) & filters.group & ~filters.edited)
98 | @errors
99 | @authorized_users_only
100 | async def skip(_, message: Message):
101 | global que
102 | try:
103 | conchat = await _.get_chat(message.chat.id)
104 | conid = conchat.linked_chat.id
105 | chid = conid
106 | except:
107 | await message.reply("Is chat even linked")
108 | return
109 | chat_id = chid
110 | if chat_id not in callsmusic.pytgcalls.active_calls:
111 | await message.reply_text("❗ Nothing is playing to skip!")
112 | else:
113 | callsmusic.queues.task_done(chat_id)
114 |
115 | if callsmusic.queues.is_empty(chat_id):
116 | callsmusic.pytgcalls.leave_group_call(chat_id)
117 | else:
118 | callsmusic.pytgcalls.change_stream(
119 | chat_id, callsmusic.queues.get(chat_id)["file"]
120 | )
121 |
122 | qeue = que.get(chat_id)
123 | if qeue:
124 | skip = qeue.pop(0)
125 | if not qeue:
126 | return
127 | await message.reply_text(f"- Skipped **{skip[0]}**\n- Now Playing **{qeue[0][0]}**")
128 |
129 |
130 | @Client.on_message(filters.command("channeladmincache"))
131 | @errors
132 | async def admincache(client, message: Message):
133 | try:
134 | conchat = await client.get_chat(message.chat.id)
135 | conid = conchat.linked_chat.id
136 | chid = conid
137 | except:
138 | await message.reply("Is chat even linked")
139 | return
140 | set(
141 | chid,
142 | [
143 | member.user
144 | for member in await conchat.linked_chat.get_members(filter="administrators")
145 | ],
146 | )
147 | await message.reply_text("❇️ Admin cache refreshed!")
148 |
--------------------------------------------------------------------------------
/GeezProject/modules/channelplay.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project)
2 | # Copyright (C) 2021 Inukaasith
3 | # Copyright (C) 2021 TheHamkerCat (Python_ARQ)
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | import json
19 | import os
20 | from os import path
21 | from typing import Callable
22 |
23 | import aiofiles
24 | import aiohttp
25 | import ffmpeg
26 | import requests
27 | import wget
28 | from PIL import Image, ImageDraw, ImageFont
29 | from pyrogram import Client, filters
30 | from pyrogram.errors import UserAlreadyParticipant
31 | from pyrogram.types import Voice
32 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
33 | from Python_ARQ import ARQ
34 | from youtube_search import YoutubeSearch
35 | from GeezProject.modules.play import generate_cover
36 | from GeezProject.modules.play import arq
37 | from GeezProject.modules.play import cb_admin_check
38 | from GeezProject.modules.play import transcode
39 | from GeezProject.modules.play import convert_seconds
40 | from GeezProject.modules.play import time_to_seconds
41 | from GeezProject.modules.play import changeImageSize
42 | from GeezProject.config import BOT_NAME as bn
43 | from GeezProject.config import DURATION_LIMIT
44 | from GeezProject.config import UPDATES_CHANNEL as updateschannel
45 | from GeezProject.config import que
46 | from GeezProject.function.admins import admins as a
47 | from GeezProject.helpers.errors import DurationLimitError
48 | from GeezProject.helpers.decorators import errors
49 | from GeezProject.helpers.admins import get_administrators
50 | from GeezProject.helpers.channelmusic import get_chat_id
51 | from GeezProject.helpers.decorators import authorized_users_only
52 | from GeezProject.helpers.filters import command, other_filters
53 | from GeezProject.helpers.gets import get_file_name
54 | from GeezProject.services.callsmusic import callsmusic
55 | from GeezProject.services.callsmusic.callsmusic import client as USER
56 | from GeezProject.services.converter.converter import convert
57 | from GeezProject.services.downloaders import youtube
58 | from GeezProject.services.queues import queues
59 |
60 | chat_id = None
61 |
62 |
63 |
64 | @Client.on_message(filters.command(["channelplaylist","cplaylist"]) & filters.group & ~filters.edited)
65 | async def playlist(client, message):
66 | try:
67 | lel = await client.get_chat(message.chat.id)
68 | lol = lel.linked_chat.id
69 | except:
70 | message.reply("Is this cat even linked?")
71 | return
72 | global que
73 | queue = que.get(lol)
74 | if not queue:
75 | await message.reply_text("Player is idle")
76 | temp = []
77 | for t in queue:
78 | temp.append(t)
79 | now_playing = temp[0][0]
80 | by = temp[0][1].mention(style="md")
81 | msg = "**Now Playing** in {}".format(lel.linked_chat.title)
82 | msg += "\n- " + now_playing
83 | msg += "\n- Req by " + by
84 | temp.pop(0)
85 | if temp:
86 | msg += "\n\n"
87 | msg += "**Queue**"
88 | for song in temp:
89 | name = song[0]
90 | usr = song[1].mention(style="md")
91 | msg += f"\n- {name}"
92 | msg += f"\n- Req by {usr}\n"
93 | await message.reply_text(msg)
94 |
95 |
96 | # ============================= Settings =========================================
97 |
98 |
99 | def updated_stats(chat, queue, vol=100):
100 | if chat.id in callsmusic.pytgcalls.active_calls:
101 | # if chat.id in active_chats:
102 | stats = "Settings of **{}**".format(chat.title)
103 | if len(que) > 0:
104 | stats += "\n\n"
105 | stats += "Volume : {}%\n".format(vol)
106 | stats += "Songs in queue : `{}`\n".format(len(que))
107 | stats += "Now Playing : **{}**\n".format(queue[0][0])
108 | stats += "Requested by : {}".format(queue[0][1].mention)
109 | else:
110 | stats = None
111 | return stats
112 |
113 |
114 | def r_ply(type_):
115 | if type_ == "play":
116 | pass
117 | else:
118 | pass
119 | mar = InlineKeyboardMarkup(
120 | [
121 | [
122 | InlineKeyboardButton("⏹", "cleave"),
123 | InlineKeyboardButton("⏸", "cpuse"),
124 | InlineKeyboardButton("▶️", "cresume"),
125 | InlineKeyboardButton("⏭", "cskip"),
126 | ],
127 | [
128 | InlineKeyboardButton("Playlist 📖", "cplaylist"),
129 | ],
130 | [InlineKeyboardButton("❌ Close", "ccls")],
131 | ]
132 | )
133 | return mar
134 |
135 |
136 | @Client.on_message(filters.command(["channelcurrent","ccurrent"]) & filters.group & ~filters.edited)
137 | async def ee(client, message):
138 | try:
139 | lel = await client.get_chat(message.chat.id)
140 | lol = lel.linked_chat.id
141 | conv = lel.linked_chat
142 | except:
143 | await message.reply("Is chat even linked")
144 | return
145 | queue = que.get(lol)
146 | stats = updated_stats(conv, queue)
147 | if stats:
148 | await message.reply(stats)
149 | else:
150 | await message.reply("No VC instances running in this chat")
151 |
152 |
153 | @Client.on_message(filters.command(["channelplayer","cplayer"]) & filters.group & ~filters.edited)
154 | @authorized_users_only
155 | async def settings(client, message):
156 | playing = None
157 | try:
158 | lel = await client.get_chat(message.chat.id)
159 | lol = lel.linked_chat.id
160 | conv = lel.linked_chat
161 | except:
162 | await message.reply("Is chat even linked")
163 | return
164 | queue = que.get(lol)
165 | stats = updated_stats(conv, queue)
166 | if stats:
167 | if playing:
168 | await message.reply(stats, reply_markup=r_ply("pause"))
169 |
170 | else:
171 | await message.reply(stats, reply_markup=r_ply("play"))
172 | else:
173 | await message.reply("No VC instances running in this chat")
174 |
175 |
176 | @Client.on_callback_query(filters.regex(pattern=r"^(cplaylist)$"))
177 | async def p_cb(b, cb):
178 | global que
179 | try:
180 | lel = await client.get_chat(cb.message.chat.id)
181 | lol = lel.linked_chat.id
182 | conv = lel.linked_chat
183 | except:
184 | return
185 | que.get(lol)
186 | type_ = cb.matches[0].group(1)
187 | cb.message.chat.id
188 | cb.message.chat
189 | cb.message.reply_markup.inline_keyboard[1][0].callback_data
190 | if type_ == "playlist":
191 | queue = que.get(lol)
192 | if not queue:
193 | await cb.message.edit("Player is idle")
194 | temp = []
195 | for t in queue:
196 | temp.append(t)
197 | now_playing = temp[0][0]
198 | by = temp[0][1].mention(style="md")
199 | msg = "**Now Playing** in {}".format(conv.title)
200 | msg += "\n- " + now_playing
201 | msg += "\n- Req by " + by
202 | temp.pop(0)
203 | if temp:
204 | msg += "\n\n"
205 | msg += "**Queue**"
206 | for song in temp:
207 | name = song[0]
208 | usr = song[1].mention(style="md")
209 | msg += f"\n- {name}"
210 | msg += f"\n- Req by {usr}\n"
211 | await cb.message.edit(msg)
212 |
213 |
214 | @Client.on_callback_query(
215 | filters.regex(pattern=r"^(cplay|cpause|cskip|cleave|cpuse|cresume|cmenu|ccls)$")
216 | )
217 | @cb_admin_check
218 | async def m_cb(b, cb):
219 | global que
220 | if (
221 | cb.message.chat.title.startswith("Channel Music: ")
222 | and chat.title[14:].isnumeric()
223 | ):
224 | chet_id = int(chat.title[13:])
225 | else:
226 | try:
227 | lel = await b.get_chat(cb.message.chat.id)
228 | lol = lel.linked_chat.id
229 | conv = lel.linked_chat
230 | chet_id = lol
231 | except:
232 | return
233 | qeue = que.get(chet_id)
234 | type_ = cb.matches[0].group(1)
235 | cb.message.chat.id
236 | m_chat = cb.message.chat
237 |
238 |
239 | the_data = cb.message.reply_markup.inline_keyboard[1][0].callback_data
240 | if type_ == "cpause":
241 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
242 | callsmusic.pytgcalls.active_calls[chet_id] == "paused"
243 | ):
244 | await cb.answer("Chat is not connected!", show_alert=True)
245 | else:
246 | callsmusic.pytgcalls.pause_stream(chet_id)
247 |
248 | await cb.answer("Music Paused!")
249 | await cb.message.edit(
250 | updated_stats(conv, qeue), reply_markup=r_ply("play")
251 | )
252 |
253 | elif type_ == "cplay":
254 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
255 | callsmusic.pytgcalls.active_calls[chet_id] == "playing"
256 | ):
257 | await cb.answer("Chat is not connected!", show_alert=True)
258 | else:
259 | callsmusic.pytgcalls.resume_stream(chet_id)
260 | await cb.answer("Music Resumed!")
261 | await cb.message.edit(
262 | updated_stats(conv, qeue), reply_markup=r_ply("pause")
263 | )
264 |
265 | elif type_ == "cplaylist":
266 | queue = que.get(cb.message.chat.id)
267 | if not queue:
268 | await cb.message.edit("Player is idle")
269 | temp = []
270 | for t in queue:
271 | temp.append(t)
272 | now_playing = temp[0][0]
273 | by = temp[0][1].mention(style="md")
274 | msg = "**Now Playing** in {}".format(cb.message.chat.title)
275 | msg += "\n- " + now_playing
276 | msg += "\n- Req by " + by
277 | temp.pop(0)
278 | if temp:
279 | msg += "\n\n"
280 | msg += "**Queue**"
281 | for song in temp:
282 | name = song[0]
283 | usr = song[1].mention(style="md")
284 | msg += f"\n- {name}"
285 | msg += f"\n- Req by {usr}\n"
286 | await cb.message.edit(msg)
287 |
288 | elif type_ == "cresume":
289 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
290 | callsmusic.pytgcalls.active_calls[chet_id] == "playing"
291 | ):
292 | await cb.answer("Chat is not connected or already playng", show_alert=True)
293 | else:
294 | callsmusic.pytgcalls.resume_stream(chet_id)
295 | await cb.answer("Music Resumed!")
296 | elif type_ == "cpuse":
297 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
298 | callsmusic.pytgcalls.active_calls[chet_id] == "paused"
299 | ):
300 | await cb.answer("Chat is not connected or already paused", show_alert=True)
301 | else:
302 | callsmusic.pytgcalls.pause_stream(chet_id)
303 |
304 | await cb.answer("Music Paused!")
305 | elif type_ == "ccls":
306 | await cb.answer("Closed menu")
307 | await cb.message.delete()
308 |
309 | elif type_ == "cmenu":
310 | stats = updated_stats(conv, qeue)
311 | await cb.answer("Menu opened")
312 | marr = InlineKeyboardMarkup(
313 | [
314 | [
315 | InlineKeyboardButton("⏹", "cleave"),
316 | InlineKeyboardButton("⏸", "cpuse"),
317 | InlineKeyboardButton("▶️", "cresume"),
318 | InlineKeyboardButton("⏭", "cskip"),
319 | ],
320 | [
321 | InlineKeyboardButton("Playlist 📖", "cplaylist"),
322 | ],
323 | [InlineKeyboardButton("❌ Close", "ccls")],
324 | ]
325 | )
326 | await cb.message.edit(stats, reply_markup=marr)
327 | elif type_ == "cskip":
328 | if qeue:
329 | qeue.pop(0)
330 | if chet_id not in callsmusic.pytgcalls.active_calls:
331 | await cb.answer("Chat is not connected!", show_alert=True)
332 | else:
333 | callsmusic.queues.task_done(chet_id)
334 |
335 | if callsmusic.queues.is_empty(chet_id):
336 | callsmusic.pytgcalls.leave_group_call(chet_id)
337 |
338 | await cb.message.edit("- No More Playlist..\n- Leaving VC!")
339 | else:
340 | callsmusic.pytgcalls.change_stream(
341 | chet_id, callsmusic.queues.get(chet_id)["file"]
342 | )
343 | await cb.answer("Skipped")
344 | await cb.message.edit((m_chat, qeue), reply_markup=r_ply(the_data))
345 | await cb.message.reply_text(
346 | f"- Skipped track\n- Now Playing **{qeue[0][0]}**"
347 | )
348 |
349 | else:
350 | if chet_id in callsmusic.pytgcalls.active_calls:
351 | try:
352 | callsmusic.queues.clear(chet_id)
353 | except QueueEmpty:
354 | pass
355 |
356 | callsmusic.pytgcalls.leave_group_call(chet_id)
357 | await cb.message.edit("Successfully Left the Chat!")
358 | else:
359 | await cb.answer("Chat is not connected!", show_alert=True)
360 |
361 |
362 | @Client.on_message(filters.command(["channelplay","cplay"]) & filters.group & ~filters.edited)
363 | @authorized_users_only
364 | async def play(_, message: Message):
365 | global que
366 | lel = await message.reply("🔄 **Processing**")
367 |
368 | try:
369 | conchat = await _.get_chat(message.chat.id)
370 | conv = conchat.linked_chat
371 | conid = conchat.linked_chat.id
372 | chid = conid
373 | except:
374 | await message.reply("Is chat even linked")
375 | return
376 | try:
377 | administrators = await get_administrators(conv)
378 | except:
379 | await message.reply("Am I admin of Channel")
380 | try:
381 | user = await USER.get_me()
382 | except:
383 | user.first_name = "helper"
384 | usar = user
385 | wew = usar.id
386 | try:
387 | # chatdetails = await USER.get_chat(chid)
388 | await _.get_chat_member(chid, wew)
389 | except:
390 | for administrator in administrators:
391 | if administrator == message.from_user.id:
392 | if message.chat.title.startswith("Channel Music: "):
393 | await lel.edit(
394 | "Remember to add helper to your channel",
395 | )
396 | pass
397 |
398 | try:
399 | invitelink = await _.export_chat_invite_link(chid)
400 | except:
401 | await lel.edit(
402 | "Add me as admin of yor channel first",
403 | )
404 | return
405 |
406 | try:
407 | await USER.join_chat(invitelink)
408 | await lel.edit(
409 | "helper userbot joined your channel",
410 | )
411 |
412 | except UserAlreadyParticipant:
413 | pass
414 | except Exception:
415 | # print(e)
416 | await lel.edit(
417 | f"🔴 Flood Wait Error 🔴 \nUser {user.first_name} couldn't join your channel due to heavy requests for userbot! Make sure user is not banned in group."
418 | "\n\nOr manually add assistant to your Group and try again",
419 | )
420 | try:
421 | await USER.get_chat(chid)
422 | # lmoa = await client.get_chat_member(chid,wew)
423 | except:
424 | await lel.edit(
425 | f" {user.first_name} Userbot not in this chat, Ask channel admin to send /play command for first time or add {user.first_name} manually"
426 | )
427 | return
428 | message.from_user.id
429 | text_links = None
430 | message.from_user.first_name
431 | await lel.edit("🔎 **Finding**")
432 | message.from_user.id
433 | user_id = message.from_user.id
434 | message.from_user.first_name
435 | user_name = message.from_user.first_name
436 | rpk = "[" + user_name + "](tg://user?id=" + str(user_id) + ")"
437 | if message.reply_to_message:
438 | entities = []
439 | toxt = message.reply_to_message.text or message.reply_to_message.caption
440 | if message.reply_to_message.entities:
441 | entities = message.reply_to_message.entities + entities
442 | elif message.reply_to_message.caption_entities:
443 | entities = message.reply_to_message.entities + entities
444 | urls = [entity for entity in entities if entity.type == 'url']
445 | text_links = [
446 | entity for entity in entities if entity.type == 'text_link'
447 | ]
448 | else:
449 | urls=None
450 | if text_links:
451 | urls = True
452 | audio = (
453 | (message.reply_to_message.audio or message.reply_to_message.voice)
454 | if message.reply_to_message
455 | else None
456 | )
457 | if audio:
458 | if round(audio.duration / 60) > DURATION_LIMIT:
459 | raise DurationLimitError(
460 | f"❌ Videos longer than {DURATION_LIMIT} minute(s) aren't allowed to play!"
461 | )
462 | keyboard = InlineKeyboardMarkup(
463 | [
464 | [
465 | InlineKeyboardButton("📖 Playlist", callback_data="cplaylist"),
466 | InlineKeyboardButton("Menu ⏯ ", callback_data="cmenu"),
467 | ],
468 | [InlineKeyboardButton(text="❌ Close", callback_data="ccls")],
469 | ]
470 | )
471 | file_name = get_file_name(audio)
472 | title = file_name
473 | thumb_name = "https://telegra.ph/file/f6086f8909fbfeb0844f2.png"
474 | thumbnail = thumb_name
475 | duration = round(audio.duration / 60)
476 | views = "Locally added"
477 | requested_by = message.from_user.first_name
478 | await generate_cover(requested_by, title, views, duration, thumbnail)
479 | file_path = await convert(
480 | (await message.reply_to_message.download(file_name))
481 | if not path.isfile(path.join("downloads", file_name))
482 | else file_name
483 | )
484 | elif urls:
485 | query = toxt
486 | await lel.edit("🎵 **Processing**")
487 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
488 | try:
489 | results = YoutubeSearch(query, max_results=1).to_dict()
490 | url = f"https://youtube.com{results[0]['url_suffix']}"
491 | # print(results)
492 | title = results[0]["title"][:40]
493 | thumbnail = results[0]["thumbnails"][0]
494 | thumb_name = f"thumb{title}.jpg"
495 | thumb = requests.get(thumbnail, allow_redirects=True)
496 | open(thumb_name, "wb").write(thumb.content)
497 | duration = results[0]["duration"]
498 | results[0]["url_suffix"]
499 | views = results[0]["views"]
500 |
501 | except Exception as e:
502 | await lel.edit(
503 | "Song not found.Try another song or maybe spell it properly."
504 | )
505 | print(str(e))
506 | return
507 | dlurl = url
508 | dlurl=dlurl.replace("youtube","youtubepp")
509 | keyboard = InlineKeyboardMarkup(
510 | [
511 | [
512 | InlineKeyboardButton("📖 Playlist", callback_data="cplaylist"),
513 | InlineKeyboardButton("Menu ⏯ ", callback_data="cmenu"),
514 | ],
515 | [
516 | InlineKeyboardButton(text="🎬 YouTube", url=f"{url}"),
517 | InlineKeyboardButton(text="Download 📥", url=f"{dlurl}"),
518 | ],
519 | [InlineKeyboardButton(text="❌ Close", callback_data="ccls")],
520 | ]
521 | )
522 | requested_by = message.from_user.first_name
523 | await generate_cover(requested_by, title, views, duration, thumbnail)
524 | file_path = await convert(youtube.download(url))
525 | else:
526 | query = ""
527 | for i in message.command[1:]:
528 | query += " " + str(i)
529 | print(query)
530 | await lel.edit("🎵 **Processing**")
531 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
532 | try:
533 | results = YoutubeSearch(query, max_results=1).to_dict()
534 | url = f"https://youtube.com{results[0]['url_suffix']}"
535 | # print(results)
536 | title = results[0]["title"][:40]
537 | thumbnail = results[0]["thumbnails"][0]
538 | thumb_name = f"thumb{title}.jpg"
539 | thumb = requests.get(thumbnail, allow_redirects=True)
540 | open(thumb_name, "wb").write(thumb.content)
541 | duration = results[0]["duration"]
542 | results[0]["url_suffix"]
543 | views = results[0]["views"]
544 |
545 | except Exception as e:
546 | await lel.edit(
547 | "Song not found.Try another song or maybe spell it properly."
548 | )
549 | print(str(e))
550 | return
551 |
552 | dlurl = url
553 | dlurl=dlurl.replace("youtube","youtubepp")
554 | keyboard = InlineKeyboardMarkup(
555 | [
556 | [
557 | InlineKeyboardButton("📖 Playlist", callback_data="cplaylist"),
558 | InlineKeyboardButton("Menu ⏯ ", callback_data="cmenu"),
559 | ],
560 | [
561 | InlineKeyboardButton(text="🎬 YouTube", url=f"{url}"),
562 | InlineKeyboardButton(text="Download 📥", url=f"{dlurl}"),
563 | ],
564 | [InlineKeyboardButton(text="❌ Close", callback_data="ccls")],
565 | ]
566 | )
567 | requested_by = message.from_user.first_name
568 | await generate_cover(requested_by, title, views, duration, thumbnail)
569 | file_path = await convert(youtube.download(url))
570 | chat_id = chid
571 | if chat_id in callsmusic.pytgcalls.active_calls:
572 | position = await queues.put(chat_id, file=file_path)
573 | qeue = que.get(chat_id)
574 | s_name = title
575 | r_by = message.from_user
576 | loc = file_path
577 | appendable = [s_name, r_by, loc]
578 | qeue.append(appendable)
579 | await message.reply_photo(
580 | photo="final.png",
581 | caption=f"#⃣ Your requested song **queued** at position {position}!",
582 | reply_markup=keyboard,
583 | )
584 | os.remove("final.png")
585 | return await lel.delete()
586 | else:
587 | chat_id = chid
588 | que[chat_id] = []
589 | qeue = que.get(chat_id)
590 | s_name = title
591 | r_by = message.from_user
592 | loc = file_path
593 | appendable = [s_name, r_by, loc]
594 | qeue.append(appendable)
595 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
596 | await message.reply_photo(
597 | photo="final.png",
598 | reply_markup=keyboard,
599 | caption="▶️ **Playing** the song requested by {} via Youtube Music 😜 in Linked Channel".format(
600 | message.from_user.mention()
601 | ),
602 | )
603 | os.remove("final.png")
604 | return await lel.delete()
605 |
606 |
607 | @Client.on_message(filters.command(["channeldplay","cdplay"]) & filters.group & ~filters.edited)
608 | @authorized_users_only
609 | async def deezer(client: Client, message_: Message):
610 | global que
611 | lel = await message_.reply("🔄 **Processing**")
612 |
613 | try:
614 | conchat = await client.get_chat(message_.chat.id)
615 | conid = conchat.linked_chat.id
616 | conv = conchat.linked_chat
617 | chid = conid
618 | except:
619 | await message_.reply("Is chat even linked")
620 | return
621 | try:
622 | administrators = await get_administrators(conv)
623 | except:
624 | await message.reply("Am I admin of Channel")
625 | try:
626 | user = await USER.get_me()
627 | except:
628 | user.first_name = "DaisyMusic"
629 | usar = user
630 | wew = usar.id
631 | try:
632 | # chatdetails = await USER.get_chat(chid)
633 | await client.get_chat_member(chid, wew)
634 | except:
635 | for administrator in administrators:
636 | if administrator == message_.from_user.id:
637 | if message_.chat.title.startswith("Channel Music: "):
638 | await lel.edit(
639 | "Remember to add helper to your channel",
640 | )
641 | pass
642 | try:
643 | invitelink = await client.export_chat_invite_link(chid)
644 | except:
645 | await lel.edit(
646 | "Add me as admin of yor channel first",
647 | )
648 | return
649 |
650 | try:
651 | await USER.join_chat(invitelink)
652 | await lel.edit(
653 | "helper userbot joined your channel",
654 | )
655 |
656 | except UserAlreadyParticipant:
657 | pass
658 | except Exception:
659 | # print(e)
660 | await lel.edit(
661 | f"🔴 Flood Wait Error 🔴 \nUser {user.first_name} couldn't join your channel due to heavy requests for userbot! Make sure user is not banned in channel."
662 | "\n\nOr manually add assistant to your Group and try again",
663 | )
664 | try:
665 | await USER.get_chat(chid)
666 | # lmoa = await client.get_chat_member(chid,wew)
667 | except:
668 | await lel.edit(
669 | f" {user.first_name} Userbot not in this channel, Ask admin to send /play command for first time or add {user.first_name} manually"
670 | )
671 | return
672 | requested_by = message_.from_user.first_name
673 |
674 | text = message_.text.split(" ", 1)
675 | queryy = text[1]
676 | query=queryy
677 | res = lel
678 | await res.edit(f"Searching 👀👀👀 for `{queryy}` on deezer")
679 | try:
680 | songs = await arq.deezer(query,1)
681 | if not songs.ok:
682 | await message_.reply_text(songs.result)
683 | return
684 | title = songs.result[0].title
685 | url = songs.result[0].url
686 | artist = songs.result[0].artist
687 | duration = songs.result[0].duration
688 | thumbnail = songs.result[0].thumbnail
689 | except:
690 | await res.edit("Found Literally Nothing, You Should Work On Your English!")
691 | return
692 | keyboard = InlineKeyboardMarkup(
693 | [
694 | [
695 | InlineKeyboardButton("📖 Playlist", callback_data="cplaylist"),
696 | InlineKeyboardButton("Menu ⏯ ", callback_data="cmenu"),
697 | ],
698 | [InlineKeyboardButton(text="Listen On Deezer 🎬", url=f"{url}")],
699 | [InlineKeyboardButton(text="❌ Close", callback_data="ccls")],
700 | ]
701 | )
702 | file_path = await convert(wget.download(url))
703 | await res.edit("Generating Thumbnail")
704 | await generate_cover(requested_by, title, artist, duration, thumbnail)
705 | chat_id = chid
706 | if chat_id in callsmusic.pytgcalls.active_calls:
707 | await res.edit("adding in queue")
708 | position = await queues.put(chat_id, file=file_path)
709 | qeue = que.get(chat_id)
710 | s_name = title
711 | r_by = message_.from_user
712 | loc = file_path
713 | appendable = [s_name, r_by, loc]
714 | qeue.append(appendable)
715 | await res.edit_text(f"{bn}= #️⃣ Queued at position {position}")
716 | else:
717 | await res.edit_text(f"{bn}=▶️ Playing.....")
718 |
719 | que[chat_id] = []
720 | qeue = que.get(chat_id)
721 | s_name = title
722 | r_by = message_.from_user
723 | loc = file_path
724 | appendable = [s_name, r_by, loc]
725 | qeue.append(appendable)
726 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
727 |
728 | await res.delete()
729 |
730 | m = await client.send_photo(
731 | chat_id=message_.chat.id,
732 | reply_markup=keyboard,
733 | photo="final.png",
734 | caption=f"Playing [{title}]({url}) Via Deezer in Linked Channel",
735 | )
736 | os.remove("final.png")
737 |
738 |
739 | @Client.on_message(filters.command(["channelsplay","csplay"]) & filters.group & ~filters.edited)
740 | @authorized_users_only
741 | async def jiosaavn(client: Client, message_: Message):
742 | global que
743 | lel = await message_.reply("🔄 **Processing**")
744 | try:
745 | conchat = await client.get_chat(message_.chat.id)
746 | conid = conchat.linked_chat.id
747 | conv = conchat.linked_chat
748 | chid = conid
749 | except:
750 | await message_.reply("Is chat even linked")
751 | return
752 | try:
753 | administrators = await get_administrators(conv)
754 | except:
755 | await message.reply("Am I admin of Channel")
756 | try:
757 | user = await USER.get_me()
758 | except:
759 | user.first_name = "GeezProject"
760 | usar = user
761 | wew = usar.id
762 | try:
763 | # chatdetails = await USER.get_chat(chid)
764 | await client.get_chat_member(chid, wew)
765 | except:
766 | for administrator in administrators:
767 | if administrator == message_.from_user.id:
768 | if message_.chat.title.startswith("Channel Music: "):
769 | await lel.edit(
770 | "Remember to add helper to your channel",
771 | )
772 | pass
773 | try:
774 | invitelink = await client.export_chat_invite_link(chid)
775 | except:
776 | await lel.edit(
777 | "Add me as admin of yor group first",
778 | )
779 | return
780 |
781 | try:
782 | await USER.join_chat(invitelink)
783 | await lel.edit(
784 | "helper userbot joined your channel",
785 | )
786 |
787 | except UserAlreadyParticipant:
788 | pass
789 | except Exception:
790 | # print(e)
791 | await lel.edit(
792 | f"🔴 Flood Wait Error 🔴 \nUser {user.first_name} couldn't join your channel due to heavy requests for userbot! Make sure user is not banned in group."
793 | "\n\nOr manually add @DaisyXmusic to your Group and try again",
794 | )
795 | try:
796 | await USER.get_chat(chid)
797 | # lmoa = await client.get_chat_member(chid,wew)
798 | except:
799 | await lel.edit(
800 | " helper Userbot not in this channel, Ask channel admin to send /play command for first time or add assistant manually"
801 | )
802 | return
803 | requested_by = message_.from_user.first_name
804 | chat_id = message_.chat.id
805 | text = message_.text.split(" ", 1)
806 | query = text[1]
807 | res = lel
808 | await res.edit(f"Searching 👀👀👀 for `{query}` on jio saavn")
809 | try:
810 | songs = await arq.saavn(query)
811 | if not songs.ok:
812 | await message_.reply_text(songs.result)
813 | return
814 | sname = songs.result[0].song
815 | slink = songs.result[0].media_url
816 | ssingers = songs.result[0].singers
817 | sthumb = "https://telegra.ph/file/f6086f8909fbfeb0844f2.png"
818 | sduration = int(songs.result[0].duration)
819 | except Exception as e:
820 | await res.edit("Found Literally Nothing!, You Should Work On Your English.")
821 | print(str(e))
822 | return
823 | keyboard = InlineKeyboardMarkup(
824 | [
825 | [
826 | InlineKeyboardButton("📖 Playlist", callback_data="cplaylist"),
827 | InlineKeyboardButton("Menu ⏯ ", callback_data="cmenu"),
828 | ],
829 | [
830 | InlineKeyboardButton(
831 | text="Join Updates Channel", url=f"https://t.me/{updateschannel}"
832 | )
833 | ],
834 | [InlineKeyboardButton(text="❌ Close", callback_data="ccls")],
835 | ]
836 | )
837 | file_path = await convert(wget.download(slink))
838 | chat_id = chid
839 | if chat_id in callsmusic.pytgcalls.active_calls:
840 | position = await queues.put(chat_id, file=file_path)
841 | qeue = que.get(chat_id)
842 | s_name = sname
843 | r_by = message_.from_user
844 | loc = file_path
845 | appendable = [s_name, r_by, loc]
846 | qeue.append(appendable)
847 | await res.delete()
848 | m = await client.send_photo(
849 | chat_id=message_.chat.id,
850 | reply_markup=keyboard,
851 | photo="final.png",
852 | caption=f"{bn}=#️⃣ Queued at position {position}",
853 | )
854 |
855 | else:
856 | await res.edit_text(f"{bn}=▶️ Playing.....")
857 | que[chat_id] = []
858 | qeue = que.get(chat_id)
859 | s_name = sname
860 | r_by = message_.from_user
861 | loc = file_path
862 | appendable = [s_name, r_by, loc]
863 | qeue.append(appendable)
864 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
865 | await res.edit("Generating Thumbnail.")
866 | await generate_cover(requested_by, sname, ssingers, sduration, sthumb)
867 | await res.delete()
868 | m = await client.send_photo(
869 | chat_id=message_.chat.id,
870 | reply_markup=keyboard,
871 | photo="final.png",
872 | caption=f"Playing {sname} Via Jiosaavn in linked channel",
873 | )
874 | os.remove("final.png")
875 |
876 |
877 | # Have u read all. If read RESPECT :-)
878 |
--------------------------------------------------------------------------------
/GeezProject/modules/chat_member_updated.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client
2 | from pyrogram.types import ChatMemberUpdated
3 |
4 | from GeezProject.function import *
5 |
6 |
7 | @Client.on_chat_member_updated()
8 | async def chat_member_updated(_, chat_member_updated: ChatMemberUpdated):
9 | if chat_member_updated.new_chat_member \
10 | and chat_member_updated.old_chat_member:
11 | (
12 | admins.admins[chat_member_updated.chat.id].append(
13 | chat_member_updated.new_chat_member.user.id,
14 | )
15 | ) if (
16 | (
17 | chat_member_updated.new_chat_member.can_manage_voice_chats
18 | ) and (
19 | (
20 | chat_member_updated.new_chat_member.user.id
21 | ) not in admins.admins[chat_member_updated.chat.id]
22 | )
23 | ) else (
24 | admins.admins[chat_member_updated.chat.id].remove(
25 | chat_member_updated.new_chat_member.user.id,
26 | )
27 | ) if (
28 | (
29 | chat_member_updated.new_chat_member.user.id
30 | ) in admins.admins[chat_member_updated.chat.id]
31 | ) else None
32 |
--------------------------------------------------------------------------------
/GeezProject/modules/gcast.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # recode by levina-lab on github
5 | # originally rewritten by using existing code (fixed)
6 |
7 | import asyncio
8 |
9 | from pyrogram import Client, filters
10 | from pyrogram.types import Dialog, Chat, Message
11 | from pyrogram.errors import UserAlreadyParticipant
12 |
13 | from GeezProject.services.callsmusic.callsmusic import client as geez
14 | from GeezProject.config import SUDO_USERS
15 |
16 | @Client.on_message(filters.command(["gcast"]))
17 | async def broadcast(_, message: Message):
18 | sent=0
19 | failed=0
20 | if message.from_user.id not in SUDO_USERS:
21 | return
22 | else:
23 | wtf = await message.reply("`memulai global cast...`")
24 | if not message.reply_to_message:
25 | await wtf.edit("balas ke pesan untuk melakukan broadcast!")
26 | return
27 | lmao = message.reply_to_message.text
28 | async for dialog in geez.iter_dialogs():
29 | try:
30 | await geez.send_message(dialog.chat.id, lmao)
31 | sent = sent+1
32 | await wtf.edit(f"`global cast...` \n\n**mengirim ke:** `{sent}` obrolan \n**gagal di:** {failed} obrolan")
33 | await asyncio.sleep(3)
34 | except:
35 | failed=failed+1
36 | await message.reply_text(f"`gcast berhasil` \n\n**terkirim ke:** `{sent}` obrolan \n**gagal di:** {failed} obrolan")
37 |
--------------------------------------------------------------------------------
/GeezProject/modules/inline.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client, errors
2 | from pyrogram.types import (
3 | InlineQuery,
4 | InlineQueryResultArticle,
5 | InputTextMessageContent,
6 | )
7 | from youtubesearchpython import VideosSearch
8 |
9 |
10 | @Client.on_inline_query()
11 | async def inline(client: Client, query: InlineQuery):
12 | answers = []
13 | search_query = query.query.lower().strip().rstrip()
14 |
15 | if search_query == "":
16 | await client.answer_inline_query(
17 | query.id,
18 | results=answers,
19 | switch_pm_text="Ketikkan Nama Lagu/video di YouTube...",
20 | switch_pm_parameter="help",
21 | cache_time=0,
22 | )
23 | else:
24 | search = VideosSearch(search_query, limit=50)
25 |
26 | for result in search.result()["result"]:
27 | answers.append(
28 | InlineQueryResultArticle(
29 | title=result["title"],
30 | description="{}, {} views.".format(
31 | result["duration"], result["viewCount"]["short"]
32 | ),
33 | input_message_content=InputTextMessageContent(
34 | "https://www.youtube.com/watch?v={}".format(result["id"])
35 | ),
36 | thumb_url=result["thumbnails"][0]["url"],
37 | )
38 | )
39 |
40 | try:
41 | await query.answer(results=answers, cache_time=0)
42 | except errors.QueryIdInvalid:
43 | await query.answer(
44 | results=answers,
45 | cache_time=0,
46 | switch_pm_text="Error: Search timed out",
47 | switch_pm_parameter="",
48 | )
49 |
--------------------------------------------------------------------------------
/GeezProject/modules/msg.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 | import os
18 | from GeezProject.config import SOURCE_CODE,ASSISTANT_NAME,PROJECT_NAME,SUPPORT_GROUP,UPDATES_CHANNEL, OWNER
19 | class Messages():
20 | HELP_MSG = [
21 | ".",
22 | f"""
23 | **Hey 👋 Selamat datang kembali di {PROJECT_NAME}
24 |
25 | ✣️ {PROJECT_NAME} dapat Memutar Lagu di Voice Chat Group Dengan cara yang Mudah.
26 |
27 | ✣️ Assistant Music » @{ASSISTANT_NAME}\n\nKlik Next untuk instruksi**
28 |
29 | """,
30 |
31 | f"""
32 | **Pengaturan**
33 |
34 | 1. Jadikan bot sebagai admin
35 | 2. Mulai obrolan suara / VCG
36 | 3. Ketik `/userbotjoin` dan coba /play
37 | × Jika Assistant Bot bergabung selamat menikmati musik,
38 | × Jika Assistant Bot tidak bergabung Silahkan Tambahkan @{ASSISTANT_NAME} ke grup Anda dan coba lagi
39 |
40 |
41 | **» Perintah Untuk dalam grup Member Juga Bisa :**
42 |
43 | × /playlist : Untuk Menampilkan daftar putar Lagu sekarang
44 | × /current : Untuk Menunjukkan Lagu sekarang yang sedang diputar
45 | × /song : Untuk Mendownload lagu di YouTube
46 | × /video : Untuk Mendownload Video di YouTube dengan detail
47 | × /vsong : Untuk Mendownload Video di YouTube dengan detail
48 | × /deezer : Untuk Mendownload lagu dari deezer
49 | × /saavn : Untuk Mendownload lagu dari website saavn
50 | × /search : Untuk Mencari Video di YouTube dengan detail
51 |
52 | **» Perintah Hanya Untuk Admin :**
53 |
54 | × /play : Untuk Memutar lagu yang Anda minta melalui youtube
55 | × /play : Untuk Memutar lagu yang Anda minta melalui link youtube
56 | × /play : Untuk Memutar lagu yang Anda minta melalui file audio
57 | × /dplay : Untuk Memutar lagu yang Anda minta melalui deezer
58 | × /splay : Untuk Memutar lagu yang Anda minta melalui jio saavn
59 | × /skip : Untuk Menskip pemutaran lagu ke Lagu berikutnya
60 | × /pause : Untuk Menjeda pemutaran Lagu
61 | × /resume : Untuk Melanjutkan pemutaran Lagu yang di pause
62 | × /end : Untuk Memberhentikan pemutaran Lagu
63 | × /userbotjoin - Untuk Mengundang asisten ke obrolan Anda
64 | × /admincache - Untuk MemRefresh admin list
65 | """
66 | ]
67 |
--------------------------------------------------------------------------------
/GeezProject/modules/play.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project)
2 | # Copyright (C) 2021 Inukaasith
3 | # Copyright (C) 2021 TheHamkerCat (Python_ARQ)
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | import json
19 | import os
20 | from os import path
21 | from typing import Callable
22 |
23 | import aiofiles
24 | import aiohttp
25 | import ffmpeg
26 | import requests
27 | import wget
28 | from PIL import Image, ImageDraw, ImageFont
29 | from pyrogram import Client, filters
30 | from pyrogram.types import Voice
31 | from pyrogram.errors import UserAlreadyParticipant
32 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message
33 | from Python_ARQ import ARQ
34 | from youtube_search import YoutubeSearch
35 |
36 | from GeezProject.config import ARQ_API_KEY
37 | from GeezProject.config import BOT_NAME as bn
38 | from GeezProject.config import DURATION_LIMIT
39 | from GeezProject.config import UPDATES_CHANNEL as updateschannel
40 | from GeezProject.config import que
41 | from GeezProject.config import SOURCE_CODE,ASSISTANT_NAME,PROJECT_NAME,SUPPORT_GROUP,BOT_USERNAME, OWNER
42 | from GeezProject.function.admins import admins as a
43 | from GeezProject.helpers.admins import get_administrators
44 | from GeezProject.helpers.channelmusic import get_chat_id
45 | from GeezProject.helpers.errors import DurationLimitError
46 | from GeezProject.helpers.decorators import errors
47 | from GeezProject.helpers.decorators import authorized_users_only
48 | from GeezProject.helpers.filters import command, other_filters
49 | from GeezProject.helpers.gets import get_file_name
50 | from GeezProject.services.callsmusic import callsmusic
51 | from GeezProject.services.callsmusic.callsmusic import client as USER
52 | from GeezProject.services.converter.converter import convert
53 | from GeezProject.services.downloaders import youtube
54 | from GeezProject.services.queues import queues
55 |
56 | aiohttpsession = aiohttp.ClientSession()
57 | chat_id = None
58 | arq = ARQ("https://thearq.tech", ARQ_API_KEY, aiohttpsession)
59 | DISABLED_GROUPS = []
60 | useer ="NaN"
61 | def cb_admin_check(func: Callable) -> Callable:
62 | async def decorator(client, cb):
63 | admemes = a.get(cb.message.chat.id)
64 | if cb.from_user.id in admemes:
65 | return await func(client, cb)
66 | else:
67 | await cb.answer("Kamu tidak diizinkan!", show_alert=True)
68 | return
69 |
70 | return decorator
71 |
72 |
73 | def transcode(filename):
74 | ffmpeg.input(filename).output(
75 | "input.raw", format="s16le", acodec="pcm_s16le", ac=2, ar="48k"
76 | ).overwrite_output().run()
77 | os.remove(filename)
78 |
79 |
80 | # Convert seconds to mm:ss
81 | def convert_seconds(seconds):
82 | seconds = seconds % (24 * 3600)
83 | seconds %= 3600
84 | minutes = seconds // 60
85 | seconds %= 60
86 | return "%02d:%02d" % (minutes, seconds)
87 |
88 |
89 | # Convert hh:mm:ss to seconds
90 | def time_to_seconds(time):
91 | stringt = str(time)
92 | return sum(int(x) * 60 ** i for i, x in enumerate(reversed(stringt.split(":"))))
93 |
94 |
95 | # Change image size
96 | def changeImageSize(maxWidth, maxHeight, image):
97 | widthRatio = maxWidth / image.size[0]
98 | heightRatio = maxHeight / image.size[1]
99 | newWidth = int(widthRatio * image.size[0])
100 | newHeight = int(heightRatio * image.size[1])
101 | newImage = image.resize((newWidth, newHeight))
102 | return newImage
103 |
104 |
105 | async def generate_cover(requested_by, title, views, duration, thumbnail):
106 | async with aiohttp.ClientSession() as session:
107 | async with session.get(thumbnail) as resp:
108 | if resp.status == 200:
109 | f = await aiofiles.open("background.png", mode="wb")
110 | await f.write(await resp.read())
111 | await f.close()
112 |
113 | image1 = Image.open("./background.png")
114 | image2 = Image.open("./etc/foreground.png")
115 | image3 = changeImageSize(1280, 720, image1)
116 | image4 = changeImageSize(1280, 720, image2)
117 | image5 = image3.convert("RGBA")
118 | image6 = image4.convert("RGBA")
119 | Image.alpha_composite(image5, image6).save("temp.png")
120 | img = Image.open("temp.png")
121 | img.save("final.png")
122 | os.remove("temp.png")
123 | os.remove("background.png")
124 |
125 |
126 | @Client.on_message(filters.command("playlist") & filters.group & ~filters.edited)
127 | async def playlist(client, message):
128 | global que
129 | if message.chat.id in DISABLED_GROUPS:
130 | return
131 | queue = que.get(message.chat.id)
132 | if not queue:
133 | await message.reply_text("**Sedang tidak Memutar lagu**")
134 | temp = []
135 | for t in queue:
136 | temp.append(t)
137 | now_playing = temp[0][0]
138 | by = temp[0][1].mention(style="md")
139 | msg = "**Lagu Yang Sedang dimainkan** di {}".format(message.chat.title)
140 | msg += "\n• " + now_playing
141 | msg += "\n• Req by " + by
142 | temp.pop(0)
143 | if temp:
144 | msg += "\n\n"
145 | msg += "**Antrian Lagu**"
146 | for song in temp:
147 | name = song[0]
148 | usr = song[1].mention(style="md")
149 | msg += f"\n• {name}"
150 | msg += f"\n• Req by {usr}\n"
151 | await message.reply_text(msg)
152 |
153 |
154 | # ============================= Settings =========================================
155 |
156 |
157 | def updated_stats(chat, queue, vol=100):
158 | if chat.id in callsmusic.pytgcalls.active_calls:
159 | # if chat.id in active_chats:
160 | stats = "Pengaturan dari **{}**".format(chat.title)
161 | if len(que) > 0:
162 | stats += "\n\n"
163 | stats += "Volume : {}%\n".format(vol)
164 | stats += "Lagu dalam antrian : `{}`\n".format(len(que))
165 | stats += "Sedang memutar lagu : **{}**\n".format(queue[0][0])
166 | stats += "Requested by : {}".format(queue[0][1].mention)
167 | else:
168 | stats = None
169 | return stats
170 |
171 |
172 | def r_ply(type_):
173 | if type_ == "play":
174 | pass
175 | else:
176 | pass
177 | mar = InlineKeyboardMarkup(
178 | [
179 | [
180 | InlineKeyboardButton("⏹", "leave"),
181 | InlineKeyboardButton("⏸", "puse"),
182 | InlineKeyboardButton("▶️", "resume"),
183 | InlineKeyboardButton("⏭", "skip"),
184 | ],
185 | [
186 | InlineKeyboardButton("📖 Playlist", "playlist"),
187 | ],
188 | [InlineKeyboardButton("🗑 Close", "cls")],
189 | ]
190 | )
191 | return mar
192 |
193 |
194 | @Client.on_message(filters.command("current") & filters.group & ~filters.edited)
195 | async def ee(client, message):
196 | if message.chat.id in DISABLED_GROUPS:
197 | return
198 | queue = que.get(message.chat.id)
199 | stats = updated_stats(message.chat, queue)
200 | if stats:
201 | await message.reply(stats)
202 | else:
203 | await message.reply("**Silahkan Nyalakan dulu VCG nya!**")
204 |
205 |
206 | @Client.on_message(filters.command("player") & filters.group & ~filters.edited)
207 | @authorized_users_only
208 | async def settings(client, message):
209 | if message.chat.id in DISABLED_GROUPS:
210 | await message.reply("**Music Player dimatikan**")
211 | return
212 | playing = None
213 | chat_id = get_chat_id(message.chat)
214 | if chat_id in callsmusic.pytgcalls.active_calls:
215 | playing = True
216 | queue = que.get(chat_id)
217 | stats = updated_stats(message.chat, queue)
218 | if stats:
219 | if playing:
220 | await message.reply(stats, reply_markup=r_ply("pause"))
221 |
222 | else:
223 | await message.reply(stats, reply_markup=r_ply("play"))
224 | else:
225 | await message.reply("**Silahkan Nyalakan dulu VCG nya!**")
226 |
227 |
228 | @Client.on_message(
229 | filters.command("musicplayer") & ~filters.edited & ~filters.bot & ~filters.private
230 | )
231 | @authorized_users_only
232 | async def hfmm(_, message):
233 | global DISABLED_GROUPS
234 | try:
235 | user_id = message.from_user.id
236 | except:
237 | return
238 | if len(message.command) != 2:
239 | await message.reply_text(
240 | "**Saya hanya mengenali** `/musicplayer on` **dan** `/musicplayer off`"
241 | )
242 | return
243 | status = message.text.split(None, 1)[1]
244 | message.chat.id
245 | if status == "ON" or status == "on" or status == "On":
246 | lel = await message.reply("`Processing...`")
247 | if not message.chat.id in DISABLED_GROUPS:
248 | await lel.edit("**Pemutar Musik Sudah Diaktifkan Di Obrolan Ini**")
249 | return
250 | DISABLED_GROUPS.remove(message.chat.id)
251 | await lel.edit(
252 | f"**Pemutar Musik Berhasil Diaktifkan Untuk Pengguna Dalam Obrolan** {message.chat.id}"
253 | )
254 |
255 | elif status == "OFF" or status == "off" or status == "Off":
256 | lel = await message.reply("`Processing...`")
257 |
258 | if message.chat.id in DISABLED_GROUPS:
259 | await lel.edit("**Pemutar Musik Sudah dimatikan Dalam Obrolan Ini**")
260 | return
261 | DISABLED_GROUPS.append(message.chat.id)
262 | await lel.edit(
263 | f"**Pemutar Musik Berhasil Dinonaktifkan Untuk Pengguna Dalam Obrolan** {message.chat.id}"
264 | )
265 | else:
266 | await message.reply_text(
267 | "**Saya hanya mengenali** `/musicplayer on` **dan** `/musicplayer off`"
268 | )
269 |
270 |
271 | @Client.on_callback_query(filters.regex(pattern=r"^(playlist)$"))
272 | async def p_cb(b, cb):
273 | global que
274 | que.get(cb.message.chat.id)
275 | type_ = cb.matches[0].group(1)
276 | cb.message.chat.id
277 | cb.message.chat
278 | cb.message.reply_markup.inline_keyboard[1][0].callback_data
279 | if type_ == "playlist":
280 | queue = que.get(cb.message.chat.id)
281 | if not queue:
282 | await cb.message.edit("**Sedang tidak Memutar lagu**")
283 | temp = []
284 | for t in queue:
285 | temp.append(t)
286 | now_playing = temp[0][0]
287 | by = temp[0][1].mention(style="md")
288 | msg = "**Lagu Yang Sedang dimainkan** di {}".format(cb.message.chat.title)
289 | msg += "\n• " + now_playing
290 | msg += "\n• Req by " + by
291 | temp.pop(0)
292 | if temp:
293 | msg += "\n\n"
294 | msg += "**Antrian Lagu**"
295 | for song in temp:
296 | name = song[0]
297 | usr = song[1].mention(style="md")
298 | msg += f"\n• {name}"
299 | msg += f"\n• Req by {usr}\n"
300 | await cb.message.edit(msg)
301 |
302 |
303 | @Client.on_callback_query(
304 | filters.regex(pattern=r"^(play|pause|skip|leave|puse|resume|menu|cls)$")
305 | )
306 | @cb_admin_check
307 | async def m_cb(b, cb):
308 | global que
309 | if (
310 | cb.message.chat.title.startswith("Channel Music: ")
311 | and chat.title[14:].isnumeric()
312 | ):
313 | chet_id = int(chat.title[13:])
314 | else:
315 | chet_id = cb.message.chat.id
316 | qeue = que.get(chet_id)
317 | type_ = cb.matches[0].group(1)
318 | cb.message.chat.id
319 | m_chat = cb.message.chat
320 |
321 | the_data = cb.message.reply_markup.inline_keyboard[1][0].callback_data
322 | if type_ == "pause":
323 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
324 | callsmusic.pytgcalls.active_calls[chet_id] == "paused"
325 | ):
326 | await cb.answer("Chat is not connected!", show_alert=True)
327 | else:
328 | callsmusic.pytgcalls.pause_stream(chet_id)
329 |
330 | await cb.answer("Music Paused!")
331 | await cb.message.edit(
332 | updated_stats(m_chat, qeue), reply_markup=r_ply("play")
333 | )
334 |
335 | elif type_ == "play":
336 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
337 | callsmusic.pytgcalls.active_calls[chet_id] == "playing"
338 | ):
339 | await cb.answer("Chat is not connected!", show_alert=True)
340 | else:
341 | callsmusic.pytgcalls.resume_stream(chet_id)
342 | await cb.answer("Music Resumed!")
343 | await cb.message.edit(
344 | updated_stats(m_chat, qeue), reply_markup=r_ply("pause")
345 | )
346 |
347 | elif type_ == "playlist":
348 | queue = que.get(cb.message.chat.id)
349 | if not queue:
350 | await cb.message.edit("Player is idle")
351 | temp = []
352 | for t in queue:
353 | temp.append(t)
354 | now_playing = temp[0][0]
355 | by = temp[0][1].mention(style="md")
356 | msg = "**Lagu Yang Sedang dimainkan** di {}".format(cb.message.chat.title)
357 | msg += "\n• " + now_playing
358 | msg += "\n• Req by " + by
359 | temp.pop(0)
360 | if temp:
361 | msg += "\n\n"
362 | msg += "**Antrian Lagu**"
363 | for song in temp:
364 | name = song[0]
365 | usr = song[1].mention(style="md")
366 | msg += f"\n• {name}"
367 | msg += f"\n• Req by {usr}\n"
368 | await cb.message.edit(msg)
369 |
370 | elif type_ == "resume":
371 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
372 | callsmusic.pytgcalls.active_calls[chet_id] == "playing"
373 | ):
374 | await cb.answer("Chat is not connected or already playng", show_alert=True)
375 | else:
376 | callsmusic.pytgcalls.resume_stream(chet_id)
377 | await cb.answer("Music Resumed!")
378 | elif type_ == "puse":
379 | if (chet_id not in callsmusic.pytgcalls.active_calls) or (
380 | callsmusic.pytgcalls.active_calls[chet_id] == "paused"
381 | ):
382 | await cb.answer("Chat is not connected or already paused", show_alert=True)
383 | else:
384 | callsmusic.pytgcalls.pause_stream(chet_id)
385 |
386 | await cb.answer("Music Paused!")
387 | elif type_ == "cls":
388 | await cb.answer("Closed menu")
389 | await cb.message.delete()
390 |
391 | elif type_ == "menu":
392 | stats = updated_stats(cb.message.chat, qeue)
393 | await cb.answer("Menu opened")
394 | marr = InlineKeyboardMarkup(
395 | [
396 | [
397 | InlineKeyboardButton("⏹", "leave"),
398 | InlineKeyboardButton("⏸", "puse"),
399 | InlineKeyboardButton("▶️", "resume"),
400 | InlineKeyboardButton("⏭", "skip"),
401 | ],
402 | [
403 | InlineKeyboardButton("📖 Playlist", "playlist"),
404 | ],
405 | [InlineKeyboardButton("❌ Close", "cls")],
406 | ]
407 | )
408 | await cb.message.edit(stats, reply_markup=marr)
409 | elif type_ == "skip":
410 | if qeue:
411 | qeue.pop(0)
412 | if chet_id not in callsmusic.pytgcalls.active_calls:
413 | await cb.answer("Chat is not connected!", show_alert=True)
414 | else:
415 | callsmusic.queues.task_done(chet_id)
416 |
417 | if callsmusic.queues.is_empty(chet_id):
418 | callsmusic.pytgcalls.leave_group_call(chet_id)
419 |
420 | await cb.message.edit("- No More Playlist..\n- Leaving VC!")
421 | else:
422 | callsmusic.pytgcalls.change_stream(
423 | chet_id, callsmusic.queues.get(chet_id)["file"]
424 | )
425 | await cb.answer("Skipped")
426 | await cb.message.edit((m_chat, qeue), reply_markup=r_ply(the_data))
427 | await cb.message.reply_text(
428 | f"- Skipped track\n- Now Playing **{qeue[0][0]}**"
429 | )
430 |
431 | else:
432 | if chet_id in callsmusic.pytgcalls.active_calls:
433 | try:
434 | callsmusic.queues.clear(chet_id)
435 | except QueueEmpty:
436 | pass
437 |
438 | callsmusic.pytgcalls.leave_group_call(chet_id)
439 | await cb.message.edit("Successfully Left the Chat!")
440 | else:
441 | await cb.answer("Chat is not connected!", show_alert=True)
442 |
443 |
444 | @Client.on_message(command("play") & other_filters)
445 | async def play(_, message: Message):
446 | global que
447 | global useer
448 | if message.chat.id in DISABLED_GROUPS:
449 | return
450 | lel = await message.reply("🔄 **Sedang Memproses Lagu**")
451 | administrators = await get_administrators(message.chat)
452 | chid = message.chat.id
453 |
454 | try:
455 | user = await USER.get_me()
456 | except:
457 | user.first_name = "GeezProject"
458 | usar = user
459 | wew = usar.id
460 | try:
461 | # chatdetails = await USER.get_chat(chid)
462 | await _.get_chat_member(chid, wew)
463 | except:
464 | for administrator in administrators:
465 | if administrator == message.from_user.id:
466 | if message.chat.title.startswith("Channel Music: "):
467 | await lel.edit(
468 | f"Ingatlah untuk menambahkan {user.first_name} ke Channel Anda",
469 | )
470 | pass
471 | try:
472 | invitelink = await _.export_chat_invite_link(chid)
473 | except:
474 | await lel.edit(
475 | "Tambahkan saya sebagai admin grup Anda terlebih dahulu",
476 | )
477 | return
478 |
479 | try:
480 | await USER.join_chat(invitelink)
481 | await USER.send_message(
482 | message.chat.id, "I joined this group for playing music in VC"
483 | )
484 | await lel.edit(
485 | "helper userbot joined your chat",
486 | )
487 |
488 | except UserAlreadyParticipant:
489 | pass
490 | except Exception:
491 | # print(e)
492 | await lel.edit(
493 | f"⛑ Flood Wait Error ⛑\n{user.first_name} tidak dapat bergabung dengan grup Anda karena banyaknya permintaan bergabung untuk userbot! Pastikan pengguna tidak dibanned dalam grup."
494 | f"\n\nAtau tambahkan @{ASSISTANT_NAME} secara manual ke Grup Anda dan coba lagi",
495 | )
496 | try:
497 | await USER.get_chat(chid)
498 | # lmoa = await client.get_chat_member(chid,wew)
499 | except:
500 | await lel.edit(
501 | f"{user.first_name} terkena banned dari Grup ini, Minta admin untuk mengirim perintah `/play` untuk pertama kalinya atau tambahkan @{ASSISTANT_NAME} secara manual"
502 | )
503 | return
504 | text_links=None
505 | await lel.edit("🔄 **Sedang Mencari Lagu**")
506 | if message.reply_to_message:
507 | entities = []
508 | toxt = message.reply_to_message.text or message.reply_to_message.caption
509 | if message.reply_to_message.entities:
510 | entities = message.reply_to_message.entities + entities
511 | elif message.reply_to_message.caption_entities:
512 | entities = message.reply_to_message.entities + entities
513 | urls = [entity for entity in entities if entity.type == 'url']
514 | text_links = [
515 | entity for entity in entities if entity.type == 'text_link'
516 | ]
517 | else:
518 | urls=None
519 | if text_links:
520 | urls = True
521 | user_id = message.from_user.id
522 | user_name = message.from_user.first_name
523 | rpk = "[" + user_name + "](tg://user?id=" + str(user_id) + ")"
524 | audio = (
525 | (message.reply_to_message.audio or message.reply_to_message.voice)
526 | if message.reply_to_message
527 | else None
528 | )
529 | if audio:
530 | if round(audio.duration / 60) > DURATION_LIMIT:
531 | raise DurationLimitError(
532 | f"❌ **Lagu dengan durasi lebih dari** `{DURATION_LIMIT}` **menit tidak boleh diputar!**"
533 | )
534 | keyboard = InlineKeyboardMarkup(
535 | [
536 | [
537 | InlineKeyboardButton("📌 Groups", url="https://t.me/GeezSupportGroup"),
538 | InlineKeyboardButton("⛑ Channel", url="https://t.me/GeezProjets"),
539 | ],
540 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
541 | ]
542 | )
543 | file_name = get_file_name(audio)
544 | title = file_name
545 | thumb_name = "https://telegra.ph/file/fa2cdb8a14a26950da711.png"
546 | thumbnail = thumb_name
547 | duration = round(audio.duration / 60)
548 | views = "Locally added"
549 | requested_by = message.from_user.first_name
550 | await generate_cover(requested_by, title, views, duration, thumbnail)
551 | file_path = await convert(
552 | (await message.reply_to_message.download(file_name))
553 | if not path.isfile(path.join("downloads", file_name))
554 | else file_name
555 | )
556 | elif urls:
557 | query = toxt
558 | await lel.edit("🎵 **Sedang Memproses Lagu**")
559 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
560 | try:
561 | results = YoutubeSearch(query, max_results=1).to_dict()
562 | url = f"https://youtube.com{results[0]['url_suffix']}"
563 | # print(results)
564 | title = results[0]["title"][:25]
565 | thumbnail = results[0]["thumbnails"][0]
566 | thumb_name = f"thumb{title}.jpg"
567 | thumb = requests.get(thumbnail, allow_redirects=True)
568 | open(thumb_name, "wb").write(thumb.content)
569 | duration = results[0]["duration"]
570 | results[0]["url_suffix"]
571 | views = results[0]["views"]
572 |
573 | except Exception as e:
574 | await lel.edit(
575 | "**Lagu tidak ditemukan.** Coba cari dengan judul lagu yang lebih jelas, Ketik `/help` bila butuh bantuan"
576 | )
577 | print(str(e))
578 | return
579 | dlurl=url
580 | dlurl=dlurl.replace("youtube","youtubepp")
581 | keyboard = InlineKeyboardMarkup(
582 | [
583 | [
584 | InlineKeyboardButton("📌 Groups", url="https://t.me/GeezSupportGroup"),
585 | InlineKeyboardButton("⛑ Channel", url="https://t.me/GeezProjects"),
586 | ],
587 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
588 | ]
589 | )
590 | requested_by = message.from_user.first_name
591 | await generate_cover(requested_by, title, views, duration, thumbnail)
592 | file_path = await convert(youtube.download(url))
593 | else:
594 | query = ""
595 | for i in message.command[1:]:
596 | query += " " + str(i)
597 | print(query)
598 | await lel.edit("🎵 **Sedang Memproses Lagu**")
599 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
600 |
601 | try:
602 | results = YoutubeSearch(query, max_results=5).to_dict()
603 | except:
604 | await lel.edit("**berikan judul lagu yang ingin kamu putar !**")
605 | # Looks like hell. Aren't it?? FUCK OFF
606 | try:
607 | toxxt = "**__silahkan pilih lagu untuk diputar:__**\n\n"
608 | j = 0
609 | useer=user_name
610 | emojilist = ["1️⃣","2️⃣","3️⃣","4️⃣","5️⃣",]
611 |
612 | while j < 5:
613 | toxxt += f"{emojilist[j]} [{results[j]['title'][:25]}](https://youtube.com{results[j]['url_suffix']})\n"
614 | toxxt += f" ├ 💡 **Duration** - {results[j]['duration']}\n"
615 | toxxt += f" └ ⚡ __Powered by Geez Music Project__\n\n"
616 |
617 | j += 1
618 | koyboard = InlineKeyboardMarkup(
619 | [
620 | [
621 | InlineKeyboardButton("1️⃣", callback_data=f'plll 0|{query}|{user_id}'),
622 | InlineKeyboardButton("2️⃣", callback_data=f'plll 1|{query}|{user_id}'),
623 | InlineKeyboardButton("3️⃣", callback_data=f'plll 2|{query}|{user_id}'),
624 | ],
625 | [
626 | InlineKeyboardButton("4️⃣", callback_data=f'plll 3|{query}|{user_id}'),
627 | InlineKeyboardButton("5️⃣", callback_data=f'plll 4|{query}|{user_id}'),
628 | ],
629 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
630 | ]
631 | )
632 | await lel.edit(toxxt,reply_markup=koyboard,disable_web_page_preview=True)
633 | # WHY PEOPLE ALWAYS LOVE PORN ?? (A point to think)
634 | return
635 | # Returning to pornhub
636 | except:
637 | await lel.edit("**Tidak ada hasil yang cukup untuk dipilih.. Mulai bermain langsung..**")
638 |
639 | # print(results)
640 | try:
641 | url = f"https://youtube.com{results[0]['url_suffix']}"
642 | title = results[0]["title"][:25]
643 | thumbnail = results[0]["thumbnails"][0]
644 | thumb_name = f"thumb{title}.jpg"
645 | thumb = requests.get(thumbnail, allow_redirects=True)
646 | open(thumb_name, "wb").write(thumb.content)
647 | duration = results[0]["duration"]
648 | results[0]["url_suffix"]
649 | views = results[0]["views"]
650 |
651 | except Exception as e:
652 | await lel.edit(
653 | "**Lagu tidak ditemukan.** Coba cari dengan judul lagu yang lebih jelas, Ketik `/help` bila butuh bantuan"
654 | )
655 | print(str(e))
656 | return
657 | dlurl=url
658 | dlurl=dlurl.replace("youtube","youtubepp")
659 | keyboard = InlineKeyboardMarkup(
660 | [
661 | [
662 | InlineKeyboardButton("📌 Groups", url="https://t.me/GeezSupportGroup"),
663 | InlineKeyboardButton("⛑ Channel", url="https://t.me/GeezProjects"),
664 | ],
665 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
666 | ]
667 | )
668 | requested_by = message.from_user.first_name
669 | await generate_cover(requested_by, title, views, duration, thumbnail)
670 | file_path = await convert(youtube.download(url))
671 | chat_id = get_chat_id(message.chat)
672 | if chat_id in callsmusic.pytgcalls.active_calls:
673 | position = await queues.put(chat_id, file=file_path)
674 | qeue = que.get(chat_id)
675 | s_name = title
676 | r_by = message.from_user
677 | loc = file_path
678 | appendable = [s_name, r_by, loc]
679 | qeue.append(appendable)
680 | await message.reply_photo(
681 | photo="final.png",
682 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Antrian Ke `{position}`\n" \
683 | + f"🎧 **Request Dari:** {message.from_user.mention}",
684 | reply_markup=keyboard)
685 |
686 | else:
687 | chat_id = get_chat_id(message.chat)
688 | que[chat_id] = []
689 | qeue = que.get(chat_id)
690 | s_name = title
691 | r_by = message.from_user
692 | loc = file_path
693 | appendable = [s_name, r_by, loc]
694 | qeue.append(appendable)
695 | try:
696 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
697 | except:
698 | message.reply("**Voice Chat Group tidak aktif, Saya tidak dapat bergabung**")
699 | return
700 | await message.reply_photo(
701 | photo="final.png",
702 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Sedang Memutar\n" \
703 | + f"🎧 **Request Dari:** {message.from_user.mention}",
704 | reply_markup=keyboard)
705 |
706 | os.remove("final.png")
707 | return await lel.delete()
708 |
709 |
710 | @Client.on_message(filters.command("ytplay") & filters.group & ~filters.edited)
711 | async def ytplay(_, message: Message):
712 | global que
713 | if message.chat.id in DISABLED_GROUPS:
714 | return
715 | lel = await message.reply("🔄 **Sedang Memproses Lagu**")
716 | administrators = await get_administrators(message.chat)
717 | chid = message.chat.id
718 |
719 | try:
720 | user = await USER.get_me()
721 | except:
722 | user.first_name = "GeezProject"
723 | usar = user
724 | wew = usar.id
725 | try:
726 | # chatdetails = await USER.get_chat(chid)
727 | await _.get_chat_member(chid, wew)
728 | except:
729 | for administrator in administrators:
730 | if administrator == message.from_user.id:
731 | if message.chat.title.startswith("Channel Music: "):
732 | await lel.edit(
733 | f"Ingatlah untuk menambahkan {user.first_name} ke Channel Anda",
734 | )
735 | pass
736 | try:
737 | invitelink = await _.export_chat_invite_link(chid)
738 | except:
739 | await lel.edit(
740 | "Tambahkan saya sebagai admin grup Anda terlebih dahulu",
741 | )
742 | return
743 |
744 | try:
745 | await USER.join_chat(invitelink)
746 | await USER.send_message(
747 | message.chat.id, "I joined this group for playing music in VC"
748 | )
749 | await lel.edit(
750 | "helper userbot joined your chat",
751 | )
752 |
753 | except UserAlreadyParticipant:
754 | pass
755 | except Exception:
756 | # print(e)
757 | await lel.edit(
758 | f"Flood Wait Error\n{user.first_name} tidak dapat bergabung dengan grup Anda karena banyaknya permintaan bergabung untuk userbot! Pastikan pengguna tidak dibanned dalam grup."
759 | f"\n\nAtau tambahkan @{ASSISTANT_NAME} secara manual ke Grup Anda dan coba lagi",
760 | )
761 | try:
762 | await USER.get_chat(chid)
763 | # lmoa = await client.get_chat_member(chid,wew)
764 | except:
765 | await lel.edit(
766 | f"{user.first_name} terkena banned dari Grup ini, Minta admin untuk mengirim perintah `/play` untuk pertama kalinya atau tambahkan @{ASSISTANT_NAME} secara manual"
767 | )
768 | return
769 | await lel.edit("🔎 **Sedang Mencari Lagu**")
770 | user_id = message.from_user.id
771 | user_name = message.from_user.first_name
772 |
773 |
774 | query = ""
775 | for i in message.command[1:]:
776 | query += " " + str(i)
777 | print(query)
778 | await lel.edit("🎵 **Sedang Memproses Lagu**")
779 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
780 | try:
781 | results = YoutubeSearch(query, max_results=1).to_dict()
782 | url = f"https://youtube.com{results[0]['url_suffix']}"
783 | # print(results)
784 | title = results[0]["title"][:25]
785 | thumbnail = results[0]["thumbnails"][0]
786 | thumb_name = f"thumb{title}.jpg"
787 | thumb = requests.get(thumbnail, allow_redirects=True)
788 | open(thumb_name, "wb").write(thumb.content)
789 | duration = results[0]["duration"]
790 | results[0]["url_suffix"]
791 | views = results[0]["views"]
792 |
793 | except Exception as e:
794 | await lel.edit(
795 | "**Lagu tidak ditemukan.** Coba cari dengan judul lagu yang lebih jelas, Ketik `/help` bila butuh bantuan"
796 | )
797 | print(str(e))
798 | return
799 | dlurl=url
800 | dlurl=dlurl.replace("youtube","youtubepp")
801 | keyboard = InlineKeyboardMarkup(
802 | [
803 | [
804 | InlineKeyboardButton("📌 Groups", url="https://t.me/GeezSupportGroup"),
805 | InlineKeyboardButton("⛑ Channel", url="https://t.me/GeezProjects"),
806 | ],
807 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
808 | ]
809 | )
810 | requested_by = message.from_user.first_name
811 | await generate_cover(requested_by, title, views, duration, thumbnail)
812 | file_path = await convert(youtube.download(url))
813 | chat_id = get_chat_id(message.chat)
814 | if chat_id in callsmusic.pytgcalls.active_calls:
815 | position = await queues.put(chat_id, file=file_path)
816 | qeue = que.get(chat_id)
817 | s_name = title
818 | r_by = message.from_user
819 | loc = file_path
820 | appendable = [s_name, r_by, loc]
821 | qeue.append(appendable)
822 | await message.reply_photo(
823 | photo="final.png",
824 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Antrian Ke `{position}`\n" \
825 | + f"🎧 **Request Dari:** {message.from_user.mention}",
826 | reply_markup=keyboard,
827 | )
828 | os.remove("final.png")
829 | return await lel.delete()
830 | else:
831 | chat_id = get_chat_id(message.chat)
832 | que[chat_id] = []
833 | qeue = que.get(chat_id)
834 | s_name = title
835 | r_by = message.from_user
836 | loc = file_path
837 | appendable = [s_name, r_by, loc]
838 | qeue.append(appendable)
839 | try:
840 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
841 | except:
842 | message.reply("**Voice Chat Group tidak aktif, Saya tidak dapat bergabung**")
843 | return
844 | await message.reply_photo(
845 | photo="final.png",
846 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Sedang Memutar\n" \
847 | + f"🎧 **Request Dari:** {message.from_user.mention}",
848 | reply_markup=keyboard,)
849 | os.remove("final.png")
850 | return await lel.delete()
851 |
852 |
853 | @Client.on_message(filters.command("dplay") & filters.group & ~filters.edited)
854 | async def deezer(client: Client, message_: Message):
855 | if message_.chat.id in DISABLED_GROUPS:
856 | return
857 | global que
858 | lel = await message_.reply("🔄 **Sedang Memproses Lagu**")
859 | administrators = await get_administrators(message_.chat)
860 | chid = message_.chat.id
861 | try:
862 | user = await USER.get_me()
863 | except:
864 | user.first_name = "GeezProject"
865 | usar = user
866 | wew = usar.id
867 | try:
868 | # chatdetails = await USER.get_chat(chid)
869 | await client.get_chat_member(chid, wew)
870 | except:
871 | for administrator in administrators:
872 | if administrator == message_.from_user.id:
873 | if message_.chat.title.startswith("Channel Music: "):
874 | await lel.edit(
875 | f"Ingatlah untuk menambahkan {user.first_name} ke Channel Anda",
876 | )
877 | pass
878 | try:
879 | invitelink = await client.export_chat_invite_link(chid)
880 | except:
881 | await lel.edit(
882 | "Tambahkan saya sebagai admin grup Anda terlebih dahulu",
883 | )
884 | return
885 |
886 | try:
887 | await USER.join_chat(invitelink)
888 | await USER.send_message(
889 | message_.chat.id, "I joined this group for playing music in VC"
890 | )
891 | await lel.edit(
892 | "helper userbot joined your chat",
893 | )
894 |
895 | except UserAlreadyParticipant:
896 | pass
897 | except Exception:
898 | # print(e)
899 | await lel.edit(
900 | f"⛑ Flood Wait Error ⛑\n{user.first_name} tidak dapat bergabung dengan grup Anda karena banyaknya permintaan bergabung untuk userbot! Pastikan pengguna tidak dibanned dalam grup."
901 | f"\n\nAtau tambahkan @{ASSISTANT_NAME} secara manual ke Grup Anda dan coba lagi",
902 | )
903 | try:
904 | await USER.get_chat(chid)
905 | # lmoa = await client.get_chat_member(chid,wew)
906 | except:
907 | await lel.edit(
908 | f"{user.first_name} terkena banned dari Grup ini, Minta admin untuk mengirim perintah `/play` untuk pertama kalinya atau tambahkan @{ASSISTANT_NAME} secara manual"
909 | )
910 | return
911 | requested_by = message_.from_user.first_name
912 |
913 | text = message_.text.split(" ", 1)
914 | queryy = text[1]
915 | query = queryy
916 | res = lel
917 | await res.edit(f"**Sedang Mencari Lagu** `{query}` **dari deezer**")
918 | try:
919 | songs = await arq.deezer(query,1)
920 | if not songs.ok:
921 | await message_.reply_text(songs.result)
922 | return
923 | title = songs.result[0].title
924 | url = songs.result[0].url
925 | artist = songs.result[0].artist
926 | duration = songs.result[0].duration
927 | thumbnail = "https://telegra.ph/file/fa2cdb8a14a26950da711.png"
928 |
929 | except:
930 | await res.edit("**Tidak Ditemukan Lagu Apa Pun!**")
931 | return
932 | try:
933 | duuration= round(duration / 60)
934 | if duuration > DURATION_LIMIT:
935 | await cb.message.edit(f"**Musik lebih lama dari** `{DURATION_LIMIT}` **menit tidak diperbolehkan diputar**")
936 | return
937 | except:
938 | pass
939 |
940 | keyboard = InlineKeyboardMarkup(
941 | [
942 | [InlineKeyboardButton(text="⛑ Channel", url="https://t.me/GeezProjects")],
943 | ]
944 | )
945 | file_path = await convert(wget.download(url))
946 | await res.edit("📥 **Generating Thumbnail**")
947 | await generate_cover(requested_by, title, artist, duration, thumbnail)
948 | chat_id = get_chat_id(message_.chat)
949 | if chat_id in callsmusic.pytgcalls.active_calls:
950 | await res.edit("adding in queue")
951 | position = await queues.put(chat_id, file=file_path)
952 | qeue = que.get(chat_id)
953 | s_name = title
954 | r_by = message_.from_user
955 | loc = file_path
956 | appendable = [s_name, r_by, loc]
957 | qeue.append(appendable)
958 | await res.edit_text(f"🎼 **Lagu yang Anda minta Sedang Antri di posisi** `{position}`")
959 | else:
960 | await res.edit_text(f"🎼️ **Playing...**")
961 |
962 | que[chat_id] = []
963 | qeue = que.get(chat_id)
964 | s_name = title
965 | r_by = message_.from_user
966 | loc = file_path
967 | appendable = [s_name, r_by, loc]
968 | qeue.append(appendable)
969 | try:
970 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
971 | except:
972 | res.edit("Voice Chat Group tidak aktif, Saya tidak dapat bergabung")
973 | return
974 |
975 | await res.delete()
976 |
977 | m = await client.send_photo(
978 | chat_id=message_.chat.id,
979 | reply_markup=keyboard,
980 | photo="final.png",
981 | caption=f"🎼️ **Sedang Memutar Lagu** [{title}]({url}) **Via Deezer**",
982 | )
983 | os.remove("final.png")
984 |
985 |
986 | @Client.on_callback_query(filters.regex(pattern=r"plll"))
987 | async def lol_cb(b, cb):
988 | global que
989 |
990 | cbd = cb.data.strip()
991 | chat_id = cb.message.chat.id
992 | typed_=cbd.split(None, 1)[1]
993 | #useer_id = cb.message.reply_to_message.from_user.id
994 | try:
995 | x,query,useer_id = typed_.split("|")
996 | except:
997 | await cb.message.edit("Lagu Tidak ditemukan")
998 | return
999 | useer_id = int(useer_id)
1000 | if cb.from_user.id != useer_id:
1001 | await cb.answer("Anda bukan orang yang meminta untuk memutar lagu!", show_alert=True)
1002 | return
1003 | await cb.message.edit("**Processing**")
1004 | x=int(x)
1005 | try:
1006 | useer_name = cb.message.reply_to_message.from_user.first_name
1007 | except:
1008 | useer_name = cb.message.from_user.first_name
1009 |
1010 | results = YoutubeSearch(query, max_results=5).to_dict()
1011 | resultss=results[x]["url_suffix"]
1012 | title=results[x]["title"][:25]
1013 | thumbnail=results[x]["thumbnails"][0]
1014 | duration=results[x]["duration"]
1015 | views=results[x]["views"]
1016 | url = f"https://youtube.com{resultss}"
1017 |
1018 | try:
1019 | duuration= round(duration / 60)
1020 | if duuration > DURATION_LIMIT:
1021 | await cb.message.edit(f"Lagu lebih lama dari {DURATION_LIMIT} menit tidak diperbolehkan diputar")
1022 | return
1023 | except:
1024 | pass
1025 | try:
1026 | thumb_name = f"thumb{title}.jpg"
1027 | thumb = requests.get(thumbnail, allow_redirects=True)
1028 | open(thumb_name, "wb").write(thumb.content)
1029 | except Exception as e:
1030 | print(e)
1031 | return
1032 | dlurl=url
1033 | dlurl=dlurl.replace("youtube","youtubepp")
1034 | keyboard = InlineKeyboardMarkup(
1035 | [
1036 | [
1037 | InlineKeyboardButton("📌 Groups", url="https://t.me/GeezSupportGroup"),
1038 | InlineKeyboardButton("🛡️ Channel", url="https://t.me/GeezProjects"),
1039 | ],
1040 | [InlineKeyboardButton(text="🗑 Close", callback_data="cls")],
1041 | ]
1042 | )
1043 | requested_by = useer_name
1044 | await generate_cover(requested_by, title, views, duration, thumbnail)
1045 | file_path = await convert(youtube.download(url))
1046 | if chat_id in callsmusic.pytgcalls.active_calls:
1047 | position = await queues.put(chat_id, file=file_path)
1048 | qeue = que.get(chat_id)
1049 | s_name = title
1050 | try:
1051 | r_by = cb.message.reply_to_message.from_user
1052 | except:
1053 | r_by = cb.message.from_user
1054 | loc = file_path
1055 | appendable = [s_name, r_by, loc]
1056 | qeue.append(appendable)
1057 | await cb.message.delete()
1058 | await b.send_photo(chat_id,
1059 | photo="final.png",
1060 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Antrian Ke `{position}`\n" \
1061 | + f"🎧 **Request Dari:** {r_by.mention}",
1062 | reply_markup=keyboard,
1063 | )
1064 | os.remove("final.png")
1065 |
1066 | else:
1067 | que[chat_id] = []
1068 | qeue = que.get(chat_id)
1069 | s_name = title
1070 | try:
1071 | r_by = cb.message.reply_to_message.from_user
1072 | except:
1073 | r_by = cb.message.from_user
1074 | loc = file_path
1075 | appendable = [s_name, r_by, loc]
1076 | qeue.append(appendable)
1077 |
1078 | callsmusic.pytgcalls.join_group_call(chat_id, file_path)
1079 | await cb.message.delete()
1080 | await b.send_photo(chat_id,
1081 | photo="final.png",
1082 | caption = f"🏷 **Judul:** [{title[:30]}]({url})\n⏱ **Durasi:** {duration}\n💡 **Status:** Sedang Memutar\n" \
1083 | + f"🎧 **Request Dari:** {r_by.mention}",
1084 | reply_markup=keyboard,
1085 | )
1086 | os.remove("final.png")
1087 |
1088 | # Have u read all. If read RESPECT :-)
1089 |
--------------------------------------------------------------------------------
/GeezProject/modules/pmpermit.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 | from pyrogram import Client
18 | import asyncio
19 | from GeezProject.config import SUDO_USERS, PMPERMIT, OWNER, PROJECT_NAME, UPDATES_CHANNEL, SUPPORT_GROUP
20 | from pyrogram import filters
21 | from pyrogram.types import Message
22 | from GeezProject.services.callsmusic.callsmusic import client as USER
23 |
24 | PMSET =True
25 | pchats = []
26 |
27 | @USER.on_message(filters.text & filters.private & ~filters.me & ~filters.bot)
28 | async def pmPermit(client: USER, message: Message):
29 | if PMPERMIT == "ENABLE":
30 | if PMSET:
31 | chat_id = message.chat.id
32 | if chat_id in pchats:
33 | return
34 | await USER.send_message(
35 | message.chat.id,
36 | f"Halo, Saya adalah **Layanan Asistant {PROJECT_NAME}.**\n\n ❗️ **Rules:**\n - Jangan Spam Pesan disini\n - Jangan Spam Lagu Biar Ga Error\n - Tutorial Cara Menggunakan bot Lihat di @{UPDATES_CHANNEL} \n\n 👉 **KIRIM LINK INVITE ATAU USERNAME GRUP, JIKA ASSISTANT TIDAK DAPAT BERGABUNG DENGAN GRUP ANDA.**\n\n ⛑ **Group Support :** @{SUPPORT_GROUP} - **Owner** {OWNER}\n\n",
37 | )
38 | return
39 |
40 |
41 |
42 | @Client.on_message(filters.command(["/pmpermit"]))
43 | async def bye(client: Client, message: Message):
44 | if message.from_user.id in SUDO_USERS:
45 | global PMSET
46 | text = message.text.split(" ", 1)
47 | queryy = text[1]
48 | if queryy == "on":
49 | PMSET = True
50 | await message.reply_text("Pmpermit turned on")
51 | return
52 | if queryy == "off":
53 | PMSET = None
54 | await message.reply_text("Pmpermit turned off")
55 | return
56 |
57 | @USER.on_message(filters.text & filters.private & filters.me)
58 | async def autopmPermiat(client: USER, message: Message):
59 | chat_id = message.chat.id
60 | if not chat_id in pchats:
61 | pchats.append(chat_id)
62 | await message.reply_text("Approoved to PM due to outgoing messages")
63 | return
64 | message.continue_propagation()
65 |
66 | @USER.on_message(filters.command("yes", [".", ""]) & filters.me & filters.private)
67 | async def pmPermiat(client: USER, message: Message):
68 | chat_id = message.chat.id
69 | if not chat_id in pchats:
70 | pchats.append(chat_id)
71 | await message.reply_text("Approoved to PM")
72 | return
73 | message.continue_propagation()
74 |
75 |
76 | @USER.on_message(filters.command("no", [".", ""]) & filters.me & filters.private)
77 | async def rmpmPermiat(client: USER, message: Message):
78 | chat_id = message.chat.id
79 | if chat_id in pchats:
80 | pchats.remove(chat_id)
81 | await message.reply_text("Dispprooved to PM")
82 | return
83 | message.continue_propagation()
84 |
--------------------------------------------------------------------------------
/GeezProject/modules/private.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 | import logging
18 | from GeezProject.modules.msg import Messages as tr
19 | from pyrogram import Client, filters
20 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
21 | from GeezProject.config import SOURCE_CODE,ASSISTANT_NAME,PROJECT_NAME,SUPPORT_GROUP,UPDATES_CHANNEL,BOT_USERNAME, OWNER
22 | logging.basicConfig(level=logging.INFO)
23 |
24 | @Client.on_message(
25 | filters.command("start")
26 | & filters.private
27 | & ~ filters.edited
28 | )
29 | async def start_(client: Client, message: Message):
30 | await message.reply_text(
31 | f"""Haii {message.from_user.first_name} saya adalah {PROJECT_NAME}\n
32 | Saya Adalah Bot Music Group, Yang dapat Memutar Lagu di Voice Chat Group Anda Dengan Mudah
33 | Saya Memiliki Banyak Fitur Seperti :
34 | • Memutar Musik.
35 | • Mendownload Lagu.
36 | • Mencari Lagu Yang ingin di Putar atau di Download.
37 | • Gunakan Perintah » /help « untuk Mengetahui Fitur Lengkapnya
38 |
39 | 📌 Special Thanks To : {OWNER}
40 |
41 | Ingin Menambahkan Saya ke Grup Anda? Tambahkan Saya Ke Group Anda!
42 | """,
43 |
44 | # Edit Yang Seharusnya Lu Edit Aja:D
45 | # Tapi Jangan di Hapus Special Thanks To nya Yaaa :'D
46 |
47 | reply_markup=InlineKeyboardMarkup(
48 | [
49 | [
50 | InlineKeyboardButton(
51 | "➕ Tambahkan saya ke Grup Anda ➕", url=f"https://t.me/{BOT_USERNAME}?startgroup=true")],
52 | [
53 | InlineKeyboardButton(
54 | "💬 Channel Updates", url=f"https://t.me/{UPDATES_CHANNEL}"),
55 | InlineKeyboardButton(
56 | "🎈 Group Support", url=f"https://t.me/{SUPPORT_GROUP}")
57 | ],[
58 | InlineKeyboardButton(
59 | "🛠 Source Code 🛠", url=f"https://{SOURCE_CODE}")
60 | ],[
61 | InlineKeyboardButton(
62 | "🎁 Donate", url=f"https://t.me/VckyouuBitch")
63 | ]
64 | ]
65 | ),
66 | reply_to_message_id=message.message_id
67 | )
68 |
69 | @Client.on_message(filters.private & filters.incoming & filters.command(['help']))
70 | def _help(client, message):
71 | client.send_message(chat_id = message.chat.id,
72 | text = tr.HELP_MSG[1],
73 | parse_mode="markdown",
74 | disable_web_page_preview=True,
75 | disable_notification=True,
76 | reply_markup = InlineKeyboardMarkup(map(1)),
77 | reply_to_message_id = message.message_id
78 | )
79 |
80 | help_callback_filter = filters.create(lambda _, __, query: query.data.startswith('help+'))
81 |
82 | @Client.on_callback_query(help_callback_filter)
83 | def help_answer(client, callback_query):
84 | chat_id = callback_query.from_user.id
85 | disable_web_page_preview=True
86 | message_id = callback_query.message.message_id
87 | msg = int(callback_query.data.split('+')[1])
88 | client.edit_message_text(chat_id=chat_id, message_id=message_id,
89 | text=tr.HELP_MSG[msg], reply_markup=InlineKeyboardMarkup(map(msg))
90 | )
91 |
92 |
93 | def map(pos):
94 | if(pos==1):
95 | button = [
96 | [InlineKeyboardButton(text = 'Next »', callback_data = "help+2")]
97 | ]
98 | elif(pos==len(tr.HELP_MSG)-1):
99 | url = f"https://t.me/{SUPPORT_GROUP}"
100 | button = [
101 | [InlineKeyboardButton("➕ Tambahkan saya ke Grup Anda ➕", url=f"https://t.me/{BOT_USERNAME}?startgroup=true")],
102 | [InlineKeyboardButton(text = '💬 Channel Updates', url=f"https://t.me/{UPDATES_CHANNEL}"),
103 | InlineKeyboardButton(text = '🔰 Group Support', url=f"https://t.me/{SUPPORT_GROUP}")],
104 | [InlineKeyboardButton(text = '🛠 Source Code 🛠', url=f"https://{SOURCE_CODE}")],
105 | [InlineKeyboardButton(text = '«', callback_data = f"help+{pos-1}")]
106 | ]
107 | else:
108 | button = [
109 | [
110 | InlineKeyboardButton(text = '«', callback_data = f"help+{pos-1}"),
111 | InlineKeyboardButton(text = '»', callback_data = f"help+{pos+1}")
112 | ],
113 | ]
114 | return button
115 |
116 |
117 | @Client.on_message(
118 | filters.command("start")
119 | & filters.group
120 | & ~ filters.edited
121 | )
122 | async def start(client: Client, message: Message):
123 | await message.reply_text(
124 | "💁🏻♂️ **Apakah Anda ingin mencari Link YouTube?**",
125 | reply_markup=InlineKeyboardMarkup(
126 | [
127 | [
128 | InlineKeyboardButton(
129 | "✅ Ya", switch_inline_query_current_chat=""
130 | ),
131 | InlineKeyboardButton(
132 | "❌ Tidak ", callback_data="close"
133 | )
134 | ]
135 | ]
136 | )
137 | )
138 |
139 |
140 | @Client.on_message(
141 | filters.command("help")
142 | & filters.group
143 | & ~ filters.edited
144 | )
145 | async def help(client: Client, message: Message):
146 | await message.reply_text(
147 | """**Klik Tombol dibawah untuk Melihat Cara Menggunakan Bot**""",
148 | reply_markup=InlineKeyboardMarkup(
149 | [
150 | [
151 | InlineKeyboardButton(
152 | "📜 Cara Menggunakan BOT 📜", url="https://t.me/Vckyouuu/32"
153 | )
154 | ]
155 | ]
156 | ),
157 | )
158 |
159 |
160 | @Client.on_message(
161 | filters.command("reload")
162 | & filters.group
163 | & ~ filters.edited
164 | )
165 | async def reload(client: Client, message: Message):
166 | await message.reply_text("""✅ Bot **berhasil dimulai ulang!**\n\n• **Daftar admin** telah **diperbarui**""",
167 | reply_markup=InlineKeyboardMarkup(
168 | [
169 | [
170 | InlineKeyboardButton(
171 | "Group Support", url=f"https://t.me/GeezSupportGroup"
172 | ),
173 | InlineKeyboardButton(
174 | "Created By", url=f"https://t.me/VckyouuBitch"
175 | )
176 | ]
177 | ]
178 | )
179 | )
180 |
181 |
--------------------------------------------------------------------------------
/GeezProject/modules/song.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from __future__ import unicode_literals
19 |
20 | import asyncio
21 | import math
22 | import os
23 | import time
24 | from random import randint
25 | from urllib.parse import urlparse
26 |
27 | import aiofiles
28 | import aiohttp
29 | import requests
30 | import wget
31 | import youtube_dl
32 | from pyrogram import Client, filters
33 | from pyrogram.errors import FloodWait, MessageNotModified
34 | from pyrogram.types import Message
35 | from youtube_search import YoutubeSearch
36 | from youtubesearchpython import SearchVideos
37 |
38 | from GeezProject.config import DURATION_LIMIT
39 | from GeezProject.modules.play import arq
40 |
41 |
42 | @Client.on_message(filters.command("song") & ~filters.channel)
43 | def song(client, message):
44 |
45 | user_id = message.from_user.id
46 | user_name = message.from_user.first_name
47 | rpk = "[" + user_name + "](tg://user?id=" + str(user_id) + ")"
48 |
49 | query = ""
50 | for i in message.command[1:]:
51 | query += " " + str(i)
52 | print(query)
53 | m = message.reply("🔎 Finding the song...")
54 | ydl_opts = {"format": "bestaudio[ext=m4a]"}
55 | try:
56 | results = YoutubeSearch(query, max_results=1).to_dict()
57 | link = f"https://youtube.com{results[0]['url_suffix']}"
58 | # print(results)
59 | title = results[0]["title"][:40]
60 | thumbnail = results[0]["thumbnails"][0]
61 | thumb_name = f"thumb{title}.jpg"
62 | thumb = requests.get(thumbnail, allow_redirects=True)
63 | open(thumb_name, "wb").write(thumb.content)
64 |
65 | duration = results[0]["duration"]
66 | results[0]["url_suffix"]
67 | results[0]["views"]
68 |
69 | except Exception as e:
70 | m.edit("❌ Found Nothing.\n\nTry another keywork or maybe spell it properly.")
71 | print(str(e))
72 | return
73 | m.edit("Downloading the song ")
74 | try:
75 | with youtube_dl.YoutubeDL(ydl_opts) as ydl:
76 | info_dict = ydl.extract_info(link, download=False)
77 | audio_file = ydl.prepare_filename(info_dict)
78 | ydl.process_info(info_dict)
79 | rep = "**🎵 Diunggah Oleh @GeezProjects **"
80 | secmul, dur, dur_arr = 1, 0, duration.split(":")
81 | for i in range(len(dur_arr) - 1, -1, -1):
82 | dur += int(dur_arr[i]) * secmul
83 | secmul *= 60
84 | message.reply_audio(
85 | audio_file,
86 | caption=rep,
87 | thumb=thumb_name,
88 | parse_mode="md",
89 | title=title,
90 | duration=dur,
91 | )
92 | m.delete()
93 | except Exception as e:
94 | m.edit("❌ Error")
95 | print(e)
96 |
97 | try:
98 | os.remove(audio_file)
99 | os.remove(thumb_name)
100 | except Exception as e:
101 | print(e)
102 |
103 |
104 | def get_text(message: Message) -> [None, str]:
105 | text_to_return = message.text
106 | if message.text is None:
107 | return None
108 | if " " in text_to_return:
109 | try:
110 | return message.text.split(None, 1)[1]
111 | except IndexError:
112 | return None
113 | else:
114 | return None
115 |
116 |
117 | def humanbytes(size):
118 | if not size:
119 | return ""
120 | power = 2 ** 10
121 | raised_to_pow = 0
122 | dict_power_n = {0: "", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"}
123 | while size > power:
124 | size /= power
125 | raised_to_pow += 1
126 | return str(round(size, 2)) + " " + dict_power_n[raised_to_pow] + "B"
127 |
128 |
129 | async def progress(current, total, message, start, type_of_ps, file_name=None):
130 | now = time.time()
131 | diff = now - start
132 | if round(diff % 10.00) == 0 or current == total:
133 | percentage = current * 100 / total
134 | speed = current / diff
135 | elapsed_time = round(diff) * 1000
136 | if elapsed_time == 0:
137 | return
138 | time_to_completion = round((total - current) / speed) * 1000
139 | estimated_total_time = elapsed_time + time_to_completion
140 | progress_str = "{0}{1} {2}%\n".format(
141 | "".join(["🔴" for i in range(math.floor(percentage / 10))]),
142 | "".join(["🔘" for i in range(10 - math.floor(percentage / 10))]),
143 | round(percentage, 2),
144 | )
145 | tmp = progress_str + "{0} of {1}\nETA: {2}".format(
146 | humanbytes(current), humanbytes(total), time_formatter(estimated_total_time)
147 | )
148 | if file_name:
149 | try:
150 | await message.edit(
151 | "{}\n**File Name:** `{}`\n{}".format(type_of_ps, file_name, tmp)
152 | )
153 | except FloodWait as e:
154 | await asyncio.sleep(e.x)
155 | except MessageNotModified:
156 | pass
157 | else:
158 | try:
159 | await message.edit("{}\n{}".format(type_of_ps, tmp))
160 | except FloodWait as e:
161 | await asyncio.sleep(e.x)
162 | except MessageNotModified:
163 | pass
164 |
165 |
166 | def get_user(message: Message, text: str) -> [int, str, None]:
167 | if text is None:
168 | asplit = None
169 | else:
170 | asplit = text.split(" ", 1)
171 | user_s = None
172 | reason_ = None
173 | if message.reply_to_message:
174 | user_s = message.reply_to_message.from_user.id
175 | reason_ = text if text else None
176 | elif asplit is None:
177 | return None, None
178 | elif len(asplit[0]) > 0:
179 | user_s = int(asplit[0]) if asplit[0].isdigit() else asplit[0]
180 | if len(asplit) == 2:
181 | reason_ = asplit[1]
182 | return user_s, reason_
183 |
184 |
185 | def get_readable_time(seconds: int) -> int:
186 | count = 0
187 | ping_time = ""
188 | time_list = []
189 | time_suffix_list = ["s", "m", "h", "days"]
190 |
191 | while count < 4:
192 | count += 1
193 | if count < 3:
194 | remainder, result = divmod(seconds, 60)
195 | else:
196 | remainder, result = divmod(seconds, 24)
197 | if seconds == 0 and remainder == 0:
198 | break
199 | time_list.append(int(result))
200 | seconds = int(remainder)
201 |
202 | for x in range(len(time_list)):
203 | time_list[x] = str(time_list[x]) + time_suffix_list[x]
204 | if len(time_list) == 4:
205 | ping_time += time_list.pop() + ", "
206 |
207 | time_list.reverse()
208 | ping_time += ":".join(time_list)
209 |
210 | return ping_time
211 |
212 |
213 | def time_formatter(milliseconds: int) -> str:
214 | seconds, milliseconds = divmod(int(milliseconds), 1000)
215 | minutes, seconds = divmod(seconds, 60)
216 | hours, minutes = divmod(minutes, 60)
217 | days, hours = divmod(hours, 24)
218 | tmp = (
219 | ((str(days) + " day(s), ") if days else "")
220 | + ((str(hours) + " hour(s), ") if hours else "")
221 | + ((str(minutes) + " minute(s), ") if minutes else "")
222 | + ((str(seconds) + " second(s), ") if seconds else "")
223 | + ((str(milliseconds) + " millisecond(s), ") if milliseconds else "")
224 | )
225 | return tmp[:-2]
226 |
227 |
228 | ydl_opts = {
229 | "format": "bestaudio/best",
230 | "writethumbnail": True,
231 | "postprocessors": [
232 | {
233 | "key": "FFmpegExtractAudio",
234 | "preferredcodec": "mp3",
235 | "preferredquality": "192",
236 | }
237 | ],
238 | }
239 |
240 |
241 | def get_file_extension_from_url(url):
242 | url_path = urlparse(url).path
243 | basename = os.path.basename(url_path)
244 | return basename.split(".")[-1]
245 |
246 |
247 | # Funtion To Download Song
248 | async def download_song(url):
249 | song_name = f"{randint(6969, 6999)}.mp3"
250 | async with aiohttp.ClientSession() as session:
251 | async with session.get(url) as resp:
252 | if resp.status == 200:
253 | f = await aiofiles.open(song_name, mode="wb")
254 | await f.write(await resp.read())
255 | await f.close()
256 | return song_name
257 |
258 |
259 | is_downloading = False
260 |
261 |
262 | def time_to_seconds(time):
263 | stringt = str(time)
264 | return sum(int(x) * 60 ** i for i, x in enumerate(reversed(stringt.split(":"))))
265 |
266 |
267 | @Client.on_message(filters.command("saavn") & ~filters.edited)
268 | async def jssong(_, message):
269 | global is_downloading
270 | if len(message.command) < 2:
271 | await message.reply_text("/saavn requires an argument.")
272 | return
273 | if is_downloading:
274 | await message.reply_text(
275 | "Another download is in progress, try again after sometime."
276 | )
277 | return
278 | is_downloading = True
279 | text = message.text.split(None, 1)[1]
280 | query = text.replace(" ", "%20")
281 | m = await message.reply_text("Searching...")
282 | try:
283 | songs = await arq.saavn(query)
284 | if not songs.ok:
285 | await message.reply_text(songs.result)
286 | return
287 | sname = songs.result[0].song
288 | slink = songs.result[0].media_url
289 | ssingers = songs.result[0].singers
290 | await m.edit("Downloading")
291 | song = await download_song(slink)
292 | await m.edit("Uploading")
293 | await message.reply_audio(audio=song, title=sname, performer=ssingers)
294 | os.remove(song)
295 | await m.delete()
296 | except Exception as e:
297 | is_downloading = False
298 | await m.edit(str(e))
299 | return
300 | is_downloading = False
301 |
302 |
303 | # Deezer Music
304 |
305 |
306 | @Client.on_message(filters.command("deezer") & ~filters.edited)
307 | async def deezsong(_, message):
308 | global is_downloading
309 | if len(message.command) < 2:
310 | await message.reply_text("/deezer requires an argument.")
311 | return
312 | if is_downloading:
313 | await message.reply_text(
314 | "Another download is in progress, try again after sometime."
315 | )
316 | return
317 | is_downloading = True
318 | text = message.text.split(None, 1)[1]
319 | query = text.replace(" ", "%20")
320 | m = await message.reply_text("Searching...")
321 | try:
322 | songs = await arq.deezer(query, 1)
323 | if not songs.ok:
324 | await message.reply_text(songs.result)
325 | return
326 | title = songs.result[0].title
327 | url = songs.result[0].url
328 | artist = songs.result[0].artist
329 | await m.edit("Downloading")
330 | song = await download_song(url)
331 | await m.edit("Uploading")
332 | await message.reply_audio(audio=song, title=title, performer=artist)
333 | os.remove(song)
334 | await m.delete()
335 | except Exception as e:
336 | is_downloading = False
337 | await m.edit(str(e))
338 | return
339 | is_downloading = False
340 |
341 |
342 | @Client.on_message(filters.command(["vsong", "video"]))
343 | async def ytmusic(client, message: Message):
344 | global is_downloading
345 | if is_downloading:
346 | await message.reply_text(
347 | "Another download is in progress, try again after sometime."
348 | )
349 | return
350 |
351 | urlissed = get_text(message)
352 |
353 | pablo = await client.send_message(
354 | message.chat.id, f"`Getting {urlissed} From Youtube Servers. Please Wait.`"
355 | )
356 | if not urlissed:
357 | await pablo.edit("Invalid Command Syntax, Please Check Help Menu To Know More!")
358 | return
359 |
360 | search = SearchVideos(f"{urlissed}", offset=1, mode="dict", max_results=1)
361 | mi = search.result()
362 | mio = mi["search_result"]
363 | mo = mio[0]["link"]
364 | thum = mio[0]["title"]
365 | fridayz = mio[0]["id"]
366 | thums = mio[0]["channel"]
367 | kekme = f"https://img.youtube.com/vi/{fridayz}/hqdefault.jpg"
368 | await asyncio.sleep(0.6)
369 | url = mo
370 | sedlyf = wget.download(kekme)
371 | opts = {
372 | "format": "best",
373 | "addmetadata": True,
374 | "key": "FFmpegMetadata",
375 | "prefer_ffmpeg": True,
376 | "geo_bypass": True,
377 | "nocheckcertificate": True,
378 | "postprocessors": [{"key": "FFmpegVideoConvertor", "preferedformat": "mp4"}],
379 | "outtmpl": "%(id)s.mp4",
380 | "logtostderr": False,
381 | "quiet": True,
382 | }
383 | try:
384 | is_downloading = True
385 | with youtube_dl.YoutubeDL(opts) as ytdl:
386 | infoo = ytdl.extract_info(url, False)
387 | duration = round(infoo["duration"] / 60)
388 |
389 | if duration > DURATION_LIMIT:
390 | await pablo.edit(
391 | f"❌ Videos longer than {DURATION_LIMIT} minute(s) aren't allowed, the provided video is {duration} minute(s)"
392 | )
393 | is_downloading = False
394 | return
395 | ytdl_data = ytdl.extract_info(url, download=True)
396 |
397 | except Exception:
398 | # await pablo.edit(event, f"**Failed To Download** \n**Error :** `{str(e)}`")
399 | is_downloading = False
400 | return
401 |
402 | c_time = time.time()
403 | file_stark = f"{ytdl_data['id']}.mp4"
404 | capy = f"**Video Name ➠** `{thum}` \n**Requested For :** `{urlissed}` \n**Channel :** `{thums}` \n**Link :** `{mo}`"
405 | await client.send_video(
406 | message.chat.id,
407 | video=open(file_stark, "rb"),
408 | duration=int(ytdl_data["duration"]),
409 | file_name=str(ytdl_data["title"]),
410 | thumb=sedlyf,
411 | caption=capy,
412 | supports_streaming=True,
413 | progress=progress,
414 | progress_args=(
415 | pablo,
416 | c_time,
417 | f"`Uploading {urlissed} Song From YouTube Music!`",
418 | file_stark,
419 | ),
420 | )
421 | await pablo.delete()
422 | is_downloading = False
423 | for files in (sedlyf, file_stark):
424 | if files and os.path.exists(files):
425 | os.remove(files)
426 |
--------------------------------------------------------------------------------
/GeezProject/modules/userbotjoin.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from pyrogram import Client, filters
19 | from pyrogram.errors import UserAlreadyParticipant
20 | import asyncio
21 | from GeezProject.helpers.decorators import authorized_users_only, errors
22 | from GeezProject.services.callsmusic.callsmusic import client as USER
23 | from GeezProject.config import SUDO_USERS
24 |
25 |
26 | @Client.on_message(filters.command(["userbotjoin"]) & ~filters.private & ~filters.bot)
27 | @authorized_users_only
28 | @errors
29 | async def addchannel(client, message):
30 | chid = message.chat.id
31 | try:
32 | invitelink = await client.export_chat_invite_link(chid)
33 | except:
34 | await message.reply_text(
35 | "Add me as admin of yor group first",
36 | )
37 | return
38 |
39 | try:
40 | user = await USER.get_me()
41 | except:
42 | user.first_name = "DaisyMusic"
43 |
44 | try:
45 | await USER.join_chat(invitelink)
46 | await USER.send_message(message.chat.id, "I joined here as you requested")
47 | except UserAlreadyParticipant:
48 | await message.reply_text(
49 | "helper already in your chat",
50 | )
51 | except Exception as e:
52 | print(e)
53 | await message.reply_text(
54 | f"🛑 Flood Wait Error 🛑 \n User {user.first_name} couldn't join your group due to heavy join requests for userbot! Make sure user is not banned in group."
55 | "\n\nOr manually add Asisstant to your Group and try again",
56 | )
57 | return
58 | await message.reply_text(
59 | "helper userbot joined your chat",
60 | )
61 |
62 |
63 | @USER.on_message(filters.group & filters.command(["userbotleave"]))
64 | @authorized_users_only
65 | async def rem(USER, message):
66 | try:
67 | await USER.leave_chat(message.chat.id)
68 | except:
69 | await message.reply_text(
70 | f"User couldn't leave your group! May be floodwaits."
71 | "\n\nOr manually kick me from to your Group",
72 | )
73 | return
74 |
75 | @Client.on_message(filters.command(["userbotleaveall"]))
76 | async def bye(client, message):
77 | if message.from_user.id in SUDO_USERS:
78 | left=0
79 | failed=0
80 | lol = await message.reply("Assistant Leaving all chats")
81 | async for dialog in USER.iter_dialogs():
82 | try:
83 | await USER.leave_chat(dialog.chat.id)
84 | left = left+1
85 | await lol.edit(f"Assistant leaving... Left: {left} chats. Failed: {failed} chats.")
86 | except:
87 | failed=failed+1
88 | await lol.edit(f"Assistant leaving... Left: {left} chats. Failed: {failed} chats.")
89 | await asyncio.sleep(0.7)
90 | await client.send_message(message.chat.id, f"Left {left} chats. Failed {failed} chats.")
91 |
92 |
93 | @Client.on_message(filters.command(["userbotjoinchannel","ubjoinc"]) & ~filters.private & ~filters.bot)
94 | @authorized_users_only
95 | @errors
96 | async def addcchannel(client, message):
97 | try:
98 | conchat = await client.get_chat(message.chat.id)
99 | conid = conchat.linked_chat.id
100 | chid = conid
101 | except:
102 | await message.reply("Is chat even linked")
103 | return
104 | chat_id = chid
105 | try:
106 | invitelink = await client.export_chat_invite_link(chid)
107 | except:
108 | await message.reply_text(
109 | "Add me as admin of yor channel first",
110 | )
111 | return
112 |
113 | try:
114 | user = await USER.get_me()
115 | except:
116 | user.first_name = "GeezProject"
117 |
118 | try:
119 | await USER.join_chat(invitelink)
120 | await USER.send_message(message.chat.id, "I joined here as you requested")
121 | except UserAlreadyParticipant:
122 | await message.reply_text(
123 | "helper already in your channel",
124 | )
125 | return
126 | except Exception as e:
127 | print(e)
128 | await message.reply_text(
129 | f"🛑 Flood Wait Error 🛑 \n User {user.first_name} couldn't join your channel due to heavy join requests for userbot! Make sure user is not banned in channel."
130 | "\n\nOr manually add Assistant to your Group and try again",
131 | )
132 | return
133 | await message.reply_text(
134 | "helper userbot joined your channel",
135 | )
136 |
137 |
--------------------------------------------------------------------------------
/GeezProject/modules/ytsearch.py:
--------------------------------------------------------------------------------
1 | # Daisyxmusic (Telegram bot project )
2 | # Copyright (C) 2021 Inukaasith
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | # the logging things
19 | import logging
20 |
21 | from pyrogram import Client as app
22 | from pyrogram.types import Message
23 | from youtube_search import YoutubeSearch
24 |
25 | logging.basicConfig(
26 | level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
27 | )
28 | logger = logging.getLogger(__name__)
29 |
30 | import pyrogram
31 |
32 | logging.getLogger("pyrogram").setLevel(logging.WARNING)
33 |
34 |
35 | @app.on_message(pyrogram.filters.command(["search"]))
36 | async def ytsearch(_, message: Message):
37 | try:
38 | if len(message.command) < 2:
39 | await message.reply_text("/search needs an argument!")
40 | return
41 | query = message.text.split(None, 1)[1]
42 | m = await message.reply_text("Searching....")
43 | results = YoutubeSearch(query, max_results=4).to_dict()
44 | i = 0
45 | text = ""
46 | while i < 4:
47 | text += f"Title - {results[i]['title']}\n"
48 | text += f"Duration - {results[i]['duration']}\n"
49 | text += f"Views - {results[i]['views']}\n"
50 | text += f"Channel - {results[i]['channel']}\n"
51 | text += f"https://youtube.com{results[i]['url_suffix']}\n\n"
52 | i += 1
53 | await m.edit(text, disable_web_page_preview=True)
54 | except Exception as e:
55 | await message.reply_text(str(e))
56 |
--------------------------------------------------------------------------------
/GeezProject/services/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/GeezProject/services/callsmusic/__init__.py:
--------------------------------------------------------------------------------
1 | from GeezProject.services.queues import queues
2 | from GeezProject.services.callsmusic.callsmusic import pytgcalls, run
3 |
4 | __all__ = ["queues", "pytgcalls", "run"]
5 |
--------------------------------------------------------------------------------
/GeezProject/services/callsmusic/callsmusic.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from pyrogram import Client
19 | from pytgcalls import PyTgCalls
20 |
21 | from GeezProject.config import API_HASH, API_ID, SESSION_NAME
22 | from GeezProject.services.queues import queues
23 |
24 | client = Client(SESSION_NAME, API_ID, API_HASH)
25 | pytgcalls = PyTgCalls(client)
26 |
27 |
28 | @pytgcalls.on_stream_end()
29 | def on_stream_end(chat_id: int) -> None:
30 | queues.task_done(chat_id)
31 |
32 | if queues.is_empty(chat_id):
33 | pytgcalls.leave_group_call(chat_id)
34 | else:
35 | pytgcalls.change_stream(chat_id, queues.get(chat_id)["file"])
36 |
37 |
38 | run = pytgcalls.run
39 |
--------------------------------------------------------------------------------
/GeezProject/services/converter/__init__.py:
--------------------------------------------------------------------------------
1 | from os import listdir, mkdir
2 |
3 | if "raw_files" not in listdir():
4 | mkdir("raw_files")
5 |
6 | from GeezProject.services.converter.converter import convert
7 |
8 | __all__ = ["convert"]
9 |
--------------------------------------------------------------------------------
/GeezProject/services/converter/converter.py:
--------------------------------------------------------------------------------
1 | # Calls Music 1 - Telegram bot for streaming audio in group calls
2 | # Copyright (C) 2021 Roj Serbest
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Affero General Public License as
6 | # published by the Free Software Foundation, either version 3 of the
7 | # License, or (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU Affero General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Affero General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | import asyncio
19 | from os import path
20 |
21 | from GeezProject.helpers.errors import FFmpegReturnCodeError
22 |
23 |
24 | async def convert(file_path: str) -> str:
25 | out = path.basename(file_path)
26 | out = out.split(".")
27 | out[-1] = "raw"
28 | out = ".".join(out)
29 | out = path.basename(out)
30 | out = path.join("raw_files", out)
31 |
32 | if path.isfile(out):
33 | return out
34 | try:
35 | proc = await asyncio.create_subprocess_shell(
36 | f"ffmpeg -y -i {file_path} -f s16le -ac 1 -ar 48000 -acodec pcm_s16le {out}",
37 | asyncio.subprocess.PIPE,
38 | stderr=asyncio.subprocess.PIPE,
39 | )
40 |
41 | await proc.communicate()
42 |
43 | if proc.returncode != 0:
44 | raise FFmpegReturnCodeError("FFmpeg did not return 0")
45 |
46 | return out
47 | except:
48 | raise FFmpegReturnCodeError("FFmpeg did not return 0")
49 |
--------------------------------------------------------------------------------
/GeezProject/services/downloaders/__init__.py:
--------------------------------------------------------------------------------
1 | from GeezProject.services.downloaders import youtube
2 |
3 | __all__ = ["youtube"]
4 |
--------------------------------------------------------------------------------
/GeezProject/services/downloaders/youtube.py:
--------------------------------------------------------------------------------
1 | from os import path
2 |
3 | from youtube_dl import YoutubeDL
4 |
5 | from GeezProject.config import DURATION_LIMIT
6 | from GeezProject.helpers.errors import DurationLimitError
7 |
8 | ydl_opts = {
9 | "format": "bestaudio/best",
10 | "verbose": True,
11 | "geo-bypass": True,
12 | "nocheckcertificate": True,
13 | "outtmpl": "downloads/%(id)s.%(ext)s",
14 | }
15 |
16 | ydl = YoutubeDL(ydl_opts)
17 |
18 |
19 | def download(url: str) -> str:
20 | info = ydl.extract_info(url, False)
21 | duration = round(info["duration"] / 120)
22 |
23 | if duration > DURATION_LIMIT:
24 | raise DurationLimitError(
25 | f"🛑 Videos longer than {DURATION_LIMIT} minute(s) aren't allowed, the provided video is {duration} minute(s)"
26 | )
27 | try:
28 | ydl.download([url])
29 | except:
30 | raise DurationLimitError(
31 | f"🛑 Videos longer than {DURATION_LIMIT} minute(s) aren't allowed, the provided video is {duration} minute(s)"
32 | )
33 | return path.join("downloads", f"{info['id']}.{info['ext']}")
34 |
--------------------------------------------------------------------------------
/GeezProject/services/queues/__init__.py:
--------------------------------------------------------------------------------
1 | from GeezProject.services.queues.queues import clear, get, is_empty, put, task_done
2 |
3 | __all__ = ["clear", "get", "is_empty", "put", "task_done"]
4 |
--------------------------------------------------------------------------------
/GeezProject/services/queues/queues.py:
--------------------------------------------------------------------------------
1 | from asyncio import Queue
2 | from asyncio import QueueEmpty as Empty
3 | from typing import Dict
4 |
5 |
6 | queues: Dict[int, Queue] = {}
7 |
8 |
9 | async def put(chat_id: int, **kwargs) -> int:
10 | if chat_id not in queues:
11 | queues[chat_id] = Queue()
12 | await queues[chat_id].put({**kwargs})
13 | return queues[chat_id].qsize()
14 |
15 |
16 | def get(chat_id: int) -> Dict[str, str]:
17 | if chat_id in queues:
18 | try:
19 | return queues[chat_id].get_nowait()
20 | except Empty:
21 | return None
22 |
23 |
24 | def is_empty(chat_id: int) -> bool:
25 | if chat_id in queues:
26 | return queues[chat_id].empty()
27 | return True
28 |
29 |
30 | def task_done(chat_id: int):
31 | if chat_id in queues:
32 | try:
33 | queues[chat_id].task_done()
34 | except ValueError:
35 | pass
36 |
37 |
38 | def clear(chat_id: int):
39 | if chat_id in queues:
40 | if queues[chat_id].empty():
41 | raise Empty
42 | else:
43 | queues[chat_id].queue = []
44 | raise Empty
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
🎵 Geez Music Projects 🎵
2 |
3 | ### A bot that can play music on Telegram Group and Channel Voice Chats
4 | #### POWERED BY [PYTGCALLS](https://github.com/pytgcalls/pytgcalls)
5 | ### Available on telegram as [@GeezMusicBot](https://t.me/GeezMusicBot)
6 |
7 |
8 |
9 |
10 |
Features
11 |
12 | - Thumbnail Support
13 | - Playlist Support
14 | - Current playback support
15 | - Showing track names when skipping
16 | - Zero downtime, Fully Stable
17 | - Deezer,Youtube & Saavn playback support
18 | - Settings panel
19 | - Control with buttons
20 | - Userbot auto join
21 |
22 | ## 🚀 Deployment
23 |
24 | ### ⚔ Self-hosting (For Devs)
25 | ```sh
26 | # Install Git First (apt-instll git)
27 | $ git clone https://github.com/vckyou/Geez-MusicProject
28 | $ cd Geez-MusicProject
29 | # Upgrade sources
30 | # Install All Requirements
31 | $ pip(3) install -r requirements.txt
32 | # Rename example.env to local.env and fill
33 | $ npm i -g npm
34 | # Start Bot
35 | $ python(3) -m GeezProject
36 | ```
37 |
38 | ### 💜 Heroku
39 |
40 | # CLOSED DEPLOY!!!
41 |
42 | Get pyrogram (p) `SESSION` from here:
43 | [](https://repl.it/@vckyou/PyrogramString?lite=1&outputonly=1)
44 |
45 | ### Commands for Group 🛠
46 | #### For all in group
47 |
48 | - `/playlist` - Show now playing list
49 | - `/current` - Show now playing
50 | - `/song ` - download songs you want quickly
51 | - `/search ` - search videos on youtube with details
52 | - `/deezer ` - download songs you want quickly via deezer
53 | - `/saavn ` - download songs you want quickly via saavn
54 | - `/video ` - download videos you want quickly
55 |
56 | #### Admins only.
57 | - `/play ` - play song you requested
58 | - `/play ` - play replied file
59 | - `/dplay ` - play song you requested via deezer
60 | - `/splay ` - play song you requested via jio saavn
61 | - `/player` - open music player settings panel
62 | - `/pause` - pause song play
63 | - `/resume` - resume song play
64 | - `/skip` - play next song
65 | - `/end` - stop music play
66 | - `/userbotjoin` - invite assistant to your chat
67 | - `/userbotleave` - remove assistant from your chat
68 | - `/admincache` - Refresh admin list
69 |
70 |
71 | #### Pmpermit
72 | - `.yes` - approove someone to pm you
73 | - `.no` - disapproove someone to pm you
74 | + Sudo Users can execute any command in any groups
75 |
76 | ### Credits
77 | Don't edit this part
78 |
79 | #### Special Credits
80 | - [Rojserbest](http://github.com/rojserbes): Callsmusic Developer
81 |
82 | This bot is based on the original work done by [Rojserbest](http://github.com/rojserbest). Without his hardwork Geez Music won't exist.
83 | Geez-Project is a modified version of [Callsmusic](https://github.com/callsmusic/callsmusic)
84 |
85 | #### Contribtors
86 | - [Vicky](https://github.com/Vckyou): Dev
87 | - [InukaASiTH](https://github.com/InukaAsith): Dev
88 | - [Rojserbest](http://github.com/rojserbes): Dev
89 | - [Wrench](https://github.com/EverythingSuckz/): Dev
90 | - [QueenArzoo](https://github.com/QueenArzoo): Dev
91 | - [lucifeermorningstar](https://github.com/lucifeermorningstar): Dev
92 | - [AuraXNetwork](https://github.com/AuraXNetwork/AuraXMusicBot)
93 | - [Hamker Cat](https://github.com/thehamkercat/)
94 | - [Anjana-Ma](https://github.com/Anjana-Ma):
95 | - [ImJanindu](https://github.com/ImJanindu):
96 | - [Laky](https://github.com/Laky-64) & [Andrew](https://github.com/AndrewLaneX): PyTgCalls
97 | - [Original Repo owners](https://github.com/suprojects/CallsMusic)
98 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Geez Music",
3 | "description": "Open-Source bot to play songs in your Telegram's Group Voice Chat. Powered by PyTgCalls.",
4 | "keywords": ["music", "voicechat", "telegram"],
5 | "repository": "https://github.com/vckyou/Geez-MusicProject",
6 | "stack": "container",
7 | "buildpacks": [
8 | {
9 | "url": "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest"
10 | }
11 | ],
12 | "env": {
13 | "SESSION_NAME": {
14 | "description": "Masukan String Session Pyrogram (P) untuk assistant yang naik ke VCG",
15 | "required": true
16 | },
17 | "BOT_TOKEN": {
18 | "description": "Masukan Bot Token dari @BotFather",
19 | "required": true
20 | },
21 | "BOT_USERNAME": {
22 | "description": "Username bot Anda tanpa @",
23 | "required": true
24 | },
25 | "BOT_NAME": {
26 | "description": "Nama Bot MusicPlayer Anda.",
27 | "required": false,
28 | "value": ""
29 | },
30 | "SUPPORT_GROUP": {
31 | "description": "Grup dukungan MusicPlayer Anda Tanpa Menggunakan ==> @ <== [skip ini jika Anda tidak punya]",
32 | "required": false,
33 | "value": "GeezSupportGroup"
34 | },
35 | "UPDATES_CHANNEL": {
36 | "description": "Updates Channel @ [skip ini jika Anda tidak punya]",
37 | "required": false,
38 | "value": "GeezProjects"
39 | },
40 | "PROJECT_NAME": {
41 | "description": "Nama proyek MusicPlayer Anda.",
42 | "required": false,
43 | "value": "Geez Projects"
44 | },
45 | "ASSISTANT_NAME": {
46 | "description": "Username Telegram asisten Music Player Anda tanpa @.",
47 | "required": true
48 | },
49 | "OWNER": {
50 | "description": "Masukan Nama atau Username Telegram",
51 | "required": true
52 | },
53 | "ARQ_API_KEY": {
54 | "description": "Ambil api dari bot telegram » t.me/ARQRobot atau @ARQRobot",
55 | "required": true
56 | },
57 | "BG_IMAGE": {
58 | "description": "Custom Background Play Musik Gunakan Foto yang Transparant format .png / .jpg",
59 | "required": false,
60 | "value": "https://telegra.ph/file/7de6a24af6cfc049a9316.png"
61 | },
62 | "API_ID": {
63 | "description": "Masukan APP ID Silahkan Ambil dari my.telegram.org/apps atau t.me/scrapmanbot",
64 | "required": true
65 | },
66 | "API_HASH": {
67 | "description": "Masukan API HASH Silahkan Ambil dari my.telegram.org/apps atau t.me/scrapmanbot",
68 | "required": true
69 | },
70 | "PMPERMIT": {
71 | "description": "Ubah untuk mematikan PMPERMIT",
72 | "required": false,
73 | "value": "ENABLE"
74 | },
75 | "SUDO_USERS": {
76 | "description": "Daftar User ID Telegram pengguna dihitung sebagai admin di semua tempat (pemisah menggunakan space)",
77 | "required": true
78 | },
79 | "DURATION_LIMIT": {
80 | "description": "Batas durasi audio maksimal untuk download (minutes).",
81 | "required": true,
82 | "value": "15"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/etc/font.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vckyou/Geez-MusicProjectOld/3e7c0513c14b9aec22b3c1f60f0270c2a940e0a3/etc/font.otf
--------------------------------------------------------------------------------
/example.env:
--------------------------------------------------------------------------------
1 | SESSION_NAME=session # If you don't deploy with docker, keep it as is and if you do so it should be a session string generated by "python str.py"
2 | BOT_TOKEN=123456:abcdefghijklmnopqrstuv
3 | BOT_NAME=HELLBOT
4 | API_ID=123456
5 | API_HASH=abcdefghijklmnopqrstuv
6 | SUDO_USERS=1111 2222 # List of user IDs separated by space
7 | DURATION_LIMIT=10 # in minutes (default: 7)
8 | ARQ_API_KEY=
9 | UPDATES_CHANNEL=Vckyouuu
10 | BG_IMAGE=https://telegra.ph/file/fa2cdb8a14a26950da711.png
11 |
12 |
--------------------------------------------------------------------------------
/heroku.yml:
--------------------------------------------------------------------------------
1 | build:
2 | docker:
3 | worker: Dockerfile
4 | run:
5 | worker: python3 -m GeezProject
6 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyrogram
2 | tgcrypto
3 | py-tgcalls==0.5.5
4 | python-dotenv
5 | youtube_dl
6 | youtube_search_python
7 | requests
8 | aiohttp
9 | aiofiles
10 | asyncio
11 | youtube_search
12 | search_engine_parser
13 | ffmpeg
14 | Pillow
15 | python-arq
16 | future
17 | psutil
18 | wget
19 |
--------------------------------------------------------------------------------
/str.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | from pyrogram import Client
4 |
5 | print("Enter your app information from my.telegram.org/apps below.")
6 |
7 |
8 | async def main():
9 | async with Client(
10 | ":memory:", api_id=int(input("API ID:")), api_hash=input("API HASH:")
11 | ) as app:
12 | print(await app.export_session_string())
13 |
14 |
15 | if __name__ == "__main__":
16 | loop = asyncio.get_event_loop()
17 | loop.run_until_complete(main())
18 |
--------------------------------------------------------------------------------