justinemter / pseudo-channel

This is a python based cli-app using the python-plex-api to control a plex-client and act like a real TV channel with show scheduling, commercial breaks, movie nights, etc. "Home-Brewed TV Channel(s) for Hackers"
GNU General Public License v3.0
128 stars 18 forks source link

[Feature Request] Extra criteria to search for when building a schedule #41

Closed irodimus closed 6 years ago

irodimus commented 6 years ago

This has been mentioned in the opening paragraph of the GitHub project but just wanted to include here in case there is a list being kept. I realize this is not a high priority but it would be cool when using the 'random' title attribute in the XML to allow for searching for genre, director, actor, or collections to create a specific schedule. This, I believe, would be the last missing feature to fully get a stylized channel, whether all tv show or all movie, or in your case, an all Kevin Bacon channel :)

justinemter commented 6 years ago

This is important. I want to save this for the "beta" version while getting the alpha situated for this weekends first "release". It's actually not so very difficult to implement as-is but I'd have to hand-make some changes to the database schema/core code. I figure once we get a decent working version as is, I can move on to this kind of thing.

justinemter commented 6 years ago

Ok, so I felt your pain and went ahead and added something that hopefully works well. When you grab the new 'develop' branch updates, you need to delete your local 'psuedo-channel.db' and run 'python PseudoChannel.py -u' to redo your local database. Once that is done, open up your .xml and edit your

<time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="" xtra='actor:tom cruise genre:action contentRating:r'>7:45 PM</time>

Notice the new attribute: xtra='actor:tom cruise genre:action contentRating:r'

At that point just update the new db via. "-xml", generate the schedule via, "-g" and if all went well you should have your random movies ranomized according to the "xtra" args in the xml.

It's important to note that I am querying the python plex api with the exact args you pass to the app. That being said, if you pass the wrong "key/value" (i.e. "rating" instead of "contentRating") it will fail and just use a random movie ignoring your args. I haven't thoroughly tested this or looked into all of the plex keys you can use, but I'm sure there is a ton!

I don't think this applies to you but if you are using the app for TV Shows, and don't want to lose your queue when deleting your DB. You can try running, "python PseudoChannel.py -e" to export your TV queue. Then when you create/update the new DB, your can run, "python PseudoChannel.py -i" which will import that older queue. It may be off by a day as It will generate the schedule and move forward but if all goes well you won't be back to the beginning. Again, Idon't think this applies to you. I'll give moe a heads up too. Cheers! :)

justinemter commented 6 years ago

Oh, also I am not popping out the movie from the randomizing function in the case it has already been scheduled recently (or even the same day). So using this extra attribute could increase your chances of getting the same movie scheduled for the same day... it's more nice for like the occasional movie, or like a Saturday night action flick. I suppose if your movies library is gigantic it may not pop up as much of a problem. Just something to keep in mind. Also, beware that if you try and schedule a "PG" block for the kids, if you add extra params that return zero results it will default to just "random" without your specified rating... so the kids could accidentally be watching Die Hard or something. Just an fyi

irodimus commented 6 years ago

Updated to the latest develop branch and did all the steps listed and it works amazingly well. I tried various attributes, together and separately:

actor
director
genre
contentRating
collection
studio*

The asterisk for 'studio' is for the issue I was having with PlexAPI 2.0.2 not working correctly when the name had spaces and it was always with this attribute. Updating to the latest PlexAPI 3.0.3 resolves it though, but you have to do a git pull for it or pip install plexapi==3.0.3.

My movie library is kinda extensive so duplicate entries are not really a big deal, but it did pop up once though :) Other than that, this added functionality now does provide for the occasional movie night like you mention which is very cool. Thank you for adding it!

One interesting thing that happened that I'm not entirely sure how or why is when I used your example:

<time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="" xtra='actor:tom cruise genre:action contentRating:r'>7:45 PM</time>

I don't know if I have a movie that fits that criteria but it did not give the error message when the criteria doesn't match and kept listing the movie "Hirokin: The Last Samurai" everytime I generated the schedule. I tried other things and that worked, but when I came back to this, same movie. It was listed as Action and content rating of R but no Tom Cruise. It was just for that though so probably nothing but my library being weird somewhere.

justinemter commented 6 years ago

Ok, very cool to hear! In regard to your 'Last Samurai" example, it seems to be a goofy bug somewhere in the plex api. I don't have a gigantic movie collection and the above

Thanks for listing those attributes! I look forward to tinkering with this. Also note: I tried to further filter random movies by the "contentRating" of "pg-13". I tried many variations and it just doesn't want to work. I isolated it away from the PseudoChannel app to make sure it wasn't anything specific to the app. That being said, it does seem that this filtering stuff isn't perfect. If you know why my "pg-13", "contentRating" doesn't work I'd be very interested... otherwise I'll have to assume it is a bug in the api. It doesn't seem to be such a big deal for "pg-13" but if you were getting a similar bug for like, "g" or "pg" rating and you needed that to work for kids, then it could be a bigger problem.

justinemter commented 6 years ago

Also, interesting about the "studio*" thing... I don't see myself ever using that, but it's really cool to have that option. I'll try it out. Thanks man. :)

irodimus commented 6 years ago

I'll look into the content rating and see what I get on my end. I did discover an issue with PlexAPI 3.0.3 though. Attempting to resume a video when starting PseudoChannel crashes RasPlex for me and errors with a connection refused:

A Connection error occurred.
HTTPConnectionPool(host='10.0.1.10', port=3005): Max retries exceeded with url: /player/playback/playMedia?address=10.0.1.7&commandID=2&containerKey=/playQueues/11399%3Fwindow%3D100%26own%3D1&key=/library/metadata/669194&machineIdentifier=20253b4dc5cce18dc752eb4dfeebf9eb9eeea237&offset=4960169&port=32400&token=[REMOVED]&X-Plex-Token=[REMOVED] (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x10d459a50>: Failed to establish a new connection: [Errno 61] Connection refused',))

Reverting back fixes it and works normally though. So I guess for now, its one or the other. Not a deal breaker or anything right now.

irodimus commented 6 years ago

I tried xtra='contentRating:pg-13' multiple times and it worked on my end. I changed the rating to something else and that worked before trying 'pg-13' again.

justinemter commented 6 years ago

That's really relieving to hear actually, cause since my app is built on their app, I want so badly for their api to be working!! :) For some reason, my library was only returning like 1 movie when I tried to filter by, "pg-13". I'm going to look into it more before making any judgments, but it's great to hear that it's working on your end.

irodimus commented 6 years ago

To answer your question above:

Ok, very cool to hear! In regard to your 'Last Samurai" example, it seems to be a goofy bug somewhere in the plex api. I don't have a gigantic movie collection and the above snippet always returns the Tom Cruise movie, "Last Samurai" for me. So for you, it seems to come close... out of curiosity, do you have the Tom Cruise movie? Maybe it gives up and hands you the next closest thing, which turns out to be: http://www.imdb.com/title/tt1693679/

I did have The Last Samurai with Tom Cruise but no matter how many times I generated a new schedule with that criteria, Hirokin was always there each time.

justinemter commented 6 years ago

Ok, yeah I was curious about this one. It seems like the api just settles for the first best result. Although I'd rather blame myself before them - as their API is so damn good, maybe try and search your lib for this movie outside of the pseudochannel app. If it still comes back with the non-tom cruise movie maybe you or I can get in contact with the python plex guys. Or maybe it has something to with my code. The only reason I'm resistant to that is that I am passing your "xtra" params straight to their api for return results. Anyway, let's hassle them. They seem to know their stuff. :)

MoeFwacky commented 6 years ago

Question about the parameters. Is it possible to enter more than one? Something like contentRating:G,PG,PG-13 or a range in the case of numerical entries like year:1990-1999?

justinemter commented 6 years ago

It doesn't look like the api supports that. I tried to experiment a little but nothing seems to take. I suppose I could run a filter on my end before passing params to the api & after. I think a better solution is to store all of that data in my local database and have a local search function. I plan to do this in the beta. The goal was to not use the plex api outside of gathering all the plex library data when running -u. However, I've been working on a user-friendly web version that makes plex api calls here and there for various convenience reasons. It's a fantastic api so I think I may take more advantage of it in other ways, leaving the "xtra" search stuff to PseudoChannel logic. So, short answer: no I don't I think so. :)

justinemter commented 6 years ago

My bad, you knew all that about the beta, etc. I thought I was replying to irodimus, I'm still waking up. Either way, we'll come up with something to make that more usable for sure!

irodimus commented 6 years ago

Question about the parameters. Is it possible to enter more than one? Something like contentRating:G,PG,PG-13 or a range in the case of numerical entries like year:1990-1999?

The PlexAPI supports ranges and multiple entries per arg, but I don't know if it will work in PseudoChannel. I will try it when I get home today and see if it works as I don't really mind messing around with my channel schedule.

I should add the arguments from the PlexAPI search code: '''

                    * unwatched: Display or hide unwatched content (True, False). [all]
                    * duplicate: Display or hide duplicate items (True, False). [movie]
                    * actor: List of actors to search ([actor_or_id, ...]). [movie]
                    * collection: List of collections to search within ([collection_or_id, ...]). [all]
                    * contentRating: List of content ratings to search within ([rating_or_key, ...]). [movie,tv]
                    * country: List of countries to search within ([country_or_key, ...]). [movie,music]
                    * decade: List of decades to search within ([yyy0, ...]). [movie]
                    * director: List of directors to search ([director_or_id, ...]). [movie]
                    * genre: List Genres to search within ([genere_or_id, ...]). [all]
                    * network: List of TV networks to search within ([resolution_or_key, ...]). [tv]
                    * resolution: List of video resolutions to search within ([resolution_or_key, ...]). [movie]
                    * studio: List of studios to search within ([studio_or_key, ...]). [music]
                    * year: List of years to search within ([yyyy, ...]). [all]

'''

justinemter commented 6 years ago

Ok cool. So I took your advice and tinkered with it a bit. You can now query movies using multiple comma delineated values like, contentRating:PG,G. And looking at that snipped it looks like you can specify by decade or decades. So if you wanted to play a random movie from your library before the year 2000, I guess you would do something like: decade:1990, 1980, 1970, etc. I'm not sure though as I haven't tested. I guess I jumped the gun by overcomplicating it and saying no too soon.

irodimus commented 6 years ago

So, tested multiple values in a parameter before the recent updates to PseudoChannel today and verified that none worked "out of the box".

Updated to recent develop branch 2205cf723b6c473aa51da2c9c6dffffe398042fc and tested parameters again with multiple values and for the most part they worked just fine, but I did run into a few where the criteria did not match the results. This I think will just need a bit more testing as I just basically updated the XML, generated schedule and viewed the result again and again.

Tested:

decadeappears to works fine with one value, i.e. 1990, but need more testing when using multiple, i.e. 1990,2000

network unable to get to work, tested with tv shows but it could be tv is not using xtra yet

year could not get to work with one value or two, needs testing

Another thing I noticed (not sure if it's a bug or caused the size of my library selection) but it appeared when using multiple values, the last value always took precedence and the first value was ignored. I had contentRating:PG,PG-13 and out of the many times I generated my schedule, a PG-13 movie was chosen. Same when using decade:1980,2000 although maybe this is a range, I'm not sure.

I didn't try the others but for what is so far working, its awesome.

irodimus commented 6 years ago

I should add that it's entirely possible that these are issues are from PlexAPI being outdated so I wouldn't spend too much time on this. I appreciate just to have the ability to have some of this in PseudoChannel.

justinemter commented 6 years ago

Hmm, dacade seems to work good on my end. I am actually using just a terminal in interactive mode for testing so you can view all the results:

from plexapi.server import PlexServer
import re

plex = PlexServer('http://media.home:32400', 'id')
movies = plex.library.section('Movies')
thestr = 'decade:1970,1980' # <-- edit this.
regex = re.compile(r"\b(\w+)\s*:\s*([^:]*)(?=\s+\w+\s*:|$)")
d = dict(regex.findall(thestr))
for key, val in d.iteritems():
    d[key] = val.split(',')
for movie in movies.search(None, **d):
    #print(d)
    print movie.title, movie.year

You can edit thestr to test various params.

network unable to get to work, tested with tv shows but it could be tv is not using xtra yet

That's correct. As of now this is only for movies. I didn't see much use adding it to tv shows, but maybe I should?

year could not get to work with one value or two, needs testing

Just tried thestr = 'year:1983,2017' and it seemed to work on my end.

Another thing I noticed (not sure if it's a bug or caused the size of my library selection) but it appeared when using multiple values, the last value always took precedence and the first value was ignored.

I'm guessing this is because of the quantity of your PG-13 or PG items. It would be nice to have more randomness though. I'll have to look into it.

Thanks for playing with it. I want to try and release an alpha this weekend so other people can play with it. The last of my worries (hopefully) was that bug where the daily_schedule table was not deleting the previous day's schedule. I never found out what was causing it but I did just implement code to completely wipe / re-create the table every time a daily_schedule was generated. So I'm pretty sure that solved it. Other than that, it should be pretty usable for other tinkerers! :)

irodimus commented 6 years ago

I agree. It mostly could be the size of my movie library that is giving me wonky results 👍

network unable to get to work, tested with tv shows but it could be tv is not using xtra yet

That's correct. As of now this is only for movies. I didn't see much use adding it to tv shows, but maybe I should?

I wanted to try it with TV shows to see if I could get it to show something random from the 'SyFy' network or 'ABC' network. I have a few TV Shows but haven't had a need to use them just yet. Maybe if creating multiple channels comes to fruition in the future like PseudoTV :)

Thanks for the code. I have something like this set up when I was testing PlexAPI but yours is more compact than mine since I hadn't visited that code in a long while.

justinemter commented 6 years ago

I wanted to try it with TV shows to see if I could get it to show something random from the 'SyFy' network or 'ABC' network.

Just thinking about this, if I hooked up "xtra" for TV Shows, If network was used it would get a random episode from a series filtered by the "network", then the queue would start from there. That could be a nice way to not have to think about what show specifically you wanted to schedule but rather just the network... also it would randomize the queue for that time block so not all your times would start from s01e01 - something I was meaning to add a fix for anyway. Very cool.

MoeFwacky commented 6 years ago

So I'm having an issue with of -xml, since adding more xtra data, but I'm having trouble isolating what entry is causing the problem. I'm hoping fresh eyes can help.

So this is the output I'm getting

pi@controller:~/channels/pseudo-channel_1 $ sudo python PseudoChannel.py -xml
Traceback (most recent call last):
  File "PseudoChannel.py", line 787, in <module>
    pseudo_channel.update_schedule()
  File "PseudoChannel.py", line 267, in update_schedule
    tree = ET.parse('pseudo_schedule.xml')
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1182, in parse
    tree.parse(source, parser)
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 656, in parse
    parser.feed(data)
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1642, in feed
    self._raiseerror(v)
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1506, in _raiseerror
    raise err
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 9, column 125

These are the movie entries I have added xtra flags to

        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60" xtra='genre:Sci&#45;Fi,comedy'>2:00</time>
        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60 xtra='genre:adventure decade:1980'>3:30</time>
        <time title="random" type="movie" strict-time="true" time-shift="5" overlap-max="60" xtra="contentRating:G,PG">6:30</time>

        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60" xtra='decade:1990 genre:Action'>1:00</time>
        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60" xtra="genre:Mystery">3:00</time>
        <time title="random" type="movie" strict-time="true" time-shift="15" overlap-max="60" xtra="contentRating:G">15:30</time>

        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60" xtra='decade:1980 genre:Sci&#45;Fi'>1:00</time>
        <time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60" xtra='decade:1980'>3:00</time>
        <time title="random" type="movie" strict-time="true" time-shift="15" overlap-max="60" xtra='contentRating:G'>15:30</time>

What am I missing?

justinemter commented 6 years ago

It looks like you're missing the closing " after the 60 in your second time entry.

<time title="random" type="movie" strict-time="false" time-shift="5" overlap-max="60 xtra='genre:adventure decade:1980'>3:30</time>

MoeFwacky commented 6 years ago

Ah, that did the trick, thanks. Don't know how I missed that.

MoeFwacky commented 6 years ago

Not sure where to drop this comment since it's not really an issue. But, I've noticed a few requests for this functionality in the /r/plex subreddit, so I've been pointing people this way as I see them. That got me wondering when you think alpha will be ready? I'm assuming you've been busy, but just curious. I'd like to really start promoting and pointing people towards it so there's a larger tester pool.

justinemter commented 6 years ago

Hmm, I've been a little busy lately so haven't had time to work on more features. However, I've had the single channel running for the past week... aside from some XML scheduling issues on my part I think it's running fairly well. How about for you? I'll run through the bug list tonight and see what is outstanding. I think it's pretty good as-is.

MoeFwacky commented 6 years ago

It's been pretty good on my end. On and off work well (there's still channel flipping bugs, but that is easily all post-alpha). I still get some longer gaps between the last commercial and first show (and occasional short 2-4 minute breaks that don't get commercials at all). Otherwise everything is running smoothly and as expected.

It's definitely stable enough once setup. Maybe if you have time, add a known issues/workarounds and troubleshooting section to the readme with the alpha release, for people who may not look through this issues section.

Also, I was wondering if it might be a good idea to add a link to the discord. I can't be on all the time, but if people have general "how do I get this working" questions that aren't related to something being broken, I could help out with that.

justinemter commented 6 years ago

It's been pretty good on my end. On and off work well (there's still channel flipping bugs, but that is easily all post-alpha). I still get some longer gaps between the last commercial and first show (and occasional short 2-4 minute breaks that don't get commercials at all). Otherwise, everything is running smoothly and as expected.

Good to hear! I'll keep the multichannel stuff on my radar too. I need to hit you up to debug more closely.

It's definitely stable enough once setup. Maybe if you have time, add a known issues/workarounds and troubleshooting section to the readme with the alpha release, for people who may not look through this issues section.

Great idea! I'll spend some time on this.

Also, I was wondering if it might be a good idea to add a link to the discord. I can't be on all the time, but if people have general "how do I get this working" questions that aren't related to something being broken, I could help out with that.

Ok, great idea. Sorry I've fallen off that. I keep having good intentions to both fix bugs/ready the alpha and also hit you up on discord... then something has been coming up and I keep pushing it. I'm going to set aside some time this week I promise. I don't mean to flake on the last stride here. I am going to make sure to get on this so we can have the "alpha" version up by this weekend. That being said, I hope to have some pushes tomorrow to get back into it. Thanks Moe! :)

Hellowlol commented 6 years ago

Please make a issue if you having problems with plexapi. We want it to be better.

justinemter commented 6 years ago

@Hellowlol the plexapi kicks ass as-is. Hey since I have you, is there a way where I can pass params to the api Library to search for media that excludes the params given? So say I wanted to grab a random movie excluding "contentRating: R"... Right now we have it pass params to include results for "random" movie time-blocks.

Hellowlol commented 6 years ago

Are you looking for a movie movie named random but or any movies that isnt R rated? If its the latter you can do.

from plexapi.server import PlexServer
import random

a_random_movie  = random.choice(PlexServer(url, token).library.section('Movies').all(contentRating_ne='R'))

This isnt available in the pypi version. It was added just a few days ago.

If speed is essensial you can do pass /library/sections/1/all?type=1&contentRating!==R to .fetchItems()

I intend to add support for every filters that plex support. But isnt comming soon.

justinemter commented 6 years ago

Oh this is great! The latter... Exactly what I was looking for: contentRating_ne='R'. I am assuming that the _ne can be added to all filter options, like decade_ne='1990'? So how I am using your api in this part of the application is I allow the user to specify a random movie in their daily xml schedule. I then allow the user to specify params to narrow-in the random time-block movie. This way the user can specify, say kid-friendly movies on Saturday morning for example. I actually pass the params that the user specifies in the XML schedule, right through to your API to grab a random result. That being said, I am assuming the user can append, _ne to all params to specify what movies they want to suppress based on the provided criteria. I look forward to trying this a little later. Thanks for your wisdom @Hellowlol. I'll be sure to give your plexapi a special shoutout in my readme if I haven't already. Cheers!

Hellowlol commented 6 years ago

Yes. You can load to loads of stuff. See http://python-plexapi.readthedocs.io/en/latest/modules/base.html#plexapi.base.PlexObject.fetchItem for what you can pass for as a dict to .all() there was a typo in my example its two not _ ^^. Just to be clear the dunder methods are for the attributes of plexapi NOT to plex. So you cant use decade_ne=1990 as it attribute does not exist. in those cases you have to use .search (the filtering happens in pms.)

justinemter commented 6 years ago

I think this makes sense, I have to read the docs more. Thanks for clarifying!

MoeFwacky commented 6 years ago

If I'm reading this right, does this also mean that using gt or lt on the end will return results that are greater than or less than for numerical values? (I'm thinking for selecting random movies within a certain duration range).

Hellowlol commented 6 years ago

@MoeFwacky Thats correct

MoeFwacky commented 6 years ago

Hmm, it looks like those don't work out of box in the xml entries. @justinemter I'm getting the For some reason, I've failed getting movie with xtra args. error when I include xtra="duration__lt:8100000 duration__gt:6300000" in the xml entry.

justinemter commented 6 years ago

It looks like this is for a different api call. I don't think it would work out-of-the-box but rather needs to be implemented on my end. We'll have to add it to the list of features to-do.