Skip to content

Instantly share code, notes, and snippets.

@mblythe86
Created September 25, 2020 16:09
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mblythe86/bad0b1ac5cb76fe94559fe582e683e1a to your computer and use it in GitHub Desktop.
Save mblythe86/bad0b1ac5cb76fe94559fe582e683e1a to your computer and use it in GitHub Desktop.
Clean unused posters/art/banners from Plex
#!/usr/bin/env ruby
# At least for movies, it looks like it copies the 'selected' stuff into the
# _stored/ folder. It also seems to use the _combined/ folder for access.
# so, I shoud be able to delete anything that's not those two.
# And after that, in the _combined folder, I can/should delete any broken links
# and remove them from <art> and <posters> in Info.xml.
# remove <reviews> from Info.xml too, since it seems to be unused.
# As far as I can tell, extras.xml can just be deleted?
# Same for Artists
# In Albums, similar, but just 'posters'.
# Probably just delete 'lyrics' because it's also unused?
# TV Shows similar - art, banners, posters, themes. seasons is probably more complicated - need to revisit.
require 'pathname'
require 'nokogiri'
metadata = Pathname.new('/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Metadata/')
['Albums','Movies','TV Shows','Artists'].each do |dir|
puts dir
(metadata+dir).each_child do |a|
puts a.basename
a.each_child do |path|
path += 'Contents'
next unless path.exist?
path.each_child do |dir|
dir.rmtree unless ['_stored','_combined'].include? dir.basename.to_s
end
path += '_combined'
#delete extras.xml
extras = path + 'extras.xml'
extras.unlink if extras.exist?
#open _combined/Info.xml
next unless (path + 'Info.xml').exist?
info_file = (path + 'Info.xml').to_s
info_xml = File.open(info_file){|f| Nokogiri::XML(f)}
#remove <reviews><item> and <lyrics><items> from Info.xml
['reviews','lyrics'].each do |type|
info_xml.search("//#{type}/item").each{|i| i.remove}
info_xml.search("//#{type}").each{|n| n.inner_html = n.inner_html.gsub(/\n\s*\n/,'')}
end
['art','banners','posters','themes'].each do |type|
next unless (path+type).exist?
(path + type).each_child do |link|
next unless link.symlink?
unless link.exist?
name = link.basename.to_s
link.unlink #delete broken symlink
#remove from Info.xml
info_xml.search("//#{type}/item[@preview='#{name}']").remove
info_xml.search("//#{type}/item[@media='#{name}']").remove
end
end
info_xml.search("//#{type}").each{|n| n.inner_html = n.inner_html.gsub(/\n\s*\n/,'')}
end
#write Info.xml
File.open(info_file, 'w'){|f| f.write info_xml.to_xml}
end
end
end
@Sonico98
Copy link

Sonico98 commented Nov 5, 2021

Works perfectly! On Arch Linux the metadata path is /var/lib/plex/Plex Media Server/Metadata/

@ados8
Copy link

ados8 commented Jan 2, 2022

Sorry I have used Plex for years and familiar with Tautulli and other scripting methods but how do I get Plex to run this script.
I know that Plex has a script folder but cannot see anywhere in the menus where it mentions running scripts.
Thanks. 😉

Edit: I should mention I'm running docker on UNRAID

@mblythe86
Copy link
Author

I briefly describe the intended usage in this reddit comment. The bottom line is that this isn't intended to run through Plex at all - I run it from a Linux command line.

To get a shell in your docker container, you can do something like this: sudo docker exec -it <container_name> /bin/bash. No guarantees that ruby is available in your docker container (or that it has the nokogiri gem to parse the XML files)...

@ados8
Copy link

ados8 commented Jan 4, 2022

I was at that conclusion as well, unfortunately Ruby is not installed and I don't know what negative affects there would be installing to docker container.

Is there any plans to get this working via Python for say Tautulli or Plex? I cannot believe that Plex doesn't have any options to delete your custom posters.

@mblythe86
Copy link
Author

No, I don't plan to port this over to Python. The script is pretty straightforward, though - maybe a few ruby-isms, but nothing too tricky. It should be pretty easy to duplicate in Python if you want to give it a shot.

@docbill
Copy link

docbill commented May 25, 2022

Traceback (most recent call last):
2: from ./plex_cleanup.rb:16:in <main>' 1: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in require'
/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- nokogiri (LoadError)

@docbill
Copy link

docbill commented May 25, 2022

Solution:

sudo apt-get update
sudo apt-get install ruby-nokogiri

@bullmoose20
Copy link

bullmoose20 commented Jun 4, 2022

I managed to get this script to compile and run against my libraries, however I don’t see any difference at all. I can share images and stuff but is this script still working properly?

Based on the Reddit comments, PMS should be stopped. When restarting, is there a need to run delete trash, clean bundles, and optimize db before seeing the improvements?

@Rayzaj
Copy link

Rayzaj commented Jul 19, 2022

I managed to get this working on Synology. Install the Ruby package from Synocommunity, then install nokogiri using "gem install nokogiri" in the terminal. Once done, modify this script to match the paths on Synology, and then run it.

@pearlythepirate
Copy link

pearlythepirate commented Feb 18, 2023

This script is not working for me but this other repo has a script that works instead!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment