4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-27 14:39:24 +00:00

Add initial Microsoft Teams support

Documentation on https://github.com/42wim/matterbridge/wiki/MS-Teams-setup
This commit is contained in:
Wim
2019-12-26 23:12:28 +01:00
parent 3af0dc3b3a
commit 795a8705c3
3362 changed files with 229502 additions and 22 deletions

2
vendor/github.com/mattn/godown/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
*.swp
godown

14
vendor/github.com/mattn/godown/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- 1.8
- 1.9.3
env:
secure: "sssm68fvzltcAnFd0Vc+OJV0eOicaTUO4I/CRX9LsnqzSsiNmaFT5o1O0Mx622ApYxCfiG3G53B8wuPzSMQxdPaSiMqzoXNLjD8gURaZBWTXc+kj9WFUoS4KW5L8KF3zrmS1u6Ja9U/elIpNqbpuwqT7sZUUJJM1JR50uEVmtP9oc/iqTKh3JK1HZCkb/PDVKs7xY5AEOhx1x0QOn9SegMUK2b83WeuSbta3Z6Rp4EW3p3WwI1WHZmm8+IYjvbwu18foQSetfro+pXCyDBpw1zLbBTDR8W02VwkH2vECMm4N7GYPmHWNx2lZFqoFp9zY5zCRUQG9KmxqbappalBCsT1ZyesUt7Wp/qYw5W+1Np7/vQhe8eeyyKMzsS7FBq8Imn4JiBPbj/1KAhVoZZKyv0qU4hgxHPZMC/JtVoTkIH3IXvTE88P92z9pFL30afQ692BXPe+XmCBph4zBdH88vksdiky9DWuXJ+O0rDCcLes45ij/wk6psdTPx3IXuMohfkO81F0pveksBYFkff8dXXxCABUzZbPaawEDnLAQKJ1m+oF3UYhPzVwrelNjFDOUq3mxsTU36uyhB9fb8sJ+BmorTD9AvqNvobcwKlQ6TaVJEhHjDJRxho82OG2gof9UbsJF3+6IM8uuUVy3TP7b1o+t8PQ3iNKTB4RUzGjJCOs="
script:
go test -v -race -coverprofile=coverage.txt -covermode=atomic
after_success:
- bash <(curl -s https://codecov.io/bash)

21
vendor/github.com/mattn/godown/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2018 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

42
vendor/github.com/mattn/godown/README.md generated vendored Normal file
View File

@ -0,0 +1,42 @@
# godown
[![Build Status](https://travis-ci.org/mattn/godown.png?branch=master)](https://travis-ci.org/mattn/godown)
[![Codecov](https://codecov.io/gh/mattn/godown/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/godown)
[![GoDoc](https://godoc.org/github.com/mattn/godown?status.svg)](http://godoc.org/github.com/mattn/godown)
[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/godown)](https://goreportcard.com/report/github.com/mattn/godown)
Convert HTML into Markdown
This is work in progress.
## Usage
```
err := godown.Convert(w, r)
checkError(err)
```
## Command Line
```
$ godown < index.html > index.md
```
## Installation
```
$ go get github.com/mattn/godown/cmd/godown
```
## TODO
* escape strings in HTML
## License
MIT
## Author
Yasuhiro Matsumoto (a.k.a. mattn)

372
vendor/github.com/mattn/godown/godown.go generated vendored Normal file
View File

@ -0,0 +1,372 @@
package godown
import (
"bytes"
"fmt"
"io"
"regexp"
"strings"
"github.com/mattn/go-runewidth"
"golang.org/x/net/html"
)
func isChildOf(node *html.Node, name string) bool {
node = node.Parent
return node != nil && node.Type == html.ElementNode && strings.ToLower(node.Data) == name
}
func hasClass(node *html.Node, clazz string) bool {
for _, attr := range node.Attr {
if attr.Key == "class" {
for _, c := range strings.Fields(attr.Val) {
if c == clazz {
return true
}
}
}
}
return false
}
func attr(node *html.Node, key string) string {
for _, attr := range node.Attr {
if attr.Key == key {
return attr.Val
}
}
return ""
}
func br(node *html.Node, w io.Writer, option *Option) {
node = node.PrevSibling
if node == nil {
return
}
switch node.Type {
case html.TextNode:
text := strings.Trim(node.Data, " \t")
if text != "" && !strings.HasSuffix(text, "\n") {
fmt.Fprint(w, "\n")
}
case html.ElementNode:
switch strings.ToLower(node.Data) {
case "br", "p", "ul", "ol", "div", "blockquote", "h1", "h2", "h3", "h4", "h5", "h6":
fmt.Fprint(w, "\n")
}
}
}
func table(node *html.Node, w io.Writer, option *Option) {
for tr := node.FirstChild; tr != nil; tr = tr.NextSibling {
if tr.Type == html.ElementNode && strings.ToLower(tr.Data) == "tbody" {
node = tr
break
}
}
var header bool
var rows [][]string
for tr := node.FirstChild; tr != nil; tr = tr.NextSibling {
if tr.Type != html.ElementNode || strings.ToLower(tr.Data) != "tr" {
continue
}
var cols []string
if !header {
for th := tr.FirstChild; th != nil; th = th.NextSibling {
if th.Type != html.ElementNode || strings.ToLower(th.Data) != "th" {
continue
}
var buf bytes.Buffer
walk(th, &buf, 0, option)
cols = append(cols, buf.String())
}
if len(cols) > 0 {
rows = append(rows, cols)
header = true
continue
}
}
for td := tr.FirstChild; td != nil; td = td.NextSibling {
if td.Type != html.ElementNode || strings.ToLower(td.Data) != "td" {
continue
}
var buf bytes.Buffer
walk(td, &buf, 0, option)
cols = append(cols, buf.String())
}
rows = append(rows, cols)
}
maxcol := 0
for _, cols := range rows {
if len(cols) > maxcol {
maxcol = len(cols)
}
}
widths := make([]int, maxcol)
for _, cols := range rows {
for i := 0; i < maxcol; i++ {
if i < len(cols) {
width := runewidth.StringWidth(cols[i])
if widths[i] < width {
widths[i] = width
}
}
}
}
for i, cols := range rows {
for j := 0; j < maxcol; j++ {
fmt.Fprint(w, "|")
if j < len(cols) {
width := runewidth.StringWidth(cols[j])
fmt.Fprint(w, cols[j])
fmt.Fprint(w, strings.Repeat(" ", widths[j]-width))
} else {
fmt.Fprint(w, strings.Repeat(" ", widths[j]))
}
}
fmt.Fprint(w, "|\n")
if i == 0 && header {
for j := 0; j < maxcol; j++ {
fmt.Fprint(w, "|")
fmt.Fprint(w, strings.Repeat("-", widths[j]))
}
fmt.Fprint(w, "|\n")
}
}
fmt.Fprint(w, "\n")
}
var emptyElements = []string{
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr",
}
func raw(node *html.Node, w io.Writer, option *Option) {
switch node.Type {
case html.ElementNode:
fmt.Fprintf(w, "<%s", node.Data)
for _, attr := range node.Attr {
fmt.Fprintf(w, " %s=%q", attr.Key, attr.Val)
}
found := false
tag := strings.ToLower(node.Data)
for _, e := range emptyElements {
if e == tag {
found = true
break
}
}
if found {
fmt.Fprint(w, "/>")
} else {
fmt.Fprint(w, ">")
for c := node.FirstChild; c != nil; c = c.NextSibling {
raw(c, w, option)
}
fmt.Fprintf(w, "</%s>", node.Data)
}
case html.TextNode:
fmt.Fprint(w, node.Data)
}
}
func bq(node *html.Node, w io.Writer, option *Option) {
if node.Type == html.TextNode {
fmt.Fprint(w, strings.Replace(node.Data, "\u00a0", " ", -1))
} else {
for c := node.FirstChild; c != nil; c = c.NextSibling {
bq(c, w, option)
}
}
}
func pre(node *html.Node, w io.Writer, option *Option) {
if node.Type == html.TextNode {
fmt.Fprint(w, node.Data)
} else {
for c := node.FirstChild; c != nil; c = c.NextSibling {
pre(c, w, option)
}
}
}
func walk(node *html.Node, w io.Writer, nest int, option *Option) {
if node.Type == html.TextNode {
if strings.TrimSpace(node.Data) != "" {
text := regexp.MustCompile(`[[:space:]][[:space:]]*`).ReplaceAllString(strings.Trim(node.Data, "\t\r\n"), " ")
fmt.Fprint(w, text)
}
}
n := 0
for c := node.FirstChild; c != nil; c = c.NextSibling {
switch c.Type {
case html.CommentNode:
fmt.Fprint(w, "<!--")
fmt.Fprint(w, c.Data)
fmt.Fprint(w, "-->\n")
case html.ElementNode:
switch strings.ToLower(c.Data) {
case "a":
fmt.Fprint(w, "[")
walk(c, w, nest, option)
fmt.Fprint(w, "]("+attr(c, "href")+")")
case "b", "strong":
fmt.Fprint(w, "**")
walk(c, w, nest, option)
fmt.Fprint(w, "**")
case "i", "em":
fmt.Fprint(w, "_")
walk(c, w, nest, option)
fmt.Fprint(w, "_")
case "del":
fmt.Fprint(w, "~~")
walk(c, w, nest, option)
fmt.Fprint(w, "~~")
case "br":
br(c, w, option)
fmt.Fprint(w, "\n\n")
case "p":
br(c, w, option)
walk(c, w, nest, option)
br(c, w, option)
fmt.Fprint(w, "\n\n")
case "code":
if !isChildOf(c, "pre") {
fmt.Fprint(w, "`")
pre(c, w, option)
fmt.Fprint(w, "`")
}
case "pre":
br(c, w, option)
var buf bytes.Buffer
pre(c, &buf, option)
var lang string
if option != nil && option.GuessLang != nil {
if guess, err := option.GuessLang(buf.String()); err == nil {
lang = guess
}
}
fmt.Fprint(w, "```"+lang+"\n")
fmt.Fprint(w, buf.String())
if !strings.HasSuffix(buf.String(), "\n") {
fmt.Fprint(w, "\n")
}
fmt.Fprint(w, "```\n\n")
case "div":
br(c, w, option)
walk(c, w, nest, option)
fmt.Fprint(w, "\n")
case "blockquote":
br(c, w, option)
var buf bytes.Buffer
if hasClass(c, "code") {
bq(c, &buf, option)
var lang string
if option != nil && option.GuessLang != nil {
if guess, err := option.GuessLang(buf.String()); err == nil {
lang = guess
}
}
fmt.Fprint(w, "```"+lang+"\n")
fmt.Fprint(w, strings.TrimLeft(buf.String(), "\n"))
if !strings.HasSuffix(buf.String(), "\n") {
fmt.Fprint(w, "\n")
}
fmt.Fprint(w, "```\n\n")
} else {
walk(c, &buf, nest+1, option)
if lines := strings.Split(strings.TrimSpace(buf.String()), "\n"); len(lines) > 0 {
for _, l := range lines {
fmt.Fprint(w, "> "+strings.TrimSpace(l)+"\n")
}
fmt.Fprint(w, "\n")
}
}
case "ul", "ol":
br(c, w, option)
var buf bytes.Buffer
walk(c, &buf, 1, option)
if lines := strings.Split(strings.TrimSpace(buf.String()), "\n"); len(lines) > 0 {
for i, l := range lines {
if i > 0 || nest > 0 {
fmt.Fprint(w, "\n")
}
fmt.Fprint(w, strings.Repeat(" ", nest)+strings.TrimSpace(l))
}
fmt.Fprint(w, "\n")
}
case "li":
br(c, w, option)
if isChildOf(c, "ul") {
fmt.Fprint(w, "* ")
} else if isChildOf(c, "ol") {
n++
fmt.Fprint(w, fmt.Sprintf("%d. ", n))
}
walk(c, w, nest, option)
fmt.Fprint(w, "\n")
case "h1", "h2", "h3", "h4", "h5", "h6":
br(c, w, option)
fmt.Fprint(w, strings.Repeat("#", int(rune(c.Data[1])-rune('0')))+" ")
walk(c, w, nest, option)
fmt.Fprint(w, "\n\n")
case "img":
fmt.Fprint(w, "!["+attr(c, "alt")+"]("+attr(c, "src")+")")
case "hr":
br(c, w, option)
fmt.Fprint(w, "\n---\n\n")
case "table":
br(c, w, option)
table(c, w, option)
case "style":
if option != nil && option.Style {
br(c, w, option)
raw(c, w, option)
fmt.Fprint(w, "\n\n")
}
case "script":
if option != nil && option.Script {
br(c, w, option)
raw(c, w, option)
fmt.Fprint(w, "\n\n")
}
default:
walk(c, w, nest, option)
}
default:
walk(c, w, nest, option)
}
}
}
type Option struct {
GuessLang func(string) (string, error)
Script bool
Style bool
}
// Convert convert HTML to Markdown. Read HTML from r and write to w.
func Convert(w io.Writer, r io.Reader, option *Option) error {
doc, err := html.Parse(r)
if err != nil {
return err
}
walk(doc, w, 0, option)
fmt.Fprint(w, "\n")
return nil
}