mirror of
https://github.com/FakeTV/pseudo-channel.git
synced 2025-12-06 00:13:38 +00:00
Merge branch 'develop'
The merge
This commit is contained in:
179
README.md
179
README.md
@@ -1,192 +1,39 @@
|
||||
# PseudoChannel.py - Your Home-Brewed TV Channels
|
||||
Update 7/4/2018 - Minor changes made to the updating process
|
||||
- Your daily_schedules will now be preserved across global updates, so if you update mid-day you won't lose the set of shows you were watching
|
||||
- Selective updating is now available through the use of -um, -utv, and -uc flags. Any amount of these can be called from PseudoChannel.py OR Global_DatabaseUpdate.py. This will only update your movies, tv, or commercial libraries respectively.
|
||||
|
||||
|
||||
Update 06/30/2018 - At last, some more updates to this great program! Listed below are some of the fixes:
|
||||
- Channel naming is now flexible, feel free to use as many as you want!
|
||||
- Channel updating can now be conducted globally through the use of Global_DatabaseUpdate. No need to run for every single channel!
|
||||
- Pesky problems regarding midnight, such as scheduling shows and starting a show after midnight, have been fixed.
|
||||
- A more "client-friendly" installer has been made in update-channels-from-git.sh
|
||||
IF THIS IS YOUR FIRST TIME: Welcome! Simply download "update-channels-from-git.sh" from the "main-dir" folder, place in the folder you would like to place pseudochannel, and change the variable FIRST_RUN to true. Then run! You'll have your first five channels ready to go.
|
||||
IF YOU'VE DONE THIS BEFORE: Same idea, but place "update-channels-from-git.sh" from the "main-dir" folder in your local "channels" folder, then run. It will update all necessary files. If you have made any custom files along the way, no need to fear; this installer will not delete your own files that you made. It will also preserve your databases, config files, and tolken file.
|
||||
|
||||
*Update 12/03/2017 - Enabled Support for Custom Library Names - If already running PseudoChannel.py, the local DB must be deleted & then rebuilt running the "-u" option. The TV Shows queue can be preserved by using the "-e" & "-i" options, all together: `python PseudoChannel.py -e -u -i`*
|
||||
|
||||
Joined by the author of [Fake TV](https://medium.com/@Fake.TV), this project aims at tackling one issue: creating a fake tv channel experience with your own media library (movies, tv shows, commercials, etc.). The idea is super simple... when you turn on your TV, rather than hopping straight to Netflix, you can choose to watch your own channel of curated media like a real channel, with randomized movie time blocks, weekend morning cartoons, 90's commercials to fill up gaps and more. We aim to add a ton of neat features but the basic idea is to have something that feels like a real TV channel. That being said it isn't supposed to "pause" nor are you supposed to intervene too much. Just like a real channel you are presented with a channel that you define once and let it go as it advances in series episodes, playing random movies where specified (defined by various parameters like genre, "Kevin Bacon", etc.). Think: weekday movie nights @ 8:00 PM. Or perhaps you want to further specify your weekly Wednesday evening movie be a movie in your Plex library that stars "Will Smith". PseudoChannel is built to interface with the Plex media server. So if you want to have your very own PseudoChannel, you first need to set up your home server using [Plex](https://www.plex.tv/). After that you can come back here to learn how to setup everything else. Although this app runs using Python and the command line, we aim to make all of it as easy as possible to understand for those who are intimidated by this sort of technology. If you have a question, are troubleshooting or have feature ideas, just leave an 'issue' here in this repository.
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
## How to Use:
|
||||
|
||||
- The instructions below are all for configuring the **"controller"** device (i.e. a laptop or raspberry pi running linux). This is the device this app runs on to control the Plex client. The **"client"** device should be a Raspberry Pi running Rasplex hooked up to your TV via HDMI - although I'm sure other devices work great too (never tried).
|
||||
- The instructions below are all for configuring the **"controller"** device (i.e. a laptop or raspberry pi running linux). This is the device this app runs on to control the Plex client. The **"client"** device should be a Raspberry Pi running Rasplex hooked up to your TV via HDMI - although I'm sure other clients work great too.
|
||||
|
||||
1. PseudoChannel uses Python 2.7. The recommended method of setting up most python environments is to use [virtualenv](http://python-guide-pt-br.readthedocs.io/en/latest/dev/virtualenvs/). This keeps all your pip packages / python versions separated on a per project basis. I find this method extremely useful but also somewhat unintuitive, especially at first. Whether you choose to use "virtualenv" to isolate your project environment or not, you can install all the PseudoChannel.py dependencies by running the following command after downloading this repository:
|
||||
0. Update:
|
||||
|
||||
```bash
|
||||
% pip install -r requirements.txt
|
||||
% sudo apt update
|
||||
```
|
||||
*You need to run the previous command using `sudo` if not in a virtualenv.*
|
||||
|
||||
2. In order to tell PseudoChannel.py how to connect to your Plex server, create an empty file named, `plex_token.py` just outside of the project directory. Within that file add your plex server url / [plex token](https://support.plex.tv/hc/en-us/articles/204059436-Finding-an-authentication-token-X-Plex-Token) like so:
|
||||
1. Install python-pip & Git:
|
||||
|
||||
```bash
|
||||
token = '<your token>'
|
||||
baseurl = 'http://192.168.1.28:32400'
|
||||
% sudo apt install python-pip git -y
|
||||
```
|
||||
*This file is important as it tells PseudoChannel.py how/where to connect to your Plex server. It should sit just outside of this /pseudo-channel/ directory.*
|
||||
|
||||
3. Edit the `pseudo_config.py` / `the pseudo_schedule.xml` to your liking. You can specify your plex media library names within the `pseudo_config.py` file... If you do not intend on using commercials just set the `useCommercialInjection` flag to `False`. There are a few other experimental options like using Google Calendar rather than an XML. It is an arduous process to initially set up and I've found the XML method to be the easiest method for organizing your schedule - so stick with that for now. Finally, setup your schedule in the xml file. There are some detailed instructions commented at the top of that file.
|
||||
|
||||
4. Run the `PseudoChannel.py` file with the following flags:
|
||||
2. Create "/channels" dir, change to that directory, and download the install.sh script to the new directory:
|
||||
|
||||
```bash
|
||||
% python PseudoChannel.py -u -xml -g -m -r
|
||||
% mkdir ./channels && cd ./channels && wget https://raw.githubusercontent.com/FakeTV/pseudo-channel/develop/main-dir/install.sh .
|
||||
```
|
||||
*You can also run `-h` to view all the options. Use `-c` to find the name(s) of your Plex client(s) to add to the config.*
|
||||
|
||||
- The `-u` flag will prepare & update (& create if not exists) the local `pseudo-channel.db`, you only need to run this once in the beginning or later when you have added new media to your Plex libraries.
|
||||
- The `-xml` flag will update the newly created local db with your schedule from the xml file - you should run this everytime you make changes to the xml.
|
||||
- The `-g` file will generate the daily schedule (for today) based on the xml. This is useful for the first run or testing (or manually advancing the daily queue forward). Running this flag say, 15 times will advance the play queue forward 15 days. It is automatically run every night at midnight to generate the daily schedule.
|
||||
- The `-m` flag makes both the .html/.xml files and starts a simple html web server in the `./schedules` directory.
|
||||
- Finally, the `-r` flag will run the app, checking the time / triggering the playstate of any media that is scheduled. It will also update the daily schedule when the clock hits 11.59 (or whatever time you've configured in the config file). If you see errors, check your entries in the xml first. Check your times, check for overlaps & make sure your are using ascii characters to replace foreign characters like umlauts and '&' characters, etc. Make sure all of your movie names / TV Series names are correct.
|
||||
|
||||
You can run `% python PseudoChannel.py` with the following options. The order is important depending on what you are doing (i.e. `% python PseudoChannel.py -u -xml -g -m -r`):
|
||||
|
||||
| Flag | Description |
|
||||
| ------------------------|--------------|
|
||||
| -u, --update | Manually update (or create if not exists) the local db when new media is added to your Plex server. |
|
||||
| -um, --update_movies | Manually update (or create if not exists) the MOVIES local db when new media is added to your Plex server. |
|
||||
| -utv, --update_tv | Manually update (or create if not exists) the TV local db when new media is added to your Plex server. |
|
||||
| -uc, --update_comm | Manually update (or create if not exists) the COMMERCIALS local db when new media is added to your Plex server. |
|
||||
| -xml, --xml | After making any edits your .xml schedule. Run this to populate the local db. |
|
||||
| -g, --generate_schedule | Manually generate the daily schedule. This is useful for testing / first run. |
|
||||
| -r, --run | Run PsuedoChannel.py. |
|
||||
| -c, --show_clients | Show connected Plex clients. |
|
||||
| -s, --show_schedule | Output the generated "Daily Schedule" to your terminal. |
|
||||
| -m, --make_html | Manually generate both html / xml docs based on the "Daily Schedule". |
|
||||
| -e, --export | Export the current queue of your "TV Shows" episodes. Useful when redoing your local DB. |
|
||||
| -i, --import | Import the previously exported queue of your "TV Shows" episodes. |
|
||||
| -eds, --export_daily_schedule | Export the daily schedule. |
|
||||
| -ids, --import_daily_schedule | Import the daily schedule. |
|
||||
|
||||
## `startstop.sh` - Alternative Way of Running the Application:
|
||||
|
||||
Within the app directory, there is a file named, `startstop.sh`. This bash script is a convenient way to start/stop the application. When run, it will start the application and save the "pid" of the process to the application directory. When run again, it will check to see if that process is running, if so it will stop it. All you have to do is run:
|
||||
3. Make the "install.sh" executable:
|
||||
|
||||
```bash
|
||||
% ./startstop.sh
|
||||
% chmod +x ./install.sh
|
||||
```
|
||||
|
||||
When you start the application with this bash script, you can close your terminal as it will keep running in the background. Later, when you come back and want to stop it... you can just execute that file once more and it will stop the running process. Please note: It's good to test the application and your configurations using the manual process above before running this bash script. Although there is a `pseudo-channel.log` that is created within the application directory, it is easier to just view the output in your terminal window - something that won't happen when using the bash script.
|
||||
|
||||
## Setting Up the Generate-Daily-Schedule Cron Task
|
||||
|
||||
Every day (usually at midnight) PseudoChannel needs to generate a new schedule. It will not do this automatically if the app is already running. This task triggers the `-g` flag which generates the new schedule for the following day. This method, as described below, only works when using the `startstop.sh` script. How it works is, it looks for a `running.pid` file in the channel directory which the `startstop.sh` script creates when the channel is run. If it exists, the script will stop the channel, run the `-g` flag, then restart the channel. If it doesn't exist, then the script will just run the `-g` flag without doing anything else. In both cases, the channel generates a new schedule for the upcoming day. Feel free to change the update times, just be sure to choose a time past midnight - so that the app knows if it is a weekend, or what weekday to generate a schedule for. If you usually watch PseudoChannel until 2:00am, set the update time to 3:00am in the crontab task.
|
||||
|
||||
Setup a cron task:
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
...then setup your new task to trigger the included `generate_daily_sched.sh` file:
|
||||
```bash
|
||||
0 0 * * * cd /home/pi/channel_01 && ./generate_daily_sched.sh > /dev/null 2>&1
|
||||
```
|
||||
|
||||
This will trigger the `generate_daily_sched.sh` bash script every day at midnight. Be sure to alter the paths in the above crontab task to match your PseudoChannel's paths.
|
||||
|
||||
|
||||
|
||||
## Futher Info:
|
||||
|
||||
Features are being added to the xml but as of now there are a few. Within the XML `<time>` entry you are able to pass in various attributes to set certain values. As of now, aside from "title" and "type" which are mandatory, you can take advantage of "time-shift". This parameter accepts values in minutes and can be no lower than "1". If the attribute, "strict-time" is set to "false", then this `<time>` entry will be shifted to a new time based on the previous time with a smaller gap calculated according to the value in "time-shift". Basically, if you do not want any gaps in your daily generated schedule you would leave "strict-time" false and set "time-shift" to "1" for all `<time>` entries. However, this will create a schedule with weird start times like, "1:57 PM". Taking advantage of the "time-shift" perameter will correct this. If you set it to a value of "5", all media is shifted and hooked on to a "pretty" time that is a multiple of 5. So if used, rather then having a "Seinfeld" episode being set to "1:57 PM" it may be recalculated and scheduled for "2:00 PM". However, if you would like to make sure that "The Simpsons" will always start every weekday at "6:00 PM" then you can simply set that `<time>` entry to `srtict-time="true"`. This will ensure that despite other non-strict times shifting around, "The Simpsons" will air every weekday at the desired "6:00 PM" as scheduled (be sure that you haven't accidentally made two time entries "strict-time" for the same day/time - this sort of thing will cause weird scheduling errors). When using "strict-time" or having the "time-shift" value > than 1 (minute), this will result in empty gaps in the schedule. Currently I have a flag in the config for "commercial injection" to fill up the gaps as much as possible with commercials from commercials in your Plex server "Commercials" library. If you do not want to use this feature or if you don't have any commercials in your Plex server, just open up that `pseudo_config.py` file and set `useCommercialInjection` to `False`. Please check the `pseudo-channel.xml` for more information.
|
||||
|
||||
## Specifying Random Movies in Your Schedule:
|
||||
|
||||
You are able to specify random movies in your XML schedule by adding a `<time>` entry as follows:
|
||||
|
||||
```xml
|
||||
<time title="random" type="movie" strict-time="false" time-shift="5" xtra='actor:mike myers genre:comedy contentRating:PG-13'>9:00 PM</time>
|
||||
```
|
||||
I have placed this time entry in the `<weekdays>` block of the XML. You can only specify `title="random"` for movie time blocks... however, you can further define parameters in the `xtra=` attribute. The `xtra` params are passed-in separated by a `:` as the delimiter as seen above. As I am using the Python Plex API to handle that logic, you can view their list of options: http://python-plexapi.readthedocs.io/en/latest/modules/library.html#plexapi.library.LibrarySection.search
|
||||
|
||||
Furthermore, if you'd like to specify multiple values in the `xtra` params, say to schedule saturday morning kid-friendly movies, you could do something like: `xtra="contentRating:G,PG"`. This works for other parameters, like `genre`: `xtra="genre:comedy,romance"`. Just beware that if the app cannot find a single movie in your library that matches your parameters, it will just give you a random movie dismissing all the params.
|
||||
|
||||
## The Automatically Generated .HTML Daily Schedule / Server
|
||||
|
||||
To view the automatically generated "Daily Pseudo Schedule" index.html as seen in the image above, find it in the generated `./schedules/` directory within the project folder. The html file is generated both when the daily schedule is updated and whenever a media item from the schedule plays or ends (you can manually generate it with the `-m` flag).
|
||||
|
||||
If you configured your `controllerServerPath` variable in the `pseudo_config.py` file, you can view your schedule by pointing your browser here:
|
||||
4. Run the install and follow the prompts:
|
||||
|
||||
```bash
|
||||
http://192.168.1.28:8000
|
||||
```
|
||||
*Where `192.168.1.28` is the IP of your controller & `8000` is the port - both perameters are configured in the `pseudo_config.py` file.*
|
||||
|
||||
## Adding New TV/Movies/Commercials to Your Channel:
|
||||
|
||||
Whenever you add new content to your Plex library, you need to run: `python PseudoChannel.py -u`. This will tell the app to check the Plex library and update the local database with new media.
|
||||
|
||||
## Multi-Channel Support:
|
||||
|
||||
You can have multpile instances of this app, specify different schedules for each instance and control it via a USB remote. Let's say you choose to have 3 channels, an all day movie channel, a 'cartoon network' channel, and a 90's channel. You would simply create a directory named something like `/channels`. Then within your `/channels` dir you would have your `plex_token.py` file and your channels named something like: `/channel_1`, `channel_2` & `channel_3`. Note: the only important naming convention here is that `_01`, `_02`, etc. is contained at the end of each directory title. Each channel directory will contain the contents of this repository, set up just as if you had a single channel. So your directory structure would look like this:
|
||||
|
||||
```bash
|
||||
-channels/
|
||||
--plex_token.py
|
||||
--channel_01/
|
||||
---pseudo-channel.db
|
||||
---PseudoChannel.py
|
||||
---...etc.
|
||||
--channel_02/
|
||||
---pseudo-channel.db
|
||||
---PseudoChannel.py
|
||||
---...etc.
|
||||
--channel_03/
|
||||
---pseudo-channel.db
|
||||
---PseudoChannel.py
|
||||
---...etc.
|
||||
% ./install.sh
|
||||
```
|
||||
|
||||
In order to get this working with a usb remote hooked up to your Raspberry Pi, you need to configure the remotes channel buttons to trigger the corresponding bash scripts. I have placed a `channelup.sh` and a `channeldown.sh` within the projects `bash-scripts/` dir. You need to move these files to the `channels/` directory to make it work. When everything is setup properly and you have configured your remote, your channel up/channel down buttons should trigger the corresponding scripts triggering the channel to change. Lastly you need to configure a crontab so your controller automatically triggers each channel to generate a new daily schedule when the clock hits, `12:00 AM`. If you are running a single channel the the app knows to update when the clock strikes mid-night. However, if you are using this multi-channel method, the bash scripts will start / stop the corresponding channels depending on what channel you are watching. There is another bash script that you configure a crontab to trigger that will generate a new daily schedule for each channel that isn't currently running.
|
||||
|
||||
*This is a work in progress.*
|
||||
|
||||
## Known Issues/Workarounds
|
||||
|
||||
By far, the most issues result from XML errors. It's important to make sure that all XML `<time>` entries are properly formatted and that you do not squeeze in too many `<time>` entries in your daily schedule. A good example of too many time entries is when you try and fill up a full 24 hours with daily content. Since PseudoChannel.py generates a new daily scedule every 24 hours, it will overwrite the previous 24 hours with the new content. So, if you were watching a movie that was scheduled to start at `11:00 PM`, the app will generate a new daily schedule when the clock hits `12:00 AM`. However, I added some logic that should allow any previous playing media to finish before beginning the next days schedule. It's best to try and avoid overfilling your schedule.
|
||||
|
||||
### Problem Solving
|
||||
|
||||
The best way to pinpoint errors and wonky-ness is to run the app in your console using: `python PseudoChannel.py -r`. Although there is a `.log` file that is generated in the working directory, the output from running the app manually is more verbose. Also, it is important to open up `psuedo_config.py` and change, `debug_mode` from `False` to `True`. This will not only show more verbose output when running PseudoChannel.py, but will also show all scheduled content (including commercials) in the generated daily schedule .html.
|
||||
|
||||
#### Inspecting the Database.
|
||||
|
||||
If you'd like to dig deeper I recommend using a database inspector utility like, [sqlitebrowser](http://sqlitebrowser.org/). The app generates a local sqlite db called, `psuedo-channel.db` located in the root of the project directory. There are a few tables to look at, the `daily_schedule` table and the `schedule` table. The former is the where all the daily generated time entries are placed and the latter is where the XML time entries are stored.
|
||||
|
||||
#### Don't Be Afraid to Delete Your Local Database/Start Over:
|
||||
|
||||
If for some reason you want to delete your old DB but don't want to lose your TV queue you can do the following...
|
||||
|
||||
1) Export the TV queue by running `python PseudoChannel.py -e`. This exports the queue to a json file.
|
||||
|
||||
2) Delete the pseudo-channel.db file.
|
||||
|
||||
3) Re-generate the fresh database by running: `python PseudoChannel.py -u`
|
||||
|
||||
4) Import the old TV queue: `python PseudoChannel.py -i`.
|
||||
|
||||
*...this has been helpful mostly when debugging/developing, but it may be helpful for others too. Of course if you don't care about your TV queue you can skip steps, 1 & 4.*
|
||||
|
||||
## Contact Mark Or Me
|
||||
|
||||
We set up [discord](https://discord.gg/7equn68) channel where you can ping Mark and I with any issues you may run into. You can find us there or file an "issue" here in this repo.
|
||||
|
||||
Stay tuned for a polished version / bug fixes.
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Special thanks to Mark @ [Fake TV](https://medium.com/@Fake.TV). Without his creative ideas and love for TV, this "PseudoChannel" wouldn't be as cool as it is. I look forward to tinkering with this project and seeing others "unplugging" and creating their own home network. Mark has some excellent ideas in regard to making this thing much more usable as a "pseudo-cable" network - I think this will be in the next version as it is the 'icing on the cake' sort of feature. Anyway, enjoy!
|
||||
You need to have your Plex server IP and [Plex Token](https://bit.ly/2p7RtOu) handy as the install script will ask for them. If you run into issues or want to know more about customizing/configuring PseudoChannel, check out the wiki for details. If you need further help, have some ideas or just want to chat all things FakeTV, visit our FakeTV Discord chat here: https://discord.gg/7equn68
|
||||
|
||||
@@ -125,29 +125,47 @@ class PseudoDailyScheduleController():
|
||||
timeB = datetime.strptime(row[8], '%I:%M:%S %p')
|
||||
if currentTime == None:
|
||||
with tag('time',
|
||||
('data-key', str(row[12])),
|
||||
('data-current', 'false'),
|
||||
('data-type', str(row[11])),
|
||||
('data-title', str(row[3])),
|
||||
('data-start-time', str(row[8])),
|
||||
('key', str(row[12])),
|
||||
('current', 'false'),
|
||||
('type', str(row[11])),
|
||||
('show-title', str(row[6])),
|
||||
('show-season', str(row[5])),
|
||||
('show-episode', str(row[4])),
|
||||
('title', str(row[3])),
|
||||
('duration', str(row[7])),
|
||||
('time-start', str(row[8])),
|
||||
('time-end', str(row[9])),
|
||||
('library', str(row[13])),
|
||||
):
|
||||
text(row[8])
|
||||
elif currentTime.hour == timeB.hour and currentTime.minute == timeB.minute:
|
||||
with tag('time',
|
||||
('data-key', str(row[12])),
|
||||
('data-current', 'true'),
|
||||
('data-type', str(row[11])),
|
||||
('data-title', str(row[3])),
|
||||
('data-start-time', str(row[8])),
|
||||
('key', str(row[12])),
|
||||
('current', 'true'),
|
||||
('type', str(row[11])),
|
||||
('show-title', str(row[6])),
|
||||
('show-season', str(row[5])),
|
||||
('show-episode', str(row[4])),
|
||||
('title', str(row[3])),
|
||||
('duration', str(row[7])),
|
||||
('time-start', str(row[8])),
|
||||
('time-end', str(row[9])),
|
||||
('library', str(row[13])),
|
||||
):
|
||||
text(row[8])
|
||||
else:
|
||||
with tag('time',
|
||||
('data-key', str(row[12])),
|
||||
('data-current', 'false'),
|
||||
('data-type', str(row[11])),
|
||||
('data-title', str(row[3])),
|
||||
('data-start-time', str(row[8])),
|
||||
('key', str(row[12])),
|
||||
('current', 'false'),
|
||||
('type', str(row[11])),
|
||||
('show-title', str(row[6])),
|
||||
('show-season', str(row[5])),
|
||||
('show-episode', str(row[4])),
|
||||
('title', str(row[3])),
|
||||
('duration', str(row[7])),
|
||||
('time-start', str(row[8])),
|
||||
('time-end', str(row[9])),
|
||||
('library', str(row[13])),
|
||||
):
|
||||
text(row[8])
|
||||
return indent(doc.getvalue())
|
||||
@@ -731,4 +749,4 @@ class PseudoDailyScheduleController():
|
||||
|
||||
self.write_refresh_bool_to_file()
|
||||
self.write_schedule_to_file(self.get_html_from_daily_schedule(now, bgImage, datalist, itemTitle))
|
||||
self.write_xml_to_file(self.get_xml_from_daily_schedule(None, None, datalist))
|
||||
self.write_xml_to_file(self.get_xml_from_daily_schedule(None, None, datalist))
|
||||
|
||||
72
main-dir/generate-html-schedules.sh
Normal file
72
main-dir/generate-html-schedules.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# file: generate-html-schedules.sh
|
||||
|
||||
#----
|
||||
# Simple script to generate the ONLY the html schedule for each individual channel. Useful when using the multi-channel-viewer.php file.
|
||||
#
|
||||
#----
|
||||
|
||||
#----
|
||||
# To Use:
|
||||
# ./generate-html-schedules.sh
|
||||
#----
|
||||
|
||||
#----BEGIN EDITABLE VARS----
|
||||
|
||||
SCRIPT_TO_EXECUTE_PLUS_ARGS='PseudoChannel.py -m'
|
||||
|
||||
OUTPUT_PREV_CHANNEL_PATH=.
|
||||
|
||||
CHANNEL_DIR_INCREMENT_SYMBOL="_"
|
||||
|
||||
PYTHON_TO_USE="$(which python)"
|
||||
|
||||
# If using 'virtualenv' with python, specify the local virtualenv dir.
|
||||
VIRTUAL_ENV_DIR="env"
|
||||
|
||||
#----END EDITABLE VARS-------
|
||||
|
||||
# If virtualenv specified & exists, using that version of python instead.
|
||||
if [ -d "$VIRTUAL_ENV_DIR" ]; then
|
||||
|
||||
PYTHON_TO_USE="$VIRTUAL_ENV_DIR/bin/python"
|
||||
|
||||
echo "+++++ Virtualenv found, using: $VIRTUAL_ENV_DIR/bin/python"
|
||||
|
||||
fi
|
||||
|
||||
# Scan the dir to see how many channels there are, store them in an arr.
|
||||
CHANNEL_DIR_ARR=( $(find . -maxdepth 1 -type d -name '*'"$CHANNEL_DIR_INCREMENT_SYMBOL"'[[:digit:]]*' -printf "%P\n" | sort -t"$CHANNEL_DIR_INCREMENT_SYMBOL" -n) )
|
||||
|
||||
# If this script see's there are multiple channels,
|
||||
# then loop through each channel and run the daily schedule generator
|
||||
if [ "${#CHANNEL_DIR_ARR[@]}" -gt 1 ]; then
|
||||
|
||||
echo "+++++ There are ${#CHANNEL_DIR_ARR[@]} channels detected."
|
||||
|
||||
for channel in "${CHANNEL_DIR_ARR[@]}"
|
||||
do
|
||||
|
||||
# If the .pid file exists for this channel, skip it because it updated the html when running.
|
||||
if [ ! -f "$channel/running.pid" ]; then
|
||||
|
||||
echo "+++++ Trying to generate HTML schedule: ""$PYTHON_TO_USE" ./"$channel"/$SCRIPT_TO_EXECUTE_PLUS_ARGS
|
||||
|
||||
cd "$channel" && $PYTHON_TO_USE $SCRIPT_TO_EXECUTE_PLUS_ARGS
|
||||
|
||||
echo "+++++ Generated: $channel - HTML schedule."
|
||||
|
||||
sleep 1
|
||||
|
||||
cd ../
|
||||
|
||||
sleep 1
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -20,11 +20,11 @@ if [ $# -gt 1 ]; then
|
||||
exit 9999
|
||||
elif [ "$1" == "develop" ]; then
|
||||
echo "Downloading the develop branch"
|
||||
SCRIPT_TO_EXECUTE_PLUS_ARGS='git clone https://github.com/mutto233/pseudo-channel . --branch develop'
|
||||
SCRIPT_TO_EXECUTE_PLUS_ARGS='git clone https://github.com/FakeTV/pseudo-channel . --branch develop'
|
||||
|
||||
else
|
||||
echo "Downloading the master branch"
|
||||
SCRIPT_TO_EXECUTE_PLUS_ARGS='git clone https://github.com/mutto233/pseudo-channel . --branch master'
|
||||
SCRIPT_TO_EXECUTE_PLUS_ARGS='git clone https://github.com/FakeTV/pseudo-channel . --branch master'
|
||||
fi
|
||||
|
||||
OUTPUT_PREV_CHANNEL_PATH=.
|
||||
@@ -115,7 +115,7 @@ read -p 'Number of Channels: ' number_of_channels
|
||||
echo "PLEX AUTH TOKEN is $server_token"
|
||||
echo "SELECT the PLEX CLIENT for this install or ENTER one manually"
|
||||
# DISPLAY A LIST OF CONNECTED CLIENTS AND ALLOW THE USER TO SELECT ONE OR ENTER ONE THAT ISN'T DISPLAYED
|
||||
clientlist=$(xmllint --xpath "//Server/@name" "http://$server_ip:$server_port/clients" | sed "s|name=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
clientlist=$(xmllint --xpath "//Server/@name" "http://$server_ip:$server_port/clients/?X-Plex-Token=$server_token" | sed "s|name=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
eval set $clientlist
|
||||
select ps_client_entry in "$@"
|
||||
do
|
||||
@@ -137,7 +137,7 @@ read -p 'Number of Channels: ' number_of_channels
|
||||
do
|
||||
#read -p 'TV Show Library Name: ' tv_library_entry
|
||||
#echo -n "\"$tv_library_entry\"" >> tv-libraries.temp
|
||||
library_list_tv=$(xmllint --xpath "//Directory[@type=\"show\"]/@title" "http://$server_ip:$server_port/library/sections" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
library_list_tv=$(xmllint --xpath "//Directory[@type=\"show\"]/@title" "http://$server_ip:$server_port/library/sections/?X-Plex-Token=$server_token" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
eval set $library_list_tv
|
||||
select tv_library_entry in "$@"
|
||||
do
|
||||
@@ -169,7 +169,7 @@ read -p 'Number of Channels: ' number_of_channels
|
||||
do
|
||||
#read -p 'Movie Library Name: ' movie_library_entry
|
||||
#echo -n "\"$movie_library_entry\"" >> movie-libraries.temp
|
||||
library_list_movie=$(xmllint --xpath "//Directory[@type=\"movie\"]/@title" "http://$server_ip:$server_port/library/sections" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
library_list_movie=$(xmllint --xpath "//Directory[@type=\"movie\"]/@title" "http://$server_ip:$server_port/library/sections/?X-Plex-Token=$server_token" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
eval set $library_list_movie
|
||||
select movie_library_entry in "$@"
|
||||
do
|
||||
@@ -212,7 +212,7 @@ read -p 'Number of Channels: ' number_of_channels
|
||||
while [[ "$enter_commercials" == @(Y|y|Yes|yes|YES) ]]
|
||||
do
|
||||
#read -p 'Commercial Library Name: ' commercial_library_entry
|
||||
library_list_commercial=$(xmllint --xpath "//Directory[@type=\"movie\"]/@title" "http://$server_ip:$server_port/library/sections" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
library_list_commercial=$(xmllint --xpath "//Directory[@type=\"movie\"]/@title" "http://$server_ip:$server_port/library/sections/?X-Plex-Token=$server_token" | sed "s|title=||g" | sed "s|^ ||g" && echo -e " Other")
|
||||
eval set $library_list_commercial
|
||||
select commercial_library_entry in "$@"
|
||||
do
|
||||
@@ -251,10 +251,9 @@ read -p 'Number of Channels: ' number_of_channels
|
||||
reset_time_minute="${reset_time_formatted: -2}"
|
||||
reset_time_minute=$(echo $reset_time_minute | sed "-e s|^[0]||")
|
||||
# SET UP CRON JOB TO RUN DAILY RESET
|
||||
sudo crontab -e &
|
||||
sudo crontab -l | grep -v 'daily-cron.sh' | crontab -
|
||||
sudo echo "$reset_time_minute $reset_time_hour * * * root $PWD/daily-cron.sh" >> pseudo-channel
|
||||
sudo chown root:root pseudo-channel && sudo chmod 600 pseudo-channel && sudo mv pseudo-channel /etc/cron.d/
|
||||
sudo echo \#\!/bin/bash > ./daily-cron.sh && echo "cd $PWD" >> ./daily-cron.sh && echo "sudo ./generate-channels-daily-schedules.sh" >> ./daily-cron.sh
|
||||
( sudo crontab -l ; echo "$reset_time_minute $reset_time_hour * * * $PWD/daily-cron.sh" ) | sudo crontab -
|
||||
|
||||
#### WRITE VARIABLES TO TOKEN AND CONFIG FILES ####
|
||||
reset_time="\"$reset_time_entry\""
|
||||
|
||||
67
main-dir/multi-channel-api.php
Normal file
67
main-dir/multi-channel-api.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<!--
|
||||
multi-channel-api.php
|
||||
|
||||
This file triggers bash-scripts based on a url string. Simply navigate your browser or use
|
||||
cURL or some other method to pass in URL params to trigger corresponding scripts.
|
||||
|
||||
*Be sure to update the directory on line 35 to your directory path:
|
||||
chdir('/home/justin/channels/');
|
||||
|
||||
To use:
|
||||
1) Install PHP
|
||||
sudo apt install php
|
||||
|
||||
2) Run screen (so you can start a simple php server and exit the console):
|
||||
screen
|
||||
|
||||
3) Navigate your directory with all the channels (i.e. /home/pi/channels/), and run a simple php server:
|
||||
php -S 192.168.1.112:8080
|
||||
-Make sure to update the IP:PORT to your client IP and whatever port you want to use/is open.
|
||||
|
||||
4) Trigger a bash script by navigating to your IP:PORT/multi-channel-api.php/?command=THE_COMMAND:
|
||||
http://192.168.1.112:8080/multi-channel-api.php/?command=KEY_CHANNELUP
|
||||
|
||||
or use cURL: curl -I --request GET http://192.168.1.112:8080/?command=KEY_CHANNELUP
|
||||
-->
|
||||
<?php
|
||||
header("HTTP/1.1 200 OK");
|
||||
if (isset($_GET['command'])) {
|
||||
echo $_GET['command'];
|
||||
$command = $_GET['command'];
|
||||
} else {
|
||||
// Fallback behaviour goes here
|
||||
}
|
||||
$old_path = getcwd();
|
||||
chdir('/home/justin/channels/');
|
||||
if ($command == "KEY_PLAY"){
|
||||
$output = shell_exec('./manual.sh 01');
|
||||
} else if ($command == "KEY_STOP"){
|
||||
$output = shell_exec('./stop-all-channels.sh');
|
||||
} else if ($command == "KEY_CHANNELUP"){
|
||||
$output = shell_exec('./channelup.sh');
|
||||
} else if ($command == "KEY_CHANNELDOWN"){
|
||||
$output = shell_exec('./channeldown.sh');
|
||||
} else if ($command == "KEY_1"){
|
||||
$output = shell_exec('./manual.sh 01');
|
||||
} else if ($command == "KEY_2"){
|
||||
$output = shell_exec('./manual.sh 02');
|
||||
} else if ($command == "KEY_3"){
|
||||
$output = shell_exec('./manual.sh 03');
|
||||
} else if ($command == "KEY_4"){
|
||||
$output = shell_exec('./manual.sh 04');
|
||||
} else if ($command == "KEY_5"){
|
||||
$output = shell_exec('./manual.sh 05');
|
||||
} else if ($command == "KEY_6"){
|
||||
$output = shell_exec('./manual.sh 06');
|
||||
} else if ($command == "KEY_7"){
|
||||
$output = shell_exec('./manual.sh 07');
|
||||
} else if ($command == "KEY_8"){
|
||||
$output = shell_exec('./manual.sh 08');
|
||||
} else if ($command == "KEY_9"){
|
||||
$output = shell_exec('./manual.sh 09');
|
||||
} else {
|
||||
//$output = shell_exec('./manual.sh 01');
|
||||
}
|
||||
chdir($old_path);
|
||||
echo "<pre>$output</pre>";
|
||||
?>
|
||||
217
main-dir/multi-channel-viewer.php
Normal file
217
main-dir/multi-channel-viewer.php
Normal file
@@ -0,0 +1,217 @@
|
||||
<!--
|
||||
multi-channel-viewer.php
|
||||
|
||||
To use:
|
||||
1) Install PHP
|
||||
sudo apt install php
|
||||
|
||||
2) Run screen (so you can start a simple php server and exit the console):
|
||||
screen
|
||||
|
||||
3) Navigate your directory with all the channels (i.e. /home/pi/channels/), and run a simple php server:
|
||||
php -S 192.168.1.112:8080
|
||||
-Make sure to update the IP:PORT to your client IP and whatever port you want to use/is open.
|
||||
|
||||
4) Point your browser to the to IP:PORT/multi-channel-viewer.php:
|
||||
http://192.168.1.112:8080/multi-channel-viewer.php
|
||||
|
||||
5) All this does is load in/display (via iframe) the html files that each channel generates.
|
||||
Click "Generate Now Playing Schedules", to generate up-to-date html schedules to view what's playing.
|
||||
-->
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title></title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="apple-touch-icon" href="icon.png">
|
||||
<link rel="shortcut icon" href="https://raw.githubusercontent.com/justinemter/pseudo-channel/master/favicon.ico" type="image/x-icon">
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
|
||||
<style type="text/css">
|
||||
.channels-selector {
|
||||
width: 124px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.channels-selector a {
|
||||
margin-top: 3px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.channels-selector .channel-left {
|
||||
float: left;
|
||||
}
|
||||
.channels-selector .channel-right {
|
||||
float: right;
|
||||
}
|
||||
.channels-selector h1 {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
form {
|
||||
margin: 20px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.schedules-html-paths {
|
||||
display: none;
|
||||
}
|
||||
.heading {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--[if lte IE 9]>
|
||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
|
||||
<![endif]-->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
|
||||
<script>window.jQuery || document.write('<script src="js/vendor/jquery-3.3.1.min.js"><\/script>')</script>
|
||||
|
||||
<?php
|
||||
$schedules_html_paths = array();
|
||||
$dirs = array_filter(glob('*'), 'is_dir');
|
||||
|
||||
foreach($dirs as $file)
|
||||
{
|
||||
if (strpos($file, 'channel') !== false) {
|
||||
array_push($schedules_html_paths, $file."/schedules/index.html");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
function updateNowPlayingSchedules() {
|
||||
exec("./generate-html-schedules.sh",$out);
|
||||
/*foreach($out as $key => $value)
|
||||
{
|
||||
echo $key." ".$value."<br>";
|
||||
}*/
|
||||
echo " Update Complete";
|
||||
}
|
||||
if (isset($_GET['update'])) {
|
||||
echo 'Generating new html schedules.';
|
||||
updateNowPlayingSchedules();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="schedules-html-paths" data-results="<?php echo implode(",",$schedules_html_paths); ?>"></div>
|
||||
|
||||
<h1 class="heading">Multi-Channel</h1>
|
||||
|
||||
<form id="myForm">
|
||||
<select id="selectNumber">
|
||||
<option>Choose a Channel</option>
|
||||
</select>
|
||||
<a id="gen-schedules" href="?update=true">Generate Now Playing Schedules</a>
|
||||
</form>
|
||||
|
||||
<div class="channels-selector">
|
||||
<a href="#" class="channel-controls channel-left"><</a>
|
||||
<h1></h1>
|
||||
<a href="#" class="channel-controls channel-right">></a>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
var getBackMyJSON = $('.schedules-html-paths').data('results');
|
||||
//console.log(getBackMyJSON);
|
||||
var schedules_html_paths = getBackMyJSON.split(',');
|
||||
//console.log(schedules_html_paths[0]);
|
||||
var select = document.getElementById("selectNumber");
|
||||
var options = [];
|
||||
for(var j = 0; j < schedules_html_paths.length; j++){
|
||||
options.push(schedules_html_paths[j]);
|
||||
//console.log(j);
|
||||
}
|
||||
$('#selectNumber').empty();
|
||||
$('#selectNumber').change(function() {
|
||||
$("#iframeHolder").empty();
|
||||
$("#iframeHolder").append('<iframe id="iframe" src="'+$(this).val()+'" width="100%" height="900"></iframe>');
|
||||
//Getting channel number
|
||||
var channelNum = getChannelNumberFromStr($(this).val());
|
||||
$thisItem = $(this);
|
||||
console.log($thisItem.val());
|
||||
$('#selectNumber option').each(function(){
|
||||
if($(this).val() == $thisItem.val()){
|
||||
console.log("I made it");
|
||||
$(this).attr("selected", "selected");
|
||||
} else {
|
||||
$(this).removeAttr("selected");
|
||||
console.log("In here")
|
||||
}
|
||||
})
|
||||
$(".channels-selector h1").empty().append(channelNum);
|
||||
});
|
||||
$.each(options, function(i, p) {
|
||||
if(i == 0){
|
||||
$('#selectNumber').append($('<option selected="selected"></option>').val(p).html(getChannelNumberFromStr(p)));
|
||||
} else {
|
||||
$('#selectNumber').append($('<option></option>').val(p).html(getChannelNumberFromStr(p)));
|
||||
}
|
||||
});
|
||||
$(".channel-right").click(function(){
|
||||
var nextItem = false;
|
||||
for(var i=0; i < $('#selectNumber option').length; i++){
|
||||
if(nextItem){
|
||||
$('#selectNumber option').eq(i).attr('selected', 'selected');
|
||||
$('#selectNumber').trigger('change');
|
||||
|
||||
break;
|
||||
} else{
|
||||
}
|
||||
if($('#selectNumber option').eq(i).attr("selected") == "selected") {
|
||||
|
||||
if(i != $('#selectNumber option').length -1){
|
||||
$('#selectNumber option').eq(i).removeAttr('selected');
|
||||
}
|
||||
nextItem = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$("#selectNumber option").each(function(i) {
|
||||
|
||||
});
|
||||
});
|
||||
$(".channel-left").click(function(){
|
||||
var nextItem = false;
|
||||
for(var i=$('#selectNumber option').length; i >= 0; i--){
|
||||
if(nextItem){
|
||||
$('#selectNumber option').eq(i).attr('selected', 'selected');
|
||||
$('#selectNumber').trigger('change');
|
||||
break;
|
||||
} else{
|
||||
//
|
||||
}
|
||||
if($('#selectNumber option').eq(i).attr("selected") == "selected") {
|
||||
|
||||
if(i != 0){
|
||||
$('#selectNumber option').eq(i).removeAttr('selected');
|
||||
}
|
||||
nextItem = true;
|
||||
|
||||
}
|
||||
}
|
||||
$("#selectNumber option").each(function(i) {
|
||||
|
||||
});
|
||||
});
|
||||
$('#selectNumber').trigger('change');
|
||||
function getChannelNumberFromStr(str){
|
||||
return str.split('channel_').pop().split('/schedules')[0];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="iframeHolder"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -12,11 +12,11 @@ pyasn1==0.3.2
|
||||
pyasn1-modules==0.0.11
|
||||
pytest==3.2.1
|
||||
pytz==2017.2
|
||||
requests==2.18.3
|
||||
requests==2.20.0
|
||||
rsa==3.4.2
|
||||
schedule==0.4.3
|
||||
six==1.10.0
|
||||
uritemplate==3.0.0
|
||||
urllib3==1.22
|
||||
urllib3==1.23
|
||||
vine==1.1.4
|
||||
yattag==1.8.0
|
||||
|
||||
Reference in New Issue
Block a user