\ Google+ import
\ Copyright (C) 2018 Bernd Paysan
\ This program is free software: you can redistribute it and/or modify
\ it under the terms of the GNU Affero General Public License as published by
\ the Free Software Foundation, either version 3 of the License, or
\ (at your option) any later version.
\ This program is distributed in the hope that it will be useful,
\ but WITHOUT ANY WARRANTY; without even the implied warranty of
\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\ GNU Affero General Public License for more details.
\ You should have received a copy of the GNU Affero General Public License
\ along with this program. If not, see .
require ../html/parser.fs
: key-pk@ ( o:key -- addr u )
author:mapped-key .ke-pk $@ key| ;
: .key64 ( o:key -- )
key-pk@ 64type ;
: replace-user ( addr u -- )
2dup "https://plus.google.com/" string-prefix? IF
2dup #24 /string authors# #@ IF
." key:" @ ..key64
2drop EXIT THEN
drop THEN
type ;
' replace-user IS href-replace
Variable pics#
Variable picbase#
Variable picdesc#
Variable album#
Variable dir#
".metadata.csv" nip Constant .mtcsv#
: match-jpg/png ( key u addr u -- ) $make { w^ fn$ }
fn$ $@ dir# #@ d0= IF
".png" fn$ $+! fn$ $@ dir# #@ d0= IF
".jpg" fn$ $@ + over - swap move
fn$ $@ dir# #@ d0= IF
2drop fn$ $free EXIT THEN
THEN
THEN
fn$ $@ 2swap pics# #!
fn$ $free ;
: unquote ( addr u -- addr' u' )
2dup + 1- c@ ',' = +
over c@ '"' = negate safe/string ?dup-IF 2dup + 1- c@ '"' = + THEN ;
: dir-skips ( addr u n -- addr' u' )
0 ?DO '/' $split 2nip LOOP ;
: basedir+name ( addr u -- addr' u' )
[: ( 2dup basename 2>r ) 3 dir-skips
2dup 2 dir-skips drop nip over - type
( 2r> type ) ;] $tmp ;
: next, ( addr u -- addr' u' )
2dup "\"\"," string-prefix? IF 3 /string EXIT THEN
BEGIN 1 /string "\"," search WHILE
over 1- c@ '"' <> UNTIL 2 safe/string THEN ;
: next-csv ( addr u -- addr' u' addr1 u1 )
2dup next, 2tuck drop nip over - unquote ;
: un-dquote ( addr u -- )
BEGIN
2dup "\"\"" search WHILE
2dup 2 /string 2>r drop 1+ nip over - type
2r> REPEAT 2drop type ;
: +album ( addr u -- )
2dup 5 umin album# #@ d0= IF
$make { w^ fn } fn cell over $@ 5 umin album# #!
ELSE
last# cell+ $ins[] drop
THEN ;
: get-pic-filename { d: mtcsv -- }
mtcsv r/o open-file throw { fd }
mtcsv .mtcsv# - to mtcsv \ for the rest, need only the basename of the file
pad $100 + $10000 fd read-line throw 2drop
pad $100 + $10000 fd read-file throw pad $100 + swap
next-csv { d: basefn }
next-csv { d: desc }
next-csv 2nip basedir+name mtcsv match-jpg/png
last# cell+ $@
basefn 2over picbase# #!
desc ['] un-dquote $tmp 2over picdesc# #!
+album
fd close-file throw ;
: get-pic-filenames ( addr u -- )
2dup open-dir throw { dd } fpath @ >r fpath off fpath also-path dd
[: { dd } !time
BEGIN
pad $100 dd read-dir throw WHILE
pad swap s" " 2swap dir# #!
REPEAT drop
0 dir# [: $@ 2dup "*.metadata.csv" filename-match IF
get-pic-filename 1+
ELSE 2drop THEN ;] #map
[: ." read " . ." pics in " .time ;]
success-color color-execute cr ;] catch
fpath $free r> fpath ! dd close-dir throw throw
dir# #frees ;
: get-avatars ( -- )
avatars[] $[]# 0= ?EXIT \ nothing to do
"avatars" .net2o-cache/ { d: dir }
dir $1FF init-dir drop
dir [: ." cd " type ." ; sort -k 3 | split -l128 - avatars.sh." ;] $tmp
w/o open-pipe throw >r
avatars[] ['] $[]. r@ outfile-execute
r> close-pipe throw to $?
dir [: ." cd " type ." ;time eval '(for i in avatars.sh.*; do curl -s $(cat $i) & done; wait)'; #rm avatars.sh.*" ;] $tmp system ;
: .avatar-file ( o:author -- addr u )
[: ." avatars/g+:" author:resourceName$ basename type ." .png" ;] $tmp
.net2o-cache/ ;
: hash-in-avatars ( -- )
authors# [: cell+ $@ drop @ >o
author:avatarImageUrl$ nip IF
.avatar-file slurp-file over >r hash-in r> free throw
author:mapped-key >o ke-avatar $! this-key-sign o>
THEN
o> ;] #map ;
: key-author ( o:author -- )
first-key? IF
my-key-default false to first-key?
ELSE
author:resourceName$ basename author:displayName$
0 .dummy-key
THEN to author:mapped-key ;
: .url ( addr u -- )
2dup "http" string-prefix? 0= IF ." https:" THEN type ;
: +avatar-author ( o:author -- )
author:avatarImageUrl$ dup IF
.avatar-file file-status 0= IF
drop 2drop
ELSE
drop [: ." -o g+:" author:resourceName$ basename type ." .png "
.url
;] $tmp avatars[] $+[]!
THEN
ELSE 2drop THEN ;
: execute>file ( ... xt addr u -- )
r/w create-file throw dup >r outfile-execute
r> close-file throw ;
$100 buffer: filter-out
filter-out bl 1- 1 fill
1 filter-out ']' + c!
: .simple-text ( addr u -- )
bounds ?DO i c@ filter-out + c@ 0= IF I c@ emit THEN LOOP ;
: .html ( -- )
comments:content$ html-untag cr ;
: .plain ( -- )
comments:content$ html>text ;
: .link ( -- )
comments:link{} ?dup-IF cr >o
'[' emit link:title$ type-esc'd ." ](" link:url$ type ')' emit cr
o> THEN ;
0 Value img-req-fid
: .mfile { d: fn -- }
fn basedir+name pics# #@ 2dup d0= IF
2drop fn .url
fn [: .url cr ;] img-req-fid outfile-execute
ELSE
." file:" picbase# #@ type
THEN ;
: .csv-link { d: fn -- }
." ![" fn picdesc# #@ .simple-text ." ](file:" fn picbase# #@ type ." )" cr ;
: .media-file ( -- )
media:url$ basename nip $100 > IF
." file:" media:localFilePath$ basename type
ELSE
media:localFilePath$ nip IF ." file:" media:url$ basename type
ELSE media:url$ .mfile THEN
THEN ;
: inline-image ( -- )
media:contentType$ "image/" string-prefix? IF
." ![" media:description$ .simple-text ." ](" .media-file ')' emit cr
ELSE
media:url$ ." [" 2dup type ." ](" type ')' emit cr
THEN ;
: .media ( -- )
comments:media{} ?dup-IF cr .inline-image THEN ;
: .album ( -- )
comments:album{} ?dup-IF cr
." ::album::" cr cr
.album:media[] $@ over @ .media:url$
basedir+name pics# #@ d0= IF
bounds U+DO
I @ .inline-image
cell +LOOP
ELSE
2drop
last# cell+ $@ 5 umin album# #@ bounds U+DO
I $@ .csv-link
cell +LOOP
THEN
THEN ;
: .post ( o:comments -- )
." post:" comments:author{} ..key64 '/' emit
." g+:" comments:url$ basename type ;
: .project ( o:comments -- )
comments:author{} .key-pk@ type
." g+:" comments:url$ basename type ;
: .author ( o:author -- )
." +[" author:displayName$ type ." ](key:" .key64 ." )" ;
: .reshared ( o:comments -- )
comments:resharedPost{} ?dup-IF cr >o
." > " comments:author{} ?dup-IF ..author ." : " THEN
'[' emit comments:content$ ['] html>text $tmp $40 umin .simple-text
." ](" .post ') emit cr cr
.html .link .media .album o>
THEN ;
: .choice ( n o:choices -- )
'1' + dup emit ." . ::votes#" emit ." :: " choices:description$ type
'\' emit cr ." ![" choices:description$ type ." ]("
choices:imageLocalFilePath$ dup IF basename type
ELSE 2drop choices:imageUrl$ .mfile THEN ." ) " ;
: .polls ( o:comments -- )
comments:poll{} ?dup-IF cr >o
0 { n }
poll:choices[] $@ bounds U+DO
n I @ ..choice cr 1 +to n
cell +LOOP o>
THEN ;
: .com/col ( o:collection -- ) cr
collectionAttachment:displayName$
." [![" 2dup type ." ](" collectionAttachment:coverPhotoUrl$ .mfile
." )](chat:g+:" type
collectionAttachment:owner{} ?dup-IF '@' emit ..key64 THEN
')' emit ;
: .collection ( o:comments -- )
comments:collectionAttachment{} ?dup-IF ..com/col THEN ;
: .community ( o:comments -- )
comments:communityAttachment{} ?dup-IF ..com/col THEN ;
: add-file { dvcs d: file -- }
[: .html .link .media .reshared .album .polls .collection .community ;] file execute>file
file dvcs .dvcs-add ;
Variable pfile$
: $pfile ( xt -- addr u )
pfile$ $free pfile$ $exec pfile$ $@ ;
: post-file ( -- )
[: ." post-" project:project$ $. ." .md" ;] $pfile ;
: comment-file ( -- addr u )
[: ." comment-" comments:resourceName$ dup 11 - /string type ." .md" ;]
$pfile ;
: add-post ( dvcs -- ) dup .post-file add-file ;
: /dirs ( addr u n -- addr' u' )
0 ?DO '/' scan 1 safe/string LOOP ;
Variable photo-path
: +photo-paths ( -- )
"../.." open-dir throw >r
BEGIN pad $100 r@ read-dir throw WHILE
pad over "." str= >r pad over ".." str= r> or 0= IF
[: dir@ type ." /../../" pad swap type ;] $tmp
compact-filename photo-path also-path
ELSE drop THEN
REPEAT drop r> close-dir throw ;
: find-file { d: fn-orig d: fn -- fn-orig addr' u' flag }
fn-orig
fn [: dir@ forth:type ." /" forth:type ;]
$tmp compact-filename 2dup file-status nip 0= dup ?EXIT drop 2drop
fn-orig fn [:
3 /dirs dirname forth:type '/' emit basename forth:type ;]
$tmp photo-path open-path-file IF 0 0 false
ELSE rot close-file throw true THEN ;
: local-media ( filename u basename u o:dsvc -- )
2dup delete-file drop 2swap
find-file IF 2over symlink ?ior dvcs-ref
ELSE 2drop 2drop THEN ;
: csv-media ( filename u o:dsvc -- )
2dup picbase# #@ local-media ;
: add-media { dvcs -- }
media:localFilePath$ dup IF
media:url$ basename dup $100 > IF
2drop media:localFilePath$ basename
THEN dvcs .local-media EXIT
THEN 2drop
media:url$ basedir+name pics# #@ d0= IF
media:contentType$ "image/*" str= IF
." media unavailable: " media:url$ type cr THEN
EXIT THEN
media:contentType$ "video/*" str= IF
media:url$ ." [" 2dup type ." ](" type ." )" cr
EXIT THEN
last# cell+ $@ dvcs .csv-media ;
: add-album { dvcs -- }
comments:album{} ?dup-IF
.album:media[] $@
over @ .media:url$
basedir+name pics# #@ d0= IF
bounds U+DO
dvcs I @ .add-media
cell +LOOP
ELSE
2drop
last# cell+ $@ 5 umin album# #@ bounds U+DO
I $@ dvcs .csv-media
cell +LOOP
THEN
THEN ;
: add-poll-photo { dvcs -- }
choices:imageLocalFilePath$ 2dup basename dvcs .local-media ;
: add-poll-photos { dvcs -- }
comments:poll{} ?dup-IF
.poll:choices[] $@ bounds U+DO
dvcs I @ .add-poll-photo
cell +LOOP
THEN ;
also net2o-base
2Variable post-ref
: add-message ( xt -- )
project:project$ $@ ?msg-log
[: sign[ msg-start execute post-ref 2@ chain, ]pksign ;] gen-cmd$
+last-signed last-signed 2@ >msg-log 2drop ;
: sigdate+ ( -- )
sigdate le-64@ 64#1 64+ sigdate le-64! ;
: add-plusones { dvcs -- }
comments:plusOnes[] $@ bounds U+DO
sigdate+
I @ .plusOnes:plusOner{} .author:mapped-key dvcs >o to my-key
[: '👍' ulit, msg-like ;] add-message o>
cell +LOOP ;
: add-reshares { dvcs -- }
comments:reshares[] $@ bounds U+DO
sigdate+
I @ .reshares:resharer{} .author:mapped-key dvcs >o to my-key
[: '' ( '🔃' or '🐙' ) ulit, msg-like ;] add-message o>
cell +LOOP ;
: add-votes { dvcs -- }
comments:poll{} ?dup-IF
0 { n }
.poll:choices[] $@ bounds U+DO
I @ .choices:votes[] $@ bounds U+DO
sigdate+
I @ .votes:voter{} .author:mapped-key dvcs >o to my-key
n [{: n :}L n '1' + ulit, msg-like ;] add-message o>
cell +LOOP
1 +to n
cell +LOOP
THEN ;
previous
Variable comment#
: add-comment ( dvcs -- )
comment-file add-file ;
: create>never ( o:comments -- )
comments:creationTime! ( comments:updateTime! 64umax )
64#-1 sigdate le-128! ;
: wrap-key ( ... xt key -- )
my-key-default >r to my-key-default catch
r> to my-key-default throw ;
: add-comments { dvcs-o -- }
comments:comments[] $@ bounds U+DO
I @ >o
dvcs-o add-comment
comments:media{} ?dup-IF >o dvcs-o add-media o> THEN
comments:author{} .author:mapped-key { mkey }
create>never
['] .plain $tmp $80 umin -trailing-garbage
dvcs-o >o pfile$ $@ dvcs:fileref[] $+[]!
['] (dvcs-ci) mkey wrap-key o>
last-msg 2@ post-ref 2!
dvcs-o add-plusones \ plusones not exported at the moment
\ dvcs-o add-reshares \ reshares of comments not possible
o>
cell +LOOP ;
: comments-base ( -- addr u )
comments:comments[] $@len IF
comments:comments[] $@ drop @ .comments:url$
ELSE
comments:url$
THEN basename ;
: ?make-group ( -- )
msg-group$ $@ group# #@ d0= IF
msg-group$ $@ make-group
THEN ;
: add-collection { dvcso | w^ groups[] -- }
comments:postAcl{} ?dup-IF >o
postAcl:collectionAcl{} ?dup-IF
.collectionAcl:collection{} ?dup-IF
[: ." g+:coll:" .collection:displayName$ type ;] $tmp
groups[] $+[]!
THEN
THEN
postAcl:communityAcl{} ?dup-IF
.communityAcl:community{} ?dup-IF
[: ." g+:comm:" .collection:displayName$ type ;] $tmp
groups[] $+[]!
THEN
THEN
postAcl:visibleToStandardAcl{} ?dup-IF
.visibleToStandardAcl:circles[] $@ bounds U+DO
I @ .circles:displayName$ dup IF
[: ." g+:circle:" type ;] $tmp groups[] $+[]!
ELSE 2drop THEN
cell +LOOP
THEN
groups[] $[]# 0= IF
postAcl:isPublic?
IF "g+:" ELSE "g+:" THEN
groups[] $+[]!
THEN
o>
THEN
comments:postKind$ "EXTERNAL_SITE_COMMENT" str= IF
"g+:external-site-comment" groups[] $+[]!
THEN
['] .plain $tmp $80 umin -trailing-garbage
dup 0= IF 2drop "" THEN ['] .project $tmp
groups[] [: msg-group$ $! 0 .?make-group
[ also net2o-base ]
[: 2over $, msg-text 2dup $, msg:posting# ulit, msg-object ;]
[ previous ]
(send-avalanche) drop msg-group$ $. space
2dup d0= IF ." " 2drop cr ELSE .chat THEN ;] $[]map
2drop 2drop groups[] $[]free ;
: write-out-article ( o:comment -- )
\ ." write out: " comments:url$ type cr
>dir redate-mode on comment# off
dvcs:new-dvcs { dvcs-o }
comments-base
2dup [: ." posts/" type ." /.n2o" ;] $tmp ~net2o-cache/..
".n2o/files" touch
dvcs-o >o "g+:" project:project$ $! project:project$ $+!
"master" project:branch$ $! save-project o>
dvcs-o add-post
dvcs-o add-album
dvcs-o add-poll-photos
comments:media{} ?dup-IF >o dvcs-o add-media o> THEN
create>never
['] .plain $tmp $100 umin -trailing-garbage
dup 0= IF 2drop "" THEN
comments:author{} .author:mapped-key { mkey }
dvcs-o >o pfile$ $@ dvcs:fileref[] $+[]!
['] (dvcs-ci) mkey wrap-key o>
last-msg 2@ post-ref 2!
dvcs-o add-plusones
dvcs-o add-reshares
dvcs-o add-votes
dvcs-o add-comments
dvcs-o .dvcs:dispose-dvcs
create>never
dvcs-o ['] add-collection mkey wrap-key
dir> redate-mode off
dvcs-objects #frees ;
: write-articles ( -- ) { | nn }
"img-req.lst" w/o create-file throw to img-req-fid
entries[] $@ bounds ?DO
nn [: ." write " 6 .r ." postings" ;]
warning-color color-execute
#-21 0 at-deltaxy
I @ .write-out-article
1 +to nn
cell +LOOP
img-req-fid close-file throw 0 to img-req-fid
nn [: ." write " 6 .r ." postings in " .time ;]
success-color color-execute cr ;
[IFUNDEF] json-load-dir
forward json-load-dir
[THEN]
: g+-import { d: dir -- }
?get-me >dir +photo-paths dir>
." Read pics metadata" cr dir get-pic-filenames \ legacy for old takeout
." Read JSON files" cr dir json-load-dir
." Write entries" cr write-articles
." Get avatars" cr get-avatars hash-in-avatars
!save-all-msgs save-keys
save-chatgroups .chatgroups ;