renameFromDisk.pl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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, $episode) = @ARGV;
  17. if (!$host || (!$section && !$series && !$season && !$episode)) {
  18. die('Usage: ' . basename($0) . ' host[:port] [section_number] [series_metadata_id] [season_metadata_id] [episode_metadata_id]');
  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 && !$episode) {
  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 (!$episode) {
  54. if ($season) {
  55. # Fetch just the provided season
  56. print STDERR 'Fetching season ' . $season . "\n";
  57. @seasons = ('/library/metadata/' . $season . '/children');
  58. } else {
  59. # Fetch the list of all seasons in each show
  60. print STDERR "Fetching seasons...\n";
  61. foreach my $show (@shows) {
  62. my $content = get($baseURL . $show);
  63. if ($DEBUG) {
  64. print STDERR $baseURL . $show . "\n";
  65. }
  66. if (!$content) {
  67. warn(basename($0) . ': Could not fetch seasons for show: ' . $show . "\n");
  68. next;
  69. }
  70. # Find all seasons in the show
  71. {
  72. my $tree = $xml->XMLin($content);
  73. # XML::Simple retuns different structure depending on the number of same-named child elements
  74. if ($tree->{'Directory'}->{'key'}) {
  75. push(@seasons, $tree->{'Directory'}->{'key'});
  76. } else {
  77. push(@seasons, keys(%{ $tree->{'Directory'} }));
  78. }
  79. }
  80. }
  81. }
  82. print STDERR 'Found ' . scalar(@seasons) . " seasons\n";
  83. }
  84. # Forget the list of shows
  85. undef(@shows);
  86. # Fetch the list of all episodes in each season
  87. my @episodes = ();
  88. if ($episode) {
  89. # Fetch just the provided episode
  90. print STDERR 'Fetching episode ' . $episode . "\n";
  91. @episodes = ('/library/metadata/' . $episode);
  92. } else {
  93. print STDERR "Fetching episodes...\n";
  94. foreach my $season (@seasons) {
  95. my $content = get($baseURL . $season);
  96. if ($DEBUG) {
  97. print STDERR $baseURL . $season . "\n";
  98. }
  99. if (!$content) {
  100. warn(basename($0) . ': Could not fetch episodes for season: ' . $season . "\n");
  101. next;
  102. }
  103. # Find all episodes in the season
  104. {
  105. my $tree = $xml->XMLin($content);
  106. # XML::Simple retuns different structure depending on the number of same-named child elements
  107. if ($tree->{'Video'}->{'key'}) {
  108. push(@episodes, $tree->{'Video'}->{'key'});
  109. } else {
  110. push(@episodes, keys(%{ $tree->{'Video'} }));
  111. }
  112. }
  113. }
  114. print STDERR 'Found ' . scalar(@episodes) . " episodes\n";
  115. }
  116. # Forget the list of seasons
  117. undef(@seasons);
  118. # Fetch the metadata from each episode
  119. print STDERR "Checking episodes...\n";
  120. foreach my $episode (@episodes) {
  121. my $content = get($baseURL . $episode);
  122. if ($DEBUG) {
  123. print STDERR $baseURL . $episode . "\n";
  124. }
  125. if (!$content) {
  126. warn(basename($0) . ': Could not fetch metadata for episode: ' . $episode . "\n");
  127. next;
  128. }
  129. # Parse the metadata
  130. {
  131. my $tree = $xml->XMLin($content);
  132. my $title = $tree->{'Video'}->{'title'};
  133. my $summary = $tree->{'Video'}->{'summary'};
  134. my $file = $tree->{'Video'}->{'Media'}->{'Part'}->{'file'};
  135. if (!$title) {
  136. warn('Invalid title for episode: ' . $episode . "\n");
  137. next;
  138. }
  139. if (!$file) {
  140. if (!$tree->{'Video'}->{'Media'}->{'key'}) {
  141. warn('No support for multi-file episodes: ' . $episode . "\n");
  142. } else {
  143. warn('Invalid file for episode: ' . $episode . "\n");
  144. }
  145. next;
  146. }
  147. # Rename if the file has a valid name but the episode does not
  148. $file = uri_unescape($file);
  149. $file = basename($file);
  150. $file =~ s/^\d+\s+\-\s*//;
  151. $file =~ s/S\d+E\d+\s+\-\s*//i;
  152. $file =~ s/\.\w{2,4}//;
  153. if ( !$file
  154. || length($file) < 2
  155. || $file =~ /NoName/i
  156. || $file =~ /Episode\s+\d+/i
  157. || $file =~ /Disc\s+\d+/i)
  158. {
  159. next;
  160. }
  161. if ($file =~ /\s+S\d+D\d+\-\d+$/) {
  162. print STDERR 'Skipping encoder-named file: ' . $file . "\n";
  163. }
  164. if ( $title =~ /^Episode\s+\d+$/
  165. || $title =~ /^\d{4}\-\d{2}\-\d{2}$/
  166. || $title =~ /Disc\s+\d+/i)
  167. {
  168. my $ua = LWP::UserAgent->new();
  169. my $encoded = uri_escape($file);
  170. print STDERR 'Renaming ' . $episode . ' from "' . $title . '" to "' . $file . '"' . "\n";
  171. my $url = $baseURL . $episode . '?title=' . $encoded . '&titleSort=' . $encoded . '&title.locked=1&titleSort.locked=1';
  172. my $request = HTTP::Request->new('PUT' => $url);
  173. $ua->request($request);
  174. if (!$summary) {
  175. print STDERR "\tAlso setting summary\n";
  176. $url = $baseURL . $episode . '?title=' . $encoded . '&summary=' . $encoded . '&summary.locked=1';
  177. $request = HTTP::Request->new('PUT' => $url);
  178. $ua->request($request);
  179. }
  180. }
  181. }
  182. }