]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - scripts/importtwitteratom.php
Merge branch 'master' of git.gnu.io:gnu/gnu-social into nightly
[quix0rs-gnu-social.git] / scripts / importtwitteratom.php
1 #!/usr/bin/env php
2 <?php
3 /*
4  * StatusNet - the distributed open-source microblogging tool
5  * Copyright (C) 2010 StatusNet, Inc.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
22
23 $shortoptions = 'i:n:f:';
24 $longoptions = array('id=', 'nickname=', 'file=');
25
26 $helptext = <<<END_OF_IMPORTTWITTERATOM_HELP
27 importtwitteratom.php [options]
28 import an Atom feed from Twitter as notices by a user
29
30   -i --id       ID of user to update
31   -n --nickname nickname of the user to update
32   -f --file     file to import (Atom-only for now)
33
34 END_OF_IMPORTTWITTERATOM_HELP;
35
36 require_once INSTALLDIR.'/scripts/commandline.inc';
37
38 function getAtomFeedDocument()
39 {
40     $filename = get_option_value('f', 'file');
41
42     if (empty($filename)) {
43         show_help();
44         exit(1);
45     }
46
47     if (!file_exists($filename)) {
48         throw new Exception("No such file '$filename'.");
49     }
50
51     if (!is_file($filename)) {
52         throw new Exception("Not a regular file: '$filename'.");
53     }
54
55     if (!is_readable($filename)) {
56         throw new Exception("File '$filename' not readable.");
57     }
58
59     $xml = file_get_contents($filename);
60
61     $dom = DOMDocument::loadXML($xml);
62
63     if ($dom->documentElement->namespaceURI != Activity::ATOM ||
64         $dom->documentElement->localName != 'feed') {
65         throw new Exception("'$filename' is not an Atom feed.");
66     }
67
68     return $dom;
69 }
70
71 function importActivityStream($user, $doc)
72 {
73     $feed = $doc->documentElement;
74
75     $entries = $feed->getElementsByTagNameNS(Activity::ATOM, 'entry');
76
77     for ($i = $entries->length - 1; $i >= 0; $i--) {
78         $entry = $entries->item($i);
79         $activity = new Activity($entry, $feed);
80         $object = $activity->objects[0];
81         if (!have_option('q', 'quiet')) {
82             print $activity->content . "\n";
83         }
84         $html = common_purify(getTweetHtml($object->link));
85
86         $content = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8');
87
88         $notice = Notice::saveNew($user->id,
89                                   $content,
90                                   'importtwitter',
91                                   array('uri' => $object->id,
92                                         'url' => $object->link,
93                                         'rendered' => $html,
94                                         'created' => common_sql_date($activity->time),
95                                         'replies' => array(),
96                                         'groups' => array()));
97     }
98 }
99
100 function getTweetHtml($url)
101 {
102     try {
103         $client = new HTTPClient();
104         $response = $client->get($url);
105     } catch (Exception $e) {
106         print "ERROR: HTTP response " . $e->getMessage() . "\n";
107         return false;
108     }
109
110     if (!$response->isOk()) {
111         print "ERROR: HTTP response " . $response->getCode() . "\n";
112         return false;
113     }
114
115     $body = $response->getBody();
116
117     return tweetHtmlFromBody($body);
118 }
119
120 function tweetHtmlFromBody($body)
121 {
122     $doc = DOMDocument::loadHTML($body);
123     $xpath = new DOMXPath($doc);
124
125     $spans = $xpath->query('//span[@class="entry-content"]');
126
127     if ($spans->length == 0) {
128         print "ERROR: No content in tweet page.\n";
129         return '';
130     }
131
132     $span = $spans->item(0);
133
134     $children = $span->childNodes;
135
136     $text = '';
137
138     for ($i = 0; $i < $children->length; $i++) {
139         $child = $children->item($i);
140         if ($child instanceof DOMElement &&
141             $child->tagName == 'a' &&
142             !preg_match('#^https?://#', $child->getAttribute('href'))) {
143             $child->setAttribute('href', 'http://twitter.com' . $child->getAttribute('href'));
144         }
145         $text .= $doc->saveXML($child);
146     }
147
148     return $text;
149 }
150
151 try {
152
153     $doc = getAtomFeedDocument();
154     $user = getUser();
155
156     importActivityStream($user, $doc);
157
158 } catch (Exception $e) {
159     print $e->getMessage()."\n";
160     exit(1);
161 }
162