Skip to content

Commit

Permalink
Merge pull request #3 from claromes/restart-flow
Browse files Browse the repository at this point in the history
Fix new tracking flow
  • Loading branch information
claromes authored Apr 29, 2023
2 parents ce52bf5 + da4432b commit 2bf15cb
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 132 deletions.
54 changes: 10 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,48 +34,14 @@ Streamlit will be served at http://localhost:8501

<br>

> Initial screen: credentials, sign in and channel inputs
<br>
<p align="center">
<img src="assets/1.png" width="700">
</p>

<br>

> Data screens: tabs and download links
<br>
<p align="center">
<img src="assets/2.png" width="700">
</p>
<p align="center">
<img src="assets/3.png" width="700">
</p>
<p align="center">
<img src="assets/4.png" width="700">
</p>
<p align="center">
<img src="assets/5.png" width="700">
</p>

**network tab is under development*
<br>

<p align="center">
<img src="assets/6.png" width="700">
</p>

<br>

> Restart tab: to track another channel
<br>
<p align="center">
<img src="assets/6.png" width="700">
</p>
### Workflow

*IMPORTANT: To test using the deploy link with your personal credentials disable the 2FA*
*IMPORTANT: disable the 2FA*

1. Create your API credentials [here](https://my.telegram.org/auth)

Expand All @@ -102,11 +68,12 @@ Streamlit will be served at http://localhost:8501

5. Switch tabs to preview or download the data

6. To track another channel, switch to last tab (`trac`) and click `restart`.
6. To track another channel, switch to last tab (`trac`) and click `new trac`.

7. Fill the input `channel name` (*copy name from channel link: t.me/CHANNEL_NAME*) and click on `trac` button

- To restart, send the same credentials and `code`
- A late message could be send to your Telegram app about other authentications
- At each tracking the dataset are grouped in the same file to allow network analysis
- A late message could be send to your Telegram app about other authentications

## Additional Information

Expand All @@ -122,8 +89,11 @@ Mostly limited to Streamlit options. The form and tabs were chosen due to common
## Roadmap

- [x] Fix dataset tab
- [ ] Fix set credentials and code in restart flow
- [x] Fix set credentials and code in restart flow
- [ ] Network tab
- [ ] Error msgs
- [ ] Storage limit alerts
- [x] Delete files after session finish
- [ ] Allow 2FA
- [ ] Add batch file upload
- [ ] Option without API credentials
Expand All @@ -140,8 +110,4 @@ Mostly limited to Streamlit options. The form and tabs were chosen due to common
- Fix dataset tab
- Fix imports
- [v0.1.0](https://github.com/claromes/telegramtrac/releases/tag/v0.1.0)
- Bellingcat Accessiblilty Hackathon submission

## Telegram App Bans in Brazil

Due to the blocking of Telegram in Brazil ([NYT article](https://www.nytimes.com/2023/04/26/briefing/brazil-telegram-ban.html)), which has already occurred on other occasions, I decided to expand the development and include in the roadmap an option without API credentials
- Bellingcat Accessiblilty Hackathon submission
Binary file removed assets/2.png
Binary file not shown.
Binary file removed assets/3.png
Binary file not shown.
Binary file removed assets/4.png
Binary file not shown.
Binary file removed assets/5.png
Binary file not shown.
Binary file removed assets/6.png
Binary file not shown.
6 changes: 3 additions & 3 deletions config/config.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Telegram API credentials]
api_id =
api_hash =
phone =
api_id =
api_hash =
phone =

2 changes: 1 addition & 1 deletion config/config_sign_in_code.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[Sign in code]
code =
code =

192 changes: 108 additions & 84 deletions streamlit/telegramtrac.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pandas import read_csv
import base64
import os
import shutil

#page config
st.set_page_config(
Expand All @@ -31,10 +32,11 @@
form_component = st.empty()
sign_in_component = st.empty()
channel_component = st.empty()
channel_component_new = st.empty()
form_component_channel = st.empty()
center_running()

trac = ''
new_trac = ''

#states
if 'channel_name' not in st.session_state:
Expand All @@ -44,101 +46,135 @@
st.session_state['code_state'] = False

if 'code_value' not in st.session_state:
st.session_state['code_value'] = 0
st.session_state['code_value'] = ''

if 'api_id' not in st.session_state:
st.session_state['api_id'] = ''

if 'api_hash' not in st.session_state:
st.session_state['api_hash'] = ''

if 'phone' not in st.session_state:
st.session_state['phone'] = ''

if 'restart' not in st.session_state:
st.session_state['restart'] = False

#title
title_component.title('telegramtrac', help="not stable", anchor=False)

#credentials
with form_component.form(key='config_form'):
api_id = st.text_input('api_id')
api_hash = st.text_input('api_hash')
phone = st.text_input('phone')
if not st.session_state.restart:
#delete all files and directories before start another tracking
dir_path_output = os.path.join('output')

config = {
'api_id': api_id,
'api_hash': api_hash,
'phone': phone
}
if os.path.exists(dir_path_output):
shutil.rmtree(dir_path_output)

config_parser = configparser.ConfigParser()
config_parser['Telegram API credentials'] = config
with open('config/config.ini', 'w') as file:
config_parser.write(file)
#credentials
with form_component.form(key='config_form'):
api_id = st.text_input('api_id')
api_hash = st.text_input('api_hash')
phone = st.text_input('phone')

send_credentials = st.form_submit_button('send credentials', type='primary')
config = {
'api_id': api_id,
'api_hash': api_hash,
'phone': phone
}

if send_credentials and api_id != '' and api_hash != '' and phone != '':
center_running()
st.session_state.code_state = True
config_parser = configparser.ConfigParser()
config_parser['Telegram API credentials'] = config
with open('config/config.ini', 'w') as file:
config_parser.write(file)

try:
cmd_tele = "pip install telethon --user"
output = subprocess.check_output(cmd_tele.split())
send_credentials = st.form_submit_button('send credentials', type='primary')

cmd_pd = "pip install pandas --user"
output = subprocess.check_output(cmd_pd.split())
if send_credentials and api_id != '' and api_hash != '' and phone != '':
center_running()
st.session_state.code_state = True

cmd_tqdm = "pip install tqdm --user"
output = subprocess.check_output(cmd_tqdm.split())
try:
# cmd_tele = "pip install telethon --user"
# output = subprocess.check_output(cmd_tele.split())

cmd_open = "pip install openpyxl --user"
output = subprocess.check_output(cmd_open.split())
# cmd_pd = "pip install pandas --user"
# output = subprocess.check_output(cmd_pd.split())

cmd_connect = 'python connect.py'
output = subprocess.check_output(cmd_connect.split())
except subprocess.CalledProcessError:
pass
except Exception:
pass
# cmd_tqdm = "pip install tqdm --user"
# output = subprocess.check_output(cmd_tqdm.split())

#sign in code
with sign_in_component.form(key='config_sign_in_form'):
if st.session_state.code_state:
code_sign_in = st.text_input('code', disabled=False)
else:
code_sign_in = st.text_input('code', disabled=True)
# cmd_open = "pip install openpyxl --user"
# output = subprocess.check_output(cmd_open.split())

if code_sign_in == '':
code_sign_in = st.session_state.code_value
cmd_connect = 'python connect.py'
output = subprocess.check_output(cmd_connect.split())
except subprocess.CalledProcessError:
pass
except Exception:
pass

config_sign_in_code = {
'code': code_sign_in
}
#sign in code
with sign_in_component.form(key='config_sign_in_form'):
if st.session_state.code_state:
code_sign_in = st.text_input('code', disabled=False)
else:
code_sign_in = st.text_input('code', disabled=True)

config_sign_in_code_parser = configparser.ConfigParser()
config_sign_in_code_parser['Sign in code'] = config_sign_in_code
with open('config/config_sign_in_code.ini', 'w') as file:
config_sign_in_code_parser.write(file)
if code_sign_in == '':
code_sign_in = st.session_state.code_value

if st.session_state.code_state:
sign_in = st.form_submit_button('sign in', disabled=False, type='primary')
else:
sign_in = st.form_submit_button('sign in', disabled=True, type='primary')
config_sign_in_code = {
'code': code_sign_in
}

if sign_in:
center_running()
st.session_state.code_value = code_sign_in

#channel name
with channel_component.form(key='channel_form'):
if sign_in and not st.session_state.code_value == 0 or st.session_state.channel_name != '':
channel_name = st.text_input('channel name', placeholder="https://t.me/CHANNEL_NAME_IS_HERE", disabled=False, key='channel_name')
trac = st.form_submit_button('trac', disabled=False, type='primary')
send_credentials = True
else:
channel_name = st.text_input('channel name', disabled=True)
trac = st.form_submit_button('trac', disabled=True, type='primary')
send_credentials = True
config_sign_in_code_parser = configparser.ConfigParser()
config_sign_in_code_parser['Sign in code'] = config_sign_in_code
with open('config/config_sign_in_code.ini', 'w') as file:
config_sign_in_code_parser.write(file)

if st.session_state.code_state:
sign_in = st.form_submit_button('sign in', disabled=False, type='primary')
else:
sign_in = st.form_submit_button('sign in', disabled=True, type='primary')

if sign_in:
center_running()
st.session_state.code_value = code_sign_in

#channel name
with channel_component.form(key='channel_form'):
if sign_in and not st.session_state.code_value == 0 or st.session_state.channel_name != '':
channel_name = st.text_input('channel name', placeholder="https://t.me/CHANNEL_NAME_IS_HERE", disabled=False, key='channel_name')
trac = st.form_submit_button('trac', disabled=False, type='primary')
send_credentials = True
else:
channel_name = st.text_input('channel name', disabled=True)
trac = st.form_submit_button('trac', disabled=True, type='primary')
send_credentials = True
else:
form_component.empty()
sign_in_component.empty()
channel_component.empty()

with form_component_channel.form(key='config_form_channel'):
#send same credentials and code
api_id = st.session_state.api_id
api_hash = st.session_state.api_hash
phone = st.session_state.phone
code = st.session_state.code_value

st.session_state.channel_name = st.text_input('channel name', placeholder="https://t.me/CHANNEL_NAME_IS_HERE", disabled=False, key='channel_name_new_trac')
new_trac = st.form_submit_button('new trac', disabled=False, type='primary')

#data tabs
if trac and st.session_state.channel_name != '':
if trac or new_trac and st.session_state.channel_name != '':
center_running()
tab1, tab2, tab3, tab4, tab5 = st.tabs(['messages', 'metadata', 'dataset', 'network', 'new trac'])

form_component.empty()
sign_in_component.empty()
channel_component.empty()
form_component_channel.empty()

try:
cmd_main = 'python main.py --telegram-channel {}'.format(st.session_state.channel_name)
Expand All @@ -160,15 +196,6 @@
subdirectories = [entry for entry in os.scandir(path) if entry.is_dir()]
path_lens = len(subdirectories) > 1

# if path_lens:
# try:
# cmd_dataset = 'python channels-to-network.py'
# output = subprocess.check_output(cmd_dataset.split())
# except subprocess.CalledProcessError:
# pass
# except Exception:
# pass

#json - main file
with tab1:
json_file = 'output/data/{}/{}_messages.json'.format(st.session_state.channel_name, st.session_state.channel_name)
Expand Down Expand Up @@ -228,7 +255,6 @@
#dataset
with tab3:
st.subheader('dataset', anchor=False)
#st.caption('Channels: {}'.format(st.session_state.channel_name))
dataset_csv_file = 'output/data/msgs_dataset.csv'

with open(dataset_csv_file, 'rb') as file:
Expand All @@ -241,16 +267,14 @@

st.dataframe(df)

#network
with tab4:
if path_lens:
st.info('Under development')
else:
st.info('There is only one channel.')
#st.info('There is only one channel.')

#restart
with tab5:
restart = st.button('restart', type='primary')

if restart:
st.experimental_rerun()
st.button('new trac', type='primary')
st.session_state.restart = True

0 comments on commit 2bf15cb

Please sign in to comment.