Skip to content

Instantly share code, notes, and snippets.

@neetsdkasu
Last active July 26, 2020 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neetsdkasu/7a5bdb72a3061697b8d564d0a1f2610e to your computer and use it in GitHub Desktop.
Save neetsdkasu/7a5bdb72a3061697b8d564d0a1f2610e to your computer and use it in GitHub Desktop.
outbox.json解析 (mastodon)
*.json
*.exe
*.txt
*.html
*.ico
*.mt
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sort"
"strings"
"time"
)
func main() {
if err := run(); err != nil {
println(err.Error())
}
}
func run() (err error) {
objects := []*Object_3_{}
files := []string{"f_outbox.json", "m_outbox.json", "p_outbox2.json"}
for _, file := range files {
var blob []byte
blob, err = ioutil.ReadFile(file)
if err != nil {
return
}
var o Object_1_
if err = json.Unmarshal(blob, &o); err != nil {
return
}
fmt.Println(file+":", len(o.OrderedItems))
objects = append(objects, o.OrderedItems...)
}
fmt.Println("total:", len(objects))
sort.Slice(objects, func(i, j int) bool {
return strings.Compare(objects[i].Published, objects[j].Published) < 0
})
out, err := os.Create("mastodon.mt")
if err != nil {
return
}
defer func() {
tmp := out.Close()
if err == nil {
err = tmp
}
}()
ommit := func(obj *Object_4_) bool {
if strings.Contains(obj.InReplyTo, "drrr_sukima") {
return true
}
return strings.Contains(obj.Content, "ツイッターボタン女子絵のまとめ")
}
ids := ObjectMap{}
for _, item := range objects {
obj, ok := item.Object.GetObject_4_()
if !ok {
continue
}
if ommit(obj) {
continue
}
ids[obj.Id] = obj
}
j := 0
for i, item := range objects[:0] {
obj, ok := item.Object.GetObject_4_()
if !ok {
continue
}
if ommit(obj) {
continue
}
fmt.Fprintln(out)
fmt.Fprintln(out, "[", j, "/", i, "]", "-------------------------")
// fmt.Fprintln(out, "Id:", item.Id)
// fmt.Fprintln(out, "Published:", item.Published)
// fmt.Fprintln(out, "Actor:", item.Actor)
// fmt.Fprintln(out, "To:", item.To)
// fmt.Fprintln(out, "Cc:", item.Cc)
// fmt.Fprintln(out, "--------------")
fmt.Fprintln(out, "Id:", obj.Id)
fmt.Fprintln(out, "Published:", obj.Published)
fmt.Fprintln(out, "Content:", obj.Content)
fmt.Fprintln(out, "Attachment:", len(obj.Attachment))
fmt.Fprintln(out, "To:", obj.To)
fmt.Fprintln(out, "Cc:", obj.Cc)
fmt.Fprintln(out, "InReplyTo:", obj.InReplyTo)
if len(obj.InReplyTo) > 0 {
_, ok := ids[obj.InReplyTo]
fmt.Fprintln(out, ok)
}
fmt.Fprintln(out, "Url:", obj.Url)
j++
content := findAnchor(obj.Content, func(url string) (int, string) {
fmt.Fprintln(out, url)
if !isMastodonURL(url) {
return 1, ""
}
switch {
case strings.Contains(url, "/media/"):
return -1, ""
case strings.Contains(url, "/tags/"):
return 0, ""
default:
return 1, ""
}
})
if strings.Compare(obj.Content, content) != 0 {
fmt.Fprintln(out, "before:", obj.Content)
fmt.Fprintln(out, "after :", content)
}
}
currentDate := 0
posts := []*Object_4_{}
for _, item := range objects[:0] {
obj, ok := item.Object.GetObject_4_()
if !ok || ommit(obj) {
continue
}
t := Toot{obj}.Time()
date := t.Year()*10000 + int(t.Month())*100 + t.Day()
if date == currentDate {
posts = append(posts, obj)
} else {
// if len(posts) > 20 && currentDate > 20170506 {
if currentDate == 20180417 {
break
}
posts = posts[:0]
posts = append(posts, obj)
currentDate = date
}
}
// fmt.Println(currentDate)
// dt := fmt.Sprintf("<p>%d</p>", currentDate)
// ss := makeList(ids, posts)
// sss := GetTestMT(0, dt, ss)
// fmt.Fprint(out, sss)
// fmt.Println("-----------")
for _, item := range objects[:0] {
obj, ok := item.Object.GetObject_4_()
if !ok || ommit(obj) {
continue
}
findAnchor(obj.Content, func(url string) (int, string) {
if !isMastodonURL(url) ||
strings.Contains(url, "/tags/") ||
strings.Contains(url, "/media/") {
if strings.Contains(url, "neetsdkasu") ||
strings.Contains(url, "usakdsteen") {
if strings.Contains(url, "twitter") && strings.Contains(url, "status") {
fmt.Println(Toot{obj}.Time().Local(), Toot{obj}.InstanceName(), "=========")
fmt.Println(url)
}
}
return -1, ""
}
if strings.Contains(url, "neetsdkasu") {
if !strings.HasSuffix(url, "neetsdkasu") {
fmt.Println(Toot{obj}.Time().Local(), Toot{obj}.InstanceName(), "*********")
fmt.Println(url)
x := fromUrlToId(url)
if t, ok := ids[x]; ok {
fmt.Println(t.Url)
}
}
return -1, ""
}
if strings.Contains(url, "@pixiv") {
fmt.Println(Toot{obj}.Time().Local(), Toot{obj}.InstanceName(), "#########")
fmt.Println(url)
// fmt.Println(obj.Content)
// fmt.Println(obj.Summary)
// fmt.Println(obj.Sensitive)
}
return -1, ""
})
}
// fmt.Println("-----------")
for _, item := range objects[:0] {
obj, ok := item.Object.GetObject_4_()
if !ok || ommit(obj) || len(obj.Attachment) == 0 {
continue
}
fmt.Println(Toot{obj}.Time().Local(), Toot{obj}.InstanceName())
for _, a := range obj.Attachment {
fmt.Println(a.Url)
}
}
for _, item := range objects[:0] {
obj, ok := item.Object.GetObject_4_()
if !ok || ommit(obj) || len(obj.Summary) == 0 {
continue
}
fmt.Println(Toot{obj}.Time().Local(), Toot{obj}.InstanceName(), "%%%%%%%%")
fmt.Println(obj.Summary)
}
currentDate = 0
dateList := []int{}
postList := [][]*Object_4_{}
tempPost := []*Object_4_{}
for _, item := range objects {
obj, ok := item.Object.GetObject_4_()
if !ok || ommit(obj) {
continue
}
t := Toot{obj}.Time()
date := t.Year()*10000 + int(t.Month())*100 + t.Day()
if date != currentDate {
dateList = append(dateList, date)
if currentDate != 0 {
postList = append(postList, tempPost)
tempPost = []*Object_4_{}
}
currentDate = date
}
tempPost = append(tempPost, obj)
}
postList = append(postList, tempPost)
fmt.Println(len(dateList))
fmt.Println(len(postList))
categories := []string{"from-md"}
const DateFormat = "2006年01月02日"
entryName := func(t time.Time) string {
return fmt.Sprintf(
`<span><time datetime="%s">%s</time>のToots</span>`,
t.Format("2006-01-02T15:04:05-07:00"),
t.Format(DateFormat),
)
}
for i, posts := range postList {
date := Toot{posts[0]}.Time()
title := date.Format(DateFormat) + "のToots"
body := entryName(date)
if i > 0 {
prevDayToot := Toot{postList[i-1][0]}
prev := fmt.Sprintf(
`&lt;&nbsp;<a href="/entry/%s">%s</a>&nbsp;|&nbsp;`,
prevDayToot.MTBaseName(),
entryName(prevDayToot.Time()),
)
body = prev + body
}
if i+1 < len(postList) {
nextDayToot := Toot{postList[i+1][0]}
body += fmt.Sprintf(
`&nbsp;|&nbsp;<a href="/entry/%s">%s</a>&nbsp;&gt;`,
nextDayToot.MTBaseName(),
entryName(nextDayToot.Time()),
)
}
body = "<p>" + body + "</p>"
ext := makeList(ids, posts) + body
entry := &BlogEntry{
Author: "Leonardone",
Title: title,
Year: date.Year(),
Month: int(date.Month()),
Day: date.Day(),
Hour: 23,
Minute: 58,
Second: 58,
Categories: categories,
ConvertBreaks: 0,
Body: body,
ExtendedBody: ext,
}
fmt.Fprint(out, entry.String())
}
forTweet, err1 := os.Create("for_tweet.txt")
if err1 != nil {
return err1
}
defer func() {
if tmp := forTweet.Close(); err == nil {
err = tmp
}
}()
tweetList := strings.Split(strings.TrimSpace(`
https://pawoo.net/@neetsdkasu/1675189
https://mstdn.jp/@neetsdkasu/26310591
https://mstdn.jp/users/neetsdkasu/updates/12709682
https://mstdn.jp/@neetsdkasu/32285368
https://mstdn.jp/users/neetsdkasu/updates/14059113
https://mstdn.jp/@neetsdkasu/36999549
https://mstdn.jp/@neetsdkasu/38015247
https://mstdn.jp/@neetsdkasu/39262835
https://mstdn.jp/@neetsdkasu/44433381
https://pawoo.net/@neetsdkasu/11218455
https://mstdn.jp/@neetsdkasu/98879873964228083
https://mstdn.jp/@neetsdkasu/99026974050479636
https://mstdn.jp/@neetsdkasu/99029607761690441
https://pawoo.net/@neetsdkasu/99457669660041098
https://mstdn.jp/@neetsdkasu/102734731464706809
https://pawoo.net/@neetsdkasu/102745981851453414
`), "\n")
empty := Toot{nil}
for _, tw := range tweetList {
key := strings.TrimSpace(tw)
fmt.Fprintf(forTweet, "%q:", key)
if key == "https://mstdn.jp/users/neetsdkasu/updates/14059113" {
key = "https://mstdn.jp/@neetsdkasu/32486901"
} else if key == "https://mstdn.jp/users/neetsdkasu/updates/12709682" {
key = "https://mstdn.jp/@neetsdkasu/28326747"
}
key = fromUrlToId(key)
if obj, ok := ids[key]; ok {
fmt.Fprintf(forTweet, " %q,", Toot{obj}.Blockquote(ids, empty))
} else {
fmt.Println("why?")
fmt.Println(tw)
fmt.Println(key)
}
fmt.Fprintln(forTweet)
}
return
}
func makeList(allToots ObjectMap, targets []*Object_4_) string {
var b strings.Builder
fmt.Fprintln(&b, `<ol class="leonardonetoot">`)
for _, toot := range targets {
t := Toot{toot}
rep := t.ReplyCode(allToots, t)
text, img := t.BodyCode(allToots)
timeStr := t.TimeCode(false)
name := t.Name()
url := t.UrlCode(t)
fmt.Fprintf(
&b,
`<li id="%s"><div style="font-size: 0.8em; color: grey;">%s&nbsp;%s&nbsp;%s</div>%s%s%s</li>`,
makeLinkTargetId(toot.Id),
timeStr,
name,
url,
rep,
text,
img,
)
fmt.Fprintln(&b)
}
fmt.Fprintln(&b, "</ol>")
return b.String()
}
package main
import "encoding/json"
type Object_10_ struct {
Items []string `json:"items"`
Next string `json:"next"`
PartOf string `json:"partOf"`
Type string `json:"type"`
}
type Object_12_ struct {
Container string `json:"@container"`
Id string `json:"@id"`
}
type Object_14_ struct {
Id string `json:"@id"`
Type string `json:"@type"`
}
type Object_5_ struct {
Blurhash string `json:"blurhash"`
MediaType string `json:"mediaType"`
Name interface{} `json:"name"`
Type string `json:"type"`
Url string `json:"url"`
}
type Object_6_ struct {
Ar string `json:"ar"`
Bg string `json:"bg"`
Da string `json:"da"`
De string `json:"de"`
En string `json:"en"`
Es string `json:"es"`
Fa string `json:"fa"`
Fr string `json:"fr"`
Hi string `json:"hi"`
HiLatn string `json:"hiLatn"`
It string `json:"it"`
Ja string `json:"ja"`
Kk string `json:"kk"`
Nl string `json:"nl"`
No string `json:"no"`
Pl string `json:"pl"`
Pt string `json:"pt"`
Ru string `json:"ru"`
Sr string `json:"sr"`
Zh string `json:"zh"`
}
type Object_9_ struct {
MediaType string `json:"mediaType"`
Type string `json:"type"`
Url string `json:"url"`
}
type Object_7_ struct {
First *Object_10_ `json:"first"`
Id string `json:"id"`
Type string `json:"type"`
}
type Object_11_ struct {
Hashtag string `json:"Hashtag"`
AtomUri string `json:"atomUri"`
Blurhash string `json:"blurhash"`
Conversation string `json:"conversation"`
FocalPoint *Object_12_ `json:"focalPoint"`
InReplyToAtomUri string `json:"inReplyToAtomUri"`
Ostatus string `json:"ostatus"`
Sensitive string `json:"sensitive"`
Toot string `json:"toot"`
VotersCount string `json:"votersCount"`
}
type Mixed_6_ struct {
// *Object_14_
// string
Value interface{}
}
func (this *Mixed_6_) UnmarshalJSON(b []byte) (err error) {
{
var x *Object_14_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_6_) GetObject_14_() (ret *Object_14_, ok bool) {
ret, ok = this.Value.(*Object_14_)
return
}
func (this *Mixed_6_) Object_14_Value() *Object_14_ {
return this.Value.(*Object_14_)
}
func (this *Mixed_6_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_6_) StringValue() string {
return this.Value.(string)
}
type Object_8_ struct {
Href string `json:"href"`
Icon *Object_9_ `json:"icon"`
Id string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Updated string `json:"updated"`
}
type Mixed_4_ struct {
// string
// *Object_11_
Value interface{}
}
func (this *Mixed_4_) UnmarshalJSON(b []byte) (err error) {
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x *Object_11_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_4_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_4_) StringValue() string {
return this.Value.(string)
}
func (this *Mixed_4_) GetObject_11_() (ret *Object_11_, ok bool) {
ret, ok = this.Value.(*Object_11_)
return
}
func (this *Mixed_4_) Object_11_Value() *Object_11_ {
return this.Value.(*Object_11_)
}
type Object_13_ struct {
Emoji string `json:"Emoji"`
Hashtag string `json:"Hashtag"`
PropertyValue string `json:"PropertyValue"`
AtomUri string `json:"atomUri"`
Conversation string `json:"conversation"`
Featured *Mixed_6_ `json:"featured"`
FocalPoint *Object_12_ `json:"focalPoint"`
InReplyToAtomUri string `json:"inReplyToAtomUri"`
ManuallyApprovesFollowers string `json:"manuallyApprovesFollowers"`
MovedTo *Mixed_6_ `json:"movedTo"`
Ostatus string `json:"ostatus"`
Schema string `json:"schema"`
Sensitive string `json:"sensitive"`
Toot string `json:"toot"`
Value string `json:"value"`
}
type Object_4_ struct {
AtomUri string `json:"atomUri"`
Attachment []*Object_5_ `json:"attachment"`
AttributedTo string `json:"attributedTo"`
Cc []string `json:"cc"`
Content string `json:"content"`
ContentMap *Object_6_ `json:"contentMap"`
Conversation string `json:"conversation"`
Id string `json:"id"`
InReplyTo string `json:"inReplyTo"`
InReplyToAtomUri string `json:"inReplyToAtomUri"`
Published string `json:"published"`
Replies *Object_7_ `json:"replies"`
Sensitive bool `json:"sensitive"`
Summary string `json:"summary"`
Tag []*Object_8_ `json:"tag"`
To []string `json:"to"`
Type string `json:"type"`
Url string `json:"url"`
}
type Mixed_2_ struct {
// string
// []*Mixed_4_
Value interface{}
}
func (this *Mixed_2_) UnmarshalJSON(b []byte) (err error) {
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x []*Mixed_4_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_2_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_2_) StringValue() string {
return this.Value.(string)
}
func (this *Mixed_2_) GetMixed_4_s() (ret []*Mixed_4_, ok bool) {
ret, ok = this.Value.([]*Mixed_4_)
return
}
func (this *Mixed_2_) Mixed_4_sValue() []*Mixed_4_ {
return this.Value.([]*Mixed_4_)
}
type Mixed_5_ struct {
// string
// *Object_13_
Value interface{}
}
func (this *Mixed_5_) UnmarshalJSON(b []byte) (err error) {
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x *Object_13_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_5_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_5_) StringValue() string {
return this.Value.(string)
}
func (this *Mixed_5_) GetObject_13_() (ret *Object_13_, ok bool) {
ret, ok = this.Value.(*Object_13_)
return
}
func (this *Mixed_5_) Object_13_Value() *Object_13_ {
return this.Value.(*Object_13_)
}
type Mixed_3_ struct {
// string
// *Object_4_
Value interface{}
}
func (this *Mixed_3_) UnmarshalJSON(b []byte) (err error) {
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x *Object_4_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_3_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_3_) StringValue() string {
return this.Value.(string)
}
func (this *Mixed_3_) GetObject_4_() (ret *Object_4_, ok bool) {
ret, ok = this.Value.(*Object_4_)
return
}
func (this *Mixed_3_) Object_4_Value() *Object_4_ {
return this.Value.(*Object_4_)
}
type Mixed_1_ struct {
// string
// []*Mixed_5_
Value interface{}
}
func (this *Mixed_1_) UnmarshalJSON(b []byte) (err error) {
{
var x string
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
{
var x []*Mixed_5_
if err = json.Unmarshal(b, &x); err == nil {
this.Value = x
return
}
}
return
}
func (this *Mixed_1_) GetString() (ret string, ok bool) {
ret, ok = this.Value.(string)
return
}
func (this *Mixed_1_) StringValue() string {
return this.Value.(string)
}
func (this *Mixed_1_) GetMixed_5_s() (ret []*Mixed_5_, ok bool) {
ret, ok = this.Value.([]*Mixed_5_)
return
}
func (this *Mixed_1_) Mixed_5_sValue() []*Mixed_5_ {
return this.Value.([]*Mixed_5_)
}
type Object_3_ struct {
Context *Mixed_2_ `json:"@context"`
Actor string `json:"actor"`
AtomUri string `json:"atomUri"`
Cc []string `json:"cc"`
Id string `json:"id"`
Object *Mixed_3_ `json:"object"`
Published string `json:"published"`
To []string `json:"to"`
Type string `json:"type"`
}
type Object_2_ struct {
Context *Mixed_1_ `json:"@context"`
Id string `json:"id"`
OrderedItems []*Object_3_ `json:"orderedItems"`
TotalItems float64 `json:"totalItems"`
Type string `json:"type"`
}
type Object_1_ *Object_2_
package main
import (
"fmt"
"strings"
)
func fromUrlToId(url string) string {
host := getHostName(url)
z := strings.Split(url, "/")
return fmt.Sprintf(
"https://%s/users/neetsdkasu/statuses/%s",
host,
z[len(z)-1],
)
}
func getHostName(url string) string {
x := strings.TrimPrefix(url, "https://")
y := strings.SplitN(x, "/", 2)
return y[0]
}
func makeLinkTargetId(id string) string {
x := strings.TrimPrefix(id, "https://")
y := strings.SplitN(x, ".", 2)
z := strings.Split(id, "/")
return y[0] + z[len(z)-1]
}
func isMastodonURL(url string) bool {
return strings.HasPrefix(url, "https://pawoo.net/") ||
strings.HasPrefix(url, "https://mstdn.jp/") ||
strings.HasPrefix(url, "https://friends.nico/")
}
func trimURL(url string) string {
url = strings.TrimPrefix(url, "https://")
r := []rune(url)
var s, t string
if len(r) <= 30 {
s = url
t = ""
} else {
s = string(r[:30])
t = fmt.Sprintf(
`<span class="invisible">%s</span>`,
string(r[30:]),
)
}
return fmt.Sprintf(
`<span class="invisible">https://</span><span class="ellipsis">%s</span>%s`,
s,
t,
)
}
func findAnchor(s string, callback func(url string) (int, string)) (ret string) {
ret = ""
for {
sep := strings.SplitN(s, "<a ", 2)
if len(sep) < 2 {
ret += s
return
}
attr := strings.SplitN(sep[1], `href="`, 2)
href := strings.SplitN(attr[1], `"`, 2)
rest := strings.SplitN(href[1], ">", 2)
body := strings.SplitN(rest[1], "</a>", 2)
s = body[1]
p, r := callback(href[0])
switch {
case p < 0:
ret += sep[0]
case p == 0:
ret += sep[0] + body[0]
case p == 1:
ret += fmt.Sprintf(
`%s<a %shref="%s"%s>%s</a>`,
sep[0], attr[0], href[0], rest[0], body[0],
)
case p > 1:
ret += sep[0] + r
}
}
}
package main
import (
"strings"
"text/template"
)
const MT_TEMP = `AUTHOR: {{.Author}}
TITLE: {{.Title}}
BASENAME: {{printf "%04d/%02d/%02d/%02d%02d%02d" .Year .Month .Day .Hour .Minute .Second}}
STATUS: Publish
ALLOW COMMENTS: 1
ALLOW PINGS: 0
CONVERT BREAKS: {{.ConvertBreaks}}
PRIMARY CATEGORY: {{index .Categories 0}}{{range .Categories}}
CATEGORY: {{.}}{{end}}
DATE: {{printf "%02d/%02d/%04d %02d:%02d:%02d" .Month .Day .Year .Hour .Minute .Second}}
-----
BODY:
{{.Body}}
-----
EXTENDED BODY:{{if .ExtendedBody}}
{{.ExtendedBody}}{{end}}
-----
EXTENDED BODY PRIVATE:
-----
EXCERPT:
-----
KEYWORDS:
-----
--------
`
var MTtemplate = template.Must(template.New("MT").Parse(MT_TEMP))
type BlogEntry struct {
Author string
Title string
Year int
Month int
Day int
Hour int
Minute int
Second int
Categories []string
ConvertBreaks int
Body string
ExtendedBody string
}
func (this *BlogEntry) String() string {
var b strings.Builder
err := MTtemplate.Execute(&b, this)
if err != nil {
println(err.Error())
}
return b.String()
}
func GetTestMT(sec int, body, ext string) string {
entry := &BlogEntry{
Author: "Leonardone",
Title: "テスト投稿",
Year: 2020,
Month: 6,
Day: 1,
Hour: 11,
Minute: 22,
Second: sec,
Categories: []string{"testing"},
Body: body,
ExtendedBody: ext,
}
return entry.String()
}
package main
import (
"fmt"
"strings"
"time"
)
type ObjectMap map[string]*Object_4_
type Toot struct{ obj *Object_4_ }
func (this Toot) IsPawoo() bool {
return strings.HasPrefix(this.obj.Id, "https://p")
}
func (this Toot) IsMstdn() bool {
return strings.HasPrefix(this.obj.Id, "https://m")
}
func (this Toot) IsFriends() bool {
return strings.HasPrefix(this.obj.Id, "https://f")
}
func (this Toot) MTBaseName() string {
return this.Time().Format("2006/01/02") + "/235858"
}
func (this Toot) IsSameDate(other Toot) bool {
if this.obj == nil || other.obj == nil {
return false
}
t1 := this.Time()
t2 := other.Time()
return t1.Year() == t2.Year() &&
t1.Month() == t2.Month() &&
t1.Day() == t2.Day()
}
func (this Toot) BodyCode(allToots ObjectMap) (string, string) {
refUrls := []string{}
pixivToot := ""
myTweet := false
tweets := []string{}
content := findAnchor(this.obj.Content, func(url string) (int, string) {
if !isMastodonURL(url) {
if strings.HasPrefix(url, "https://twitter.com") &&
strings.Contains(url, "/status/") {
if url == "https://twitter.com/neetsdkasu/status/985238337463107584" {
myTweet = true
} else {
tweets = append(tweets, url)
}
return -1, ""
}
return 1, ""
}
switch {
case strings.Contains(url, "/media/"):
return -1, ""
case strings.Contains(url, "/tags/"):
return 0, ""
case strings.HasSuffix(url, "@neetsdkasu"):
return 2, fmt.Sprintf(
`<span class="mastodonuser">@neetsdkasu@%s</span>`,
getHostName(url),
)
case strings.Contains(url, "neetsdkasu"):
// たぶん自分のトゥートの引用
println("self,ref?", url)
refUrls = append(refUrls, url)
return -1, ""
default:
// 他のアカウントへの言及か他のアカウントの引用トゥート
if url == "https://pawoo.net/@itm_nlab" {
return 2, `<span class="mastodonuser">@itm_nlab@pawoo.net</span>`
}
if strings.Contains(url, "@pixiv") {
pixivToot = url
return -1, ""
}
println("ref?", url)
return 1, ""
}
})
if len(pixivToot) > 0 {
x := strings.SplitN(content, "<p>", 2)
y := strings.SplitN(x[1], "</p>", 3)
content = fmt.Sprintf(
`%s<blockquote><p><a href="%s" target="_blank" rel="nofollow noopener noreferrer external">%s</a></p></blockquote>%s`,
x[0],
pixivToot,
trimURL(pixivToot),
y[2],
)
}
if content == "<p></p>" {
content = "<p>&nbsp;</p>"
}
if len(this.obj.Summary) > 0 {
summary := fmt.Sprintf(
`<div style="border-bottom: 1px dotted;">%s</div>`,
this.obj.Summary,
)
content = summary + content
}
for _, url := range refUrls {
id := fromUrlToId(url)
if obj, ok := allToots[id]; ok {
content += Toot{obj}.Blockquote(allToots, this)
} else if len(allToots) == 0 {
content += fmt.Sprintf(
`<blockquote><a target="_blank" href="%s" rel="noopener noreferrer nofollow external">%s</a></blockquote>`,
url,
trimURL(url),
)
} else {
content += fmt.Sprintf(
`<blockquote><del><a target="_blank" href="%s" rel="noopener noreferrer nofollow external">%s</a></del></blockquote>`,
url,
trimURL(url),
)
}
}
if myTweet {
content += `<blockquote><div style="font-size: 0.8em; color: grey;"><a href="/entry/2018/04/15/235959#tweet985238337463107584" style="text-decoration: none; color: unset;"><time datetime="2018-04-15T04:28:19+09:00">2018年04月15日 04:28:19</time>&nbsp;@neetsdkasu</a>&nbsp;<a style="color: black;" target="_blank" href="https://twitter.com/neetsdkasu/status/985238337463107584" title="https://twitter.com/neetsdkasu/status/985238337463107584" rel="noopener noreferrer external">#</a></div><p>Lv2の問題、誤読が酷くて40分以上も間違った考察してて酷かった、Lv3は残り時間8分のとこで読み始めたがはみるとんへいろ勘違いしててループ検出コードなど出して死んでた…システスの結果2問正解まさかの23位でratingはhighestの無事青色のdiv1に上がれましたとさ(おしまい) </p><a target="_blank" href="https://pbs.twimg.com/media/DaxEQ6KUMAAr2iS.jpg" rel="noopener"><img src="https://pbs.twimg.com/media/DaxEQ6KUMAAr2iS.jpg" width="100" alt="image-0"></a><a target="_blank" href="https://pbs.twimg.com/media/DaxETBVV4AAr7SW.jpg" rel="noopener"><img src="https://pbs.twimg.com/media/DaxETBVV4AAr7SW.jpg" width="100" alt="image-1"></a></blockquote>`
}
for _, url := range tweets {
content += fmt.Sprintf(
`<blockquote class="twitter-tweet" data-conversation="none" data-theme="dark"><a href="%s" target="_blank" rel="nofollow noreferrer noopener external">%s</a></blockquote>`,
url,
trimURL(url),
)
}
img := ""
for i, m := range this.obj.Attachment {
url := m.Url
if this.IsPawoo() {
url = "https://img.pawoo.net" + url
} else if this.IsMstdn() {
url = "https://media.mstdn.jp" + url
}
img += fmt.Sprintf(
`<a target="_blank" href="%s" rel="noopener"><img src="%s" width="100" alt="image-%d"></a>`,
url,
url,
i,
)
}
return content, img
}
func (this Toot) ReplyCode(allToots ObjectMap, baseDate Toot) string {
if len(this.obj.InReplyTo) == 0 {
return ""
}
InReplyTo := this.obj.InReplyTo
for {
if rep, ok := allToots[InReplyTo]; ok {
other := Toot{rep}
if this.IsSameDate(other) {
return fmt.Sprintf(
`<span><a href="#%s">%s</a></span>`,
makeLinkTargetId(rep.Id),
other.Name(),
)
}
return fmt.Sprintf(
`<span><a href="/entry/%s#%s">%s</a></span>`,
other.MTBaseName(),
makeLinkTargetId(rep.Id),
other.Name(),
)
} else if InReplyTo == "https://pawoo.net/users/neetsdkasu/updates/2022165" {
InReplyTo = "https://pawoo.net/users/neetsdkasu/statuses/7059366"
} else {
return "<span>@ERROR " + this.obj.InReplyTo + "</span>"
}
}
}
func (this Toot) UrlCode(dayToot Toot) string {
if this.IsFriends() {
href := "#" + makeLinkTargetId(this.obj.Id)
if !this.IsSameDate(dayToot) {
href = "/entry/" + this.MTBaseName() + href
}
return fmt.Sprintf(
`<a style="color: black;" target="_blank" href="%s" rel="noopener" title="%s">#</a>`,
href,
this.obj.Url,
)
} else {
return fmt.Sprintf(
`<a style="color: black;" target="_blank" href="%s" rel="noopener noreferrer nofollow external" title="%s">#</a>`,
this.obj.Url,
this.obj.Url,
)
}
}
var EmptyObjectMap = ObjectMap{}
func (this Toot) Blockquote(allToots ObjectMap, dayToot Toot) string {
timeStr := this.TimeCode(!this.IsSameDate(dayToot))
name := this.Name()
rep := this.ReplyCode(allToots, dayToot)
text, img := this.BodyCode(EmptyObjectMap)
href := "#" + makeLinkTargetId(this.obj.Id)
if !this.IsSameDate(dayToot) {
href = "/entry/" + this.MTBaseName() + href
}
url := this.UrlCode(dayToot)
return fmt.Sprintf(
`<blockquote><div style="font-size: 0.8em; color: grey;"><a href="%s" style="text-decoration: none; color: unset;">%s&nbsp;%s</a>&nbsp;%s</div>%s%s%s</blockquote>`,
href,
timeStr,
name,
url,
rep,
text,
img,
)
}
func (this Toot) Time() time.Time {
t, err := time.Parse(time.RFC3339, this.obj.Published)
if err != nil {
println(err.Error())
}
return t.Local()
}
func (this Toot) TimeCode(full bool) string {
t := this.Time()
var dt string
if full {
dt = t.Format("2006年01月02日 15:04:05")
} else {
dt = t.Format("15:04:05")
}
return fmt.Sprintf(
`<time datetime="%s">%s</time>`,
t.Format("2006-01-02T15:04:05-07:00"),
dt,
)
}
func (this Toot) InstanceName() string {
return getHostName(this.obj.Id)
}
func (this Toot) Name() string {
return "@neetsdkasu@" + this.InstanceName()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment