Skip to content

Instantly share code, notes, and snippets.

@vbatts
Last active December 19, 2022 20:50
Show Gist options
  • Save vbatts/8eb80eabba200e4209c326afd567f015 to your computer and use it in GitHub Desktop.
Save vbatts/8eb80eabba200e4209c326afd567f015 to your computer and use it in GitHub Desktop.
terrible instagram export HTML
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"sort"
"strings"
"time"
)
const theirTS = "2006-01-02T15:04:05"
const anchorTS = "2006_01_02_15_04_05"
func main() {
f, err := os.OpenFile("media.json", os.O_RDONLY, os.FileMode(0644))
if err != nil {
log.Fatal(err)
}
d := json.NewDecoder(f)
m := Media{}
err = d.Decode(&m)
if err != nil {
f.Close()
log.Fatal(err)
}
f.Close()
f, err = os.OpenFile("comments.json", os.O_RDONLY, os.FileMode(0644))
if err != nil {
log.Fatal(err)
}
d = json.NewDecoder(f)
c := Comments{}
err = d.Decode(&c)
if err != nil {
f.Close()
log.Fatal(err)
}
f.Close()
mComb := []MediaObject{}
mComb = append(mComb, m.Photos...)
mComb = append(mComb, m.Videos...)
cComb := []CommentObject{}
cComb = append(cComb, c.MediaComments...)
cComb = append(cComb, c.LiveComments...)
sort.Sort(MediaObjectSlice(mComb))
sort.Sort(CommentObjectSlice(cComb))
var mMark, cMark int
mLen, cLen := len(mComb), len(cComb)
for {
if mMark == mLen && cMark == cLen {
break
}
if mMark == mLen {
fmt.Println(cComb[cMark].HTML())
cMark++
continue
} else if cMark == cLen {
fmt.Println(mComb[mMark].HTML())
mMark++
continue
}
if mComb[mMark].Time().Before(cComb[cMark].Time()) {
fmt.Println(mComb[mMark].HTML())
mMark++
} else {
fmt.Println(cComb[cMark].HTML())
cMark++
}
}
}
type Objector interface {
Time() time.Time
HTML() string
}
type MediaObjectSlice []MediaObject
func (os MediaObjectSlice) Len() int {
return len(os)
}
func (os MediaObjectSlice) Less(i, j int) bool {
return os[i].Time().Before(os[j].Time())
}
func (os MediaObjectSlice) Swap(i, j int) {
os[i], os[j] = os[j], os[i]
}
type CommentObjectSlice []CommentObject
func (os CommentObjectSlice) Len() int {
return len(os)
}
func (os CommentObjectSlice) Less(i, j int) bool {
return os[i].Time().Before(os[j].Time())
}
func (os CommentObjectSlice) Swap(i, j int) {
os[i], os[j] = os[j], os[i]
}
type Media struct {
Photos []MediaObject `json:"photos"`
Videos []MediaObject `json:"videos"`
}
type Object struct {
TakenAt Timestamp `json:"taken_at"`
}
func (o Object) Time() time.Time {
return o.TakenAt.Time
}
type MediaObject struct {
Object
Caption string `json:"caption"`
Path string `json:"path"`
Location string `json:"location"`
}
func (mo MediaObject) HTML() string {
tsAnchor := mo.Time().Format(anchorTS)
var path string
if strings.HasSuffix(mo.Path, ".mp4") {
path = `<video id="` + tsAnchor + `" controls><source src="` + mo.Path + `" type="video/mp4"></video>`
} else {
path = `<img id="` + tsAnchor + `" src="` + mo.Path + `">`
}
var loc string
if mo.Location != "" {
loc = mo.Location + "<br/>"
}
return fmt.Sprintf(`
<div id="media">
%s
<p>
%s
</p>
<p>
%s
<a class="anchor" href="#%s">%s</a>
</p>
</div>
<hr/>
`, path, mo.Caption, loc, tsAnchor, mo.Time())
}
type Timestamp struct {
time.Time
}
func (ts *Timestamp) UnmarshalJSON(buf []byte) error {
var raw string
err := json.Unmarshal(buf, &raw)
if err != nil {
fmt.Printf("error decoding timestamp: %s (%s)\n", raw, err)
return err
}
*&ts.Time, err = time.Parse(theirTS, raw)
if err != nil {
return err
}
return nil
}
type Comments struct {
MediaComments []CommentObject `json:"media_comments"`
LiveComments []CommentObject `json:"live_comments"`
}
type CommentObject struct {
Object
Comment string
Username string
}
func (co CommentObject) HTML() string {
tsAnchor := co.Time().Format(anchorTS)
return fmt.Sprintf(`
<div id="comment">
@%s (<a id="%s" href="#%s">%s</a>): %s
<br/>
</div>
<hr/>
`, co.Username, tsAnchor, tsAnchor, co.Time(), co.Comment)
}
func (co *CommentObject) UnmarshalJSON(buf []byte) error {
var raw []string
err := json.Unmarshal(buf, &raw)
if err != nil {
fmt.Printf("error decoding timestamp: %s (%s)\n", raw, err)
return err
}
var ts time.Time
ts, err = time.Parse(theirTS, raw[0])
if err != nil {
return err
}
*&co.TakenAt = Timestamp{
Time: ts,
}
*&co.Comment = raw[1]
*&co.Username = raw[2]
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment