2e427b4739ad40e1851b86f00a28ac5c3fb7540f
[tweeper.git] / src / rss_converter_instagram.com.xsl
1 <!--
2   Stylesheet to convert Instagram user timelines to RSS.
3
4   Copyright (C) 2015-2018  Antonio Ospite <ao2@ao2.it>
5
6   This file is part of tweeper.
7
8   This program is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 -->
21 <xsl:stylesheet version="1.0"
22     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
23     xmlns:php="http://php.net/xsl"
24     exclude-result-prefixes="php">
25
26     <xsl:param name="generate-enclosure"/>
27
28     <xsl:output method="xml" indent="yes"/>
29
30     <xsl:variable name="BaseURL">
31         <xsl:text>https://instagram.com</xsl:text>
32     </xsl:variable>
33
34     <xsl:variable name="user-name" select="//ProfilePage/graphql/user/username"/>
35
36     <!--
37          NOTE: some users do not specify the full name.
38
39          Remember to handle this case when using it and fall-back to the plain
40          user name when appropriate.
41     -->
42     <xsl:variable name="full-name" select="//ProfilePage/graphql/user/full_name"/>
43
44     <xsl:variable name="location-name" select="//LocationsPage/graphql/location/name"/>
45
46     <xsl:variable name="hashtag-name" select="//TagPage/graphql/hashtag/name"/>
47
48     <xsl:variable name="screen-name">
49         <xsl:choose>
50             <xsl:when test="$location-name != ''">
51                 <xsl:value-of select="$location-name"/>
52             </xsl:when>
53             <xsl:when test="$hashtag-name != ''">
54                 <xsl:value-of select="$hashtag-name"/>
55             </xsl:when>
56             <xsl:when test="$full-name != ''">
57                 <xsl:value-of select="$full-name"/>
58             </xsl:when>
59             <xsl:otherwise>
60                 <xsl:value-of select="$user-name"/>
61             </xsl:otherwise>
62         </xsl:choose>
63     </xsl:variable>
64
65     <xsl:template match="//edges/node">
66         <xsl:variable name="item-content-image" select="./display_url"/>
67         <xsl:variable name="item-content-caption" select="./edge_media_to_caption/edges/node/text"/>
68         <xsl:variable name="item-permalink" select="concat($BaseURL, '/p/', ./shortcode, '/')"/>
69         <item>
70             <title>
71                 <xsl:variable name="title-length" select="140"/>
72                 <xsl:variable name="item-content-title" select="normalize-space(concat($screen-name, ': ', $item-content-caption))"/>
73                 <!-- ellipsize, inspired from http://stackoverflow.com/questions/13622338 -->
74                 <xsl:choose>
75                     <xsl:when test="string-length($item-content-title) > $title-length">
76                         <xsl:variable name="truncated-length" select="$title-length - 3"/>
77                         <xsl:value-of select="substring($item-content-title, 1, $truncated-length)"/>
78                         <xsl:text>...</xsl:text>
79                     </xsl:when>
80                     <xsl:otherwise>
81                         <xsl:value-of select="$item-content-title"/>
82                     </xsl:otherwise>
83                 </xsl:choose>
84             </title>
85             <link>
86                 <xsl:value-of select="$item-permalink"/>
87             </link>
88             <guid>
89                 <xsl:value-of select="$item-permalink"/>
90             </guid>
91             <pubDate>
92                 <xsl:variable name="timestamp" select="./taken_at_timestamp"/>
93                 <xsl:value-of select="php:functionString('Tweeper\Tweeper::epochToRssDate', $timestamp)"/>
94             </pubDate>
95             <description>
96                 <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
97                 <p>
98                     <xsl:if test="./is_video/text() = 1">
99                         (Video)
100                     </xsl:if>
101                     <xsl:value-of select="$item-content-caption"/>
102                 </p><br />
103                 <a href="{$item-permalink}"><img src="{$item-content-image}" style="max-width: 100%"/></a>
104                 <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
105             </description>
106             <xsl:if test="$generate-enclosure = 1">
107                 <xsl:copy-of select="php:functionString('Tweeper\Tweeper::generateEnclosure', $item-content-image)"/>
108             </xsl:if>
109         </item>
110     </xsl:template>
111
112     <xsl:template match="/">
113
114         <xsl:variable name="channel-title" select="concat('Instagram / ', $screen-name)"/>
115         <xsl:variable name="channel-link">
116             <xsl:choose>
117                 <xsl:when test="$location-name != ''">
118                     <xsl:variable name="location-id" select="//LocationsPage/graphql/location/id"/>
119                     <xsl:value-of select="concat($BaseURL, '/explore/locations/', $location-id)"/>
120                 </xsl:when>
121                 <xsl:when test="$hashtag-name != ''">
122                     <xsl:value-of select="concat($BaseURL, '/explore/tags/', $hashtag-name)"/>
123                 </xsl:when>
124                 <xsl:otherwise>
125                     <xsl:value-of select="concat($BaseURL, '/', $user-name)"/>
126                 </xsl:otherwise>
127             </xsl:choose>
128         </xsl:variable>
129         <xsl:variable name="channel-image" select="//profile_pic_url"/>
130
131         <rss version="2.0">
132             <xsl:attribute name="xml:base"><xsl:value-of select="$BaseURL" /></xsl:attribute>
133             <channel>
134                 <generator>Tweeper</generator>
135                 <title>
136                     <xsl:value-of select="$channel-title"/>
137                 </title>
138                 <link>
139                     <xsl:value-of select="$channel-link"/>
140                 </link>
141                 <description>
142                     <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
143                     <xsl:choose>
144                         <xsl:when test="$location-name != ''">
145                             <xsl:variable name="location-latitude" select="//LocationsPage/graphql/location/lat"/>
146                             <xsl:variable name="location-longitude" select="//LocationsPage/graphql/location/lng"/>
147                             <xsl:value-of select="concat($location-name, ' (', $location-latitude, ', ', $location-longitude, ')')"/>
148                         </xsl:when>
149                         <xsl:when test="$hashtag-name != ''">
150                             <xsl:value-of select="concat('#', $hashtag-name)"/>
151                         </xsl:when>
152                         <xsl:otherwise>
153                             <xsl:value-of select="normalize-space(concat($screen-name, '. ', //user/biography))"/>
154                             <xsl:variable name="external-url" select="//user/external_url"/>
155                             <xsl:if test="$external-url != ''">
156                                 <xsl:text> </xsl:text><a href="{$external-url}"><xsl:value-of select="$external-url"/></a>
157                             </xsl:if>
158                         </xsl:otherwise>
159                     </xsl:choose>
160                     <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
161                 </description>
162                 <xsl:if test="$channel-image != ''">
163                     <image>
164                         <title>
165                             <xsl:value-of select="$channel-title"/>
166                         </title>
167                         <link>
168                             <xsl:value-of select="$channel-link"/>
169                         </link>
170                         <url>
171                             <xsl:value-of select="$channel-image"/>
172                         </url>
173                     </image>
174                 </xsl:if>
175                 <xsl:apply-templates select="//ProfilePage/graphql/user/edge_owner_to_timeline_media/edges/node|//LocationsPage/graphql/location/edge_location_to_media/edges/node|//TagPage/graphql/hashtag/edge_hashtag_to_media/edges/node"/>
176             </channel>
177         </rss>
178     </xsl:template>
179 </xsl:stylesheet>