renameFromDisk.pl 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. # Includes
  5. use URI::Escape;
  6. use XML::Simple;
  7. use LWP::Simple;
  8. use File::Basename;
  9. use HTTP::Request::Common;
  10. # Debug
  11. my $DEBUG = 0;
  12. if ($ENV{'DEBUG'}) {
  13. $DEBUG = 1;
  14. }
  15. # Parameters
  16. my ($host, $section, $series, $season) = @ARGV;
  17. if (!$host || (!$section && !$series && !$season)) {
  18. die('Usage: ' . basename($0) . ' host[:port] [section_number] [series_metadata_number] [season_metadata_number]');
  19. }
  20. # Globals
  21. if (!($host =~ /\:\d+$/)) {
  22. $host .= ':32400';
  23. }
  24. my $baseURL = 'http://' . $host;
  25. my $xml = new XML::Simple;
  26. my @shows = ();
  27. if (!$season) {
  28. if ($series) {
  29. # Fetch just the provided show
  30. print STDERR 'Fetching show ' . $series . "\n";
  31. @shows = ('/library/metadata/' . $series . '/children');
  32. } else {
  33. # Fetch the list of all shows in the section
  34. print STDERR "Fetching shows...\n";
  35. {
  36. my $content = get($baseURL . '/library/sections/' . $section . '/all/');
  37. if ($DEBUG) {
  38. print STDERR $baseURL . '/library/sections/' . $section . '/all/' . "\n";
  39. }
  40. if (!$content) {
  41. die(basename($0) . ': Unable to fetch data for section: ' . $section . "\n");
  42. }
  43. # Find all TV shows in the section
  44. {
  45. my $tree = $xml->XMLin($content);
  46. @shows = keys(%{ $tree->{'Directory'} });
  47. }
  48. }
  49. print STDERR 'Found ' . scalar(@shows) . " shows\n";
  50. }
  51. }
  52. my @seasons = ();
  53. if ($season) {
  54. # Fetch just the provided season
  55. print STDERR 'Fetching season ' . $season . "\n";
  56. @seasons = ('/library/metadata/' . $season . '/children');
  57. } else {
  58. # Fetch the list of all seasons in each show
  59. print STDERR "Fetching seasons...\n";
  60. foreach my $show (@shows) {
  61. my $content = get($baseURL . $show);
  62. if ($DEBUG) {
  63. print STDERR $baseURL . $show . "\n";
  64. }
  65. if (!$content) {
  66. warn(basename($0) . ': Could not fetch seasons for show: ' . $show . "\n");
  67. next;
  68. }
  69. # Find all seasons in the show
  70. {
  71. my $tree = $xml->XMLin($content);
  72. # XML::Simple retuns different structure depending on the number of same-named child elements
  73. if ($tree->{'Directory'}->{'key'}) {
  74. push(@seasons, $tree->{'Directory'}->{'key'});
  75. } else {
  76. push(@seasons, keys(%{ $tree->{'Directory'} }));
  77. }
  78. }
  79. }
  80. }
  81. print STDERR 'Found ' . scalar(@seasons) . " seasons\n";
  82. # Forget the list of shows
  83. undef(@shows);
  84. # Fetch the list of all episodes in each season
  85. my @episodes = ();
  86. print STDERR "Fetching episodes...\n";
  87. foreach my $season (@seasons) {
  88. my $content = get($baseURL . $season);
  89. if ($DEBUG) {
  90. print STDERR $baseURL . $season . "\n";
  91. }
  92. if (!$content) {
  93. warn(basename($0) . ': Could not fetch episodes for season: ' . $season . "\n");
  94. next;
  95. }
  96. # Find all episodes in the season
  97. {
  98. my $tree = $xml->XMLin($content);
  99. # XML::Simple retuns different structure depending on the number of same-named child elements
  100. if ($tree->{'Video'}->{'key'}) {
  101. push(@episodes, $tree->{'Video'}->{'key'});
  102. } else {
  103. push(@episodes, keys(%{ $tree->{'Video'} }));
  104. }
  105. }
  106. }
  107. print STDERR 'Found ' . scalar(@episodes) . " episodes\n";
  108. # Forget the list of seasons
  109. undef(@seasons);
  110. # Fetch the metadata from each episode
  111. print STDERR "Checking episodes...\n";
  112. foreach my $episode (@episodes) {
  113. my $content = get($baseURL . $episode);
  114. if ($DEBUG) {
  115. print STDERR $baseURL . $episode . "\n";
  116. }
  117. if (!$content) {
  118. warn(basename($0) . ': Could not fetch metadata for episode: ' . $episode . "\n");
  119. next;
  120. }
  121. # Parse the metadata
  122. {
  123. my $tree = $xml->XMLin($content);
  124. my $title = $tree->{'Video'}->{'title'};
  125. my $summary = $tree->{'Video'}->{'summary'};
  126. my $file = $tree->{'Video'}->{'Media'}->{'Part'}->{'file'};
  127. if (!$title) {
  128. warn('Invalid title for episode: ' . $episode . "\n");
  129. next;
  130. }
  131. if (!$file) {
  132. if (!$tree->{'Video'}->{'Media'}->{'key'}) {
  133. warn('No support for multi-file episodes: ' . $episode . "\n");
  134. } else {
  135. warn('Invalid file for episode: ' . $episode . "\n");
  136. }
  137. next;
  138. }
  139. # Rename if the file has a valid name but the episode does not
  140. $file = uri_unescape($file);
  141. $file = basename($file);
  142. $file =~ s/^\d+\s+\-\s*//;
  143. $file =~ s/S\d+E\d+\s+\-\s*//i;
  144. $file =~ s/\.\w{2,4}//;
  145. if (!$file || length($file) < 2 || $file =~ /NoName/i || $file =~ /Episode\s+\d+/i) {
  146. next;
  147. }
  148. if ($file =~ /\s+S\d+D\d+\-\d+$/) {
  149. print STDERR 'Skipping encoder-named file: ' . $file . "\n";
  150. }
  151. if ($title =~ /^Episode\s+\d+$/ || $title =~ /^\d{4}\-\d{2}\-\d{2}$/) {
  152. my $ua = LWP::UserAgent->new();
  153. my $encoded = uri_escape($file);
  154. print STDERR 'Renaming ' . $episode . ' from "' . $title . '" to "' . $file . '"' . "\n";
  155. my $url = $baseURL . $episode . '?title=' . $encoded . '&titleSort=' . $encoded . '&title.locked=1&titleSort.locked=1';
  156. my $request = HTTP::Request->new('PUT' => $url);
  157. $ua->request($request);
  158. if (!$summary) {
  159. print STDERR "\tAlso setting summary\n";
  160. $url = $baseURL . $episode . '?title=' . $encoded . '&summary=' . $encoded . '&summary.locked=1';
  161. $request = HTTP::Request->new('PUT' => $url);
  162. $ua->request($request);
  163. }
  164. }
  165. }
  166. }