Compare commits
5 commits
327bb0d732
...
f164ddaa22
Author | SHA1 | Date | |
---|---|---|---|
f164ddaa22 | |||
670e7d42ba | |||
6793fda0c8 | |||
3eae1f36ce | |||
7fcff2566a |
4 changed files with 237 additions and 170 deletions
|
@ -26,7 +26,7 @@ class Toot(db.Model):
|
||||||
favourites_count = db.Column(db.Integer)
|
favourites_count = db.Column(db.Integer)
|
||||||
language = db.Column(db.Text)
|
language = db.Column(db.Text)
|
||||||
|
|
||||||
class Reblog(db.Model):
|
class Other(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
acct = db.Column(db.Text)
|
acct = db.Column(db.Text)
|
||||||
url = db.Column(db.Text)
|
url = db.Column(db.Text)
|
||||||
|
|
|
@ -12,16 +12,20 @@
|
||||||
<a href="{{ toot.url }}" target="_blank"
|
<a href="{{ toot.url }}" target="_blank"
|
||||||
rel="noopener noreferrer">
|
rel="noopener noreferrer">
|
||||||
<span class="time">
|
<span class="time">
|
||||||
{% if toot. visibility == "public"%}
|
{% if toot.visibility == "public"%}
|
||||||
<span class="visibility-icon"><i class="fa-solid fa-earth-americas fa-globle"></i></span>
|
<span class="visibility-icon"><i class="fa-solid fa-earth-americas fa-globle"></i></span>
|
||||||
{% elif toot. visibility == "unlisted"%}
|
{% elif toot.visibility == "unlisted"%}
|
||||||
<span class="visibility-icon"><i class="fa-solid fa-lock-open fa-unlock"></i></span>
|
<span class="visibility-icon"><i class="fa-solid fa-lock-open fa-unlock"></i></span>
|
||||||
{% elif toot. visibility == "private"%}
|
{% elif toot.visibility == "private"%}
|
||||||
<span class="visibility-icon"><i class="fa-solid fa-lock"></i></span>
|
<span class="visibility-icon"><i class="fa-solid fa-lock"></i></span>
|
||||||
{% elif toot. visibility == "direct"%}
|
{% elif toot.visibility == "direct"%}
|
||||||
<span class="visibility-icon"><i class="fa-solid fa-envelope fa-at"></i></span>
|
<span class="visibility-icon"><i class="fa-solid fa-envelope fa-at"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<time>{{ toot.created_at }}</time></span></a>
|
<time>{{ toot.created_at }}
|
||||||
|
{% if toot.edited_at != None %}
|
||||||
|
<strong>*</strong>
|
||||||
|
{% endif %}
|
||||||
|
</time></span></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{% if toot.spoiler_text != "" %}
|
{% if toot.spoiler_text != "" %}
|
||||||
|
@ -73,7 +77,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="action-bar">
|
<div class="action-bar">
|
||||||
{% if not toot.is_reblog %}
|
{% if toot.is_myself %}
|
||||||
|
<span><i class="fa-solid fa-satellite-dish"></i><a href="{{ url_for('grab', toot_id=toot.id) }}"
|
||||||
|
target=" _blank">抓取回复</a></span>
|
||||||
<span><i class="fa-solid fa-up-right-and-down-left-from-center"></i><a
|
<span><i class="fa-solid fa-up-right-and-down-left-from-center"></i><a
|
||||||
href="{{ url_for('context', toot_id=toot.id) }}" target=" _blank">上下文</a></span>
|
href="{{ url_for('context', toot_id=toot.id) }}" target=" _blank">上下文</a></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
82
BDSM/toot.py
82
BDSM/toot.py
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
from BDSM import db
|
from BDSM import db
|
||||||
from BDSM.models import Reblog, Toot, Tag, Media, Emoji, Poll
|
from BDSM.models import Other, Toot, Tag, Media, Emoji, Poll
|
||||||
import sys
|
import sys
|
||||||
|
import dateutil.parser
|
||||||
|
|
||||||
def app_register(url):
|
def app_register(url):
|
||||||
print("Registering app")
|
print("Registering app")
|
||||||
|
@ -14,7 +15,7 @@ def app_register(url):
|
||||||
scopes=["read"]
|
scopes=["read"]
|
||||||
)
|
)
|
||||||
|
|
||||||
def archive_toot(url):
|
def app_login(url):
|
||||||
mastodon = Mastodon(
|
mastodon = Mastodon(
|
||||||
client_id='pyBDSM_clientcred.secret',
|
client_id='pyBDSM_clientcred.secret',
|
||||||
access_token='user.secret',
|
access_token='user.secret',
|
||||||
|
@ -35,21 +36,26 @@ def archive_toot(url):
|
||||||
# exit in either case
|
# exit in either case
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
return mastodon, user
|
||||||
|
|
||||||
|
def get_context(url, toot_id):
|
||||||
|
mastodon, user = app_login(url)
|
||||||
acct = mastodon.me().acct
|
acct = mastodon.me().acct
|
||||||
statuses_count = str(mastodon.me().statuses_count)
|
context = mastodon.status_context(toot_id)
|
||||||
|
statuses = []
|
||||||
|
statuses= context['ancestors'] + context['descendants']
|
||||||
|
toot_process(statuses, acct)
|
||||||
|
|
||||||
statuses = mastodon.account_statuses(user["id"], limit=20)
|
db.session.commit()
|
||||||
# xx = statuses['created_at'].astimezone(tz_cn)
|
|
||||||
# pprint(xx.strftime("%m/%d/%Y, %H:%M:%S"))
|
|
||||||
# pprint(statuses)
|
|
||||||
|
|
||||||
happy_counter = 20
|
|
||||||
|
|
||||||
while(True):
|
|
||||||
|
def toot_process(statuses, my_acct, duplicates_counter=0):
|
||||||
for status in statuses:
|
for status in statuses:
|
||||||
is_reblog = False
|
is_reblog = False
|
||||||
|
is_myself = False
|
||||||
if status['reblog'] != None:
|
if status['reblog'] != None:
|
||||||
if acct == status['reblog']['account']['acct']:
|
if my_acct == status['reblog']['account']['acct']:
|
||||||
reblog_myself = True
|
reblog_myself = True
|
||||||
else:
|
else:
|
||||||
reblog_myself = False
|
reblog_myself = False
|
||||||
|
@ -61,7 +67,7 @@ def archive_toot(url):
|
||||||
created_at = status['created_at']
|
created_at = status['created_at']
|
||||||
|
|
||||||
toot = Toot(id=id, created_at=created_at, reblog_myself=reblog_myself, reblog_id=reblog_id)
|
toot = Toot(id=id, created_at=created_at, reblog_myself=reblog_myself, reblog_id=reblog_id)
|
||||||
db.session.add(toot)
|
db.session.merge(toot)
|
||||||
# cur.execute('''INSERT OR REPLACE INTO TOOT (id,created_at,reblog_myself,reblog_id) \
|
# cur.execute('''INSERT OR REPLACE INTO TOOT (id,created_at,reblog_myself,reblog_id) \
|
||||||
# VALUES (?,?,?,?)''',(id, created_at, reblog_myself, reblog_id))
|
# VALUES (?,?,?,?)''',(id, created_at, reblog_myself, reblog_id))
|
||||||
|
|
||||||
|
@ -71,10 +77,23 @@ def archive_toot(url):
|
||||||
status = status['reblog']
|
status = status['reblog']
|
||||||
|
|
||||||
id = status['id']
|
id = status['id']
|
||||||
|
|
||||||
acct = status['account']['acct']
|
acct = status['account']['acct']
|
||||||
|
if my_acct == acct:
|
||||||
|
is_myself = True
|
||||||
|
else:
|
||||||
|
is_myself = False
|
||||||
|
|
||||||
url = status['url']
|
url = status['url']
|
||||||
created_at = status['created_at']
|
created_at = status['created_at']
|
||||||
edited_at = status['edited_at'] if status['edited_at'] != None else None
|
|
||||||
|
if 'edited_at' in status:
|
||||||
|
edited_at = status['edited_at']
|
||||||
|
if isinstance(edited_at, str):
|
||||||
|
edited_at = dateutil.parser.parse(status['edited_at'])
|
||||||
|
else:
|
||||||
|
edited_at = None
|
||||||
|
|
||||||
in_reply_to_id = status['in_reply_to_id']
|
in_reply_to_id = status['in_reply_to_id']
|
||||||
in_reply_to_account_id = status['in_reply_to_account_id']
|
in_reply_to_account_id = status['in_reply_to_account_id']
|
||||||
content = status['content']
|
content = status['content']
|
||||||
|
@ -86,7 +105,7 @@ def archive_toot(url):
|
||||||
|
|
||||||
media = Media(id=media_dict['id'], type=media_dict['type'], url=media_dict['url'],
|
media = Media(id=media_dict['id'], type=media_dict['type'], url=media_dict['url'],
|
||||||
remote_url=media_dict['remote_url'], description=media_dict['description'])
|
remote_url=media_dict['remote_url'], description=media_dict['description'])
|
||||||
db.session.add(media)
|
db.session.merge(media)
|
||||||
# cur.execute('''INSERT OR REPLACE INTO MEDIA (id,type,url,remote_url,description) \
|
# cur.execute('''INSERT OR REPLACE INTO MEDIA (id,type,url,remote_url,description) \
|
||||||
# VALUES (?,?,?,?,?)''',(media_dict['id'], media_dict['type'], media_dict['url'], \
|
# VALUES (?,?,?,?,?)''',(media_dict['id'], media_dict['type'], media_dict['url'], \
|
||||||
# media_dict['remote_url'], media_dict['description']))
|
# media_dict['remote_url'], media_dict['description']))
|
||||||
|
@ -103,7 +122,7 @@ def archive_toot(url):
|
||||||
|
|
||||||
poll = Poll(id=poll_dict['id'], expires_at=expires_at, multiple=poll_dict['multiple'], \
|
poll = Poll(id=poll_dict['id'], expires_at=expires_at, multiple=poll_dict['multiple'], \
|
||||||
votes_count=poll_dict['votes_count'], options=options)
|
votes_count=poll_dict['votes_count'], options=options)
|
||||||
db.session.add(poll)
|
db.session.merge(poll)
|
||||||
# cur.execute('''INSERT OR REPLACE INTO POLL (id,expires_at,multiple,votes_count,options) \
|
# cur.execute('''INSERT OR REPLACE INTO POLL (id,expires_at,multiple,votes_count,options) \
|
||||||
# VALUES (?,?,?,?,?)''',(poll_dict['id'], expires_at, poll_dict['multiple'], \
|
# VALUES (?,?,?,?,?)''',(poll_dict['id'], expires_at, poll_dict['multiple'], \
|
||||||
# poll_dict['votes_count'], options))
|
# poll_dict['votes_count'], options))
|
||||||
|
@ -127,7 +146,7 @@ def archive_toot(url):
|
||||||
url=emoji['url'],
|
url=emoji['url'],
|
||||||
static_url=emoji['static_url'],
|
static_url=emoji['static_url'],
|
||||||
count=count)
|
count=count)
|
||||||
db.session.add(emoji_data)
|
db.session.merge(emoji_data)
|
||||||
# cur.execute('''INSERT INTO EMOJI (shortcode,url,static_url,count) \
|
# cur.execute('''INSERT INTO EMOJI (shortcode,url,static_url,count) \
|
||||||
# VALUES (?,?,?,?)''', (shortcode, emoji['url'], emoji['static_url'], count))
|
# VALUES (?,?,?,?)''', (shortcode, emoji['url'], emoji['static_url'], count))
|
||||||
else:
|
else:
|
||||||
|
@ -146,7 +165,7 @@ def archive_toot(url):
|
||||||
if status['tags'] != []:
|
if status['tags'] != []:
|
||||||
for tag in status['tags']:
|
for tag in status['tags']:
|
||||||
tag_data = Tag(id=id, name=tag['name'])
|
tag_data = Tag(id=id, name=tag['name'])
|
||||||
db.session.add(tag_data)
|
db.session.merge(tag_data)
|
||||||
# cur.execute('''INSERT OR REPLACE INTO TAG (id,name) \
|
# cur.execute('''INSERT OR REPLACE INTO TAG (id,name) \
|
||||||
# VALUES (?,?)''',(id, tag['name']))
|
# VALUES (?,?)''',(id, tag['name']))
|
||||||
|
|
||||||
|
@ -160,7 +179,11 @@ def archive_toot(url):
|
||||||
favourites_count = status['favourites_count']
|
favourites_count = status['favourites_count']
|
||||||
language = status['language']
|
language = status['language']
|
||||||
|
|
||||||
table = Reblog() if is_reblog else Toot()
|
if is_reblog or not is_myself:
|
||||||
|
table = Other()
|
||||||
|
else:
|
||||||
|
table = Toot()
|
||||||
|
|
||||||
table.id=id
|
table.id=id
|
||||||
table.acct = acct
|
table.acct = acct
|
||||||
table.url=url
|
table.url=url
|
||||||
|
@ -183,18 +206,41 @@ def archive_toot(url):
|
||||||
table.favourites_count=favourites_count
|
table.favourites_count=favourites_count
|
||||||
table.language=language
|
table.language=language
|
||||||
|
|
||||||
db.session.add(table)
|
if Toot.query.get(id) == None or Other.query.get(id) == None:
|
||||||
|
duplicates_counter += 1
|
||||||
|
|
||||||
|
db.session.merge(table)
|
||||||
# sql = f'''INSERT OR REPLACE INTO {table} (id,url,created_at,edited_at,in_reply_to_id,in_reply_to_account_id,content,\
|
# sql = f'''INSERT OR REPLACE INTO {table} (id,url,created_at,edited_at,in_reply_to_id,in_reply_to_account_id,content,\
|
||||||
# media_list,spoiler_text,poll_id,emoji_list,visibility,reblogged,favourited,bookmarked,sensitive,reblogs_count,\
|
# media_list,spoiler_text,poll_id,emoji_list,visibility,reblogged,favourited,bookmarked,sensitive,reblogs_count,\
|
||||||
# favourites_count,language) \
|
# favourites_count,language) \
|
||||||
# VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
|
# VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
|
||||||
# cur.execute(sql,(id,url,created_at,edited_at,in_reply_to_id,in_reply_to_account_id,content,media_list,spoiler_text,\
|
# cur.execute(sql,(id,url,created_at,edited_at,in_reply_to_id,in_reply_to_account_id,content,media_list,spoiler_text,\
|
||||||
# poll_id,emoji_list,visibility,reblogged,favourited,bookmarked,sensitive,reblogs_count,favourites_count,language))
|
# poll_id,emoji_list,visibility,reblogged,favourited,bookmarked,sensitive,reblogs_count,favourites_count,language))
|
||||||
|
return duplicates_counter
|
||||||
|
|
||||||
|
def archive_toot(url):
|
||||||
|
mastodon, user = app_login(url)
|
||||||
|
acct = mastodon.me().acct
|
||||||
|
statuses_count = str(mastodon.me().statuses_count)
|
||||||
|
|
||||||
|
statuses = mastodon.account_statuses(user["id"], limit=20)
|
||||||
|
# xx = statuses['created_at'].astimezone(tz_cn)
|
||||||
|
# pprint(xx.strftime("%m/%d/%Y, %H:%M:%S"))
|
||||||
|
# pprint(statuses)
|
||||||
|
|
||||||
|
happy_counter = 20
|
||||||
|
duplicates_counter = 0
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
duplicates_counter = toot_process(statuses, acct)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
print(str(happy_counter) + ' / ' + statuses_count)
|
print(str(happy_counter) + ' / ' + statuses_count)
|
||||||
happy_counter += 20
|
happy_counter += 20
|
||||||
|
|
||||||
|
if duplicates_counter >= 10:
|
||||||
|
print("检测到重复嘟文达到十次,取消存档……")
|
||||||
|
break
|
||||||
|
|
||||||
statuses = mastodon.fetch_next(statuses)
|
statuses = mastodon.fetch_next(statuses)
|
||||||
# statuses = None
|
# statuses = None
|
||||||
if statuses == None:
|
if statuses == None:
|
||||||
|
|
|
@ -5,8 +5,8 @@ import pytz
|
||||||
from flask import render_template, request, url_for, redirect, flash
|
from flask import render_template, request, url_for, redirect, flash
|
||||||
from flask_sqlalchemy import Pagination
|
from flask_sqlalchemy import Pagination
|
||||||
from BDSM import app, db
|
from BDSM import app, db
|
||||||
from BDSM.models import Media, Settings, Toot, Emoji, Reblog
|
from BDSM.models import Media, Settings, Toot, Emoji, Other
|
||||||
from BDSM.toot import app_register, archive_toot
|
from BDSM.toot import app_register, archive_toot, get_context
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from datetime import timezone
|
from datetime import timezone
|
||||||
|
@ -53,7 +53,8 @@ def search():
|
||||||
def context(toot_id):
|
def context(toot_id):
|
||||||
def get_reply(reply_id):
|
def get_reply(reply_id):
|
||||||
toots = Toot.query.order_by(Toot.created_at.desc()).filter_by(in_reply_to_id=reply_id).all()
|
toots = Toot.query.order_by(Toot.created_at.desc()).filter_by(in_reply_to_id=reply_id).all()
|
||||||
toots = process_toot(toots)
|
other_toots = Other.query.order_by(Other.created_at.desc()).filter_by(in_reply_to_id=reply_id).all()
|
||||||
|
toots = process_toot(toots) + process_toot(other_toots)
|
||||||
|
|
||||||
for i in toots:
|
for i in toots:
|
||||||
if i.in_reply_to_id != None:
|
if i.in_reply_to_id != None:
|
||||||
|
@ -70,6 +71,8 @@ def context(toot_id):
|
||||||
while(in_reply_to_id != None):
|
while(in_reply_to_id != None):
|
||||||
toot = []
|
toot = []
|
||||||
toot_ = Toot.query.get(toots[0].in_reply_to_id)
|
toot_ = Toot.query.get(toots[0].in_reply_to_id)
|
||||||
|
if toot_ == None:
|
||||||
|
toot_ = Other.query.get(toots[0].in_reply_to_id)
|
||||||
if toot_ == None:
|
if toot_ == None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -80,6 +83,17 @@ def context(toot_id):
|
||||||
|
|
||||||
return render_template('view.html', toots=toots,)
|
return render_template('view.html', toots=toots,)
|
||||||
|
|
||||||
|
@app.route('/grab/<int:toot_id>', methods=['GET', 'POST'])
|
||||||
|
def grab(toot_id):
|
||||||
|
settings = Settings.query.first()
|
||||||
|
account = settings.account[1:]
|
||||||
|
username, domain = account.split("@")
|
||||||
|
url = "https://" + domain
|
||||||
|
|
||||||
|
get_context(url, toot_id)
|
||||||
|
flash('抓取完成……大概!')
|
||||||
|
return redirect(url_for('context',toot_id=toot_id))
|
||||||
|
|
||||||
@app.route('/settings', methods=['GET', 'POST'])
|
@app.route('/settings', methods=['GET', 'POST'])
|
||||||
def settings():
|
def settings():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -145,9 +159,6 @@ def archive():
|
||||||
settings = Settings.query.first()
|
settings = Settings.query.first()
|
||||||
if settings == None:
|
if settings == None:
|
||||||
return redirect(url_for('settings'))
|
return redirect(url_for('settings'))
|
||||||
elif len(Toot.query.all()) > 0:
|
|
||||||
flash('现暂不支持重复存档!') #TODO
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
else:
|
else:
|
||||||
account = settings.account[1:]
|
account = settings.account[1:]
|
||||||
username, domain = account.split("@")
|
username, domain = account.split("@")
|
||||||
|
@ -173,15 +184,19 @@ def process_toot(toots_):
|
||||||
toot.created_at = toot.created_at.replace(tzinfo=timezone.utc)
|
toot.created_at = toot.created_at.replace(tzinfo=timezone.utc)
|
||||||
toot.created_at = toot.created_at.astimezone(user_timezone).strftime(fmt)
|
toot.created_at = toot.created_at.astimezone(user_timezone).strftime(fmt)
|
||||||
|
|
||||||
|
if hasattr(toot, 'reblog_id'):
|
||||||
|
toot.is_myself = True
|
||||||
if toot.reblog_id != None:
|
if toot.reblog_id != None:
|
||||||
if toot.reblog_myself:
|
if toot.reblog_myself:
|
||||||
toot = Toot.query.get(toot.reblog_id)
|
toot = Toot.query.get(toot.reblog_id)
|
||||||
toot = SimpleNamespace(**toot.__dict__)
|
toot = SimpleNamespace(**toot.__dict__)
|
||||||
toot.is_reblog = True
|
toot.is_reblog = True
|
||||||
else:
|
else:
|
||||||
toot = Reblog.query.get(toot.reblog_id)
|
toot = Other.query.get(toot.reblog_id)
|
||||||
toot = SimpleNamespace(**toot.__dict__)
|
toot = SimpleNamespace(**toot.__dict__)
|
||||||
toot.is_reblog = True
|
toot.is_reblog = True
|
||||||
|
else:
|
||||||
|
toot.is_myself = False
|
||||||
|
|
||||||
if toot.media_list != "":
|
if toot.media_list != "":
|
||||||
toot.medias = []
|
toot.medias = []
|
||||||
|
|
Loading…
Reference in a new issue