Skip to content

Commit

Permalink
Updated README. Small bug fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
DEFENDORe committed May 15, 2020
1 parent 1dd068b commit 5979ef8
Show file tree
Hide file tree
Showing 21 changed files with 168 additions and 86 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
bin/
.pseudotv/
web/public/bundle.js
128 changes: 90 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,68 +1,90 @@
# pseudotv-plex

PseudoTV is a Plex DVR plugin. It allows you to host your own fake live tv service by dynamically streaming media from your Plex servers(s). Your channels and settings are all manged throught the PseudoTV Web UI.
Create live TV channel streams from media on your Plex servers.

PseudoTV will show up as a HDHomeRun device within Plex. When configuring your Plex Tuner, simply use the generatered `./.pseudotv/xmltv.xml` file for EPG data. PseudoTV will automatically refresh your Plex server's EPG data and channel mappings (if specified to do so in settings) when configuring channels via the Web UI. Ensure your FFMPEG path is set correctly via the Web UI, and enjoy!
Project recently migrated from [gitlab](https://gitlab.com/DEFENDORe/pseudotv-plex) to github to improve development flow (docker builds and binary releases).

<img src="./resources/pseudotv.png" width="200">

Configure your channels, programs, commercials and settings using the PseudoTV web UI.

Access your channels by adding the spoofed PseudoTV HDHomerun tuner to Plex, or utilize the M3U Url with any 3rd party app.

EPG (Guide Information) data is stored to `.pseudotv/xmltv.xml`

## Features
- Docker support and prepackage binaries for Windows, Linux and Mac
- Docker image and prepackage binaries for Windows, Linux and Mac
- Web UI for channel configuration and app settings
- Select media across multiple Plex servers
- Ability to auto update Plex EPG and channel mappings
- Auto Update the xmltv.xml file at a set interval (in hours). You can also set the amount EPG cache (in hours).
- Select media (desired programs and commercials) across multiple Plex servers
- Sign into your Plex servers using any sign in method (Username, Email, Google, Facebook, etc.)
- Ability to auto update Plex DVR guide data and channel mappings
- Auto update the xmltv.xml file at a set interval (in hours). You can also set the amount EPG cache (in hours).
- Continuous playback support
- Commercial support
- Media track selection (video, audio, subtitle)
- Subtitle Support (some subtitle formats may cause a delay when starting an ffmpeg session)
- Internal Subs Supported
- ASS (slow, I would avoid unless you got a bitchin cpu)
- SRT (slow, I would avoid unless you got a bitchin cpu)
- Commercial support. 5 commercial slots for a program (BEFORE, 1/4, 1/2, 3/4, AFTER). Place as many commercials as desired per slot to chain commercials.
- Media track selection (video, audio, subtitle). (subtitles disabled by default)
- Subtitle support (some subtitle formats may cause a delay when starting an ffmpeg session) Supported subs below.
- Internal Subs
- ASS (slow)
- SRT (slow)
- PGS (fast)
- External Subs Supported
- External Subs
- ASS (moderate)
- SRT (moderate)
- Ability to overlay channel icon over stream
- Auto deinterlace any Plex media not marked `"scanType": "progressive"`

## Recent Bug Fixes and Notes
- Removed FFPROBE requirment. Use Plex API for stream selection
- Fixed issue with bulk imports fucking up season, episode order
- Fixed an issue where Safari (and probably other browsers) couldn't load the web UI fully.
- Plex accounts linked to google, facebook, etc can now sign in
- PseudoTV will now host a dummy channel (Channel 1) when no channels configured. This makes setup a bit easier, no longer have to create a channel first..
- No longer required to specify host address. I'm a fucking idiot and made shit more complicated than it needed to be. `channels.m3u` and `lineup.json` will now generate URLs based on the incoming http request.
- Removed --host, and --xmltv arguments altogether
- Added channel/app info to ts stream
## Useful Tips/Info

## Useful Tips

- Internal SRT/ASS subtitle may cause a delay when starting stream
- Internal and External SRT/ASS subtitles may cause a delay when starting stream (only when subtitles are activated). For internal SRT/ASS subtitles, FFMPEG needs to perform a subtitle track extraction from the original media before the requested stream can be started. External SRT/ASS subtitle files still need to be sliced to the correct start time and duration so even they may cause a delay when starting a stream. Image based subs (PGS) should have little to no impact.
- Utilize your hardware accelerated encoders, or use mpeg2 instead of h264 by changing the default video encoder in FFMPEG settings. *Note that some encoders may not be capable of handling every transcoding scenario, libx264 and mpeg2video seem to be the most stable.*
- Intel Quick Sync: `h265_qsv`, `mpeg2_qsv`
- Intel Quick Sync: `h264_qsv`, `mpeg2_qsv`
- NVIDIA GPU: `h264_nvenc`
- MPEG2 `mpeg2video`
- H264 `libx264` (default)
- MacOS `h264_videotoolbox`
- **Enable the option to log ffmpeg's stderr output directly to the pseudotv app console, for detecting issues**
- Host your own images for channel icons, program icons, etc.. Simply add your image to `.pseudotv/images` and reference them via `http://pseudotv-ip:8000/images/myImage.png`
- Use the Block Shuffle feature to play a specified number of TV episodes before advancing to the next available TV show in the channel. You can also specify to randomize the TV Show order. Any movies added to the channel will be pushed to the end of the program lineup, this is also applicable the "Sort TV Shows" option.
- Plex is smart enough not to open another stream if it currently is being viewed by another user. This allows only one transcode session for mulitple viewers if they are watching the same channel.
- Even if your Plex server is running on the same machine as the PseudoTV app, use your network address (not a loopback) when configuring your Plex Server(s) in the web UI.

## Installation
## Limitations

*Please delete your old `.pseudotv` directory before using the new version. I'm sorry but it'd take more effort than its worth to convert the old databases..*
- Plex Pass is required to unlock Plex Live TV/DVR feature
- Only one EPG source can be used with Plex server. This may cause an issue if you are adding the pseudotv tuner to a Plex server with Live TV/DVR already enabled/configured.
- PseudoTV does not watch your Plex server for media updates/changes. You must manually remove and readd your programs for any changes to take effect. Same goes for Plex server changes (changing IP, port, etc).. all media will fail..

Unless your are using the Docker image, you must download and install **ffmpeg** to your system and set the correct path in the PseudoTV Web UI.

By default, pseudotv will create the directory `.pseudotv` wherever pseudotv is launched from. Your `xmltv.xml` file and config databases are stored here. An M3U can also be downloaded via the Web UI (useful if using xTeVe).
## Installation

**Do not use the Web UI XMLTV URL when feeding Plex the xmltv.xml file. Plex fails to update it's EPG from a URL for some reason (at least on Windows). Use the local file path to `.pseudotv/xmltv.xml`**
*Please delete your old `.pseudotv` directory before using the new build. I'm sorry but it'd take more effort than its worth to convert the old databases..*

Unless your are using Docker/Unraid, you must download and install **ffmpeg** to your system and set the correct path in the PseudoTV Web UI.

By default, pseudotv will create the directory `.pseudotv` wherever pseudotv is launched from. Your `xmltv.xml` file and config databases are stored here.

#### Binary Release
[Download](https://gitlab.com/DEFENDORe/pseudotv-plex/-/releases) and run the PseudoTV executable (argument defaults below)
[Download](https://github.com/DEFENDORe/pseudotv/releases) and run the PseudoTV executable (argument defaults below)
```
./pseudotv-win.exe --port 8000 --database ./pseudotv
./pseudotv-win-x64.exe --port 8000 --database ./pseudotv
```

#### Docker Image
#### Docker

The Docker repository can be viewed [here](https://hub.docker.com/r/defendore/pseudotv).

Use Docker to fetch PseudoTV, then run the container.. (replace `C:\.pseudotv` with your desired config directory location)
```
git clone https://gitlab.com/DEFENDORe/pseudotv-plex.git
docker pull defendore/pseudotv
docker run --name pseudotv -p 8000:8000 -v C:\.pseudotv:/home/node/app/.pseudotv defendore/pseudotv
```

#### Building Docker image from source

Build docker image from source and run the container. (replace `C:\.pseudotv` with your desired config directory location)

```
git clone https://github.com/DEFENDORe/pseudotv
cd pseudotv-plex
docker build -t pseudotv .
docker run --name pseudotv -p 8000:8000 -v C:\.pseudotv:/home/node/app/.pseudotv pseudotv
Expand All @@ -78,17 +100,47 @@ Click the "Add Container" button
Select either the pseudotv template or the pseudotv-nvidia template if you want nvidia hardware accelerated transcoding.
Make sure you have the Unraid Nvidia plugin installed and change your video encoder to h264_nvenc in the pseudotv ffmpeg settings.

#### Source
#### From Source

Install NodeJS and FFMPEG

```
git clone https://gitlab.com/DEFENDORe/pseudotv-plex.git
git clone https://github.com/DEFENDORe/pseudotv
cd pseudotv-plex
npm install
npm run build
npm run start
```

## Plex Setup

Add the PseudoTV spoofed HDHomerun tuner to Plex via Plex Settings.

If the tuner isn't automatically listed, manually enter the network address of pseudotv. Example:
```
127.0.0.1:8000
```

When prompted for a Postal/Zip code, click the `"Have an XMLTV guide on your server? Click here to use that instead."` link.

Enter the location of the `.pseudotv/xmltv.xml` file. Example (Windows):
```
C:\.pseudotv\xmltv.xml
```

**Do not use the Web UI XMLTV URL when feeding Plex the xmltv.xml file. Plex fails to update it's EPG from a URL for some reason (at least on Windows). Use the local file path to `.pseudotv/xmltv.xml`**

## App Preview
<img src="./docs/channels.png" width="500">
<br/>
<img src="./docs/channel-config.png" width="500">
<br/>
<img src="./docs/plex-guide.png" width="500">
<br/>
<img src="./docs/plex-stream.png" width="500">

## Development
Building Binaries: (uses `babel` and `pkg`)
Building/Packaging Binaries: (uses `browserify`, `babel` and `pkg`)
```
npm run build
npm run compile
Expand Down
Binary file added docs/channel-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/channels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/plex-guide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/plex-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,14 @@ app.listen(process.env.PORT, () => {

function initDB(db) {
let ffmpegSettings = db['ffmpeg-settings'].find()
if (!fs.existsSync(process.env.DATABASE + '/resources/font.ttf')) {
if (!fs.existsSync(process.env.DATABASE + '/font.ttf')) {
let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/font.ttf')))
fs.writeFileSync(process.env.DATABASE + '/font.ttf', data)
}
if (!fs.existsSync(process.env.DATABASE + '/images/pseudotv.png')) {
let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/pseudotv.png')))
fs.writeFileSync(process.env.DATABASE + '/images/pseudotv.png', data)
}

if (ffmpegSettings.length === 0) {
db['ffmpeg-settings'].save({
Expand All @@ -109,9 +113,6 @@ function initDB(db) {
audioRate: 48000,
bufSize: 1000,
audioEncoder: 'ac3',
preferAudioLanguage: 'false',
audioLanguage: 'eng',
deinterlace: false,
logFfmpeg: false,
args: `-threads 4
-ss STARTTIME
Expand Down
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,17 @@
},
"bin": "dist/index.js",
"pkg": {
"assets": ["dist/web/public/**/*","dist/resources/**/*"],
"targets": ["x86", "x64", "linux", "macos", "windows"]
"assets": [
"dist/web/public/**/*",
"dist/resources/**/*"
],
"targets": [
"x86",
"x64",
"linux",
"macos",
"windows"
]
},
"devDependencies": {
"@babel/cli": "^7.8.4",
Expand Down
2 changes: 1 addition & 1 deletion pseudotv-nvidia.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ PseudoTV will show up as a HDHomeRun device within Plex. When configuring your P
<Category/>
<WebUI>http://[IP]:[PORT:8000]</WebUI>
<TemplateURL/>
<Icon>https://raw.githubusercontent.com/powdermilkman/pseudotv/master/pseudotv.png</Icon>
<Icon>https://raw.githubusercontent.com/DEFENDORe/pseudotv/master/resources/pseudotv.png</Icon>
<ExtraParams>--runtime=nvidia</ExtraParams>
<PostArgs/>
<CPUset/>
Expand Down
10 changes: 3 additions & 7 deletions pseudotv.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,18 @@
<Privileged>false</Privileged>
<Support/>
<Project/>
<Overview>PseudoTV is a Plex DVR plugin. It allows you to host your own fake live tv service by dynamically streaming media from your Plex servers(s). Your channels and settings are all manged throught the PseudoTV Web UI.&#xD;
&#xD;
PseudoTV will show up as a HDHomeRun device within Plex. When configuring your Plex Tuner, simply use the generatered ./.pseudotv/xmltv.xml file for EPG data. PseudoTV will automatically refresh your Plex server's EPG data and channel mappings (if specified to do so in settings) when configuring channels via the Web UI. Ensure your FFMPEG path is set correctly via the Web UI, and enjoy!</Overview>
<Overview>Create live TV channel streams from media on your Plex server(s).</Overview>
<Category/>
<WebUI>http://[IP]:[PORT:8000]</WebUI>
<TemplateURL/>
<Icon>https://raw.githubusercontent.com/powdermilkman/pseudotv/master/pseudotv.png</Icon>
<Icon>https://raw.githubusercontent.com/DEFENDORe/pseudotv/master/resources/pseudotv.png</Icon>
<ExtraParams></ExtraParams>
<PostArgs/>
<CPUset/>
<DateInstalled>1589436589</DateInstalled>
<DonateText/>
<DonateLink/>
<Description>PseudoTV is a Plex DVR plugin. It allows you to host your own fake live tv service by dynamically streaming media from your Plex servers(s). Your channels and settings are all manged throught the PseudoTV Web UI.&#xD;
&#xD;
PseudoTV will show up as a HDHomeRun device within Plex. When configuring your Plex Tuner, simply use the generatered ./.pseudotv/xmltv.xml file for EPG data. PseudoTV will automatically refresh your Plex server's EPG data and channel mappings (if specified to do so in settings) when configuring channels via the Web UI. Ensure your FFMPEG path is set correctly via the Web UI, and enjoy!</Description>
<Description>Create live TV channel streams from media on your Plex server(s).</Description>
<Networking>
<Mode>host</Mode>
<Publish>
Expand Down
File renamed without changes
5 changes: 1 addition & 4 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ function api(db, xmltvInterval) {
audioRate: 48000,
bufSize: 1000,
audioEncoder: 'ac3',
preferAudioLanguage: 'false',
audioLanguage: 'eng',
deinterlace: false,
logFfmpeg: false,
args: `-threads 4
-ss STARTTIME
Expand Down Expand Up @@ -176,7 +173,7 @@ OUTPUTFILE`
data += `${req.protocol}://${req.get('host')}/video?channel=${channels[i].number}\n`
}
if (channels.length === 0) {
data += `#EXTINF:0 tvg-id="1" tvg-name="PseudoTV" tvg-logo="",PseudoTV\n`
data += `#EXTINF:0 tvg-id="1" tvg-name="PseudoTV" tvg-logo="https://raw.githubusercontent.com/DEFENDORe/pseudotv/master/resources/pseudotv.png",PseudoTV\n`
data += `${req.protocol}://${req.get('host')}/setup\n`
}
res.send(data)
Expand Down
4 changes: 2 additions & 2 deletions src/ffmpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ class FFMPEG extends events.EventEmitter {
else if (code === 255)
this.emit('close', code)
else
this.emit('error', { code: code, cmd: `${tmpargs.join(' ')}` })
this.emit('error', { code: code, cmd: `${opts.ffmpegPath} ${tmpargs.join(' ')}` })
})
}
kill() {
this.ffmpeg.kill('SIGQUIT')
this.ffmpeg.kill()
}
}

Expand Down
14 changes: 8 additions & 6 deletions src/ffmpegText.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ const path = require('path')
class FFMPEG_TEXT extends events.EventEmitter {
constructor (opts, title, subtitle) {
super()
this.ffmpegPath = opts.ffmpegPath

this.args = [
'-threads', opts.threads,
'-f', 'lavfi',
'-re',
'-stream_loop', '-1',
'-i', 'color=c=black:s=1280x720',
'-i', `color=c=black:s=${opts.videoResolution}`,
'-f', 'lavfi',
'-i', 'anullsrc',
'-vf', `drawtext=fontfile=${process.env.DATABASE}/font.ttf:fontsize=30:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:text='${title}',drawtext=fontfile=${process.env.DATABASE}/font.ttf:fontsize=20:fontcolor=white:x=(w-text_w)/2:y=(h+text_h+20)/2:text='${subtitle}'`,
'-c:v', 'libx264',
'-c:a', 'ac3',
'-c:v', opts.videoEncoder,
'-c:a', opts.audioEncoder,
'-f', 'mpegts',
'pipe:1'
]
Expand All @@ -38,8 +36,12 @@ class FFMPEG_TEXT extends events.EventEmitter {
this.ffmpeg.on('close', (code) => {
if (code === null)
this.emit('close', code)
else if (code === 0)
this.emit('close', code)
else if (code === 255)
this.emit('close', code)
else
this.emit('error', { code: code, cmd: `${this.args.join(' ')}` })
this.emit('error', { code: code, cmd: `${opts.ffmpegPath} ${this.args.join(' ')}` })
})
}
kill() {
Expand Down
9 changes: 8 additions & 1 deletion src/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function video(db) {

console.log(`\r\nStream starting. Channel: 1 (PseudoTV)`)

let ffmpeg = new FFMPEG_TEXT(ffmpegSettings, 'PseudoTV', 'Configure your channels using the PseudoTV Web UI')
let ffmpeg = new FFMPEG_TEXT(ffmpegSettings, 'PseudoTV (No Channels Configured)', 'Configure your channels using the PseudoTV Web UI')

ffmpeg.on('data', (data) => { res.write(data) })

Expand All @@ -29,6 +29,9 @@ function video(db) {
res.status(500).send("FFMPEG ERROR")
return
})
ffmpeg.on('close', () => {
res.send()
})

res.on('close', () => { // on HTTP close, kill ffmpeg
ffmpeg.kill()
Expand Down Expand Up @@ -73,6 +76,10 @@ function video(db) {
return
})

ffmpeg.on('close', () => {
res.send()
})

ffmpeg.on('end', () => { // On finish transcode - END of program or commercial...
if (lineup.length === 0) { // refresh the expired program/lineup
prog = helperFuncs.getCurrentProgramAndTimeElapsed(Date.now(), channel)
Expand Down
4 changes: 2 additions & 2 deletions src/xmltv.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ function WriteXMLTV(channels, xmlSettings) {
ws.on('close', () => { resolve() })
ws.on('error', (err) => { reject(err) })
_writeDocStart(xw)
if (channels.length === 0) {
_writeChannels(xw, [{ number: 1, name: "PseudoTV", icon: null }])
if (channels.length === 0) { // Write Dummy PseudoTV Channel if no channel exists
_writeChannels(xw, [{ number: 1, name: "PseudoTV", icon: "https://raw.githubusercontent.com/DEFENDORe/pseudotv/master/resources/pseudotv.png" }])
let program = {
program: {
type: 'movie',
Expand Down
Loading

0 comments on commit 5979ef8

Please sign in to comment.