Skip to content

libtype not handled properly for ShowSection search with kwargs #623

Closed

Description

@mikethecalamity

I was trying to run the following:

shows = plex.library.section('Shows')
for show in shows.searchShows(unwatchedLeaves = True):
    print(show.title)

and I receive the following error:

    for show in shows.searchShows(unwatchedLeaves = True):
  File "C:\Program Files\Python36\lib\site-packages\plexapi\library.py", line 907, in searchShows
    return self.search(libtype='show', **kwargs)
  File "C:\Program Files\Python36\lib\site-packages\plexapi\library.py", line 669, in search
    args[category] = self._cleanSearchFilter(category, value, libtype)
  File "C:\Program Files\Python36\lib\site-packages\plexapi\library.py", line 717, in _cleanSearchFilter
    raise BadRequest('Unknown filter category: %s' % category)
plexapi.exceptions.BadRequest: Unknown filter category: unwatchedLeaves

When I delved into the code I saw:
https://github.com/pkkid/python-plexapi/blob/master/plexapi/library.py#L718-723

categories = [x.key for x in self.filterFields()]
...
elif category not in categories

And it looks like at this point, based on the key values of .filterFields() the category has to be show.unwatchedLeaves to not throw an error. I also tried making that my kwarg (shows.searchShows(show.unwatchedLeaves = True) but python did not like that at all.

It seems like the libtype needs to be appended on the front of the category at some point?

Activity

  1. mikethecalamity commented on Dec 15, 2020

    @mikethecalamity
    Author

    Oh I just found #622 which looks like the same issue and you may have fixed it.

  2. blacktwin commented on Jan 19, 2021

    @blacktwin
    Collaborator

    You won't be able to use the libtype.filtertype for kwarg, you'll have to create a dictionary add the kwarg attrib.

    shows = plex.library.section('Shows')
    for show in shows.searchShows(**{"show.unwatchedLeaves":True}):
        print(show.title)

    This will get you by until the PR linked is finished.

  3. ParadoxGBB commented on Jan 26, 2021

    @ParadoxGBB

    I think I'm hitting this as well on 4.3.0... documentation still says this is a prime scenario:

    movies = plexServer.library.section(plexTargetLibrary)
    for video in movies.search(unwatched=True):
    	if video.type == 'show':
    

    Now throws:

    [1/26/2021 6:12:29 AM] [python.exe]: Traceback (most recent call last):
    [1/26/2021 6:12:29 AM] [python.exe]: File "F:\GREG\OneDrive\tools\CinAdmin\PlexApiScripts\Mark-PlexMediaWatched.py", line 66, in
    [1/26/2021 6:12:29 AM] [python.exe]: for video in movies.search(unwatched=True):
    [1/26/2021 6:12:29 AM] [python.exe]: File "F:\GREG\OneDrive\tools\PlexAPI\current\plexapi\library.py", line 668, in search
    [1/26/2021 6:12:29 AM] [python.exe]: args[category] = self._cleanSearchFilter(category, value, libtype)
    [1/26/2021 6:12:29 AM] [python.exe]: File "F:\GREG\OneDrive\tools\PlexAPI\current\plexapi\library.py", line 717, in _cleanSearchFilter
    [1/26/2021 6:12:29 AM] [python.exe]: raise BadRequest('Unknown filter category: %s' % category)
    [1/26/2021 6:12:29 AM] [python.exe]: plexapi.exceptions.BadRequest: Unknown filter category: unwatched

  4. blacktwin commented on Jan 26, 2021

    @blacktwin
    Collaborator

    One potential issue is how should we cover instances where the filter category is shared across libtypes? For instance show.unwatched and episode.unwatched both exist so in the example above what libtype should be used? Should this show all unwatched shows or all unwatched episodes?

    movies = plexServer.library.section(plexTargetLibrary)
    for video in movies.search(unwatched=True):
    	print(video.title)

    You'd need to define the libtype somewhere in the search when dealing with a hierarchical library like Shows or Music. Either **{'episode.unwatched':True} or movies.searchEpisode(unwatched=True) should be working solution (not yet). If the libtype is not defined then we'll raise an error stating the need to pick a libtype. I'm currently testing this.

  5. ParadoxGBB commented on Jan 26, 2021

    @ParadoxGBB

    Speaking for myself, and I'm sure that's there's other considerations that I'm missing --- I'm not even familiar with the full hierarchy map here, but I'd love something like video.unwatched or even media.unwatched that would be smart enough to translate the number of track plays for Tracks > 0 for things like podcasts.

  6. Hellowlol commented on Jan 26, 2021

    @Hellowlol
    Collaborator

    I agree that some of the search features can be a bit rough around the edges and there are some bugs.
    What works well are library.filterFields() and the operators that we added way back.

    Unless speed is a issue and i generally end up using all() with somekind of operator.

    What are you trying to do?

  7. ParadoxGBB commented on Jan 26, 2021

    @ParadoxGBB

    Me? Probably too much ;-). I have a lot of integration points between my project and Plex (https://bitbucket.org/ParadoxGBB/cinadmin/src/master/) and am in the process of expanding in a few ways that are out of scope here.

    Here specifically while it's a bug and edged rough, it's also different than the previous version and I hope I can get the basic case of a filtered search working again without reverting versions or trying something else --- the workaround listed above I haven't gotten working yet but I haven't had the time to delve into it deeply yet.

    To try to stay in scope here, I'm synchronizing library states between multiple platforms, such as watched / unwatched. For my use case performance is a significant consideration because these libraries are quite large and I don't want to iterate through every item often yet I want those state differences to be minimal at all possible.

    Generally, I'm not a fan how Plex delineates between media types (and some of its automatic matching logic seems wonky to me too), and its lack of API documentation (especially compared to Kodi), but none of those things are your fault and I appreciate anything that wraps them together more easily --- but I would have hoped things would have been a bit more hierarchical and inheritable with strong capabilities as close as possible to the base.

    But many of these media clients as they grow seem to place a lot of care in distinctions between movies, shows, episodes, tracks, abums, photos, etc. when other platforms are making these classifications less relevant and in some cases arbitrary. I find the most useful is audio vs. video, episodic vs. theatrical, and I tend to try to designate things as "consumed", not "watched" or "listened" the moment I started adding better support for podcasts. I want to look at anything for all libraries and both mark and read whether or not they're consumed.

    (thanks for reading, know this was long)

  8. blacktwin commented on Jan 26, 2021

    @blacktwin
    Collaborator

    @ParadoxGBB for your use case you'd want to identify the library type before searching and change the search based on the library type.

  9. Hellowlol commented on Jan 27, 2021

    @Hellowlol
    Collaborator

    @ParadoxGBB Thanks, the scrips you bare using seems pretty basic so the biggest speed improvements i can see here is to use the PlexServer() class directy if you have local access to the server. Using account use plex relays that are much slower.

  10. self-assigned this
    on Jan 27, 2021
  11. added a commit that references this issue on Jan 27, 2021
  12. blacktwin commented on Jan 27, 2021

    @blacktwin
    Collaborator

    From the PR referencing this issue:

    Just some examples of what will work now with the current state of this PR:

    library = plex.library.section('TV Shows')
    library.search(unwatchedLeaves=True)                     # resolves to search show.unwatchedLeaves
    library.searchShows(unwatched=True)                      # resolves to search episode.unwatched
    library.search(unwatched=True)                           # resolves to search episode.unwatched
    library.search(**{'episode.unwatchedLeaves':True})       # resolves to episode.unwatchedLeaves and errors as this pairing does not exist

    The idea would be to try to pick the correct pairing of libtype.category based on what the user provides. This is somewhat loose in the example of library.searchShows(unwatched=True) as show.unwatched does not exist but episode.unwatched does so it's likely that is what was intended.

    Another example for when the category exists in multiple libtypes.

    len(library.search(title='True'))
    # plexapi.exceptions.BadRequest: Specify the libtype. This category exists in multiple libtypes in this library. Use searchEpisodes(), searchShows() or **{show.title: ""}, **{episode.title: ""}

    This BadRequest will be dynamic to the library's search functions and libtype.category pairing. So Music would return with it valid functions and kwargs options.

    len(musicLibrary.search(title='True'))
    # plexapi.exceptions.BadRequest: Specify the libtype. This category exists in multiple libtypes in this library. Use searchAlbums(), searchArtists(), searchTracks() or **{artist.title: ""}, **{album.title: ""}, **{track.title: ""}
  13. speedyflipper commented on Feb 22, 2021

    @speedyflipper

    I believe I'm seeing this issue to while trying to check for duplicates. I tested the following code on PlexAPI 4.3.0 and 3.2.0. I get an error in 4.3.0 but runs correctly in 3.2.0

    from plexapi.server import PlexServer
    PlexServer("http://localhost:32400", "XXXXXX").library.section("TV Shows").searchEpisodes(duplicate=True)
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions