NoMoreNicksLeft

Plex Library Scheduler script

Jul 15th, 2016
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 5.89 KB | None | 0 0
  1. #!/usr/bin/perl
  2. use strict;
  3. use experimental 'smartmatch';
  4.  
  5. use WWW::Mechanize;
  6. use JSON::XS;
  7. use MIME::Base64;
  8. use XML::Simple;
  9. use Term::ReadKey;
  10. use HTTP::Cookies;
  11.  
  12. ########################################################################################################################
  13. #                                                        main{}                                                        #
  14. ########################################################################################################################
  15.  
  16. # All separate instances of this script (or any other Plex-interacting software) needs its own id.
  17. my $uuid = '99';
  18.  
  19. # Does this thing even have a proper uuid?
  20. if ($uuid eq '1') {
  21.     # Self-modifying code?
  22.  
  23. }
  24.  
  25. # Arguments. This is perl, no one nancies around about "debates" and "discussions".
  26. my ($servername, $friendname, $status, $librarynames) = @ARGV;
  27. if ($#ARGV != 3) {
  28.     print "\nUsage: plex_share_changer.pl server friend [enable|disable] library1,library2\n";
  29.     exit 1;
  30. }
  31. unless ($status eq "enable" || $status eq "disable") {
  32.     print "\nUsage: plex_share_changer.pl server friend [enable|disable] library1,library2\n";
  33.     exit 1;
  34. }
  35. my @lns = split(',', $librarynames);
  36.  
  37. # Suddenly web robot.
  38. my $mech = WWW::Mechanize->new(autocheck => 0);
  39. $mech->agent_alias('Mac Safari');
  40.  
  41. # Some headers we apparently need...
  42. $mech->add_header('X-Plex-Client-Identifier' => $uuid);
  43. $mech->add_header('X-Plex-Product' => 'Library Share Kicker');
  44. $mech->add_header('X-Plex-Version' => '0.01');
  45.  
  46. # We need to check if we already have a usable token.
  47. if (-e "$ENV{'HOME'}/.plextoken") {
  48.     my $token = do { local(@ARGV, $/) = "$ENV{'HOME'}/.plextoken"; <> };
  49.     $mech->add_header('X-Plex-Token' => $token);
  50.  
  51.     # This token might be stale, or the file might have been garbled. We'll check, and if it's bad bounce to the
  52.     # subroutine anyway.
  53.     $mech->get("https://plex.tv/pms/servers.xml");
  54.     if (!$mech->success()) {
  55.         &authenticate;
  56.     }
  57. }
  58. else {
  59.     &authenticate;
  60. }
  61.  
  62. # Let's get the server id.
  63. my %servers;
  64. $mech->get("https://plex.tv/pms/servers.xml");
  65. my $xml2 = XMLin($mech->content(), ForceArray => 1);
  66. foreach my $key (keys $xml2->{'Server'}) {
  67.     if ($xml2->{'Server'}->{$key}->{'owned'}) {
  68.         $servers{$key} = $xml2->{'Server'}->{$key}->{'machineIdentifier'};
  69.     }
  70. }
  71. # Notes: It looks like it might be theoretically possible for a single user to have more than one server (why?), so we
  72. # keep all of them that are "owned", and use whichever one they've specified. Unless they give bullshit, then we just
  73. # tell them to go fuck themselves. Nicely though, and cryptically.
  74. unless ($servers{$servername}) {
  75.     print "No such server.\n";
  76.     exit 2;
  77. }
  78.  
  79. # We need to get a list of users.
  80. my %users;
  81. $mech->get("https://plex.tv/api/users");
  82. my $xml = XMLin($mech->content(), ForceArray => 1);
  83. foreach my $key (keys $xml->{'User'}) {
  84.     $users{$xml->{'User'}->{$key}->{'title'}} = $xml->{'User'}->{$key}->{'Server'}->{$servername}->{'id'};
  85. }
  86.  
  87. unless ($users{$friendname}) {
  88.     print "No such friend.\n";
  89.     exit 3;
  90. }
  91.  
  92. # Now we need a list of library ids.
  93. my @libraries;
  94. $mech->get("https://plex.tv/api/servers/" . $servers{$servername} . "/shared_servers/" . $users{$friendname});
  95. my $xml3 = XMLin($mech->content(), ForceArray => 1);
  96. foreach my $key (keys $xml3->{'SharedServer'}->{$servername}->{'Section'}) {
  97.     if    ($status eq "enable") {
  98.         # if in array or if already
  99.         if ($xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'shared'}) {
  100.             push(@libraries, $xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'id'});
  101.         }
  102.         elsif ($xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'title'} ~~ @lns) {
  103.             push(@libraries, $xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'id'});
  104.         }
  105.     }
  106.     elsif ($status eq "disable") {
  107.         # if already and not in array
  108.         if ($xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'shared'} &&
  109.             !($xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'title'} ~~ @lns)) {
  110.             push(@libraries, $xml3->{'SharedServer'}->{$servername}->{'Section'}->{$key}->{'id'});
  111.         }
  112.     }
  113. }
  114.  
  115. # Send the update to plex.tv for library sharing... once this is done, only those libraries in @libraries will still be
  116. # shared. (This is why we went through checking if they were already shared, so we could add them to the list.)
  117. my $j = encode_json { "server_id" => $servers{$servername}, "shared_server" => { "library_section_ids" => \@libraries } };
  118. $mech->put("https://plex.tv/api/servers/" . $servers{$servername} . "/shared_servers/" . $users{$friendname},
  119.            'Content-Type' => 'application/json',
  120.            Content => $j);
  121.  
  122. ########################################################################################################################
  123. #                                                     Subroutines.                                                     #
  124. ########################################################################################################################
  125.  
  126. sub authenticate {
  127.     # Ok, so we'll need a password...
  128.     print "Username (email): ";
  129.     my $u = <STDIN>;
  130.     chomp($u);
  131.     print "Password: ";
  132.     ReadMode ('noecho');
  133.     my $p = <STDIN>;
  134.     chomp($p);
  135.     ReadMode ('restore');
  136.     print "\n";
  137.  
  138.     # Just sign in.
  139.     $mech->add_header('Authorization' => 'Basic ' . encode_base64("$u:$p"));
  140.     $mech->post("https://plex.tv/users/sign_in.json");
  141.     # Parse for a token!
  142.     my $json = JSON::XS->new->utf8->decode($mech->content());
  143.     $mech->add_header('X-Plex-Token' => $json->{'user'}->{'authentication_token'});
  144.     # So we don't have to do this a second time.
  145.     open(my $fh, '>', "$ENV{'HOME'}/.plextoken");
  146.     print $fh $json->{'user'}->{'authentication_token'};
  147.     close $fh;
  148. }
Add Comment
Please, Sign In to add comment