diff --git a/.env.example b/.env.example index 4ea22d5..8a442cc 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,9 @@ API_ID=123456 API_HASH="123456789abcdef" +MYSQL_ROOT_PASSWORD=1234abcd +MYSQL_DATABASE=telemovris +MYSQL_USER=telemovris +MYSQL_PASSWORD=abcd1234 +MYSQL_HOST="telemovris_db" +REQUEST_URL="telemovris_web" +REQUEST_PORT=8000 #use docker internal port, not the exposed one \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 811b4ef..9fef8bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,4 +10,38 @@ services: - ./data:/data environment: - API_ID=${API_ID} - - API_HASH=${API_HASH} \ No newline at end of file + - API_HASH=${API_HASH} + - REQUEST_URL=${REQUEST_URL} + - REQUEST_PORT=${REQUEST_PORT} + + telemovris_db: + image: mysql:8 + container_name: telemovris_db + volumes: + - ./db:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + restart: unless-stopped + + telemovris_adminer: + image: adminer + container_name: telemovris_adminer + restart: unless-stopped + ports: + - 8558:8080 + + telemovris_web: + build: telemovris_web + image: telemovris_web:latest + container_name: telemovris_web + restart: unless-stopped + ports: + - 8777:8000 + environment: + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - MYSQL_HOST=${MYSQL_HOST} \ No newline at end of file diff --git a/telemovris/Dockerfile b/telemovris/Dockerfile index 84ea5bb..6af8ce7 100644 --- a/telemovris/Dockerfile +++ b/telemovris/Dockerfile @@ -4,8 +4,11 @@ RUN apt update RUN apt install ffmpeg make cmake gcc g++ python3-dev gcc g++ openssl libssl-dev libopus0 libopus-dev -y RUN mkdir /app ADD requirements.txt /app -ADD *.py /app/ RUN pip install -r /app/requirements.txt +#ADD tgvoip_pyrogram /install/tgvoip_pyrogram +#WORKDIR /install/tgvoip_pyrogram +#RUN python3 setup.py install +ADD *.py /app/ WORKDIR /app diff --git a/telemovris/requirements.txt b/telemovris/requirements.txt index 0c4b3e3..93b783e 100644 --- a/telemovris/requirements.txt +++ b/telemovris/requirements.txt @@ -2,4 +2,5 @@ Pyrogram==1.4.0 TgCrypto==1.2.5 pytgvoip==0.0.7.1 pytgvoip-pyrogram==0.0.11 -gTTS==2.3.2 \ No newline at end of file +gTTS==2.3.2 +mysql-connector-python==8.0.32 \ No newline at end of file diff --git a/telemovris/telemovris.py b/telemovris/telemovris.py index 3d94a02..2228be3 100644 --- a/telemovris/telemovris.py +++ b/telemovris/telemovris.py @@ -1,12 +1,23 @@ import asyncio import os import pyrogram +import logging +import time +import subprocess +import re +import requests +import json from hashlib import md5 from gtts import gTTS -from tgvoip import VoIPServerConfig +from tgvoip import VoIPServerConfig, CallState from tgvoip_pyrogram import VoIPFileStreamService +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO +) + +logger = logging.getLogger(__name__) client = pyrogram.Client(os.environ.get('SESSION_NAME', '/data/telemovris'), api_hash=os.environ.get('API_HASH'), @@ -17,29 +28,73 @@ VoIPServerConfig.set_bitrate_config(80000, 100000, 60000, 5000, 5000) loop = asyncio.get_event_loop() voip_service = VoIPFileStreamService(client, receive_calls=False) -@client.on_message(pyrogram.filters.command('callme')) -async def callme(cl, message: pyrogram.types.Message): +request_url = os.environ.get("REQUEST_URL") +request_port = os.environ.get("REQUEST_PORT") + +def get_audio_duration(location: str) -> float: + args = ("ffprobe", "-show_entries", "format=duration", "-i", location) + popen = subprocess.Popen(args, stdout=subprocess.PIPE) + popen.wait() + output = popen.stdout.read() + r = re.findall(r'(?<=duration=)(.*)(?=\\n\[/F)', str(output)) + return float(r[0]) + +def generate_audio(message_text): + audio_name = md5(message_text.encode('utf-8')).hexdigest() + if not os.path.isfile(f"/data/audio/{audio_name}.raw"): + logging.info(f"Audio {audio_name} not found, generating") + tts = gTTS(text=message_text, lang="es") + tts.save(f"/data/audio/{audio_name}.wav") + os.system(f"ffmpeg -i /data/audio/{audio_name}.wav -f s16le -ac 1 -ar 48000 -acodec pcm_s16le /data/audio/{audio_name}.raw") + else: + logging.info(f"Audio {audio_name} found") + + return audio_name, get_audio_duration(f"/data/audio/{audio_name}.wav") + +async def main(user, message_text, audio): + async with client: + audio_name, audio_duration = generate_audio(message_text) + + logging.info(f"Calling {user}") + call = await voip_service.start_call(user) + await client.send_message(user, message_text) + if audio: + call.play(f"/data/audio/{audio_name}.raw") + call_has_ended = False + + @call.on_call_state_changed + def state_changed(call, state): + print(f'State changed: {state}') + + @call.on_call_ended + async def call_ended(call): + global call_has_ended + call_has_ended = True + + t1 = time.perf_counter() + while True: + t2 = time.perf_counter() + await asyncio.sleep(1) + try: + logging.info(call.ctrl.call_duration) + if call.ctrl.call_duration > audio_duration or call_has_ended or (call.state == CallState.WAITING and int(t2-t1) > 25): + await call.discard_call() + break + except: + break + +while True: + time.sleep(5) try: - message_text = message.text.split('/callme ')[1] - audio_name = md5(message_text.encode('utf-8')).hexdigest() - - if not os.path.isfile(f"/data/audio/{audio_name}.raw"): - tts = gTTS(text=message_text, lang="es") - tts.save(f"/data/audio/{audio_name}.wav") - os.system(f"ffmpeg -i /data/audio/{audio_name}.wav -f s16le -ac 1 -ar 48000 -acodec pcm_s16le /data/audio/{audio_name}.raw") - - await client.send_message(message.from_user.id, f"Llamando con el texto: {message_text}") - call = await voip_service.start_call(message.from_user.id) - call.play(f"/data/audio/{audio_name}.raw") - #call.set_output_file(f'/data/audio/{audio_name}_output.raw') - except: - await client.send_message(message.from_user.id, 'No se ha detectado ningĂșn texto despuĂ©s del comando') - -async def main(): - await client.start() - print(await client.export_session_string()) - await pyrogram.idle() - -loop.run_until_complete(main()) - - + logging.info("Checking for new messages...") + response = requests.get(f"http://{request_url}:{request_port}/getmessage") + if response.content != '': + response_json = json.loads(response.content) + user = response_json[1] + message = response_json[2] + audio = response_json[3] + logging.info(f"Calling {user}") + loop.run_until_complete(main(f"@{user}", message, audio)) + logging.info("Call finished") + except Exception as e: + logging.info(f"Error: {e}") \ No newline at end of file diff --git a/telemovris_web/Dockerfile b/telemovris_web/Dockerfile new file mode 100644 index 0000000..4f11eee --- /dev/null +++ b/telemovris_web/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.9 + +RUN mkdir /app +ADD requirements.txt /app +RUN pip install -r /app/requirements.txt +ADD *.py /app/ + +WORKDIR /app + +ENV FLASK_APP app.py +ENV FLASK_ENV development +ENV FLASK_RUN_PORT 8000 +ENV FLASK_RUN_HOST 0.0.0.0 + +EXPOSE 8000 + +CMD ["flask", "run"] \ No newline at end of file diff --git a/telemovris_web/app.py b/telemovris_web/app.py new file mode 100644 index 0000000..8e031b9 --- /dev/null +++ b/telemovris_web/app.py @@ -0,0 +1,80 @@ +import os +from flask import Flask, request +import mysql.connector +import logging +import json + +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO +) + +logger = logging.getLogger(__name__) + + +def connect_db(): + db = mysql.connector.connect( + host = os.environ.get("MYSQL_HOST"), + user = os.environ.get("MYSQL_USER"), + password = os.environ.get("MYSQL_PASSWORD"), + database = os.environ.get("MYSQL_DATABASE") + ) + return db + +def populate_db(): + con = connect_db() + cur = con.cursor(prepared=True) + cur.execute('CREATE TABLE IF NOT EXISTS messages (id INT AUTO_INCREMENT PRIMARY KEY, user VARCHAR(255), message VARCHAR(255), audio BOOLEAN, processed BOOLEAN)') + con.commit() + con.close() + +def query_messages(): + con = connect_db() + cur = con.cursor(prepared=True) + cur.execute('SELECT id, user, message, audio FROM messages WHERE processed IS false LIMIT 1') + ret = cur.fetchall() + con.close() + return ret + +def insert_message(user, message, audio): + con = connect_db() + cur = con.cursor(prepared=True) + params = (user, message, audio) + cur.execute('INSERT INTO messages (user, message, audio, processed) VALUES (%s, %s, %s, 0)', params) + con.commit() + con.close() + +def update_message(id): + con = connect_db() + cur = con.cursor(prepared=True) + cur.execute(f'UPDATE messages SET processed = true WHERE id = {id}') + con.commit() + con.close() + +server = Flask(__name__) + +@server.route('/getmessage') +def getmessage(): + rec = query_messages() + + try: + update_message(rec[0][0]) + return json.dumps(rec[0]) + except Exception as e: + logging.info(f"Error: {e}") + return '' + +@server.route('/sendmessage', methods=['GET']) +def sendmessage(): + user = request.args.get('user') + message = request.args.get('message') + audio = request.args.get('audio') + + try: + insert_message(user, message, audio) + return f"Inserted {user} - {message} - {audio}" + except Exception as e: + logging.info(f"Error: {e}") + return '' + +if __name__ == '__main__': + server.run() \ No newline at end of file diff --git a/telemovris_web/requirements.txt b/telemovris_web/requirements.txt new file mode 100644 index 0000000..252f07d --- /dev/null +++ b/telemovris_web/requirements.txt @@ -0,0 +1,2 @@ +Flask==2.0.1 +mysql-connector-python==8.0.32 \ No newline at end of file