birdcries.net

Check-in [d6dc29d150]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:transferred into fossil
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d6dc29d1507a138763517f78ba2996ae545b870308a09030f4b46eff554df18f
User & Date: Cthulhux 2019-09-11 20:54:38
Context
2020-08-18
09:04
Completed CPAN documentation. Leaf check-in: 8329566a22 user: Cthulhux tags: trunk
2019-09-11
20:54
transferred into fossil check-in: d6dc29d150 user: Cthulhux tags: trunk
20:53
initial empty check-in check-in: 928ee40c06 user: Cthulhux tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added LICENSE.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MIT No Attribution

Copyright 2019 <git@tuxproject.de>

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added README.md.





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
This is birdcries.net.

Install it yourself?

1. Get Perl 5 and CPAN.
2. `cpan install File::Util::Tempdir Twitter::API Mojolicious Mojolicious::Plugin::CHI`
3. Make a `config.pl` file according to `config-dist.pl`.
4. Run `birdcries.pl` over a capable server, e.g. [hypnotoad](https://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Hypnotoad).

Enjoy.

Added birdcries.pl.













































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env perl

package birdcries;

# ----------------------------------------------------
# This is the birdcries service.
# It provides a no-bullshit UI to view single tweets
# from a certain bird-themed website.
#
# https://birdcries.net
# ----------------------------------------------------

use strict;
use warnings;
use utf8;
use feature ':5.10';

use Twitter::API;
use Mojolicious::Lite;
use Try::Tiny;
use File::Util::Tempdir qw(get_tempdir);

# ----------------------------------------------------
# Twitter setup
# ----------------------------------------------------

our %conf;
require "./config.pl";

our $client = Twitter::API->new_with_traits(
    traits              => 'Enchilada',
    consumer_key        => $conf{'consumer_key'},
    consumer_secret     => $conf{'consumer_secret'},
    access_token        => $conf{'access_token'},
    access_token_secret => $conf{'access_token_secret'}
);

try {
    my $r = $client->verify_credentials;
}
catch {
    # Could not log in. :-(
    die $_ unless is_twitter_api_error($_);
 
    say $_->http_request->as_string;
    say $_->http_response->as_string;

    if ( $_->is_token_error ) {
        say "There's something wrong with this token."
    }
    if ( $_->twitter_error_code == 326 ) {
        say "Twitter thinks we're a spam bot.";
    }
};

# ----------------------------------------------------
# Caching
# ----------------------------------------------------

my $cachedir = get_tempdir();
if (defined $conf{'cachedir'}) {
    $cachedir = $conf{'cachedir'};
}

plugin 'CHI' => {
  Birdcries => {
    driver   => 'File',
    root_dir => $cachedir
  }
};

# ----------------------------------------------------
# Routing
# ----------------------------------------------------

get '/' => sub {
    # This is the default "home" page.
    # Display general information:
    my $c = shift;
    
    $c->stash(sitetitle => $conf{'sitetitle'});
    $c->stash(sitedom   => $conf{'sitedomain'});
    
    $c->render(template => 'start');
};

get '/:name/status/:id' => sub {
    # Actually open a tweet (with a certain ID).
    my $c = shift;
    my $id = $c->stash('id');
    my $name = $c->stash('name');
    
    my $tweet;
    my $retval;
    
    if ($conf{'use_cache_files'} == 1 && defined $c->chi('Birdcries')->get($id)) {
        # Save some time (and API calls), don't fetch tweets twice.
        $retval = $c->chi('Birdcries')->get($id);
        
        # Store the value for debug reasons:
        $c->stash(was_cached => 1);
    }
    else {
        my ($result, $context) = $client->show_status({
            id => $id,
            include_card_uri => 0,
            tweet_mode => 'extended'
        });
        
        if ($conf{'use_cache_files'} == 1) {
            # Only store the result if caching is not turned off.
            $c->chi('Birdcries')->set($id => $result);
        }
        
        $c->stash(was_cached => 0);
        $retval = $result;
    }
    
    if ($conf{'display_avatars'} == 1) {
        # The administrator wants us to fetch avatar pictures.
        $c->stash(avatar => $retval->{user}{profile_image_url_https});
    }
    else {
        $c->stash(avatar => "");
    }
    
    if (defined $retval->{full_text}) {
        # 280-character tweet detected.
        $tweet = $retval->{full_text};
    }
    else {
        $tweet = $retval->{text};
    }
    
    # URL handling:
    # Find long ("expanded") URLs, use them wisely.    
    if (defined $retval->{entities}->{urls}) {
        foreach my $url (@{$retval->{entities}->{urls}}) {
            my ($shorturl, $longurl) = map { $url->{$_} } qw(url expanded_url);
            
            # Replace <url> by <expanded_url> in our tweet text.
            $tweet =~ s/$shorturl/$longurl/g;
        }
    }
    
    if ($conf{'auto_link_href'} == 1) {
        # We add <a href> around valid HTTP(S) URLs.
        $tweet =~ s/((http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/[^\s]*)?)/<a href="$1" target="_blank">$1<\/a>/g;
    }
    
    $c->content_for(tweet => $tweet);
    
    $c->stash(author    => $name);
    $c->stash(authordisplay => $retval->{user}{screen_name});
    $c->stash(datetime  => $retval->{created_at});
    $c->stash(tweetid   => $id);
    
    $c->stash(sitetitle => $conf{'sitetitle'});
    $c->stash(sitedom   => $conf{'sitedomain'});
    
    $c->stash(use_cache => $conf{'use_cache_files'});
    
    $c->render(template => 'tweet');
};

app->start;

Added config-dist.pl.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env perl

# ----------------------------------------------------
# This is the birdcries service.
# It provides a no-bullshit UI to view single tweets
# from a certain bird-themed website.
#
# https://birdcries.net
# ----------------------------------------------------

our %conf = (

# ----------------------------------------------------
# General stuff
# ----------------------------------------------------

# Used for the header and the start site:
sitetitle           => 'b i r d c r i e s',
sitedomain          => 'birdcries.net',

# While birdcries will never show files attached to an
# original tweet, it can automatically add <a href>
# around URLs in said tweet, including (but not limited
# to) those which contain the attachments. Set this value
# to 0 if you don't want us to.
auto_link_href      => 1,

# ----------------------------------------------------
# Privacy
# ----------------------------------------------------

# Should we fetch and display avatar pictures from Twitter?
display_avatars     => 1,

# ----------------------------------------------------
# Caching
# ----------------------------------------------------

# Enables a file-based cache (you'll need some free space).
# This is highly recommended to avoid running into Twitter's
# artificial API limitations: You can fetch max. 1 tweet per
# second.
use_cache_files     => 1,

# By default, birdcries uses your system's tempdir to store
# its cache. If you prefer to set a different path, you'll
# need to uncomment the following line and adjust its value.
# cachedir            => '/temp',

# ----------------------------------------------------
# Twitter setup
# ----------------------------------------------------

# Register a new application with Twitter and put its tokens here:
consumer_key        => '',
consumer_secret     => '',
access_token        => '',
access_token_secret => '',

# ----------------------------------------------------
# That's it.
# ----------------------------------------------------

);

Added public/IBMPlexSerif-Regular.woff.

cannot compute difference between binary files

Added public/IBMPlexSerif-Regular.woff2.

cannot compute difference between binary files

Added public/base.css.



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@font-face {
    font-family: IBMPlexSerif;
    src: url(IBMPlexSerif-Regular.woff2) format("woff2"), url(IBMPlexSerif-Regular.woff) format("woff");
}

body {
    background-color: white;
    font-family: IBMPlexSerif, Vollkorn, serif;
    margin: 0;
    padding: 8px;
}

a:link, a:visited {
    color: blue;
    text-decoration: underline;
}

footer {
    position: fixed;
    bottom: 5px;
    left: 5px;
    padding: 6px;
    display: block;
    background-color: lightyellow;
    width: 100%;
}

header {
    background-color: black;
    display: block;
    font-size: 24px;
    font-weight: bold;
    padding: 4px;
}

header a:link, header a:visited {
    color: lightgrey;
    text-decoration: none;
}

main {
    margin: 20px;
}

#avatar {
    float: left;
    padding-right: 10px;
}

#datetime {
    font-size: 13px;
}

#tweetcard {
    clear: both;
    font-size: 24px;
    padding: 8px;
}

#metalinks {
    padding: 4px 2px;
    margin-top: 8px;
    border-top: 1px solid darkblue;
    font-size: 13px;
}

Added templates/layouts/base_layout.html.ep.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!doctype html>
<html>
  <head>
    <title><%= title %></title>
    %= stylesheet '/base.css'
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charset="utf-8" />
  </head>
  <body>
    <header><a href="/" title="Back to the start"><%= $sitetitle %></a></header>
    <main>
      <article><%= content %></article>
    </main>
    <footer>Made with rolling eyes.</footer>
  </body>
</html>

Added templates/not_found.html.ep.







>
>
>
1
2
3
% title 'B I R D C R I E S &nbsp; 4 0 4';
% layout 'base_layout';
Whatever you tried: Please try to go back.

Added templates/start.html.ep.









































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
% title 'B I R D C R I E S';
% layout 'base_layout';
This is birdcries.

<br /><br />

Replace <em>twitter.com</em> in any Twitter status link by <em><%= $sitedom %></em> to get a less shitty read-only view of the tweet which is faster and will respect your privacy! You can use <a href="https://greasyfork.org/en/scripts/388575-twitter-to-birdcries">this</a> userscript to automatize it.

<br /><br />

<em>Example:</em> Turn <a href="https://twitter.com/jack/status/20">this legendary tweet</a> into <a href="https://<%= $sitedom %>/jack/status/20">this</a> less annoying view.

<br /><br />

<b>Features and non-features:</b>

<br /><br />

No JavaScript.

<br /><br />

No login/logout, no cookies.

<br /><br />

No inline media except the avatar (which is optional).

<br /><br />

No video, no audio, no attachments whatsoever.

<br /><br />

<b>Code and donations:</b>

<br /><br />

The code is on <a href="https://code.rosaelefanten.org/birdcries">Fossil.</a>

<br /><br />

<em>birdcries</em> is licensed under the terms of the MIT No Attribution license. See the LICENSE file for more details.

<br /><br />

This server is expensive. Mind to help me pay for it?

<br />

Give me <b>Bitcoins:</b> <em>1VdaTSJ2mxDnmqb9QnXyUQks3nt2gQzyX</em><br />
Give me <b>Litecoins:</b> <em>LdTqDsXPB78W1s5BVRJwGMBzPCx7RFYyCD</em>

Added templates/tweet.html.ep.

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% title 'B I R D C R I E S :: Showing a single cry';
% layout 'base_layout';
<div id="authorcard">
  <div id="avatar"><img src="<%= $avatar %>" id="avatarpic" /></div>
  <div id="authorname">
    <a href="https://twitter.com/<%= $author %>" title="Open the profile on Twitter" target="_blank">@<%= $author %></a>
    (<%= $authordisplay %>)
  </div>
  <div id="datetime"><%= $datetime %></div>
</div>

<div id="tweetcard">
  %= content 'tweet'
</div>

<!--
  use_cache_files: <%= $use_cache %>
  was_cached: <%= $was_cached %>
-->

<div id="metalinks">
  Tweet ID: <%= $tweetid %><br />
  <a href="https://twitter.com/<%= $author %>/status/<%= $tweetid %>" target="_blank">Show on Twitter</a>
</div>