From e3bf0462ec9ec8aca3fd5da61d0fc2990194d54e Mon Sep 17 00:00:00 2001 From: retoor Date: Sat, 23 Nov 2024 19:56:52 +0100 Subject: [PATCH] Working --- README.md | 3 + drstats.db | Bin 0 -> 151552 bytes setup.cfg | 10 +- src/drstats.egg-info/PKG-INFO | 4 + src/drstats.egg-info/SOURCES.txt | 3 + src/drstats.egg-info/entry_points.txt | 5 +- src/drstats.egg-info/requires.txt | 1 + src/drstats/__init__.py | 0 src/drstats/__main__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 150 bytes src/drstats/__pycache__/db.cpython-312.pyc | Bin 0 -> 1900 bytes .../__pycache__/devrant.cpython-312.pyc | Bin 0 -> 3103 bytes .../__pycache__/statistics.cpython-312.pyc | Bin 0 -> 4518 bytes src/drstats/__pycache__/sync.cpython-312.pyc | Bin 0 -> 2730 bytes src/drstats/db.py | 47 +++++++++ src/drstats/devrant.py | 93 ++++++++++++++++++ src/drstats/statistics.py | 73 ++++++++++++++ src/drstats/sync.py | 55 +++++++++++ 18 files changed, 289 insertions(+), 5 deletions(-) create mode 100644 drstats.db create mode 100644 src/drstats/__init__.py create mode 100644 src/drstats/__main__.py create mode 100644 src/drstats/__pycache__/__init__.cpython-312.pyc create mode 100644 src/drstats/__pycache__/db.cpython-312.pyc create mode 100644 src/drstats/__pycache__/devrant.cpython-312.pyc create mode 100644 src/drstats/__pycache__/statistics.cpython-312.pyc create mode 100644 src/drstats/__pycache__/sync.cpython-312.pyc create mode 100644 src/drstats/db.py create mode 100644 src/drstats/devrant.py create mode 100644 src/drstats/statistics.py create mode 100644 src/drstats/sync.py diff --git a/README.md b/README.md index e1021b8..5a7f94c 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,7 @@ Simple project to determine health of the devrant platform. +## Credits +Thanks to Rohan Burke (coolq). The creator of the dr api wrapper this project uses. Since it isn't made like a package, i had to copy his source files to my source folder. His library: https://github.com/coolq1000/devrant-python-api/ + diff --git a/drstats.db b/drstats.db new file mode 100644 index 0000000000000000000000000000000000000000..bf0308d7ec363c346f59eecefd2fc269ddf09586 GIT binary patch literal 151552 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 NjgHt323&WM{{c!~Om+YO literal 0 HcmV?d00001 diff --git a/setup.cfg b/setup.cfg index f467468..e58b50e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,12 +16,14 @@ python_requires = >=3.7 install_requires = aiohttp>=3.10.10 dataset>=1.6.2 - pirant>=0.1.4.dev1 - git+https://github.com/aayush26/pirant - + matplotlib>=3.9.2 + [options.packages.find] where = src [options.entry_points] console_scripts = - dr.rant_stats = drstats.statistics:rant_stats + dr.sync = drstats.sync:sync + dr.rant_stats_per_day = drstats.statistics:rant_stats_per_day + dr.rant_stats_per_weekday = drstats.statistics:rant_stats_per_weekday + dr.rant_stats_per_hour = drstats.statistics:rant_stats_per_hour \ No newline at end of file diff --git a/src/drstats.egg-info/PKG-INFO b/src/drstats.egg-info/PKG-INFO index bd87795..3a2fc1e 100644 --- a/src/drstats.egg-info/PKG-INFO +++ b/src/drstats.egg-info/PKG-INFO @@ -9,6 +9,7 @@ Requires-Python: >=3.7 Description-Content-Type: text/markdown Requires-Dist: aiohttp>=3.10.10 Requires-Dist: dataset>=1.6.2 +Requires-Dist: matplotlib>=3.9.2 # dRStats @@ -16,4 +17,7 @@ Requires-Dist: dataset>=1.6.2 Simple project to determine health of the devrant platform. +## Credits +Thanks to Rohan Burke (coolq). The creator of the dr api wrapper this project uses. Since it isn't made like a package, i had to copy his source files to my source folder. His library: https://github.com/coolq1000/devrant-python-api/ + diff --git a/src/drstats.egg-info/SOURCES.txt b/src/drstats.egg-info/SOURCES.txt index c9cf144..5c61138 100644 --- a/src/drstats.egg-info/SOURCES.txt +++ b/src/drstats.egg-info/SOURCES.txt @@ -3,7 +3,10 @@ pyproject.toml setup.cfg src/drstats/__init__.py src/drstats/__main__.py +src/drstats/db.py +src/drstats/devrant.py src/drstats/statistics.py +src/drstats/sync.py src/drstats.egg-info/PKG-INFO src/drstats.egg-info/SOURCES.txt src/drstats.egg-info/dependency_links.txt diff --git a/src/drstats.egg-info/entry_points.txt b/src/drstats.egg-info/entry_points.txt index 7c1ba90..98708c1 100644 --- a/src/drstats.egg-info/entry_points.txt +++ b/src/drstats.egg-info/entry_points.txt @@ -1,2 +1,5 @@ [console_scripts] -dr.rant_stats = drstats.statistics:rant_stats +dr.rant_stats_per_day = drstats.statistics:rant_stats_per_day +dr.rant_stats_per_hour = drstats.statistics:rant_stats_per_hour +dr.rant_stats_per_weekday = drstats.statistics:rant_stats_per_weekday +dr.sync = drstats.sync:sync diff --git a/src/drstats.egg-info/requires.txt b/src/drstats.egg-info/requires.txt index 9c7930a..ae712de 100644 --- a/src/drstats.egg-info/requires.txt +++ b/src/drstats.egg-info/requires.txt @@ -1,2 +1,3 @@ aiohttp>=3.10.10 dataset>=1.6.2 +matplotlib>=3.9.2 diff --git a/src/drstats/__init__.py b/src/drstats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/drstats/__main__.py b/src/drstats/__main__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/drstats/__pycache__/__init__.cpython-312.pyc b/src/drstats/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5bc5dff6e50284095e4d7d2cc430f44617a636ac GIT binary patch literal 150 zcmX@j%ge<81d~pfr-SInAOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdWvZW%pPQ;*lvHq~^xA6@n%um#ow9&+$SZH90Z!{@DWBtz=S z@b_f&^<)GNGc*wCPt;^{qgbGLT2YkRc|?o~d{Drfu&@g8!-7doNc1wz*tyMAFv%dj zs()q~k>^tCOj?C^a)wo=BjXWnxAjrS9%XBc9=?Q8xhvzU$4KWb(rt+ek1$UPT_Q|+u%=Usv5rV7UAqNbW>@k56a0@R84i7uk%E;MXp_lrjmfSw2O#1j>{SGW@5$cW2S846eSi)7{WnSmvWoa7 e39>2w>*h%|G<|{~?8>L>fo~wxk}e7%+vhisyVY6% literal 0 HcmV?d00001 diff --git a/src/drstats/__pycache__/devrant.cpython-312.pyc b/src/drstats/__pycache__/devrant.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7fc45d3838cea43b8063c1c87a2fa127dbd7a025 GIT binary patch literal 3103 zcmd5;&ube;6rSDLUG1(UtB&&nJG4=3$5LvwKGCBe{tq?A;34$9I)N>9Eibs>;b-`my7c53pYrw-`N%$u1v zGw=K6Tm76&>I6#a!TVPq#0dElJ5f=)jm--JAo^{*$R~mbaZ|5>m&FaTWU`1hD&5?W%~Rl6CME$)NM3{-Q;jfjf#fBq0hzoEwFEWf zp2<+hpjMz(=VBSvk9E&dJ2>UKRp-N8?#7K9S=KvXu28jd#V)qN<`P&6zs;Y5o$I6& zxOW;RV5VH07nHgXQQ+ z^k6UAbzZK^mqTXYey-s&iQfJ+JMPdtg=}fh{&?di4Vw`1mlsmnpjdBYV%Y} zJ$R?MI`YF*OC9q@9#eJkaEFQs$s7AyC9%|ZzUUJ1o*0dh_`5$=fH_ z)gf=BttGspn-G!gj`a$RERz>ujhNO2M(>D#Y7h4kvgNt*9IBu?VJSs=6FHy;RCmGp z->CL=)0cD10xwQ+44M%+LV>vP>H7-D@EoJ@I2vRNhlfdcADE27F{>P(J?}@e2h9MQ zy&??T<#L@eioHu@4&TKFF7{=VC5Pj4&j`MT zR}4HEDaZ~`-{!6_TNP&B z^~kzDe(yj_KkglQBE(C3zZ-53*uSTc9z{HLJ>pz>`r!4&o>uMRNqr zZfry@W7@F&|=Nc0LEw<6-k`OC64A*iQ5#88tZ|W8Z6$ao3N+|6M3h zTPN@nFk!JBDxspYQkXVFC_*{#rNFZr0$VB{Qa=!FjA2-8r)YPb7Z3?FTS$D|Qqv(4 zse%6_2$LDjR}BLXX&An47}GYJEn_=j7&EhlaySx7-+tJeA4D^Z1_{G6VD6LPp@lTU z*T&HxU7ZiWERe^sQE#9lQBnR&RmEgyZ_v`9wLfT4aiF6ItvL9GptY&OXc!e^;Tfk3 zRt3(baInT&9%iO15Q?S-q(Ght%m1Z=}mbVD`o^J9j=?4n_Wil4xd z;BF{EzR0*QSV11}M9yp(RISRbip$}TD||9awpHQBu}RBjg-_seRNx><&(x2?JfGpG z!H3G}`~s#!1wnWsih}f1CBpuv(x-xud_vH6z7mO)Sgid<2mer#-&)?Dwyb#l?HGIu zl1rx>r<*rd``6c9X*BgBg#RIP}y)9C2=GK^ZxYJM6L`Ngi IP;lLU0J#otc>n+a literal 0 HcmV?d00001 diff --git a/src/drstats/__pycache__/statistics.cpython-312.pyc b/src/drstats/__pycache__/statistics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..291f822eedd82641ad6b4b21ca32a6f9ded2e903 GIT binary patch literal 4518 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 literal 0 HcmV?d00001 diff --git a/src/drstats/db.py b/src/drstats/db.py new file mode 100644 index 0000000..71b1e85 --- /dev/null +++ b/src/drstats/db.py @@ -0,0 +1,47 @@ +db_path = "./drstats.db" +import dataset + +def get_db(): + db = dataset.connect(f"sqlite:///{db_path}") + db.query("drop view if exists rant_stats_per_day") + db.query(""" +CREATE VIEW rant_stats_per_day AS SELECT + count(0) AS count, + DATE(created) AS created_date, + CASE strftime('%w', DATE(created)) + WHEN '0' THEN 'Sunday' + WHEN '1' THEN 'Monday' + WHEN '2' THEN 'Tuesday' + WHEN '3' THEN 'Wednesday' + WHEN '4' THEN 'Thursday' + WHEN '5' THEN 'Friday' + WHEN '6' THEN 'Saturday' + END AS weekday +FROM rants +GROUP BY created_date +ORDER BY created_date; +""") + db.query("DROP VIEW IF EXISTS rant_stats_per_weekday") + db.query(""" +CREATE VIEW rant_stats_per_weekday AS SELECT + count(0) AS count, + DATE(created) AS created_date, + CASE strftime('%w', DATE(created)) + WHEN '0' THEN 'Sunday' + WHEN '1' THEN 'Monday' + WHEN '2' THEN 'Tuesday' + WHEN '3' THEN 'Wednesday' + WHEN '4' THEN 'Thursday' + WHEN '5' THEN 'Friday' + WHEN '6' THEN 'Saturday' + END AS weekday +FROM rants +GROUP BY weekday +ORDER BY created_date; +""") + db.query("drop view if exists rant_stats_per_hour") + db.query("create view rant_stats_per_hour as select count(0) as count, strftime('%H', created) AS hour from rants GROUP BY hour order by hour") + #db.query("drop view if exists rant_stats_per_weekday") + #db.query("create view rant_stats_per_weekday as select count(0) as count, strftime('%w',created) as weekday_int, strftime('%A',created) as weekday from rants group by weekday_int order by weekday_int;") + + return db \ No newline at end of file diff --git a/src/drstats/devrant.py b/src/drstats/devrant.py new file mode 100644 index 0000000..17f7b42 --- /dev/null +++ b/src/drstats/devrant.py @@ -0,0 +1,93 @@ +""" + Devrant.io API. Written by Rohan Burke (coolq). +""" + +import requests, json + +class Devrant: + + API = 'https://www.devrant.io/api/' + + """ + get_profile(id): + Return JSON object with all information about that user. + """ + def get_profile(self, id_): + url = self.API + 'users/' + str(id_) + params = { + 'app': 3, + } + + r = requests.get(url, params) + obj = json.loads(r.text) + return obj + + """ + get_search(term): + Return JSON object containing all results of that search. Index ['rants'] for rants. + """ + def get_search(self, term): + url = self.API + 'devrant/search' + params = { + 'app': 3, + 'term': term + } + + r = requests.get(url, params) + obj = json.loads(r.text) + return obj + + """ + get_rant(sort, index): + Return JSON object of that rant. + """ + def get_rant(self, sort, index): + rants = self.get_rants(sort, 1, index)['rants'] + if rants: + return rants[0] + + """ + get_rants(sort, limit, skip): + Return JSON object with range skip-limit. Max limit is 50, increase the skip to get rants further down. + """ + def get_rants(self, sort, limit, skip): + url = self.API + 'devrant/rants' + params = { + 'app': 3, + 'sort': sort, + 'limit': limit, + 'skip': skip + } + + r = requests.get(url, params) + obj = json.loads(r.text) + return obj + + """ + get_user_id(name): + Return JSON with containing the id for that user, E.g. if `coolq` is inputted, it shall return `{'success': True, 'user_id': 703149}`. + """ + def get_user_id(self, name): + url = self.API + 'get-user-id' + params = { + 'app': 3, + 'username': name + } + + r = requests.get(url, params) + obj = json.loads(r.text) + return obj + +if __name__ == '__main__': + # Simple demo, runs through rants sorted by most recent. + dr = Devrant() + i = 0 + while True: + result = dr.get_rant('recent', i) + print('\n'*50) + name = result['user_username'] + tags = ', '.join(result['tags']) + print('-' + name + '-'*(50 - (len(name) + 1))) + print(result['text']) + print('-' + tags + '-'*(50 - (len(tags) + 1))) + i += 1 \ No newline at end of file diff --git a/src/drstats/statistics.py b/src/drstats/statistics.py new file mode 100644 index 0000000..4555337 --- /dev/null +++ b/src/drstats/statistics.py @@ -0,0 +1,73 @@ +from drstats.db import get_db +from drstats import sync +import asyncio +import matplotlib +import matplotlib.pyplot as plt + +def get_date_range(): + db = get_db() + for record in db.query("SELECT min(date(created)) as start_date, max(date(created)) as end_date FROM rants"): + return record['start_date'], record['end_date'] + +def get_date_range_str(): + start_date, end_date = get_date_range() + return f"from {start_date} to {end_date}" + + +def rant_stats_per_day(): + db = get_db() + x = [] + y = [] + matplotlib.use('TkAgg') + for record in db.query("SELECT * FROM rant_stats_per_day"): + print(record) + y.append(record['count']) + x.append(record['created_date'].replace('2014-',"") + " " + str(record['weekday'])) + + plt.plot(x, y, label=get_date_range_str(), color='blue') + plt.xticks(rotation=20) + plt.xlabel('Date') + plt.ylabel('Rant count') + plt.title('Rants per day') + plt.legend() + plt.savefig(f'export/rants_per_day_{get_date_range_str()}.png') + plt.show() + +def rant_stats_per_weekday(): + db = get_db() + x = [] + y = [] + matplotlib.use('TkAgg') + for record in db.query("SELECT * FROM rant_stats_per_weekday"): + print(record) + y.append(record['count']) + x.append(str(record['weekday'])) + + plt.plot(x, y, label=get_date_range_str(), color='green') + plt.xticks(rotation=20) + plt.xlabel('Weekday') + plt.ylabel('Rant count') + plt.title('Rants per weekday') + plt.legend() + plt.savefig(f'export/rants_per_weekday_{get_date_range_str()}.png') + plt.show() + + +def rant_stats_per_hour(): + db = get_db() + x = [] + y = [] + matplotlib.use('TkAgg') + for record in db.query("SELECT * FROM rant_stats_per_hour"): + print(record) + y.append(record['count']) + x.append(record['hour']) + + plt.plot(x, y, label=get_date_range_str(), color='pink') + plt.xticks(rotation=45) + plt.xlabel('Hour') + plt.ylabel('Rant count') + plt.title('Rants per hour') + plt.legend() + plt.savefig(f'export/rants_per_hour_{get_date_range_str()}.png') + plt.show() \ No newline at end of file diff --git a/src/drstats/sync.py b/src/drstats/sync.py new file mode 100644 index 0000000..4739599 --- /dev/null +++ b/src/drstats/sync.py @@ -0,0 +1,55 @@ +from drstats.devrant import Devrant +from drstats.db import get_db +import json +import asyncio +from pprint import pprint as pp + +dr = Devrant() +db = get_db() + + +from datetime import datetime + +def timestamp_to_string(timestamp): + return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S') + +async def get_recent_rants(start_from=1,page_size=10): + page = 0 + while True: + rants = dr.get_rants('recent',page_size,start_from)['rants'] + page += 1 + for rant in rants: + if rant is None: + break + rant['tags'] = json.dumps('tags' in rant and rant['tags'] or '') + rant['created'] = timestamp_to_string(rant['created_time']) + rant = json.loads(json.dumps(rant,default=str)) + + for key,value in rant.items(): + if isinstance(value, list) or isinstance(value, dict): + value = json.dumps(value) + rant[key] = value + + yield rant + start_from += page_size + +async def sync_rants(): + count = 0; + start_from = 0 #db['rants'].count() + print(start_from) + await asyncio.sleep(2) + + page_size = 20 + + async for rant in get_recent_rants(start_from,page_size): + start_from += page_size + count += 1 + pp(rant) + rant['tags'] = json.dumps(rant['tags']) + db['rants'].upsert(rant,['id']) + print(rant) + print(f"Upserted {count} rant(s).") + + +def sync(): + print(asyncio.run(sync_rants())) \ No newline at end of file