comment podcast episodes
This commit is contained in:
parent
ca2d26f57b
commit
d891a58971
13 changed files with 329 additions and 46 deletions
|
@ -54,7 +54,8 @@ class Podcast(Item):
|
|||
# pass
|
||||
class PodcastEpisode(Item):
|
||||
category = ItemCategory.Podcast
|
||||
url_path = "podcastepisode"
|
||||
url_path = "podcast/episode"
|
||||
demonstrative = _("这集节目")
|
||||
# uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
|
||||
program = models.ForeignKey(Podcast, models.CASCADE, related_name="episodes")
|
||||
guid = models.CharField(null=True, max_length=1000)
|
||||
|
@ -67,6 +68,17 @@ class PodcastEpisode(Item):
|
|||
cover_url = models.CharField(null=True, max_length=1000)
|
||||
duration = models.PositiveIntegerField(null=True)
|
||||
|
||||
@property
|
||||
def parent_item(self):
|
||||
return self.program
|
||||
|
||||
def get_absolute_url_with_position(self, position=None):
|
||||
return (
|
||||
self.absolute_url
|
||||
if position is None or position == ""
|
||||
else f"{self.absolute_url}?position={position}"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
index_together = [
|
||||
[
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
</script>
|
||||
{% endif %}
|
||||
{% if jquery %}
|
||||
<script src="https://cdn.staticfile.org/jquery/3.6.1/jquery.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/jquery/3.6.3/jquery.min.js"></script>
|
||||
{% else %}
|
||||
<script src="https://cdn.staticfile.org/cash/8.1.2/cash.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/cash/8.1.3/cash.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$.fn.is_visible = function visible() {
|
||||
return this.filter((_, elt) => (elt.offsetWidth || elt.offsetHeight || elt.getClientRects().length)).length > 0;
|
||||
|
@ -29,7 +29,7 @@
|
|||
};
|
||||
</script>
|
||||
{% endif %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/htmx/1.8.4/htmx.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/htmx/1.8.5/htmx.min.js"></script>
|
||||
<script src="{% static 'lib/js/hyperscript-0.9.7.min.js' %}"></script>
|
||||
<script src="{% static 'lib/js/rating-star.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/boofilsic.css' %}">
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{% load strip_scheme %}
|
||||
{% load thumb %}
|
||||
|
||||
{% block opengraph %}
|
||||
{% block head %}
|
||||
{% if item.author %}
|
||||
<meta property="og:book:author" content="{% for author in item.author %}{{ author }}{% if not forloop.last %},{% endif %}{% endfor %}">
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{{ item.cover.url }}">
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
<meta property="og:description" content="{{ item.brief }}">
|
||||
{% block opengraph %}
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
<title>{{ site_name }} - {% trans item.category.label %} | {{ item.title }}</title>
|
||||
{% include "common_libs.html" with jquery=0 %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{% load strip_scheme %}
|
||||
{% load thumb %}
|
||||
|
||||
{% block opengraph %}
|
||||
{% block head %}
|
||||
<script src=" https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/shikwasa.min.js "></script>
|
||||
<link href=" https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/style.min.css " rel="stylesheet"></link>
|
||||
{% endblock %}
|
||||
|
@ -88,11 +88,12 @@
|
|||
{% block sidebar %}
|
||||
<div class="aside-section-wrapper">
|
||||
<div class="action-panel" id="episodes">
|
||||
<div class="action-panel__label">{% trans '最近更新' %}</div>
|
||||
<div class="action-panel__label">{% trans '近期单集' %}</div>
|
||||
<div >
|
||||
{% for ep in item.recent_episodes %}
|
||||
<p>
|
||||
<a data-media="{{ ep.media_url }}" data-cover="{{ ep.cover_url|default:item.cover }}" class="episode" href="{{ep.link}}">{{ ep.title }}</a>
|
||||
<a data-media="{{ ep.media_url }}" data-cover="{{ ep.cover_url|default:item.cover }}" class="episode" href="{{ep.url}}" data-uuid="{{ep.uuid}}">{{ ep.title }}</a>
|
||||
<a href="#" hx-get="{% url 'journal:comment' item.uuid ep.uuid %}" hx-target="body" hx-swap="beforeend"><span class="comment icon"></span></a>
|
||||
</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
@ -122,37 +123,42 @@
|
|||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
album = "{{ item.title|escapejs }}"
|
||||
artists = "{{ item.hosts|join:' / '|escapejs }}"
|
||||
function create_player(audio) {
|
||||
window.player = new Shikwasa.Player({
|
||||
container: () => document.querySelector('.player'),
|
||||
preload: 'metadata',
|
||||
autoplay: true,
|
||||
themeColor: '#1190C0',
|
||||
fixed: {
|
||||
type: 'fixed',
|
||||
position: 'bottom'
|
||||
},
|
||||
audio: audio
|
||||
});
|
||||
$('.shk-title').on('click', e=>{
|
||||
window.location = "#episodes";
|
||||
});
|
||||
$('.footer').attr('style', 'margin-bottom: 120px !important');
|
||||
}
|
||||
$(()=>{
|
||||
$('.episode').on('click', e=>{
|
||||
e.preventDefault();
|
||||
ele = e.target;
|
||||
album = "{{ item.title|escapejs }}"
|
||||
artists = "{{ item.hosts|join:' / '|escapejs }}"
|
||||
title = $(ele).text();
|
||||
cover_url = $(ele).data('cover');
|
||||
media_url = $(ele).data('media');
|
||||
if (!media_url) return;
|
||||
window.current_item_uuid = $(ele).data('uuid');
|
||||
if (!window.player) {
|
||||
window.player = new Shikwasa.Player({
|
||||
container: () => document.querySelector('.player'),
|
||||
preload: 'metadata',
|
||||
autoplay: true,
|
||||
themeColor: '#1190C0',
|
||||
fixed: {
|
||||
type: 'fixed',
|
||||
position: 'bottom'
|
||||
},
|
||||
audio: {
|
||||
title: title,
|
||||
cover: cover_url,
|
||||
src: media_url,
|
||||
album: album,
|
||||
artist: artists
|
||||
}
|
||||
});
|
||||
$('.shk-title').on('click', e=>{
|
||||
window.location = "#episodes";
|
||||
});
|
||||
create_player({
|
||||
title: title,
|
||||
cover: cover_url,
|
||||
src: media_url,
|
||||
album: album,
|
||||
artist: artists
|
||||
})
|
||||
} else {
|
||||
window.player.update({
|
||||
title: title,
|
||||
|
@ -164,7 +170,18 @@
|
|||
}
|
||||
window.player.play()
|
||||
});
|
||||
$('.footer').attr('style', 'margin-bottom: 120px !important');
|
||||
{% if focus_item %}
|
||||
loc = 1 * "{{request.GET.position|escapejs}}";
|
||||
window.current_item_uuid = "{{focus_item.uuid}}";
|
||||
create_player({
|
||||
title: "{{ focus_item.title | escapejs }}",
|
||||
cover: "{{ focus_item.cover_url | default:'' | escapejs }}",
|
||||
src: "{{ focus_item.media_url | escapejs }}",
|
||||
album: album,
|
||||
artist: artists
|
||||
})
|
||||
if (loc) window.player._initSeek = loc;
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
15
catalog/templates/podcastepisode.html
Normal file
15
catalog/templates/podcastepisode.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "item_base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load humanize %}
|
||||
{% load admin_url %}
|
||||
{% load mastodon %}
|
||||
{% load oauth_token %}
|
||||
{% load truncate %}
|
||||
{% load strip_scheme %}
|
||||
{% load thumb %}
|
||||
|
||||
{% block head %}
|
||||
<meta http-equiv="refresh" content="0;url={{ item.program.absolute_url }}?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
|
||||
{% endblock %}
|
|
@ -50,6 +50,11 @@ def retrieve(request, item_path, item_uuid):
|
|||
return redirect(item.merged_to_item.url)
|
||||
if not skipcheck and item.is_deleted:
|
||||
return HttpResponseNotFound("item not found")
|
||||
focus_item = None
|
||||
if request.GET.get("focus"):
|
||||
focus_item = get_object_or_404(
|
||||
Item, uid=base62.decode(request.GET.get("focus"))
|
||||
)
|
||||
mark = None
|
||||
review = None
|
||||
mark_list = None
|
||||
|
@ -87,6 +92,7 @@ def retrieve(request, item_path, item_uuid):
|
|||
item.class_name + ".html",
|
||||
{
|
||||
"item": item,
|
||||
"focus_item": focus_item,
|
||||
"mark": mark,
|
||||
"review": review,
|
||||
"mark_list": mark_list,
|
||||
|
|
|
@ -195,3 +195,33 @@ progress {
|
|||
.markdownx-editor {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: lightgray;
|
||||
}
|
||||
.icon:hover {
|
||||
color: #00a1cc;
|
||||
}
|
||||
.comment.icon {
|
||||
box-sizing: unset;
|
||||
position: absolute;
|
||||
margin-left: 2px;
|
||||
margin-top: 4px;
|
||||
width: 15px;
|
||||
height: 10px;
|
||||
border: solid 1px currentColor;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.comment.icon:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 8px;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
background-color: white;
|
||||
border-bottom: solid 1px currentColor;
|
||||
border-right: solid 1px currentColor;
|
||||
}
|
||||
|
|
|
@ -187,6 +187,9 @@ class Memo(Content):
|
|||
|
||||
class Comment(Content):
|
||||
text = models.TextField(blank=False, null=False)
|
||||
focus_item = models.ForeignKey(
|
||||
Item, on_delete=models.PROTECT, null=True, related_name="focused_comments"
|
||||
)
|
||||
|
||||
@property
|
||||
def html(self):
|
||||
|
@ -950,7 +953,9 @@ class Mark:
|
|||
|
||||
@cached_property
|
||||
def comment(self):
|
||||
return Comment.objects.filter(owner=self.owner, item=self.item).first()
|
||||
return Comment.objects.filter(
|
||||
owner=self.owner, item=self.item, focus_item__isnull=True
|
||||
).first()
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
|
|
83
journal/templates/comment.html
Normal file
83
journal/templates/comment.html
Normal file
|
@ -0,0 +1,83 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load humanize %}
|
||||
{% load admin_url %}
|
||||
{% load mastodon %}
|
||||
{% load oauth_token %}
|
||||
{% load truncate %}
|
||||
{% load highlight %}
|
||||
{% load thumb %}
|
||||
|
||||
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
|
||||
<div class="modal-underlay" _="on click trigger closeModal"></div>
|
||||
<div class="modal-content">
|
||||
<div class="add-to-list-modal__head">
|
||||
<span class="add-to-list-modal__title">{% trans '分享' %} {{ item.title }}: {{ focus_item.title }}</span>
|
||||
<span class="add-to-list-modal__close-button modal-close" _="on click trigger closeModal">
|
||||
<span class="icon-cross">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<polygon
|
||||
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
|
||||
</polygon>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="add-to-list-modal__body">
|
||||
<form action="{% url 'journal:comment' item.uuid focus_item.uuid %}" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<textarea name="text" cols="40" rows="10" placeholder="超过360字部分实例可能无法显示" maxlength="360" id="id_text">{% if comment.text %}{{ comment.text }}{% endif %}</textarea>
|
||||
|
||||
<div class="mark-modal__share-checkbox float-right">
|
||||
<label for="id_share_to_mastodon"><input type="checkbox" name="share_to_mastodon" id="id_share_to_mastodon" value="1" checked>分享到联邦网络</label>
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__option">
|
||||
<div class="mark-modal__visibility-radio">
|
||||
<span>可见性:
|
||||
<ul id="id_visibility">
|
||||
<li><label for="id_visibility_0"><input type="radio" name="visibility" value="0" required="" id="id_visibility_0" {% if comment.visibility == 0 or not comment %}checked{% endif %}> 公开</label> </li>
|
||||
<li><label for="id_visibility_1"><input type="radio" name="visibility" value="1" required="" id="id_visibility_1" {% if comment.visibility == 1 %}checked{% endif %}> 仅关注者</label> </li>
|
||||
<li><label for="id_visibility_2"><input type="radio" name="visibility" value="2" required="" id="id_visibility_2" {% if comment.visibility == 2 %}checked{% endif %}> 仅自己</label> </li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mark-modal__confirm-button">
|
||||
<input type="submit" class="button float-right" value="保存">
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
input:invalid#position {
|
||||
border: red dashed 1px;
|
||||
}
|
||||
</style>
|
||||
<div class="mark-modal__option">
|
||||
<div class="mark-modal__visibility-radio">
|
||||
<span>
|
||||
<label for="share_position"><input type="checkbox" name="share_position" value="1" id="share_position"> 分享播放位置: </label>
|
||||
<input type="input" name="position" id="position" value="00:00:00" class="html-duration-picker" pattern="[0-9]{2}:[0-9]{2}:[0-9]{2}" title="hh:mm:ss" style="display: none;">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
if (window.player && window.current_item_uuid == "{{ focus_item.uuid }}"){
|
||||
$('#share_position').prop('checked', true);
|
||||
$("#position").show()
|
||||
var t = ~~ window.player.currentTime;
|
||||
$('#position').val(('0' + ~~(t/3600)).substr(-2) + ':' + ('0' + ~~(t%3600/60)).substr(-2) + ':' + ("0" + t%60).substr(-2))
|
||||
}
|
||||
$('#share_position').on('click', ()=>{
|
||||
if ($('#share_position').prop('checked')) {
|
||||
$("#position").show()
|
||||
} else {
|
||||
$("#position").hide()
|
||||
}
|
||||
})
|
||||
</script>
|
|
@ -21,6 +21,7 @@ urlpatterns = [
|
|||
path("like/<str:piece_uuid>", like, name="like"),
|
||||
path("unlike/<str:piece_uuid>", unlike, name="unlike"),
|
||||
path("mark/<str:item_uuid>", mark, name="mark"),
|
||||
path("comment/<str:item_uuid>/<str:focus_item_uuid>", comment, name="comment"),
|
||||
path(
|
||||
"add_to_collection/<str:item_uuid>", add_to_collection, name="add_to_collection"
|
||||
),
|
||||
|
|
|
@ -21,12 +21,19 @@ from django.db.models import Q
|
|||
from management.models import Announcement
|
||||
from django.utils.baseconv import base62
|
||||
from .forms import *
|
||||
from mastodon.api import share_review, share_collection
|
||||
from mastodon.api import (
|
||||
get_spoiler_text,
|
||||
share_review,
|
||||
share_collection,
|
||||
get_status_id_by_url,
|
||||
post_toot,
|
||||
get_visibility,
|
||||
)
|
||||
from users.views import render_user_blocked, render_user_not_found
|
||||
from users.models import User, Report, Preference
|
||||
from common.utils import PageLinksGenerator
|
||||
from user_messages import api as msg
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
PAGE_SIZE = 10
|
||||
|
@ -172,6 +179,91 @@ def mark(request, item_uuid):
|
|||
return HttpResponseBadRequest()
|
||||
|
||||
|
||||
@login_required
|
||||
def comment(request, item_uuid, focus_item_uuid):
|
||||
item = get_object_or_404(Item, uid=base62.decode(item_uuid))
|
||||
focus_item = get_object_or_404(Item, uid=base62.decode(focus_item_uuid))
|
||||
if focus_item.parent_item != item:
|
||||
return HttpResponseNotFound()
|
||||
comment = Comment.objects.filter(
|
||||
owner=request.user, item=item, focus_item=focus_item
|
||||
).first()
|
||||
if request.method == "GET":
|
||||
return render(
|
||||
request,
|
||||
"comment.html",
|
||||
{
|
||||
"item": item,
|
||||
"focus_item": focus_item,
|
||||
"comment": comment,
|
||||
},
|
||||
)
|
||||
elif request.method == "POST":
|
||||
if request.POST.get("delete", default=False):
|
||||
if not comment:
|
||||
return HttpResponseNotFound()
|
||||
comment.delete()
|
||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
|
||||
visibility = int(request.POST.get("visibility", default=0))
|
||||
text = request.POST.get("text")
|
||||
position = (
|
||||
request.POST.get("position")
|
||||
if request.POST.get("share_position")
|
||||
else "0:0:0"
|
||||
)
|
||||
try:
|
||||
pos = datetime.strptime(position, "%H:%M:%S")
|
||||
position = pos.hour * 3600 + pos.minute * 60 + pos.second
|
||||
except:
|
||||
raise
|
||||
position = 0
|
||||
share_to_mastodon = bool(request.POST.get("share_to_mastodon", default=False))
|
||||
shared_link = None
|
||||
post_error = False
|
||||
if share_to_mastodon:
|
||||
shared_link = comment.metadata.get("shared_link") if comment else None
|
||||
status_id = get_status_id_by_url(shared_link)
|
||||
link = focus_item.get_absolute_url_with_position(position or None)
|
||||
status = f"分享{ItemCategory(item.category).label}《{item.title}》的《{focus_item.title}》\n{link}\n{text}"
|
||||
spoiler, status = get_spoiler_text(status, item)
|
||||
try:
|
||||
response = post_toot(
|
||||
request.user.mastodon_site,
|
||||
status,
|
||||
get_visibility(visibility, request.user),
|
||||
request.user.mastodon_token,
|
||||
False,
|
||||
status_id,
|
||||
spoiler,
|
||||
)
|
||||
if response and response.status_code in [200, 201]:
|
||||
j = response.json()
|
||||
if "url" in j:
|
||||
shared_link = j["url"]
|
||||
except Exception as e:
|
||||
raise
|
||||
post_error = True
|
||||
if comment:
|
||||
comment.visibility = visibility
|
||||
comment.text = text
|
||||
if shared_link:
|
||||
comment.metadata["shared_link"] = shared_link
|
||||
comment.save()
|
||||
else:
|
||||
comment = Comment.objects.create(
|
||||
owner=request.user,
|
||||
item=item,
|
||||
focus_item=focus_item,
|
||||
text=text,
|
||||
visibility=visibility,
|
||||
metadata={"shared_link": shared_link},
|
||||
)
|
||||
if post_error:
|
||||
return render_relogin(request)
|
||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
|
||||
def collection_retrieve(request, collection_uuid):
|
||||
collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid))
|
||||
if not collection.is_visible_to(request.user):
|
||||
|
@ -712,7 +804,7 @@ def profile(request, user_name):
|
|||
ItemCategory.Movie,
|
||||
ItemCategory.TV,
|
||||
ItemCategory.Music,
|
||||
# ItemCategory.Podcast,
|
||||
ItemCategory.Podcast,
|
||||
ItemCategory.Game,
|
||||
]
|
||||
for category in visbile_categories:
|
||||
|
|
|
@ -117,6 +117,8 @@ def post_toot(
|
|||
response.status_code = 200
|
||||
if response.status_code != 200:
|
||||
logger.error(f"Error {url} {response.status_code}")
|
||||
print(payload)
|
||||
print(response)
|
||||
except Exception:
|
||||
response = None
|
||||
return response
|
||||
|
@ -454,6 +456,34 @@ def revoke_token(site, token):
|
|||
post(url, data=payload, headers={"User-Agent": USER_AGENT})
|
||||
|
||||
|
||||
def get_status_id_by_url(url):
|
||||
if not url:
|
||||
return None
|
||||
r = re.match(
|
||||
r".+/(\w+)$", url
|
||||
) # might be re.match(r'.+/([^/]+)$', u) if Pleroma supports edit
|
||||
return r[1] if r else None
|
||||
|
||||
|
||||
def get_spoiler_text(text, item):
|
||||
if text.find(">!") != -1:
|
||||
spoiler_text = f"关于《{item.title}》 可能有关键情节等敏感内容"
|
||||
return spoiler_text, text.replace(">!", "").replace("!<", "")
|
||||
else:
|
||||
return None, text
|
||||
|
||||
|
||||
def get_visibility(visibility, user):
|
||||
if visibility == 2:
|
||||
return TootVisibilityEnum.DIRECT
|
||||
elif visibility == 1:
|
||||
return TootVisibilityEnum.PRIVATE
|
||||
elif user.get_preference().mastodon_publish_public:
|
||||
return TootVisibilityEnum.PUBLIC
|
||||
else:
|
||||
return TootVisibilityEnum.UNLISTED
|
||||
|
||||
|
||||
def share_mark(mark):
|
||||
from catalog.common import ItemCategory
|
||||
|
||||
|
@ -479,16 +509,8 @@ def share_mark(mark):
|
|||
MastodonApplication.objects.get(domain_name=user.mastodon_site).star_mode,
|
||||
)
|
||||
content = f"{mark.translated_status}《{mark.item.title}》{stars}\n{mark.item.absolute_url}\n{mark.text or ''}{tags}"
|
||||
update_id = None
|
||||
if mark.shared_link: # "https://mastodon.social/@username/1234567890"
|
||||
r = re.match(
|
||||
r".+/(\w+)$", mark.shared_link
|
||||
) # might be re.match(r'.+/([^/]+)$', u) if Pleroma supports edit
|
||||
update_id = r[1] if r else None
|
||||
spoiler_text = None
|
||||
if content.find(">!") != -1:
|
||||
spoiler_text = f"关于《{mark.item.title}》 可能有关键情节等敏感内容"
|
||||
content = content.replace(">!", "").replace("!<", "")
|
||||
update_id = get_status_id_by_url(mark.shared_link)
|
||||
spoiler_text, content = get_spoiler_text(content, mark.item)
|
||||
response = post_toot(
|
||||
user.mastodon_site,
|
||||
content,
|
||||
|
|
Loading…
Add table
Reference in a new issue