├── LICENSE ├── README.md ├── requirements.txt └── telegram_downloader ├── config.py ├── downloader.py ├── main.py └── utils.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 nascimento anderson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram Downloader 2 | 3 | Este projeto permite baixar mensagens de chats do Telegram, incluindo mídias, arquivos e textos, organizando-os em pastas. Ele também suporta a coleta de metadados das mensagens. 4 | 5 | ## Ferramentas e Bibliotecas 6 | 7 | ![Visual Studio Code](https://img.shields.io/badge/Visual%20Studio%20Code-0078d7.svg?style=for-the-badge&logo=visual-studio-code&logoColor=white) 8 | ![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54) 9 | ![Git](https://img.shields.io/badge/git-%23F05033.svg?style=for-the-badge&logo=git&logoColor=white) 10 | ![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white) 11 | ![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black) 12 | 13 | 14 | * [VSCode](https://code.visualstudio.com/download) - Editor de Código 15 | * [Python](https://www.python.org/downloads/) - Instalador do Python 16 | * [telethon 1.24.0](https://pypi.org/project/Telethon/) - Biblioteca 17 | * [Git](https://git-scm.com/downloads) - Gerenciador de Versões 18 | 19 | ## Estrutura do Projeto 20 | 21 | - `telegram_downloader/`: Diretório principal com o código fonte. 22 | - `config.py`: Configurações de API e sessão. 23 | - `downloader.py`: Funções principais para baixar mensagens e mídias. 24 | - `utils.py`: Funções utilitárias para manipulação de arquivos. 25 | - `main.py`: Script principal para executar o projeto. 26 | - `requirements.txt`: Dependências do projeto. 27 | - `README.md`: Documentação do projeto. 28 | 29 | ## Instalação 30 | 31 | 1. Clone o repositório: 32 | 33 | ```bash 34 | git clone https://github.com/andiimdevlp/telegram-downloader.git 35 | cd telegram-downloader 36 | ``` 37 | 38 | 2. Crie e ative um ambiente virtual: 39 | 40 | ```bash 41 | python -m venv venv 42 | ``` 43 | 44 | Ative o ambiente virtual: 45 | 46 | ```bash 47 | # No Linux/MacOS: 48 | source venv/bin/activate 49 | 50 | # No Windows: 51 | venv\Scripts\activate 52 | ``` 53 | 54 | 3. Instale as dependências: 55 | 56 | ```bash 57 | pip install -r requirements.txt 58 | ``` 59 | 60 | 4. Configure suas credenciais do Telegram: 61 | - Abra o arquivo telegram_downloader/config.py. 62 | - Insira seu `API_ID` e `API_HASH`, obtidos no [My Telegram](https://my.telegram.org/auth). 63 | 64 | ## Uso 65 | 1. Inicie o script principal: 66 | 67 | ```bash 68 | python -m telegram_downloader.main 69 | ``` 70 | 2. Após iniciar o script, todos os chats serão listados e salvos no arquivo `listagem_chats.txt`. Use essa listagem para escolher o ID do chat que deseja baixar. 71 | 72 | 3. Digite o `chat_id` desejado quando solicitado. 73 | 74 | - Se o chat for um fórum, você será solicitado a inserir o ID do tópico específico para baixar as mensagens. 75 | 4. O script coletará os metadados e fará o download das mensagens do chat. 76 | 77 | ## Estrutura de Pastas 78 | 79 | As mensagens e mídias baixadas serão organizadas em uma pasta que utiliza o nome do chat como base. Dentro dessa pasta, arquivos de texto e mídias estarão nomeados de acordo com o ID da mensagem para garantir unicidade. 80 | 81 | ## Exemplo de Estrutura de Pastas 82 | 83 | ```bash 84 | telegram_downloader/ 85 | │ 86 | ├── metadados_Plataforma_Cafeina.json 87 | ├── plano_download_Plataforma_Cafeina.json 88 | ├── Plataforma_Cafeina/ 89 | │ ├── Plataforma_Cafeina_mensagens_texto.json 90 | │ ├── 123457_imagem.jpg 91 | │ └── 123458_video.mp4 92 | └── listagem_chats.txt 93 | ``` 94 | 95 | ## Contribuindo 96 | 97 | Contribuições são bem-vindas! Sinta-se à vontade para abrir issues ou enviar pull requests. 98 | 99 | 1. Fork o repositório. 100 | 2. Crie sua branch (git checkout -b minha-branch). 101 | 3. Commit suas mudanças (git commit -am 'Minha nova funcionalidade'). 102 | 4. Envie para o branch (git push origin minha-branch). 103 | 5. Abra um Pull Request. 104 | 105 | ## Licença 106 | 107 | Este projeto está licenciado sob a Licença MIT. Veja o arquivo [LICENSE](https://choosealicense.com/licenses/mit/) para mais detalhes. 108 | 109 | 110 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | telethon 2 | -------------------------------------------------------------------------------- /telegram_downloader/config.py: -------------------------------------------------------------------------------- 1 | API_ID = 'API_ID' 2 | API_HASH = 'API_HASH' 3 | SESSION_NAME = 'telegram_download' 4 | -------------------------------------------------------------------------------- /telegram_downloader/downloader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | from telethon import TelegramClient 4 | from telethon.tl.types import Channel 5 | from .utils import nome_arquivo_seguro, salvar_json, carregar_json, criar_pasta_se_necessario 6 | from datetime import datetime 7 | 8 | class TelegramDownloader: 9 | def __init__(self, api_id, api_hash, session_name): 10 | self.client = TelegramClient(session_name, api_id, api_hash) 11 | self.contador = 10000 12 | 13 | async def coletar_metadados(self, chat_id, target_topic_id=None): 14 | """Coleta metadados das mensagens de um chat e salva em um arquivo JSON.""" 15 | try: 16 | chat_entity = await self.client.get_entity(chat_id) 17 | chat_titulo = chat_entity.title 18 | nome_seguro = nome_arquivo_seguro(chat_titulo) 19 | 20 | pasta_chat = os.path.join(os.getcwd(), nome_seguro) 21 | criar_pasta_se_necessario(pasta_chat) 22 | 23 | metadados = [] 24 | 25 | async for msg in self.client.iter_messages(chat_id): 26 | if target_topic_id and msg.reply_to_msg_id != target_topic_id: 27 | continue 28 | mensagem_info = { 29 | 'id': msg.id, 30 | 'data': msg.date.isoformat(), 31 | 'remetente': msg.sender_id, 32 | 'texto': msg.message if msg.message else '', 33 | 'tem_midia': bool(msg.media), 34 | 'media_tipo': None, 35 | 'media_tamanho': None 36 | } 37 | 38 | if msg.media: 39 | if hasattr(msg.media, 'document') and msg.media.document: 40 | mensagem_info['media_tipo'] = msg.media.document.mime_type 41 | mensagem_info['media_tamanho'] = msg.media.document.size 42 | elif hasattr(msg.media, 'photo') and msg.media.photo: 43 | mensagem_info['media_tipo'] = 'photo' 44 | mensagem_info['media_tamanho'] = 'Desconhecido' 45 | 46 | metadados.append(mensagem_info) 47 | 48 | salvar_json(metadados[::-1], os.path.join(pasta_chat, f'metadados_{nome_seguro}.json')) 49 | print(f'Metadados das mensagens do chat "{chat_titulo}" salvos com sucesso.') 50 | 51 | await self.baixar_todas_mensagens(chat_id, chat_titulo, pasta_chat, target_topic_id) 52 | 53 | except Exception as e: 54 | print(f"Erro ao coletar metadados do chat: {e}") 55 | 56 | async def baixar_todas_mensagens(self, chat_id, chat_titulo, pasta_chat, target_topic_id=None): 57 | """Baixa todas as mensagens do chat, verificando o plano de download para evitar downloads duplicados.""" 58 | metadados = carregar_json(os.path.join(pasta_chat, f'metadados_{nome_arquivo_seguro(chat_titulo)}.json')) 59 | plano = carregar_json(os.path.join(pasta_chat, f'plano_download_{nome_arquivo_seguro(chat_titulo)}.json')) 60 | ids_baixados = {msg['id'] for msg in plano} 61 | 62 | print(f"Baixando mensagens do chat: {chat_id}. Total de metadados: {len(metadados)}") 63 | 64 | mensagens_texto = [] 65 | 66 | for msg in metadados: 67 | if msg['id'] not in ids_baixados: 68 | try: 69 | mensagem_telegram = await self.client.get_messages(chat_id, ids=msg['id']) 70 | 71 | if mensagem_telegram.media: 72 | # Usar o nome original do arquivo, preservando o # 73 | arquivo_path = await mensagem_telegram.download_media(file=pasta_chat) 74 | nome_arquivo = f"{self.contador:05d} - {os.path.basename(arquivo_path)}" 75 | 76 | # Corrigir para permitir # e outros caracteres especiais 77 | destino_final = os.path.join(pasta_chat, nome_arquivo) 78 | 79 | os.rename(arquivo_path, destino_final) 80 | print(f'Mídia baixada: {destino_final}') 81 | 82 | if mensagem_telegram.message and not mensagem_telegram.media: 83 | mensagens_texto.append({ 84 | "id": msg['id'], 85 | "usuario": mensagem_telegram.sender_id, 86 | "datahora": mensagem_telegram.date.isoformat(), 87 | "mensagem": mensagem_telegram.message 88 | }) 89 | 90 | plano.append(msg) 91 | salvar_json(plano, os.path.join(pasta_chat, f'plano_download_{nome_arquivo_seguro(chat_titulo)}.json')) 92 | 93 | self.contador += 1 94 | 95 | except Exception as e: 96 | print(f"Erro ao baixar mensagem {msg['id']}: {e}") 97 | 98 | if mensagens_texto: 99 | nome_arquivo_texto = f"{nome_arquivo_seguro(chat_titulo)}_mensagens_texto.json" 100 | caminho_texto = os.path.join(pasta_chat, nome_arquivo_texto) 101 | salvar_json(mensagens_texto, caminho_texto) 102 | print(f'Mensagens de texto salvas em: {caminho_texto}') 103 | 104 | async def listar_chats(self): 105 | """Lista todos os chats e salva IDs em um arquivo txt.""" 106 | dialogs = await self.client.get_dialogs() 107 | with open('listagem_chats.txt', 'w', encoding='utf-8') as file: 108 | for dialog in dialogs: 109 | if dialog.is_group or dialog.is_channel: 110 | chat_id = dialog.entity.id 111 | chat_name = dialog.name 112 | file.write(f"Chat: {chat_name} (ID: {chat_id})\n") 113 | print(f"Chat: {chat_name} (ID: {chat_id})") 114 | 115 | async def verificar_chat_forum(self, chat_id): 116 | """Verifica se o chat é um fórum e solicita o ID do tópico, se necessário.""" 117 | try: 118 | entity = await self.client.get_entity(chat_id) 119 | if isinstance(entity, Channel) and entity.forum: 120 | topic_id = int(input(f"{entity.title} é um fórum. Digite o ID do tópico de origem: ")) 121 | return entity.title, topic_id 122 | else: 123 | return entity.title, None 124 | except Exception as e: 125 | print(f"Erro ao obter informações do chat: {e}") 126 | return None, None 127 | -------------------------------------------------------------------------------- /telegram_downloader/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import asyncio 4 | 5 | # Ajuste para compatibilidade com asyncio no Windows 6 | if os.name == 'nt': # Verifica se está rodando no Windows 7 | asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) 8 | 9 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 10 | 11 | from telegram_downloader.downloader import TelegramDownloader 12 | from telegram_downloader.config import API_ID, API_HASH, SESSION_NAME 13 | 14 | async def main(): 15 | downloader = TelegramDownloader(API_ID, API_HASH, SESSION_NAME) 16 | await downloader.client.start() 17 | 18 | await downloader.listar_chats() 19 | 20 | chat_id = input("Digite o ID do chat que deseja baixar: ") 21 | if chat_id.isdigit(): 22 | chat_id = int(chat_id) 23 | 24 | chat_titulo, target_topic_id = await downloader.verificar_chat_forum(chat_id) 25 | 26 | if chat_titulo: 27 | await downloader.coletar_metadados(chat_id, target_topic_id) 28 | 29 | print("Processo de coleta de metadados concluído.") 30 | 31 | if __name__ == '__main__': 32 | asyncio.run(main()) 33 | -------------------------------------------------------------------------------- /telegram_downloader/utils.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | import os 4 | 5 | def nome_arquivo_seguro(nome): 6 | """Remove caracteres inválidos do nome do arquivo.""" 7 | return re.sub(r'[\\/*?:"<>|]', "_", nome) 8 | 9 | def salvar_json(dados, caminho): 10 | """Salva dados em um arquivo JSON com encoding UTF-8.""" 11 | with open(caminho, 'w', encoding='utf-8') as file: 12 | json.dump(dados, file, ensure_ascii=False, indent=4) 13 | 14 | def carregar_json(caminho): 15 | """Carrega dados de um arquivo JSON com encoding UTF-8.""" 16 | if os.path.exists(caminho): 17 | with open(caminho, 'r', encoding='utf-8') as file: 18 | return json.load(file) 19 | return [] 20 | 21 | def criar_pasta_se_necessario(caminho): 22 | """Cria uma pasta se ela não existir, com suporte para Windows e Linux.""" 23 | os.makedirs(caminho, exist_ok=True) 24 | --------------------------------------------------------------------------------