Skip to content

Instantly share code, notes, and snippets.

@Code-Hex
Last active August 1, 2022 11:58
Show Gist options
  • Select an option

  • Save Code-Hex/e1f78e63ebe71ffc1d7b20453c088fab to your computer and use it in GitHub Desktop.

Select an option

Save Code-Hex/e1f78e63ebe71ffc1d7b20453c088fab to your computer and use it in GitHub Desktop.

Revisions

  1. Code-Hex revised this gist Aug 1, 2022. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -55,8 +55,6 @@ func run(ctx context.Context) error {
    return nil
    }

    var replacer = strings.NewReplacer("\\n", "\n")

    type Message struct {
    Text string
    Timestamp string // to use save point
    @@ -76,6 +74,7 @@ func history(ctx context.Context, slackClient *slack.Client) ([]*Message, error)
    return nil, err
    }
    for _, message := range resp.Messages {
    // If failed, you can continue to specify the timestamp here!
    // if message.Timestamp <= "1648392833.619319" {
    // continue
    // }
  2. Code-Hex created this gist Aug 1, 2022.
    12 changes: 12 additions & 0 deletions go.mod
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    module github.com/Code-Hex/slack2discord

    go 1.18

    require (
    github.com/Code-Hex/dd v1.1.0 // indirect
    github.com/bwmarrin/discordgo v0.25.0 // indirect
    github.com/gorilla/websocket v1.4.2 // indirect
    github.com/slack-go/slack v0.11.2 // indirect
    golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
    golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
    )
    151 changes: 151 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,151 @@
    package main

    import (
    "context"
    "fmt"
    "html"
    "os"
    "regexp"
    "strconv"
    "strings"
    "sync"
    "time"

    "github.com/bwmarrin/discordgo"
    "github.com/slack-go/slack"
    )

    func main() {
    if err := run(context.Background()); err != nil {
    fmt.Fprintf(os.Stderr, "failed to run: %q", err)
    os.Exit(1)
    }
    }

    const slackChannel = "C..." // slack channel ID
    const discordChannel = "..." // discord channel ID

    // < # opening angle bracket
    // ([^>\|]+) # link
    // (?:\|([^>]+))? # label
    // > # closing angle bracket
    var re = regexp.MustCompile(`<([^>\|]+)(?:\|([^>]+))?>`)

    func run(ctx context.Context) error {
    slackClient := slack.New("xoxp-...")
    session, err := discordgo.New("...")
    if err != nil {
    return err
    }

    messages, err := history(ctx, slackClient)
    if err != nil {
    return err
    }
    for _, m := range messages {
    fmt.Println("-------", m.Timestamp)
    fmt.Println(m.Text)
    _, err = session.ChannelMessageSend(discordChannel, m.Text)
    if err != nil {
    return fmt.Errorf("failed to send message: %w", err)
    }
    time.Sleep(time.Millisecond * 500)
    }
    // fmt.Println(dd.Dump(messages))
    return nil
    }

    var replacer = strings.NewReplacer("\\n", "\n")

    type Message struct {
    Text string
    Timestamp string // to use save point
    }

    func history(ctx context.Context, slackClient *slack.Client) ([]*Message, error) {
    var (
    cursor string
    messages []*Message
    )
    for i := 0; ; i++ {
    resp, err := slackClient.GetConversationHistoryContext(ctx, &slack.GetConversationHistoryParameters{
    ChannelID: slackChannel,
    Cursor: cursor,
    })
    if err != nil {
    return nil, err
    }
    for _, message := range resp.Messages {
    // if message.Timestamp <= "1648392833.619319" {
    // continue
    // }
    text := strings.TrimSpace(message.Text)
    if text == "" {
    continue
    }
    if strings.Contains(text, "さんがチャンネルに参加しました") {
    continue
    }
    if strings.Contains(text, "がこのチャンネルの説明を") {
    continue
    }
    replacedText := re.ReplaceAllStringFunc(text, func(s string) string {
    parts := re.FindStringSubmatch(s)
    link := parts[1]
    return link
    })

    t, err := ts2time(message.Timestamp)
    if err != nil {
    return nil, err
    }

    content := fmt.Sprintf("(%s)\n\n%s", t.Format("2006-01-02 15:04:05"), html.UnescapeString(replacedText))
    messages = append(messages, &Message{
    Text: content,
    Timestamp: message.Timestamp,
    })
    }
    if !resp.HasMore {
    break
    }
    cursor = resp.ResponseMetaData.NextCursor
    time.Sleep(time.Millisecond * 500)
    fmt.Println(i, len(messages), cursor)
    }
    return reverse(messages), nil
    }

    var jst *time.Location
    var once sync.Once

    func getJST() *time.Location {
    once.Do(func() {
    jst, _ = time.LoadLocation("Asia/Tokyo")
    })
    return jst
    }

    func ts2time(ts string) (time.Time, error) {
    sep := strings.Split(ts, ".")
    if len(sep) != 2 {
    return time.Time{}, fmt.Errorf("unexpected ts: %s", ts)
    }
    sec, ms := sep[0], sep[1]
    seci, err := strconv.Atoi(sec)
    if err != nil {
    return time.Time{}, fmt.Errorf("seci: %w", err)
    }
    msi, err := strconv.Atoi(ms)
    if err != nil {
    return time.Time{}, fmt.Errorf("msi: %w", err)
    }
    return time.Unix(int64(seci), int64(msi)).In(getJST()), nil
    }

    func reverse(s []*Message) []*Message {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
    s[i], s[j] = s[j], s[i]
    }
    return s
    }