Created
May 17, 2019 05:51
-
-
Save yarrom/e26c8cf524ea38e08285107ec7de37b4 to your computer and use it in GitHub Desktop.
Viber chat history to html converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"errors" | |
"fmt" | |
"github.com/json-iterator/go" | |
"os" | |
"path/filepath" | |
"strings" | |
) | |
func check(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func skip_utf8_bom(rd *bufio.Reader) error { | |
aBom, err := rd.Peek(3) | |
if err == nil && bytes.Equal(aBom, []byte{0xEF, 0xBB, 0xBF}) { | |
_, err := rd.Discard(3) | |
//fmt.Printf("%d bytes of BOM discarded.\n", n) | |
return err | |
} else { | |
return err | |
} | |
} | |
type ViberHistory struct { | |
Date, Time, | |
Name, Phone, | |
Text string | |
} | |
func scan_csv(rd *bufio.Reader, wr *bufio.Writer) error { | |
err := skip_utf8_bom(rd) | |
if err != nil { | |
return err | |
} | |
wr.Write([]byte(fmt.Sprintf( | |
`<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset=\"utf-8\"> | |
<title>История переписки</title> | |
<style> | |
pre { | |
white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */ | |
white-space: -pre-wrap; /* Opera */ | |
white-space: -o-pre-wrap; /* Opera */ | |
white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) | |
http://www.w3.org/TR/css3-text/#white-space */ | |
word-wrap: break-word; /* IE 5.5+ */ | |
} | |
</style> | |
</head> | |
<body>`))) | |
const ( | |
ss_Date = iota | |
ss_Time = iota | |
ss_Name = iota | |
ss_Phone = iota | |
ss_Text = iota | |
) | |
var ( | |
aBufRead []byte = make([]byte, 1) | |
nRead int | |
ss int = ss_Date | |
b byte | |
aBuf [2048]byte | |
nBuf int = 0 | |
vh ViberHistory | |
sDatePrev string = "" | |
) | |
for { | |
nRead, _ = rd.Read(aBufRead) | |
if nRead == 0 { | |
break | |
} | |
for i := 0; i < nRead; i++ { | |
b = aBufRead[i] | |
if b == ',' && ss != ss_Text { // Delimiter reached | |
switch ss { | |
case ss_Date: | |
vh.Date = string(aBuf[0:nBuf]) | |
case ss_Time: | |
vh.Time = string(aBuf[0:nBuf]) | |
case ss_Name: | |
vh.Name = string(aBuf[0:nBuf]) | |
case ss_Phone: | |
vh.Phone = string(aBuf[0:nBuf]) | |
} | |
ss++ | |
nBuf = 0 | |
} else if b == 0x0D { | |
aB, err := rd.Peek(1) | |
if err == nil && len(aB) == 1 && aB[0] == 0x0A { // End Of Line reached | |
if ss != ss_Text { | |
return errors.New("Unexpected End Of Line reached") | |
} | |
vh.Text = string(aBuf[0:nBuf]) | |
preprocess_line(&vh) | |
if sDatePrev != vh.Date { | |
wr.Write([]byte(fmt.Sprintf("<center><h3>%s</h3></center>\n", vh.Date))) | |
sDatePrev = vh.Date | |
} | |
wr.Write([]byte(fmt.Sprintf("%s <b>%s</b>: <pre>%s</pre>\n", vh.Time, vh.Name, vh.Text))) | |
_, _ = rd.Discard(1) | |
ss++ | |
nBuf = 0 | |
} | |
} else { | |
if nBuf >= len(aBuf) { | |
return errors.New(fmt.Sprintf("Unexpected End Of buffer reached: %d", nBuf)) | |
} | |
aBuf[nBuf] = b | |
nBuf++ | |
} | |
if ss > ss_Text { | |
ss = ss_Date | |
} | |
} | |
} | |
wr.Write([]byte(fmt.Sprintf("</body></html>\n"))) | |
return nil | |
} | |
func preprocess_line(vh *ViberHistory) { | |
if key := "add/"; bytes.Equal([]byte(vh.Text)[0:len(key)], []byte(key)) { | |
vh.Text = "<b><i>теперь в чате</i></b>" | |
} else if key := "add_by_link/"; bytes.Equal([]byte(vh.Text)[0:len(key)], []byte(key)) { | |
vh.Text = "<b><i>использовал(а) ссылку из приглашения</i></b>" | |
} else if key := "message_deleted/"; bytes.Equal([]byte(vh.Text)[0:len(key)], []byte(key)) { | |
vh.Text = "<b><i>удалил(а) сообщение</i></b>" | |
} else if key := "group_rename/"; bytes.Equal([]byte(vh.Text)[0:len(key)], []byte(key)) { | |
s := strings.Split(vh.Text, "//") | |
vh.Text = fmt.Sprintf("<b><i>переименовал(а) группу в \"%s\"</i></b>", s[len(s)-1]) | |
} else if vh.Text[0] == '[' && vh.Text[len(vh.Text)-1] == ']' { | |
var val interface{} | |
err := json.Unmarshal([]byte(vh.Text), &val) | |
vh.Text = "" | |
if err == nil { | |
switch v := val.(type) { | |
case []interface{}: | |
for _, itemV := range v { | |
switch w := itemV.(type) { | |
case map[string]interface{}: | |
_type, _type_ok := w["Type"] | |
if _type_ok && _type == "txt" { | |
_action, _action_ok := w["Action"] | |
_text, _text_ok := w["Text"] | |
_, _underline_ok := w["Underline"] | |
if _action_ok && _text_ok && _underline_ok { | |
switch z := _action.(type) { | |
case map[string]interface{}: | |
if _name, _name_ok := z["name"]; _name_ok && _name == "openurl" { | |
if _parameters, _parameters_ok := z["parameters"]; _parameters_ok { | |
switch x := _parameters.(type) { | |
case map[string]interface{}: | |
if _url, _url_ok := x["url"]; _url_ok { | |
vh.Text += fmt.Sprintf(" <a href=\"%v\">%v</a>", _url, _text) | |
} | |
default: | |
} | |
} | |
} | |
default: | |
} | |
} | |
} else if _type_ok && _type == "info" { | |
if _PushText, _PushText_ok := w["PushText"]; _PushText_ok { | |
vh.Text += fmt.Sprintf(" %v", _PushText) | |
} | |
} | |
default: | |
} | |
} | |
default: | |
} | |
} | |
} | |
} | |
var json = jsoniter.ConfigCompatibleWithStandardLibrary | |
func main() { | |
var ( | |
sNameIn, sNameOut string = "", "" | |
flIn, flOut *os.File | |
info os.FileInfo | |
wr *bufio.Writer | |
err error | |
) | |
if len(os.Args) > 1 { | |
sNameIn = os.Args[1] | |
} else { | |
check(errors.New("Input file name not specified")) | |
} | |
if len(os.Args) > 2 { | |
sNameOut = os.Args[2] | |
} else { | |
sExt := filepath.Ext(sNameIn) | |
sNameOut = sNameIn[0:len(sNameIn)-len(sExt)] + ".html" | |
} | |
flIn, err = os.Open(sNameIn) | |
check(err) | |
defer flIn.Close() | |
flOut, err = os.OpenFile(sNameOut, os.O_CREATE|os.O_WRONLY, 0644) | |
check(err) | |
defer flOut.Close() | |
info, err = flOut.Stat() | |
check(err) | |
if info.Size() > 0 { | |
err = flOut.Truncate(0) | |
check(err) | |
} | |
wr = bufio.NewWriter(flOut) | |
defer wr.Flush() | |
err = scan_csv(bufio.NewReader(flIn), wr) | |
check(err) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment