Lady_Aleena has asked for the wisdom of the Perl Monks concerning the following question:

Okay, I know that the people here are not really big on Twitter, well, not as much as I am anyway. Twitter has a list limit per account (20), so I can keep more lists, I am planning on creating some more accounts where I can keep lists together and make more. I could have done this manually, but that would have lead to a very sore wrist and head and dead mouse batteries. So, I decided to try to write a script to do it. Net::Twitter::Lite uses OO, so I am being a very bad coder and cargo culting a lot from examples given to me elsewhere.

It looks like I will need three scripts to complete the task, and I would just like a couple of pairs of eyeballs to look over the code I have written so far and maybe give a few pointers.

This first script gets the data from my main account and is going to put that data into various files for storage.

use warnings; use strict; use Net::Twitter::Lite; use Data::Dumper; use lib '../../files/perl/lib'; use Base::Roots qw(get_data); use Base::Nifty qw(filify); my $directory = 'personal/Twitter'; my $file_die = "Can't open the file"; my $twit_id = "Lady_Aleena"; my $nt = Net::Twitter::Lite->new( consumer_key => 'in the code', consumer_secret => 'in the code', access_token => 'in the code', access_token_secret => 'in the code', ); # Not all data I want is on Twitter, some of these lists are not creat +ed, # but I want to create them in the third script. my %twitter_lists = ( 'Andromeda' => { 'network' => 'unknown', }, 'Babylon 5' => { 'network' => 'unknown', }, 'Body of Proof' => { 'network' => 'ABC', }, 'Bones' => { 'network' => 'FOX', }, 'Buffy and Angel' => { 'network' => 'unknown', }, 'Burn Notice' => { 'network' => 'USA', }, 'Castle' => { 'network' => 'ABC', }, 'Chuck' => { 'network' => 'NBC', }, 'Covert Affairs' => { 'network' => 'USA', }, 'Doctor Who' => { 'network' => 'BBC', }, 'ER' => { 'network' => 'NBC', }, 'Eureka Warehouse13 Alphas' => { 'network' => 'Syfy', }, 'Firefly' => { 'network' => 'unknown', }, 'Haven' => { 'network' => 'Syfy', }, 'Law & Order' => { 'network' => 'NBC', }, 'Leverage' => { 'network' => 'TNT', }, 'Necessary Roughness' => { 'network' => 'USA', }, 'No Ordinary Family' => { 'network' => 'ABC' }, 'Rizzoli & Isles' => { 'network' => 'TNT', }, 'Sanctuary' => { 'network' => 'Syfy', }, 'seaQuest' => { 'network' => 'NBC', }, 'Stargate' => { 'network' => 'Syfy', }, 'Star Trek' => { 'network' => 'unknown', }, 'Studio 60' => { 'network' => 'NBC', }, 'White Collar' => { 'network' => 'USA', }, 'The X-Files & Millennium' => { 'network' => 'FOX', }, ); # my @raw_lists; for ( my $cursor = -1; $cursor; ) { my $r = $nt->get_lists({ user => $twit_id, cursor => $cursor }); push @raw_lists, @{$r->{lists}}; $cursor = $r->{next_cursor}; } my @lists; for my $list (@raw_lists) { my $name = $list->{'name'}; $twitter_lists{$name}{'name'} = $name; $twitter_lists{$name}{'slug'} = $list->{'slug'}; $twitter_lists{$name}{'id'} = $list->{'id'}; $twitter_lists{$name}{'mode'} = $list->{'mode'}; $twitter_lists{$name}{'description'} = $list->{'description'}; push @lists, $list->{'slug'}; } my %raw_lists_follows; for my $list (@lists) { for ( my $cursor = -1; $cursor; ) { my $r = $nt->list_members($twit_id, $list, { cursor => $cursor }); push @{$raw_lists_follows{$list}{following}}, @{$r->{users}}; $cursor = $r->{next_cursor}; } for ( my $cursor = -1; $cursor; ) { my $r = $nt->list_subscribers($twit_id, $list, { cursor => $cursor + }); push @{$raw_lists_follows{$list}{followers}}, @{$r->{users}}; $cursor = $r->{next_cursor}; } } sub get_list_name { my ($slug) = @_; for my $twitter_list (keys %twitter_lists) { if ($twitter_lists{$twitter_list}{slug} eq $slug) { return $twitter_list; } } } for my $raw_list (keys %raw_lists_follows) { my $list = get_list_name($raw_list); for my $following (@{$raw_lists_follows{$raw_list}{following}}) { my $name = $following->{'name'}; $twitter_lists{$list}{following}{$name}{'name'} = $name; $twitter_lists{$list}{following}{$name}{'screen_name'} = $followin +g->{'screen_name'}; $twitter_lists{$list}{following}{$name}{'id'} = $following->{'id'} +; } for my $followers (@{$raw_lists_follows{$raw_list}{followers}}) { my $name = $followers->{'name'}; $twitter_lists{$list}{followers}{$name}{'name'} = $name; $twitter_lists{$list}{followers}{$name}{'screen_name'} = $follower +s->{'screen_name'}; $twitter_lists{$list}{followers}{$name}{'id'} = $followers->{'id'} +; } } my @twitter_list_file_lines; for $twitter_list (sort keys %twitter_lists) { my $list_name = $twitter_lists{$twitter_list}{name}; my $list_slug = $twitter_lists{$twitter_list}{slug}; my $list_id = $twitter_lists{$twitter_list}{id}; my $list_description = $twitter_lists{$twitter_list}{description}; my $list_network = $twitter_lists{$twitter_list}{network}; push @twitter_list_file_lines, qq($list_name|$list_slug|$list_id|$li +st_description|$list_network); for my $follow ('following','followers') { $directory .= "lists/".filify($list_name); my $people_list_file_name = filify(qq($list_name/$follow.txt)); my @person_list_lines = (); for my $person (sort keys %{$twitter_lists{$twitter_list}{$follow} +}) { my $follow_name = $twitter_lists{$twitter_list}{$follow}{$person +}{name}; my $follow_screen_name = $twitter_lists{$twitter_list}{$follow}{ +$person}{screen_name}; my $follow_id = $twitter_lists{$twitter_list}{$follow}{$person}{ +id}; push @person_list_lines, qq($follow_name|$follow_screen_name|$fo +llow_id); } open(my $people_list_file, '>', get_data($directory,$people_list_f +ile_name) or die "$file_die $people_file"; print $people_list_file join("\n",@person_list_lines); } } open(my $twitter_list_file, '>', get_data($directory,"twitter_lists.tx +t") or die $file_die; print $twitter_list_file join("\n",@twitter_list_file_lines);

There is a second script that I have yet to write. I still need to figure out how to get a new access_token and access_token_secret for each new account I will be manually creating. After I get the access_token and access_token_secret for each account, I will be putting those into a file which I will access in the next script.

The third script will take the data from the first script, move it around a bit, and create new lists with the same information under the new accounts with the exception of who is following the relocated lists. I do not think that I can script a move like that.

use warnings; use strict; use Net::Twitter::Lite; use lib '../../files/perl/lib'; use Base::Roots qw(get_data); use Base::Nifty qw(get_hash filify); my $directory = 'personal/Twitter'; my $file_die = "Can't open the file"; my %twitter_lists; my %twitter_lists_data = ( file => qq($directory/twitter_lists.txt), headings => [qw(name slug id description network)], ); get_hash(\%twitter_lists,\%twitter_lists_data); my %networks; for my $list (sort keys %twitter_lists) { my $network = $twitter_lists{$twitter_list}{network}; push @{$networks{$network}}, $list; } for my $network (sort keys %networks) { if ($network !~ /unknown/ or scalar(@{$networks{$network}}) > 1) { my $twit_id = "LadyAleena$network"; my $nt = Net::Twitter::Lite->new( consumer_key => 'in the code', consumer_secret => 'in the code', access_token => , # I need to write the script to get thi +s. access_token_secret => , # I need to write the script to get thi +s. ); for my $show (sort @{$networks{$network}}) { my $directory .= "lists/".filify($list_name); my $slug = $twitter_lists{$show}{slug}; my $r = $nt->create_list({user => $twit_id, name => $show}); my %following_list; my %following_list_data = ( file => qq($directory/following.txt), headings => [qw(name screen_name id)], ); get_hash(\%following_list,%following_list_data); for my $follow (sort keys %following_list) { my $screen_name = $following_list{$follow}{screen_name}; my $r = $nt->add_list_member({user => $twit_id, list_id => $sl +ug, id => $screen_name}); } } } }

At the end of the third script, I am still trying to decide what I am going to do to announce the moves. Do I send a message to all the lists followers individually? Do I announce the move from my main account to all my followers? I am still undecided there, but I do not expect anyone to help me with that decision, since it is mostly how irritating on Twitter do I want to get. :)

My head is a bit fuzzy from all of this cargo culting. I probably have way too much code here for the task. I have used a few homemade modules and subroutines in there. I will add them to the end of this post if needed.

Have a cookie and a very nice day!
Lady Aleena

Replies are listed 'Best First'.
Re: Did I use Net::Twitter::lite correctly for moving lists between accounts?
by Anonymous Monk on Aug 17, 2011 at 01:54 UTC

    This first script gets the data from my main account and is going to put that data into various files for storage.

    Your program flow is interleaved/buried between variable/subroutine declarations and loops.

    If I were you, I would make more functions (one for each loop), so that each program boils down to

    #!/usr/bin/perl -- use strict; use warnings; ... Main( @ARGV ); exit( 0 ); sub Main { my $blah = Function1(); my @blah = Function2($blah); @blah = Function3( \@blah ); ... }
    And of course, use meaningful function names

    Do I send a message to all the lists followers individually? Do I announce the move from my main account to all my followers?

    Ask yourself:
    Do I really want my followers to follow?
    Are my followers twitter-savvy technically inclined individuals?
    If the answer is yes, do both, and make it easy for them to follow you on the correct, new list (or whatever twitter boom bah)

    My head is a bit fuzzy from all of this cargo culting. I probably have way too much code here for the task.

    The code (the how) is distracting your from the why -- don't look at the code, don't think in terms of code/API calls, try thinking in terms of joe-twitter-user / joe-twitter-follower

      As a followup to my above post, and to partially answer the question of why your question received a downvote (as tye says , why your question sucks), here is what I think

      stackoverflow moderators would probably reject this question, as
      not-a-real-question
      not specific enough
      too many questions
      move to codereview at stackexchange
      ...

      You try to follow the pattern from How do I post a question effectively?, but the title isn't effective because you really ask 2-5 different questions, and your question isn't really Did I use Net::Twitter::lite correctly for moving lists between accounts?

      Or if the Title is one of your actual questions, what happened when you tried? :D

      I don't do twitter, so don't really feel like creating a test account, testing the code, deleting the account :)

      Hi

        move to codereview at stackexchange

        Yes, clearly "her node sucked" because she shouldn't have posted it to perlmonks.org. She should have posted it to the other of our family of sites, the one that allows people to request code reviews. What was that site? Oh, yes: perlmonks.org.

        - tye        

Re: Did I use Net::Twitter::lite correctly for moving lists between accounts?
by GrandFather (Saint) on Aug 17, 2011 at 11:52 UTC

    The following is not an answer to your question, but may help you with testing your code. I've mocked Net::Twitter::Lite using Test::MockObject to avoid needing to use Twitter in testing the code at all. I've also removed all the stuff I didn't understand that prevented the code running and generating what looks like it may be useful output and I've printed to the console rather than generate output files. With all that in mind, consider:

    use warnings; use strict; use Test::MockObject; my $mock; BEGIN { $mock = Test::MockObject->new (); $mock->fake_module ('Net::Twitter::Lite'); $mock->fake_new ('Net::Twitter::Lite'); $mock->mock (get_lists => \&mock_get_lists); $mock->mock (list_members => \&mock_list_members); $mock->mock (list_subscribers => \&mock_list_subscribers); } require Net::Twitter::Lite; my $directory = 'personal/Twitter'; my $twit_id = "Lady_Aleena"; my $nt = Net::Twitter::Lite->new ( consumer_key => 'in the code', consumer_secret => 'in the code', access_token => 'in the code', access_token_secret => 'in the code', ); # Not all data I want is on Twitter, some of these lists are not creat +ed, # but I want to create them in the third script. my %twitter_lists = ( 'Andromeda' => {'network' => 'unknown',}, 'Babylon 5' => {'network' => 'unknown',}, 'Body of Proof' => {'network' => 'ABC',}, 'Bones' => {'network' => 'FOX',}, 'Buffy and Angel' => {'network' => 'unknown',}, 'Burn Notice' => {'network' => 'USA',}, 'Castle' => {'network' => 'ABC',}, 'Chuck' => {'network' => 'NBC',}, 'Covert Affairs' => {'network' => 'USA',}, 'Doctor Who' => {'network' => 'BBC',}, 'ER' => {'network' => 'NBC',}, 'Eureka Warehouse13 Alphas' => {'network' => 'Syfy',}, 'Firefly' => {'network' => 'unknown',}, 'Haven' => {'network' => 'Syfy',}, 'Law & Order' => {'network' => 'NBC',}, 'Leverage' => {'network' => 'TNT',}, 'Necessary Roughness' => {'network' => 'USA',}, 'No Ordinary Family' => {'network' => 'ABC'}, 'Rizzoli & Isles' => {'network' => 'TNT',}, 'Sanctuary' => {'network' => 'Syfy',}, 'seaQuest' => {'network' => 'NBC',}, 'Stargate' => {'network' => 'Syfy',}, 'Star Trek' => {'network' => 'unknown',}, 'Studio 60' => {'network' => 'NBC',}, 'White Collar' => {'network' => 'USA',}, 'The X-Files & Millennium' => {'network' => 'FOX',}, ); # my @raw_lists; for (my $cursor = -1; $cursor;) { my $r = $nt->get_lists ({user => $twit_id, cursor => $cursor}); push @raw_lists, @{$r->{lists}}; $cursor = $r->{next_cursor}; } my @lists; for my $list (@raw_lists) { my $name = $list->{'name'}; $twitter_lists{$name}{'name'} = $name; $twitter_lists{$name}{'slug'} = $list->{'slug'}; $twitter_lists{$name}{'id'} = $list->{'id'}; $twitter_lists{$name}{'mode'} = $list->{'mode'}; $twitter_lists{$name}{'description'} = $list->{'description'}; push @lists, $list->{'slug'}; } my %raw_lists_follows; for my $list (@lists) { for (my $cursor = -1; $cursor;) { my $r = $nt->list_members ($twit_id, $list, {cursor => $cursor +}); push @{$raw_lists_follows{$list}{following}}, @{$r->{users}}; $cursor = $r->{next_cursor}; } for (my $cursor = -1; $cursor;) { my $r = $nt->list_subscribers ($twit_id, $list, {cursor => $cu +rsor}); push @{$raw_lists_follows{$list}{followers}}, @{$r->{users}}; $cursor = $r->{next_cursor}; } } for my $raw_list (keys %raw_lists_follows) { my $list = get_list_name ($raw_list); for my $following (@{$raw_lists_follows{$raw_list}{following}}) { my $name = $following->{'name'}; $twitter_lists{$list}{following}{$name}{'name'} = $name; $twitter_lists{$list}{following}{$name}{'screen_name'} = $following->{'screen_name'}; $twitter_lists{$list}{following}{$name}{'id'} = $following->{' +id'}; } for my $followers (@{$raw_lists_follows{$raw_list}{followers}}) { my $name = $followers->{'name'}; $twitter_lists{$list}{followers}{$name}{'name'} = $name; $twitter_lists{$list}{followers}{$name}{'screen_name'} = $followers->{'screen_name'}; $twitter_lists{$list}{followers}{$name}{'id'} = $followers->{' +id'}; } } my @twitter_list_file_lines; for my $twitter_list (sort keys %twitter_lists) { my $tl = $twitter_lists{$twitter_list}; my $listName = $tl->{list_name}; next if ! defined $tl->{slug}; push @twitter_list_file_lines, @{$tl}{qw(name slug id description +network)}; for my $follow ('following', 'followers') { my @person_list_lines = (); for my $person (sort keys %{$tl->{$follow}}) { my $follow_name = $tl->{$follow}{$person}{name}; my $follow_screen_name = $tl->{$follow}{$person}{screen_na +me}; my $follow_id = $tl->{$follow}{$person}{id}; push @person_list_lines, qq($follow_name|$follow_screen_name|$follow_id); } print "PLF: ", join ("\n ", @person_list_lines), "\n"; } } print "\nTLF: ", join "\n ", @twitter_list_file_lines, ''; sub get_list_name { my ($slug) = @_; for my $twitter_list (keys %twitter_lists) { next if !defined $twitter_lists{$twitter_list}{slug}; if ($twitter_lists{$twitter_list}{slug} eq $slug) { return $twitter_list; } } } sub mock_get_lists { my ($self, $params) = @_; my %listsByUser = ( Lady_Aleena => [ { name => 'Andromeda', slug => 1, id => 1, description => 'Broom cupboard', network => 'ethernet' }, ], ); my $lists = $listsByUser{$params->{user}}; return $params->{cursor} ? {lists => $lists} : $lists; } sub mock_list_members { my ($self, $twit_id, $list, $params) = @_; my %membersById = ( Lady_Aleena => [ [ {name => 'Joe', screen_name => 'Stretch', id => 4}, {name => 'Bill', screen_name => 'Bill', id => 5}, {name => 'Sarah', screen_name => 'Sam', id => 6}, ], ], ); my $members = $membersById{$twit_id}[$list - 1]; return $params->{cursor} ? {users => $members} : $members; } sub mock_list_subscribers { my ($self, $twit_id, $list, $params) = @_; my %subscribersById = ( Lady_Aleena => [ [ {name => 'Sandy', screen_name => 'Grit', id +=> 1}, {name => 'Carla', screen_name => 'Carla', id +=> 2}, {name => 'Fred', screen_name => 'Fish and Chips', id +=> 3}, ], ], ); my $subscribers = $subscribersById{$twit_id}[$list - 1]; return $params->{cursor} ? {users => $subscribers} : $subscribers; }

    Prints:

    PLF: Bill|Bill|5 Joe|Stretch|4 Sarah|Sam|6 PLF: Carla|Carla|2 Fred|Fish and Chips|3 Sandy|Grit|1 TLF: Andromeda 1 1 Broom cupboard unknown
    True laziness is hard work
Re: Did I use Net::Twitter::lite correctly for moving lists between accounts?
by Khen1950fx (Canon) on Aug 17, 2011 at 04:36 UTC
    I'm not into Twitter, and I never will be, but curiosity got the better of me. I fiddled with the first script, made some adjustments, and ran it. I kept getting
    Rate limit exceeded. Clients may not make more than 150 requests per h +our
    Another reason why I find Twitter annoying:). Here's what I tried: