Last active
December 19, 2022 20:50
-
-
Save vbatts/8eb80eabba200e4209c326afd567f015 to your computer and use it in GitHub Desktop.
terrible instagram export HTML
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 ( | |
"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