From bac4b191b26bc45d555ed7416db3c2c523995b8a Mon Sep 17 00:00:00 2001 From: Dan Ferguson Date: Sun, 10 May 2020 23:37:31 -0400 Subject: [PATCH] 0.0.5 - Bug fixes, subtitles, Google auth, channel icon overlay, dummy channel, other front end shit.. --- README.md | 54 ++++-- index.js | 62 +++---- package.json | 4 +- resources/font.ttf | Bin 0 -> 172064 bytes src/api.js | 40 +++-- src/ffmpeg.js | 137 ++++++++++++--- src/ffmpegText.js | 50 ++++++ src/hdhr.js | 14 +- src/helperFuncs.js | 43 ++--- src/plex.js | 6 +- src/video.js | 60 +++++-- src/xmltv.js | 32 +++- web/directives/channel-config.js | 31 ++-- web/directives/ffmpeg-settings.js | 28 +-- web/directives/plex-library.js | 69 +++++--- web/directives/plex-settings.js | 4 +- web/directives/program-config.js | 13 +- web/public/index.html | 8 +- web/public/templates/channel-config.html | 146 ++++++++++------ web/public/templates/ffmpeg-settings.html | 22 +-- web/public/templates/hdhr-settings.html | 1 - web/public/templates/plex-library.html | 2 +- web/public/templates/plex-settings.html | 14 +- web/public/templates/program-config.html | 32 +++- web/public/views/channels.html | 7 +- web/services/plex.js | 200 ++++++++++++++-------- 26 files changed, 709 insertions(+), 370 deletions(-) create mode 100644 resources/font.ttf create mode 100644 src/ffmpegText.js diff --git a/README.md b/README.md index 0b60292..2c47efc 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,63 @@ # pseudotv-plex -Create your own Live TV channels from media on your Plex Server(s). +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. -Simply create your Channels, add the PseudoTV tuner to Plex, and enjoy your fake TV service. - -## How it works - -FFMPEG is used to transcode media on the fly to MPEG2/AC3 mpegts streams (with constant bitrate, resolution, framerate). Cool thing about the MPEG2 codec and MPEGTS format is that files can be concatenated together without messing up the file structure. This allows PseudoTV to support continous playback and commercials without having Plex trip balls when a new video segment is hit. +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! ## Features - +- Docker support 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). - Continuous playback support - Commercial support -- Docker and prepackage binaries for Windows, Linux and Mac +- 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) + - PGS (fast) + - External Subs Supported + - ASS (moderate) + - SRT (moderate) +- Ability to overlay channel icon over stream +- Auto deinterlace any Plex media not marked `"scanType": "progressive"` -## Release Notes -- Channels are now created through the Web UI -- Plex Transcoding is disabled (media timeline updates are disabled too). If anybody can figure out how to get Plex to transcode to MPEG2, let me know.. If Plex could transcode to MPEG2/MPEGTS then we might not even need FFMPEG. -- Previous versions of pseudotv (I think it was the first build) had a bug where everytime the app was restarted, a new client ID was registered with Plex. Plex would fill up with authorized devices and in some case would crash Plex Server or cripple performance. Please check your authorized devices in Plex and clean up any PseudoTV duplicates. I'm sorry I didn't spot this sooner, this may be a headache cleaning up. -- Fixed the HDHR tuner count. You can now set the number of tuners availble to Plex. +## 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 + +- Internal SRT/ASS subtitle may cause a delay when starting stream +- 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` + - NVIDIA GPU: `h264_nvenc` + - MPEG2 `mpeg2video` + - H264 `libx264` (default) +- 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` ## Installation +*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..* + 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). -**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 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`** #### Binary Release [Download](https://gitlab.com/DEFENDORe/pseudotv-plex/-/releases) and run the PseudoTV executable (argument defaults below) ``` -./pseudotv-win.exe --host 127.0.0.1 --port 8000 --database ./pseudotv --xmltv ./pseudotv/xmltv.xml +./pseudotv-win.exe --port 8000 --database ./pseudotv ``` #### Docker Image @@ -55,8 +77,6 @@ npm run build npm run start ``` - - ## Development Building Binaries: (uses `babel` and `pkg`) ``` diff --git a/index.js b/index.js index e083ae3..cf3e95c 100644 --- a/index.js +++ b/index.js @@ -11,23 +11,15 @@ const HDHR = require('./src/hdhr') const xmltv = require('./src/xmltv') const Plex = require('./src/plex') -const helperFuncs = require('./src/helperFuncs') - for (let i = 0, l = process.argv.length; i < l; i++) { if ((process.argv[i] === "-p" || process.argv[i] === "--port") && i + 1 !== l) process.env.PORT = process.argv[i + 1] - if ((process.argv[i] === "-h" || process.argv[i] === "--host") && i + 1 !== l) - process.env.HOST = process.argv[i + 1] if ((process.argv[i] === "-d" || process.argv[i] === "--database") && i + 1 !== l) process.env.DATABASE = process.argv[i + 1] - if ((process.argv[i] === "-x" || process.argv[i] === "--xmltv") && i + 1 !== l) - process.env.XMLTV = process.argv[i + 1] } process.env.DATABASE = process.env.DATABASE || './.pseudotv' -process.env.XMLTV = process.env.XMLTV || './.pseudotv/xmltv.xml' process.env.PORT = process.env.PORT || 8000 -process.env.HOST = process.env.HOST || "127.0.0.1" if (!fs.existsSync(process.env.DATABASE)) fs.mkdirSync(process.env.DATABASE) @@ -51,18 +43,11 @@ let xmltvInterval = { console.log('XMLTV Updated at ', xmltvInterval.lastRefresh.toLocaleString()) let plexServers = db['plex-servers'].find() for (let i = 0, l = plexServers.length; i < l; i++) { // Foreach plex server - let ips = helperFuncs.getIPAddresses() - for (let y = 0, l2 = ips.length; y < l2; y++) { - if (ips[y] === plexServers[i].host) { - plexServers[i].host = "127.0.0.1" // If the plex servers IP is the same as PseudoTV, just use the loopback cause for some reason PUT and POST requests will fail. - break - } - } var plex = new Plex(plexServers[i]) - await plex.GetDVRS().then(async (dvrs) => { // Refresh guide and channel mappings + await plex.GetDVRS().then(async (dvrs) => { // Refresh guide and channel mappings if (plexServers[i].arGuide) plex.RefreshGuide(dvrs).then(() => { }, (err) => { console.error(err, i) }) - if (plexServers[i].arChannels) + if (plexServers[i].arChannels && channels.length !== 0) plex.RefreshChannels(channels, dvrs).then(() => { }, (err) => { console.error(err, i) }) }) } @@ -97,7 +82,7 @@ app.use(api.router(db, xmltvInterval)) app.use(video.router(db)) app.use(hdhr.router) app.listen(process.env.PORT, () => { - console.log(`HTTP server running on port: http://${process.env.HOST}:${process.env.PORT}`) + console.log(`HTTP server running on port: http://*:${process.env.PORT}`) let hdhrSettings = db['hdhr-settings'].find()[0] if (hdhrSettings.autoDiscovery === true) hdhr.ssdp.start() @@ -105,34 +90,37 @@ app.listen(process.env.PORT, () => { function initDB(db) { let ffmpegSettings = db['ffmpeg-settings'].find() + if (!fs.existsSync(process.env.DATABASE + '/resources/font.ttf')) { + let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/font.ttf'))) + fs.writeFileSync(process.env.DATABASE + '/font.ttf', data) + } + if (ffmpegSettings.length === 0) { db['ffmpeg-settings'].save({ - ffmpegPath: "/usr/bin/ffmpeg", - ffprobePath: "/usr/bin/ffprobe", + ffmpegPath: '/usr/bin/ffmpeg', offset: 0, - threads: '4', - videoEncoder: 'mpeg2video', + threads: 4, + videoEncoder: 'libx264', videoResolution: '1280x720', - videoFrameRate: '30', - videoBitrate: '10000k', - audioBitrate: '192k', - audioChannels: '2', - audioRate: '48000', - bufSize: '1000k', + videoFrameRate: 30, + videoBitrate: 10000, + audioBitrate: 192, + audioChannels: 2, + audioRate: 48000, + bufSize: 1000, audioEncoder: 'ac3', preferAudioLanguage: 'false', audioLanguage: 'eng', - deinterlace: true, - logFfmpeg: true, + deinterlace: false, + logFfmpeg: false, args: `-threads 4 -ss STARTTIME --t DURATION -re -i INPUTFILE --vf yadif --map 0:v +-t DURATION +-map VIDEOSTREAM -map AUDIOSTREAM --c:v mpeg2video +-c:v libx264 -c:a ac3 -ac 2 -ar 48000 @@ -145,8 +133,12 @@ function initDB(db) { -minrate:v 10000k -maxrate:v 10000k -bufsize:v 1000k +-metadata service_provider="PseudoTV" +-metadata CHANNELNAME -f mpegts -output_ts_offset TSOFFSET +-muxdelay 0 +-muxpreload 0 OUTPUTFILE` }) } @@ -155,7 +147,7 @@ OUTPUTFILE` db['xmltv-settings'].save({ cache: 12, refresh: 4, - file: process.env.XMLTV + file: `${process.env.DATABASE}/xmltv.xml` }) } let hdhrSettings = db['hdhr-settings'].find() diff --git a/package.json b/package.json index 315eaaf..a061782 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "dev-client": "watchify ./web/app.js -o ./web/public/bundle.js", "dev-server": "nodemon index.js --ignore ./web/ --ignore ./db/ --ignore ./xmltv.xml", "compile": "babel index.js -d dist && babel src -d dist/src", - "package": "copyfiles ./web/public/**/* ./dist && pkg . --out-path bin", + "package": "copyfiles ./web/public/**/* ./dist && copyfiles ./resources/**/* ./dist && pkg . --out-path bin", "clean": "del-cli --force ./bin ./dist ./.pseudotv ./web/public/bundle.js" }, "author": "Dan Ferguson", @@ -27,7 +27,7 @@ }, "bin": "dist/index.js", "pkg": { - "assets": "dist/web/public/**/*", + "assets": ["dist/web/public/**/*","dist/resources/**/*"], "targets": ["x86", "x64", "linux", "macos", "windows"] }, "devDependencies": { diff --git a/resources/font.ttf b/resources/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1a7f3b0bba45b7470a4240c3ec67595eeeb02192 GIT binary patch literal 172064 zcmbS!2V4|M(|32z%q~e;vLeC)0wx4OzOn&2AE+g< zYyU2T=@su^u_JD1 z?*pDY_3SsYN0|5YorF{?Pw3O?y}I=u(QW#$1%!CU5+W7r)xAr%yw%r+;N9{lAKeQX z4(}b#A>9q>QoZ^Q8}aF4lfOZ`9U<T}BMj))bskeg?|x z2XyJ*orJzPMVN0dFre3)sAz>ZxP7A_$#R6S-UoREi z*}3{(q&S+v@AL)4Nq!sk9;;5K3uOsI`QCs(0L=jLfJ%Ug zfFwX2KrcW?=0_&c7o>vdLVgfOk@;d-GC_Dos%uM=_EHPtDmjsbQWeres!A4$(*WI( z9zyy^JIO*;o2(NDlTgVK`7OypEyc4PfN3aSQo)I$jAu7UL-9V!#gMU5C~?&~kZ?&y z%7~dnD_$i{Sw%8MXiMCIorJz5N?1Vzwvbdro$bVlWQ-UN`lkRIkrwP02^D9O=4f{$ zb0lLKHSZBafgQ;#&1aMyN=AxvP?o><3yEhL!2YBW+f3}lA!NAl7x9!n5r0ub{Df@c z1l*kMB$XK>JAg|_%}5gSCDX*Qq?@>hbdpw*j$$lvqVQ{sn2z*E{sdtY=y*apN*N?U zQ;sy%v>`pg^V-^}=FegrX(CO**j)hMUXU4@6QsVliS!iblOM$y=+_c5Nz5VfkQ+bd zP3DSA$sDm831IQWU;35ILz!{f-K3kgDrwK0$S=|i(u`%8pGhgCt+)#BttVr}Ph>a? z2H&ca1mQVZC>Y2P;Q{C$gT6bGiOfhwuqLF8aEFW%{73`Vk4z#YZw?`*PQaL3rkcQ* zPbMGMk(@<6J$e5ihs&j7q_{K+vQwGp#d)NkluDKZ*OT6phSC-iC$%SiF_x{xvt+SY z6lG?RmSQ60+naRZw2Qx!p==A;EcPLuq8r8_7vnvHOb}x*=JNodkkdpm0lbTo(n!2! zA?YFRBFW-tbCzZ>iIij#ASIAqb~8w*-CVL<)1FjBy9*>cGEbu+rL=2N?=8|m`UCR0 z88YcWs%SccFJDk*CYhsMPL^uFkfj=LQcUv&{n3(nQd81b+mfsi{|3EdNqccFnJcs- zQ^n6DM3YQ>MNiTM<1kGefbm#H{51mb5~Ps_c?*=TqmS2-?m;?h=8$Qcw`82;Mf@}a zQLY!DI%%evg1I+{gouO9_mOU?xk`LB&+yJn^E+OTwgF@z9`e-FoQb))R71%$%uOHg z!a-Y`Y|})Om6{yzz=FM8|ncZ}U9jJ2MOv-2UI zn(M?@N=N!DnJbltTy7b?j$X^XjY1B~!eaZmdg7Wn+PJfYcsJkcH?gD*NMyyNx zv=uQvgGjLS6|(h!be4ue4u+Cp&@WRor7(`C%oinp)I9=qmqyu=m;*b}CgeyHg}S}b z#yGN2GXgYV9*7$;b{jFD&yh;PPL%J7c7_o@jB#_#N7764kaW_tAl0SPBupHQc~=v> zIZA44R+3n)3H7WZ!zB^#mnW@2w?Ep8lUk99ng*z=Ch-@_gMN2H>|n7hm>qx~cYr>J z1rx{PJ{lZjma(c`2mJxn6$WfB4F-cWES{e%)ERdB-llvf2tmx0Nh9{3Efu`?Up1}L?7sjlHheo z5)P;ds0~;QNI-kFFn=Vm6YWK6#QVaSZS?hqZ z?TCX$kG!6M38cDa0q_jif&k<%KpiVl#v3qzl#)JxrgrH2Y4m*&>O(z%WavZ(@fx1- z_Bh?VFMpG|cG0No4Ji%&#&B5y!~>cDq5+Knbum_8UOq8vLdJd7+QXKSRY0NXo zD(32P=;VnQZ%$u4^ieYGj6IWJSAHi+&><^DM>0xuG&crL;=p;xpK-`<=eun~PxY17 z0;Zw8OyDQ59VN&TaS|CIwjs{qQ4%Hgh0dx#e&lu0U8I9%DQMUY8=^BC(Dy2UK7jIo z9)PZZD8N8K0)YEKPq{5rpalG_66S9VSn0k+&N6 z@JZm0G=prkmju#LI86jiUGqoL9((|=F@Gv@8B_c@_-9gE^WPlAx#k<(Ct{n;FBLzF z`&!=v_+E{#XI?Ht*(s z2Jk+>)&l>E`&iZh--`QJ7T~@W2i_;%-hW`;FSN&f%kN_Nn~>{xrO%um-uM3jbDxy^ zh5r@9UsZg@+U8y8$7=BH67T`w$H3qt@q+I|fLCgE!LN0Kp9J5Q%Z1|K!pB5E7NSf_ zK5nJp-^nZmzaX>tIB@>_8;e8D8~C_ze*GJB|5))+RUDt6uB`aX@LT^^tjG|2TWfrk z*zs}aWAT5*&^6(TUksmI@r(0)bM7B=AKe;rKb8BXil54T(oyD(3UD2Zx&L1Q`hn{a zYoK}NjnKD~fj0wI^0}huD6Xfhf$MN<;5y#AE!3^(9}6Bu`dGJPxfh|+Z2)>6?al{m z1snk_9)L024k-43>nbZy=;Jj0n@(<5EWquBHE_OIz`74s_lm9Jed54vSUxE8W}5s$ z+9`ivwdGuCnR$~GCud0m%|^DxJe@!1YcyqkV4N)LGA^_KUXO7Z;W|LV+KcNAMIUfq zocrJKnHcxG;afw`%~9qyU%Ozvgt7NSTj|O(KIc(J@w@q)gwM}qG+!Sb<8y}F2Hw5| z-@1T4UJm6Y_}vO!n2&re@b!VRR^)mB^l{oSpV}#No%__hz5F#`{(8-iKU4f~zOLhI zKb`MSCx^jfevmHSzoCcb`D_|4nTr`1A-vUb6G13C#l zwD}_<4Dt5d_Fyf+{eO!dQ+Ns=oAZOOH8fZs@Ow+W7HpYA7QLqUr&y0+{1Yti71Rx$ zVN9lR-YM9kODul91!J9p_nUFP^M3vZ#`;ECgJ4~wtUa)%w$Sq(tP@+BmwhMy`}+L9 z=y^;3{yR3`6dRf6{I}}=1z-uADkZWZfn9qMcXSn=Y)-c>INm_FT2QkU~L1<@wB2_m(730i1Eb^qx3(P}h zu68GkuM^&;6ki4LAtgqWk1cc9VuPe~*+gGYHdhfZn12;V$S=ir=Jm=m_@G?h zD>_us@9^j0+jBp^KyP#ZpX=oOwSr=MaIe@2z7~M~h8>v7^DVZ3`{xDqbDO~1fd8)4 z%hwCsUh%a6ubbN;UO(0$ir>wj^E|Yn_~YE~=l(ulGhBr%aG#OCk9N5&uz*rNe{L1b z5!gN6HvF;?L|IBoI(tVE&I@CLM$&4SAc&H3kt{#Pa3|Vn@RKBsMvyd;l2B51xH6H6 zqM#JV6~&nyPYC!YY9&z;P&Mk%NK7MYMN!hCuprmCrB&SMA0jq7}sZs~%OYJw=M^~4LYQ*FM8ccAEJiw?VM?ijF;RvX zGKD$AWtfxA1f}Zu_y6t&=k$Lo ztK=7qE9m6^_}oxtAv(Zs6}nVjC<*=&2<4T6RNJj(3m2{GuFZKPwcdGA4-(24>eogfDdPlvB-b3%J5739`!}XE+s`~2sIQ=mF zc>Q|)7X3DTs{Ww#wX> zey`7>*LTossJ{GOPeHHe2)_#JgjC_6a6!0=UK24`3>WK)O~tO_AaRs9LtG=yim?N0?h)sGINY3~&^18Sq3cYkS2m=68PVB+3K+e|~H{o4_WrNo+Ek zg59jqY%ZI}=CcLtSGJH$B9qx7wwNtpOWAK^3Yp55vE^(9Tgg_j)npo(&bF|vY#ZCo z_IqV&K&pu!u zc^>=7KCxW(C;N+iW`C3UWC8n!ePLhOHM@|bHgpK43B9&(`*UytQa)DeV>B1&*iCh+* z3ERmvVF$S`?1a`z6^!Htxk+vbyM=6F54kPuC3l2l-U;t%6pf}aw6ZuwoGN?}K8nM|5yB@S7ut8a zIG#49O~kR{IN?v>FX1!&iN@2Wv>9yhiRM;` zSwRupbKsUs58yKpZas9g0*rh6&?c}`gmeXLSAmTL-T{C%BhVqx<%FC;)!1*sSgSA* z_#EI0@}~jw6BYo5-92R=>K5+j;{G<^4qy`CF5n^Z7Xd#4JO)ewWCF60kGTy?sRFO_ z1>imMIgKCkVLI?fz-Qz`vl5&RA^!ko05~t8JDCAk&If2zVuoIEM*bdPoeG$Fgu1AJ zIY_800GgDce>7MHG7C6F11h6%G?94r~;V{%=KOj@}B}%R)IiQ(JFvgLz!Ul-paJsH584pGcd6zBHwH9AKKetU^Ke3iU|tj263`j>=o3u@bit593h2*( z?zrcD>H+A9GGl>z0Wj9s<0BMf#({w6l(!8ai-8xYK$ZZn0dO8K1>OnZ{KHt#4=M;4 zEBaLhHWe5ai38*B16qxe{Kvn=Js6bW%LxwpBkAcB= zb`E7$0jH@zP(Ql^fXr|?Ww|PlO?U@c0>$MIU?eyY$b(?70@(`etOA#BAy5S_;{s$3 z=Pnc(hb|-qFdg>*g8mDTCjqj<(>P0`0#9RHp)H93nGrBH(3u2UlnCH2v?dYe0l-HN zWEb#n0Ps>NyBrumb_0VK0(hXjhdv7c0{IkH=L4^6jS2+b1oop;;B~K4f$Rfb57+?U z?QB$m><8vN;=tSFJlc%<4*+u>@&57lIo-%3hky^}1FxH>0pv6=AD<%t-o{ZCxGoTm zm`-r?(g4zMglL}3o(IpNSqSa6Te#OT=QxzXx1g1egA4@S#1+I6+ zIx6t773%`xQU5={O;r${12>g$hDCa7z^^##L+uXbT!3GhzauJ@gC4 z7<(ZKaM=+%svx`o?xX^jC$Tf23(9MOf6j-Az+C|Yk?#OJ2rwA+zXTovNJ73Ba57*x z@;N_8sDN`;L>#Gt@D_L!U>eHvF`NN_4&XKcaZ?p00M7=@M}B$W1%O`xlK=|=OORg? zcq!mFw8h708DJ&y`53MOVE&6!0BZo4v)qP=TL4>8{sZtfz;*y=75N<4iTqE%20$tR z^x^CT5f9>BK5m%D3XBKFTo#WYzcKJpz%jsBz;VDy)bl6sDFDWk{shd&EFHjkz{le< z@>>I60o+FUzk%Au#4C2MW2<4^x3I0_Jo8=wje?DsVa0uUCOC0p1AMf-;a( z{ZniO!Ts+92Y^(dXvZIY=Rnbpzo!ax12Fo^ zfuc?SU=;}J@~@x*-2{xW_wR%m1u1-?QLsILOfdys%c75M5spc|k&%I_g02xH8F?t^Nj0MJ4A!wo&90$=ri zL;g1r`QU+URsrW|i8&8oLO#kGNclzv`=)JEDV>wBpPHu{;!3943!OWK8fbaFzE1Br z15FGyu<{04)<4uBl-Jia2tjq5w+&3tr|44}bW73K)%WVs%^(IT7!SIqB!uY=q($4_ zxVCKTZ-`AOQE=NmA)#uhLFCoo4U|qvKm~pBD*#rq!c3tCseB{7K?rWzwpm-lgt!uh z*tmoe{{H$phT~1!8ji=6@J~nxHE0TG1g&Fx7gMR#mN#h1h8pbD8d|h9#Fj9Sgp?Fs zUyHVZ{)P!DDJ4?S155h2ZF)Z?|IUcD&HxAM?57i&qAH+3{}MbS&_B>06eh%l8tltA zYSFe1Nc0DZ4&@Ey>x3E{%Ns(0oXV$$&>8xa7Htp2!nx?W-;T^^+4cY_FT5O-P{I%h zV)Zlj>%h1CJl@M9u&Q-&M zO6Z7PIkJydu29O`1-JXyPq7h!9{f(IU#)__JHHbP@}%(6ex5~no~CQFA3{s;J8f*G z{CDlzH>_HwIM1`6-0i2Tf&9*4_|J`_{rR2a{NWwcJg4NuM$sjCUXk*peB7P*UC|$7 z%K5qCju>@CwIEgNHRL>@!CK=Px8C>{Nkra;m-UrmtU^%iCY1;bQUD{*Xi`v(Au67memfF{~pKhP)P|sn$!*xdo$G(o6 z9Zx&{||JOcu;t)@OI&A!v6@r5^kzEqT z=-BAp(NAKk#cYd_E4Qt@w@Q&J&8sY^Vy@b}>aJ?#tBtAlsd}sGXKGZhVXP_EtW|Sa z&A)%>`oq&$pV%I;+iUsNYE^4-tsAvV)*fE_!H;ErTob2{8y)woPSZNW>s+c^weG>X zx%J}e&8l~+et7-P^?zyL*`RTQIStYqx-{(3Fs+e$qiK!IjT0JQZ&JI-{-4VHH0P%a z@nz#v;&YphZ2GNP{boy=3(W^Nf7YUPi_Dh2TiLf-+1jb~@YaXh2yF(ox!v}+gcb>x z+BIpnuHE15%eSxJeoXrX?f>X7ro-!wQb&EqnH{q_HS097)0WP(bCb>qox67)+<9#0 z>xsdM!xJwh-c8KzQm4zpE`R>q=;sGrdvzVwbwby3-5k4lbqnm4-0e(vyY3^qf9cV# z$Ic#ydYtPS+;dXTIX##4+}P9D%e&XuUUz%F?DbD?vA3>wV(+v*&HJ3`8{T(mUsJz6 z{ciQI)_?N=X+YZnTL+j14jVXO;H-g%{)d0323{O^bKv8Fe-H8=RDDo~L8AvvAN1>> zvxB9RgD(tOHe~ORYeTY!d>LA6=$T=?hJ8+ANf(mClMTar4!=C2!HBgZ zT}P&lavQZ}wB6`_qo<8tGy34@8)IsX={4r}G5g2ljGZv{)VR2DQ^x%|Ztb}H<6e&U z93M8m+W6Ju|C%swqR+&+lM*H+Oer!Yc}m)p+^N;4{yr^uTAOJ{rw2~&KRtIwgBhb{ zoS#W&M$8;N^UTc8DPbw?QqKJ1`^%_bPR}YntNE<;v(C?UoE<&8+3am|9Ou-Yb6{?% zxzpwv=02a-Zr<#9cji0H|7re_19=I(l2=R1E$y~+-O_KrX@6_^+r?!amKm1iE>Bv1e?_eo>sLmtthMsjm6@w5tQxc` zb9LR-8`qRvllpt*-!s-eW#KXuspgj+Z-QcP`zTY52j=!*JV>liEM^no%&i8-t9MjSYKN}9yoij z82;%G&OgKsbvv}_u+!nd!&MJAJKXi~=)-dkFFU;P@R7qe4!=1f9PvI<@ksq6iARPU znR#T*k$p!lA9;SnbkzB1@X?w_TOI9pbllN}N4Fe3arExd?4uu#*&Xvf7JjVWv5v=v z9!oj4_Smjt7mhtR_UX8Ayu|T{<8jB^9Upvr^6_QIQ;(lKe)sr?6YWo!Pr958JX!T* z(~~_X{X1cAdF!=H{8qGk>2I&N`nBK3n5#gR`y9_B%WI?A)`<&l=92 zIeYc&!?S;$)0}fX=X);dT-|f+&kZ>@`P{N|sprzpWu41CFP(QeU-Ep|`PlQ#&v!dN z`uzO!E6;B}zvujk^ViQmJOAN)UYcE+ds?})n6#hLx}_zj%}QIBb};QyT4vfm7aTA2 zxp3*ivkTuYx?U`OG4^7civuoBy}07yj*G`G-n#hmqB-3&y>5DP`n2?w>ATY}q~A}^ zz2tbw>r&vQs+XEw>UnA0rA3#vUOIW{-leyfh07k7%U!O1x#i`)mnU6bdf9OK+~tRt z|Gd)S%780Vt}MT@?aGlW*RQ+{}2BVY=#mwcOR{tBtRAy*lvf z)T{HaZoF!|ns)W()wfqo*W9m#T&r@e&b8LpdR-fLE#=zsYn!eext4bA@wE@vwb#9` zhhCq1edG1R*RNlHeS_Zcx)E@r!i}mo>fUI6qtlH(H>Td0ePhv$l{Yrr*nVTrjUzYC z+_-e(=8cCpvTx+v`0Hkon?W~YZZ^2t{${_M({9eWx%lR)n;UPr+$wV`_Ez&--EJk{ znsaNzZTH(gw=3PQemm}V``bfqkGehScFOGqw>RHTy?x;JiQ8$nuin0UJL~qV+aGU# zxud&N?2i6U(w(t)rrud`XV;xWcTU~8f9L6)uXlBKL+;kR+v;w=yHoD2xV!6a+TDkD z^X}Q*^S&2wugbkf_uAa+dT-Rd`S<>~ckJG|dsptgxM#lac;D-O;Qg@s)$Z53AAi5i z{m%E3@6W!!=>E3*r|#ds|LOkM2kb%d2VoEDJ&1qMO8aMZ*34>vzN{_xtvrw_k9a(z_xQSC?V9u0mp`_bk{sgI64N_%wwQO;w{ z^TnLRVdW&W1AJM(yEdgi0d4_PeB zEvtOik69hC1NTeT+N^_FSF_$e(L5>kr0kREC$*pa^rYRB!A~YXS^mWMDs3Uo@P9K@l<~1@vPjlm}fsei+|SsS^sC_pDlj2{n_bf_n&>r zw$IjQM`zd0{wcd%c8}~4*(up8vbSfS%f6odIQvcZ-_M2T&d*Cc4|yK;eDQPBi|Q}N zytx0e+RJG#Z@vnDHS^W{S1Vs_dbRV_zE{UyoqKiV)$Lc0U%hzs<+bDMfY()CH+$Xt z^~Be|y-t0d_B!kJmp3kN%Dk!dCgDx@H-q1deKYgTqBp<4+5P7DoAfu2-h6nI_tx&M z`&<3n@^34@jeFblZLhbZ-p+cv^zHh$hPQ{`o_~Ae?TfcxavX9za{_WIs&EEBT zH|pJ_cPa1IzT5Kd@Vjg8?!9~R?)AG*@9p2ayf6OV|9zSF72j8RU+aB?_qRVZ_^|cE zt`EmPT>bFm!|M;9KeCTSKYD)*{uuGG=EsH~TYvod!mJR>r!bX@nu}(8sC&I{F^C!Aap}z>JZqyWY=9Fu62KqfZ zoj|7(=uFiVF*uZK>wl-jp9v^wpkd(^X&{=f6dmE|;jRe?rsJ-9Q6hh7IH6(vDfQ`g zQTTeQN~1N#_bBOR4i$qn%Sm}M!B{r50=n>>?%Si2_LlAk zA`ximz8(oZ?|yM7J@0;TT`Hpm-8VYh2l8AeU8caLlJC1%D+$FJJ zUrH8qi@tJT_1T-b#8~*XeQddv$5kyHnGi)7ovm=633& z=ZCZ7QU+iSb~V41W=dzUQ|V1YNEE3;W*eod)i`~U&fu28uO*agY2_LX*^Uk~R1Q-{ zUlBYDV}ihoAkG*_ou1V?!(osWvD6b!~-#^gWJTR-7ElR~Ih*DWctHg8UuzH>{HA8IykGOiJG z-7$T}_D%B3ty|)2#y0q=M$INNcIwZK6_-xgym@B*$$xB^rK!`ZRf7g~TDPf}moaVQ z#@Y2IZQe9fifhxNQKPyoTQ>Z&zBr^l^i^wc%|$wmQ%FIiB3Wjv5E02aRzYXbW$>#n zxWqM;jo_33e@a*crx+5&xZvnZaA7c(wlBevpfAmlt~8e>qnrB7#jO}m6))z-k*7;> zAVUdVYRN+BG5VEM^rpQoHLNgKVP6b{M&%S_NK2!mB6V6X{}7G7loSy|wOqgicdwY3 zXmAz0Ydv6Xs~HmAcq+b4A&Cv0gszH#xG)>WE8$xzZ< z$fJ&m_VWCm?#fqI)X{tO0co;45@#AInIKnWYw=yLj_8b97gzM27{o9`5vVq|O0KRk zUN|GG)wz0UgBhDJ=EJn`**op%)@9+-K8|KhU(nUGUhO%3NW~kSd*X!nPskbOsneL2fL!w<>qI4`IB*xR#)r&P7_0RP1#XFbI@e7~uVS*it zeI$34x7V6Jj6S3hUeuGOrTEOKDW8@{X7HYtU`>Q!(5d)-K<%lBAs3a&l2P11!ipK} zf$hVJp|zkGNr)7Jyd*cRAcWAy@|74`0g((^CR)C5e*SLb0wKNa<|NuyUORMKTlsSz zs+V8&;H|`w1!7roFL8wKMrGV;LIyO2GGGw64)yo&cL{XykMehkWIN~>dCFUP5*_ze z@P8!7)6_>iI8BLz2*Hs zwVz)1$j&}DQAa&y&swrem?N$Pwg{2d0u{i?i1KGGO}VTHvqx}=lIiBZ=vst}97v#% zI65gU@_C~Ht2CG$sl>W%su)P96JekRgJ$3`f zRSjkF6~Zfe1=7e9$5@SHV>O}Nj`lXc6$3Dbi-2?Wje<`}w9ZwROa9z-01XZn-KHoy zK6f2-sV;?GQnXrO50BctT-`#H8Kremv{sB5@aDtY_rjZx@81ZygGLP> zBn%mqG)Q3G<+Jh$9BiqWN2}7R@@4so`=w)hj>~(~&mTC$xrE3&GfR8mB~?`=Ndjq- zg|tEk2zxH*f*6)66q01baZ}{N)d_TwqJkos`IEeyRrV9-kGgafbvJ|Mj|CTslcq)& zZ?1#XCS1^j%YQT>xNzsn;G#>lw`#&u%_Y$Ag}L0h!hxN9tpZ~ft!QiLAnGs1=7rMi z-U&%vlPBel%=-1lU!!NqE7VLmI)g@M3yl`-YNXD*7x1f$ev}S2uBNo3@dw-)oOP+%Li!9;ms+|oY4j*f`D;+C z0fo63(8%v~0oK`F3=AlhZ;iR;45ZT*4w~G5(9h#?hu@rX@5|V(BgV?P_pix+=1%NC zc+!k%bA@_zNWWe~2e%)zzvul^KW{Hz#xUyi%glp`BSs7vItCJ131iU~^6LPd(NG-* z8v~*!5Nxa5jVkr1cE&MKmL=iqCz(;F& z)6ycGHf>m{cOf5*lGdB&7SW};TjjdA^IT&|Z?1cxTil?g1c-^NhdTjxLn1vr;p?b& zNxLInC~7)fy8HNy7iRMKy!^%SP0=yk28~S_S-V3tyT%?}lh;?3KW9CXzdSwIXYiVo zsmlW+!PO-6CPvyv+~M1HH+ty(IUyc8gJm_L%%A`06@=MJbs4oJzgOr9zf1Kf>;~^u ziNYip?h%Ls`vv_VFe3PS0s-*g+&v?rb-_Xx-}FDdlJ=f>EPuOkPyR@gXs5SLr~1vf zGj4*kFHN|2ezg4I_9Hn5F>|Q}4(u9D4cawoxc1muYPS*NQwMSqjq%Zt$nWR_Wt8~9 zNVWrmuQU`cQyR$iuo!JRXl8Xx&ca8j%-7pu&MD~ZUimuFi}+)&Ww_D4d?@FZz0Tmx z?TVpPzHaou;ConjrpPE4%QE&JymT4NyfSpK&G-x6W$?)8Tt*QCSSY_jhG8&Lg9?-2 zACyGF41+stabN_+?c+Qwyc5}g&O=7ad3Wy0-^L8;)c-^Jr4QF9-WWgj!Dzn$2mAFu z*k26qyD2ruRUG312@Lt8CJ}CIvNR6ynN_N*TT+m<80-&p|9|3 z8T>Oy3vuz#5h*YV8b^qLk$c{qCW1I0EG8>YlTi61g8t8 zIXLhF-;Zn%GQUHOV%Jq_f;cTv?6qmJkeIiIjd}WBo^?W=^&ZqzH~%Rt#fTOofh5sr zUn+>pCq~pKe?)E8wE+<70E}p=PodMn{V5V=6p4<%sk60vPC6yj;GsN3H!zA8FWMt8 z-`wF#C#_&{zp=LORQr^7>5lDM_s(TGr_!>Pj;_uAZ1_VgR{HhmwyCR*l&(>)Q`asn zQZJ|PTeoUtqj_>#wFc_apON-*HO*aV9*HKkv0AP6V;rZcn$8f2-joe9L|U!M`26RN zlpXqH$E8$?rhD&?*V*8C#g-f(uV4M8lV5 zG10CNUr#SV18p7SiX#R1+(_dp@{|`ZQ7RsR1n~wyEScwZ~+Qi+n;pep-r$=<+ z=P$IUF;6Jcuvv7XZ)il=z*$W5RerpzapMnZ>!@aK+1jQ{XYcQzgXxUZ^6Z?C^18jH z17?=4csu<%4aWBndp_OAHvqF{%KXy@$3AHkyO z3Uj&H_AN|?SB!M=j}Up7LDjqzNm$;HpnL-yxRB=lOtYnFya}5CQ-ObN z8!F-cwUryerH(rWEF`KD7boHs7|aEU8&)n=;u}x-#+M!P-}8h8)MeL48eA;T_18HY zQrYHpix#`nd#~hg8)$gijLWp@7WwP@mA`y^HSz5~(^l~H0O$WT@ZS;ozrK-qDog|4 zJ@R$MclplQ=v2r?&g3G6$$YN5B7DKbK*5F6$i10`bjJx=Zv6)N%9)KD&fR2}PfLbv z^6B&jSLCx>#An~0e|gm`=PR@yr>U_*Q!`a270I(0-U5HnQKR^Sh^|?ySA4tmwNQ*CNYjpJEQ4qCJM<_B!OUDbO z#qobyjTwC%1upo$VYcpBkcPYNkRf@=N1B`T1`Gtxiki zQs0vQl$F11Nfpkeo@_4PV5N`r?6Z+ZT^>Rk(xD%oQ0-qigWk&D+R~E8^Z6weQ^u^x zcgDMg>2=j+Fqk9vY=F~LW#-(jx!JQ6v5nLd8Q))z8l_4NICn+?q2^q=njmjU*|i$}++V-4=DL zj6LTJ4l!atclRNq2k}XoTr0tByfS+9_j6 zV`{aX%BInIJW|2sIvBl{u&yi|fPWKUJ)^=a2654ir1ROLyaA>Qm?LUEnm)KIN(Ov~ zZ8ig7nXpQ87SpUGEV~0nibK!nVt1?w&_%79>Z2W{Mam&RdC z(Dig3t(R9^ZoWruQ5<9YZN1pxYg3xZCVg8ab}@~Y^&nHFSn|THJ!x#D`EefZEZBq< zY=*-kISQ?o*=J;u;{RwB#D$9T5ugxHFOz9F7te2^{kOkCNG?u)GXhH>`C@MCFuUs; zMP+tFLm=+2GS0>#6z~cb!D`LOHHz(Gi>p?PNzjXk0#@Q77?=bef{BuR7s@%iQsp;G z=o0EiyHU5r)U@x9^#|CYjeqQ6##{1{?b~VW)#f*8-R)cDV>hKwaI?*CT7HnfQk=h5 z?ZORk%YnF&c%y^6vc_@H8JzN|R@h+?8_VL$=tvda^DmVQb7r*>0GS2D6tgP^1}XM7 zIK-dMH?hz^sh|A9BwwfD)91_^C#SKJrl*oYzIyB3#qlGOXX6is8d4roC@NMfG z?Nr|uyD0j6x@;mi1;U2qNby1|z`a0yVG;znGp(04i2H07Bdf3!R<@9(#V03!T`ym# zQP+^q*3{jct@8dq)*WC6Hf;u5ugF&uPA&Yah%IYB%d+`(tGDv!Le4${XNwXq(!nSd zQ{vj#Z_wrUz(ze-G=kBYDaOv(CbkHEE4y#7*Vs{ljCk4ficge$_lA1FA5($~A^vQu z{M^Jy9(A2Pj@FYunod%2!n~1&b^g2iVvX{P_kvDhhn3)S{%gc%KtM{wqzkfBY|82@tIy|vg zpIT$n49^B#88>8NpUzGDcAvOu(B9igmuHTd(HFf#U{o|>ZK%{5KT7joUq1}iWDvApG^xk z`tZ%?S_4cber|Fx+Y z^6f6P?m>JPLSfyA_zKiHTCA=OSvLNNh3$%(*FuQ3iq)lj!WlIx!e%{BsZNT@8pYyr zqdOBHYnGDh)06UD`5dC!_vk6P9xWxTWkpRDOaaW(^qM_l*Z8RLuMTd3Dm(0-Db3kX zrL=9)sTQih5>ANPCZr7w4#ZcU#pGhL>_v++nHlqXnO?GD{PQnLnxchSXu+P;Ra>yB z)FR8)f{bOpvYbPFLMl`rMtcdHPH2`Jf1DAB^7o*V1cz^@*+-MR=y&15dNDSA4R3LZ ze3<#*Z^CLxDP@BSF;JUnViS);H()HeC(L{{Y><1=rBcS1%}2BfcihdBg>Il-fX(4M z`dl(B-WcMfkOB7(Eb)V6_;MZXIw5|$QE3+u7nG)9ST9<4fv-|*+;BHE8x`pi=)`x& zH*M0)`KQ7WO&i{aD0WwfLdzNwVl!I`tz3qYY8BgtW+XoI1xO<#a*y#cEw`1Hy(Dgw zBiU_J8Pq12YboF23D_yM@g1xg6JAl`!JnmheT7BGj^V9};#CIuLhr#x#POXG!Z!#! zjI`TX@Dtz(sgpz5MdN&gB-me&KT!|yDh=anxpweqzaeVm3+bO>^iuW=3|@t{(F?Ne zh3Jt&lSRG?xvZ#eFGcDd6@-Hec->}I?dr%4POQC?tB-4W*XpifM{ahk!h!W1w>*z(Z&3 zZuKy_sk>Wls@KA|2_aC5yJca5Mdv9`3gR1*6CY`#gM$8bjNw1`zTA04NXwTf2nV^k zD7#-;7j*R6g=~voV=Yfc!Hy4&(ao8My!f_{XW?wdGzOm| zi-J_dJ2JuxoDSqN#bS8;BgO?@nkN3`scn67A2{{jd-P52_@qU3eq5A1 zfdze~VIx@CuVl~^8u4kvfvNQJq(hwc7LXH1aM=SZ#%V@RB|c;D)Zyrm%58-_3*nY! zfYF;Mto07tea!ocH|w~&v-d!6Hh8z6cNjCi`s#D<}!NjW(aaR`)f4&98qlf|)>HatX!xCP|S!194^6;anhU3cNn|e>Kb$5NY(Ju6g z-4J&g_{n#zd5-*CmVchMV*1!FeTCJt#=4Fg3wh$3zPB_U*avE5)OvUp$dl4Tet3${ z2}KwDySsdiqRX)M-1)&Rko~Vv4?_3KNediA2n_J>;M;E3Hf%V*JGQ>2bkvRq4}@vE zyY4>idem-L;_kdrocqn?)}j-*UmTilnlT_Km5|4**8}OURn%oIcRU@xJ_b z*6^p*h7MXka#ru1M?Zd=n*3|MI=_yX%7XG}=*0ftUflfLwdsPXlgBqmq7^=`J2Z|y z7=4smnUPTL|6s=G$d5*ce2-A4&J@KkTY6cr$!P5wapUG-J)>!Kq@FK<`EI)s1fczf z@1^ae+%BCK)X&WoPN&F8rW)+vppKLBzM)ly?_3C-C*6dFDMEhuZzuOGL@1sKxXXjE zPB@4dW_^S&KbBH>cyD}et}NG^QXc_*u_`TIxnaY~F%24E1AmX)h)zYDPKfU|G74V& zOb@tUu-dUv$BG1t;uTd0lje!R~ z67#4e8DSKyV$6zFvy7wS|5*}BO_qe^?10iQWp9%YcY%%MGm8q!`7BAREdSvl>Ix+g zhZQjlUeVCV00fRzQPgPN0=Y`&B1yYwhn&6JH2K!9oh-LquNJ*MXs&d0L5*Co>fosx zH=aFVs=|)`2e9Q}bkyq}sX~pvW2L1?w1{ zO89UohF})U*H|_R)MDstOc}f+n`0t4;Rmh}FE4k#RYdq1Kg*tf{J3We?^72?Iy!rC zww#lj@_FX$k;7-Pkk#gy^7B_!*5swoin9HtBgYS{KYj$%jgb@a_o-Cs2I2UeLS4Ss zQ!t#CQCF7imV}~QE&9~r3>p7F{2vT=$+g?TTZ^tojhz_-MVvzO=ZC{EjzyN*I=4Ah=zUM zcw{tvn|x56lWaG7P=wSo+AC+HzvEFTO2je-mJl;e1Y3u`jrNZDCl~T3lfqvwwktex zQ`Ov;nzkz{1qdDNCYXH0sv~C?<@2Tye8&rDJDBt}+J}@bm^U^K^Sj3a>{O)!t;!}imH2COJOBGHaqkkzy^9lHSZAt{%a)1{~!0PlakJNyZ z{Om4wW}?~szW=n?`*!ci_qn}VH|^eu`mT%rbb4yWu(#5Pu8G}faILsXrQ2?rb@=#i zbvrh!S-Iv9ZAP_OuqW}4F0DH@;Jvdmzhy(DTJU6A8i|!BR+N2g zz7Dk7dFKaLthR(yH-{S(?zt!)rH3XEVHWr`E_C~`V-pVETJo3Oru8*r z91eS7>%IGKss&xc!S%nPCAhY-SamL|Hi}oF%R;1$K~WrgJ|2WAhi(3C=6O^ySPA}c zUl;NzIQ2ba*ps_8wPtR1pK+H@u_LCsm&XhC-_CL_;X8NX9;o?l+{Z$IB65~Q!L-L; zj>VvZ6H2rtl77wpCeOSsPs>A0N%QTjs+;{0S4zk2ccVU*Ds9ZCjj&r9Q_M`kf{Q3y zRz^uh4hqVrL*VOdH@8SJa$Amk_x#Ie=jA&&J0I<%@$AjFv+RYbxLDOxl0D^p_e0-b zf;QWjkA)~D=3`0NtbPj&2L9g=;DAx1qJPJH-1ruYfX!_zyy<0HRNg~d%YWXvjU{+% zc`tQhw`e!h8`FI{M4rQfm@%C{Ljp+JQa#79hWOJuLhf-w}VK z1t*WeljESkHXdYQgGCZ;7Lxzxc+dnEo40@knX-lWlP6cR+ozZDQK&30W%D&P5Z#V3 zx+>9a0`E~7aK&a9Lr*n?ulle|OqB{3N=8?S2iefoQbJUvz^I6*C>$;E;``iMoQ3!F zVqN6b+7l;)J%;e@n(g>cUfPu=-pn#Sxv~3E#H`9+?_{;_@bu=_%AjHgMx_-ZI!Y|* zKTgH+AQWx2X_Nd(qj=^eKywmkE(V&V;{3E0;lU3+jg=$ooMx9|{CuIoB`np|ie|}` zk1EdD@;&aD;HaozEFSpD{YVcihH$W;ghAZ9S2Tq0HJ&`VYtQ{E=8PAuTfe?yt}-h! z`@s1uW7e5N*^!)YNp!OKKnMfhYN0K@D?o5!#V8b0ghB}8OL}X)1t%KcmcWi#?-N0G zytrG&Rc{4|i-reVA|remU(bjSj?QT~cG-`?KQ=kBcVWY+^M4Hav8CW@cwBj=f3KEX z?^l}=FsLQ`iD~je`kUAUymQ7nL92e7q}4&2s?k@&!9-6w8%y{HC|uyf zpzP~d#8#Qg(3v)3D>x|M0$`6y{SwGU`LxD8%vj6?YFRnHYqN!>L_~06k$+&qu=I9S zKR{9AB7)Z4lf@^D&^!~*EI7X}J$>K#RR_dp+T`}nb%=`eYC7YR&+FF#)bD}MO{x#b z%JjLjA~8umU!TWDD8aV0I7T`JjnvENt(<64Ip+#nYnniBZ-LFX-W95EV|pbI>4 zlA0(hP<1qHg71Y3J4b$|$f%{tbmyOxVU|HrS$)BUg^;~fvIxFB<3nS>E*?%TVPfJ7 zA{wT#%Ud^Jx_r7MTlozOwmhI zmS7(=bV{Ip`m$l22l9X{G|bFDb)_WT2N%AG%A z^e-dm?PDSbEbG6&UBrxTThg=A z`%LKEyk(nSgMS;~;Zu4{v({lzy0D~XUAX*Uk2FoiQtODgxNdQA6;;I7{B3YT;0Z>@8*?n0EHL`T zROXEH)8ShgevQnZYmpeDNWRJq%`k+98Cj%qOqpSS0H^7&KVToKe2--xwwu`N?2%E# zo_p%4y22BTe1duvCXL?eaoteF@a+nFgfo#rg-OMn;A6A=@2T=X&{GeeMFmx2r2=vC zQRgb^OSuN&fErFC=+wgrVyB(*@gv7pt=qn$L)#8Ld$mt!M>j5(->q9MzhAK&pP$B3 zx20d-AEJ%u1lsV>A$kAF6Y{>ptmV?RH+K)-adX3>#1=D>lai-3`+4d{T5{`pIaA&y zXKva;^_woxcIVE?8|8lT#Gq(~PCBcODtDxegx z10qGGYodr`_vZgScXl>2fWGhh`~06rHrZsed(XY+p87rK_VOq3I$|vi;%-YJi>&tf<;8>sFR;LXUcWhSVqm?6gOv5wNNG0 z;cQU7s@I^+gO)}0Djq9|N1a23F`(-=T}#u>1QxOr{%UV{;ZwD^mx$672Zj?WocJF6 zThhNI__uO#D#OUBoVYjA@CR{`mFcIbtu0U2V{f&>-_iXua^MTxNfMX>g+O}-hlYj3 zLJh^oCXi_a*%RCDMMks+yvVH1xD_no-4Djss$%zA?Nhtyy6n1L>UViZ`u+uWJpTf_ zcH(>FRc$y$E|1wa7Z~`eb>JG!MM)iA-sA)#5_uxWt68vgr`Ca#U*}7m8Fw;ZwXX$tw7lRZ@e* zCdAl+L)ol>t5yykvU=^Hl)7~XHfU%)z3$rT)z{YX@%2-xG-=Ym0Y1MQQjvLz1D=+j zrGZv~2NmLWzJWD=RYe||h(_&U^(A|MpSQJ`RRj{;Iugb?2$t5cc6|GHd^PLy9jolv zBe#^Nf66o1j8EBwd=QVltAW1Ps`W5z=1!`I%Vs8JW~z}A`wr=?lPyrLVi-Tqyo`gd_-!MYPAn-pOw94V9)t%l(c#h zv-Yb~Hl=pz=y#`#8q~Ml2&^*=-MhDAouzfs=u28h)TA zYk~gt@(6VyrGv47Hp4nSwW=e;Hw>6{H4un2kXB5*3ng$%6#fZ_Nv`|?DWr#q3EX8} z39+n5%NeO}B-J{!d0O_SS9t$-|MsZXlxA(3BE1rGzDm5X?S5n8Ju8!ElsO{wa&{PePX@vk?B^6sAgF#@{bS z^sgj*)j&%R)yGwtN~b9fP`CX}VHE+N(W8ED_M^XX3m1ONU<7*bZ@w;g4#);W|Mj|TyW9%z z8>V`=-WQ+-A=izqp@*x~_W z=OmV`5Nn-BpEU*dPO|Psl&KnU5k#ZL&%&iK?E>*L8s*{@q;g~vC&mWYsWwwO_&FOE zgm1q436q^wxjZg-5$N*Ts;3suhD^~Ba>D1pr{Gs)-=F~aKTI64aqxs(Jg(K! z3p_e*^SI+I^^+rO*B#r_rA4z&tV{D|U6dZ{Po3P-;Js6)H(7fQ9o(ZukD){Ql78(1 z{raxZuS+~hzb>JE*Z6q{M8u|BcUltI*@Ew-mH4_8-C8}EU5b)W$ZGL7Z%tAq{0)xW zdI9@~*IIsuZApK7Nm|Y9?2KHr@NaZ@o%ox6_!|dg2)+L{`Wq=qeglVLmr7cas8^l# zIZ-YiI0Cm)Sm>5HDcD*sn8 zP^hR0f^dO9Eo$pYrzVRs85s0w2v`M?O$-aNa;P*`N@>`yW6uul2j)pnPJVf7b?0VY z(%)LTPFj|+sQJJi1G{$V-Fok(&p+P0sY`=VDXcI;AQe2t=C{KQ^n;w3sL`yuL4`pk zvXV&*=y5(ZK!cYfdSftqa?I5MDoXT;p8#Kdp}N7SwF1S9kc&f|3xa`AT2#P^C`Ytx zZ|BJL<6a;08*&}_rZYW2D&@QrEUkF{h)pQQ+F%q}&KchS3{PeKq}glje5!5U+I4BZ(8yikADU&9Lt?ttT- z6Yt`YS3(rkqW&UO8Y{k_sRy;ofVXeVu@|MvNxJp%h3+3%L?D*|m`RHV5{2qn!qSrM zp+VN*Fa`~aiA_}!7(_Eb%rO8l?|Xknr|pYQEoZ^%ne293m#k%ux9YQ}?PdYXEFCY; z!-ZWu)U;D#34YCkO$b3H~X9 zOaihXB9lOh$E!bKpRK!rt0EEOTcFRzTi zMgp7l$Db^aKhDd|%X>O$(fo9Pn}2)!*{4r9pw>K&7oB!vhQQm-20mpqP#fhfUDQ}Z ze-Xf3tn_h(z|jIUH-a%zu`^>(++?A+pGMQQoXHO3;m#XlR)Fio8s5&lWrR>lER1MT;e1Nri-GBL6$g^9 zti#=eqZgJMh5~OFu!oR6g-%~66CfXiHGXlzKdM0*JOWodPwkwrfqW8toxvTr+yu32Q5B0bC$%N z59Z8US1o2s)tVnyFLzn$RDRfFON>ATiKQQStER0yPy^*~>+M>tGXfZ;T{|BE zoe-h(m^(G%XBRki1f&D}M0^N6e+&t2vY-us8j2Gc+6>^<1Jo2Ok(EhG0FG~1yodvW z)xy%kn8jl`=0h`yg{;o8 zuHuAyiLkU&6%DHfd=rdQJW}tA7m9TuX+3pAX|G~bhIqOA7h#3J0Euu}3jHZ}^(#nL z(i}zPKe;D0@2JxV|Er^YC)K;k)FvYvHy+u<(WqLJCe>aeOHKx|Zk+NuI;aymEe>a- z#8b$ORtm<(W320>OsE5Q9x+@IIKU|Jg@Sw$LI@jT-#Ov_InkHs$PA1w>?ArElEwhn zkWoxRI!KetHkVjVC3M2T_VpL_Jq>t5myQh<_5CuhCM%ct8W0Me)%bVik|)j)P=%Q6 zOYibe09Gimy| z7Gd3ll@L})U=E_|DBrPOqNtm(Q3=F2;uo+(5M4)BE0AL8u9hCqsFa)+HGy>NtR*H- zMrEKQBg28(K*t1Wo^y<{dt?5eR3@kt*@)66>S(u-@EO@KyQaa%G$XBa6Ij=xE~M48 zJfMNdPFnz*VGzDW)?1_4boET>ZvAA%F}srrHm!We23=%Jv;ifWZG+k|_S*1buH+{f z3?NP`FL*L6H}`FX0Lt?o>>xkSKHzPXYP5+Ez;W;3- zYAAxoK^j}O;1nt42B;pzd!Tx;U^je}b@mx`I%hvSyrph6-_q4Hx(ry<7~H>n$2V7; z#rB;HI9nt~`hNWIevX^C2NLqM5A7A;qldw>T&^=hhqw@%o~|6VFBV&2;(Zk0PzEjZPM=TGX@e`Kc(dzc!$g!$}X)jnW>%Y#uK{u!?s z>7!Kjy?BJ5J8>D3q!Vn~Tuh=VfzI-kE$h^XofYk``cR4YaXon1DSWY?e7YY3zmTE9ZUF|AJ zUswXP_=pxEjC0wgotWRvf3j+QG~}Dd&bHo*#&pQ8-@N`8#_K%Pfp0UKeZMvf7_~Gn%>&jMM_hzl#=)cJ%&mD&jezN7*p+j>fL<~y@ z_am4jErXv^#FDJah8i*zNr-dm7g
h}nbI!7$fg`g%jGMHsI6;dmGA6LaTaO;a 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 NSDLFxS=xl2`X5i?+06g| literal 0 HcmV?d00001 diff --git a/src/api.js b/src/api.js index d475835..714d9c6 100644 --- a/src/api.js +++ b/src/api.js @@ -64,31 +64,29 @@ function api(db, xmltvInterval) { router.post('/api/ffmpeg-settings', (req, res) => { // RESET db['ffmpeg-settings'].update({ _id: req.body._id }, { ffmpegPath: req.body.ffmpegPath, - ffprobePath: req.body.ffprobePath, offset: 0, - threads: '4', - videoEncoder: 'mpeg2video', + threads: 4, + videoEncoder: 'libx264', videoResolution: '1280x720', - videoFrameRate: '30', - videoBitrate: '10000k', - audioBitrate: '192k', - audioChannels: '2', - audioRate: '48000', - bufSize: '1000k', + videoFrameRate: 30, + videoBitrate: 10000, + audioBitrate: 192, + audioChannels: 2, + audioRate: 48000, + bufSize: 1000, audioEncoder: 'ac3', preferAudioLanguage: 'false', audioLanguage: 'eng', - deinterlace: true, - logFfmpeg: true, + deinterlace: false, + logFfmpeg: false, args: `-threads 4 -ss STARTTIME --t DURATION -re -i INPUTFILE --vf yadif --map 0:v +-t DURATION +-map VIDEOSTREAM -map AUDIOSTREAM --c:v mpeg2video +-c:v libx264 -c:a ac3 -ac 2 -ar 48000 @@ -101,8 +99,12 @@ function api(db, xmltvInterval) { -minrate:v 10000k -maxrate:v 10000k -bufsize:v 1000k +-metadata service_provider="PseudoTV" +-metadata CHANNELNAME -f mpegts -output_ts_offset TSOFFSET +-muxdelay 0 +-muxpreload 0 OUTPUTFILE` }) let ffmpeg = db['ffmpeg-settings'].find()[0] @@ -128,7 +130,7 @@ OUTPUTFILE` _id: req.body._id, cache: 12, refresh: 4, - file: process.env.XMLTV + file: process.env.DATABASE + '/xmltv.xml' }) var xmltv = db['xmltv-settings'].find()[0] res.send(xmltv) @@ -171,7 +173,11 @@ OUTPUTFILE` var data = "#EXTM3U\n" for (var i = 0; i < channels.length; i++) { data += `#EXTINF:0 tvg-id="${channels[i].number}" tvg-name="${channels[i].name}" tvg-logo="${channels[i].icon}",${channels[i].name}\n` - data += `http://${process.env.HOST}:${process.env.PORT}/video?channel=${channels[i].number}\n` + 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 += `${req.protocol}://${req.get('host')}/setup\n` } res.send(data) }) diff --git a/src/ffmpeg.js b/src/ffmpeg.js index 0376ac9..13d54ba 100644 --- a/src/ffmpeg.js +++ b/src/ffmpeg.js @@ -1,14 +1,15 @@ const spawn = require('child_process').spawn -var events = require('events') +const events = require('events') +const fs = require('fs') -class ffmpeg extends events.EventEmitter { - constructor(opts) { +class FFMPEG extends events.EventEmitter { + constructor(opts, channel) { super() this.offset = 0 this.args = [] this.opts = opts + this.channel = channel this.ffmpegPath = opts.ffmpegPath - this.ffprobePath = opts.ffprobePath let lines = opts.args.split('\n') for (let i = 0, l = lines.length; i < l; i++) { let x = lines[i].indexOf(' ') @@ -20,46 +21,130 @@ class ffmpeg extends events.EventEmitter { } } } - getStreams(file) { + // This is used to generate ass subtitles from text subs to be used with the ass filter in ffmpeg. + createSubsFromStream(file, startTime, duration, streamIndex, output) { + if (process.env.DEBUG) console.log('Generating .ass subtitles') + let exe = spawn(this.ffmpegPath, [ + '-threads', this.opts.threads, + '-ss', startTime, + '-i', file, + '-t', duration, + '-map', `0:${streamIndex}`, + '-f', 'ass', + output + ]) return new Promise((resolve, reject) => { - let ffprobe = spawn(this.ffprobePath, [ '-v', 'quiet', '-show_streams', '-of', 'json', file ]) - let str = "" - ffprobe.stdout.on('data', (chunk) => { - str += chunk - }) - ffprobe.on('close', () => { - resolve(str) + if (this.opts.logFfmpeg) { + exe.stderr.on('data', (chunk) => { + process.stderr.write(chunk) + }) + } + exe.on('close', (code) => { + if (code === 0) { + if (process.env.DEBUG) console.log('Successfully generated .ass subtitles') + resolve() + } else { + console.log('Failed generating .ass subtitles.') + reject() + } }) }) } async spawn(lineupItem) { - let audioIndex = -1 - if (this.opts.preferAudioLanguage === 'true') { - let streams = JSON.parse(await this.getStreams(lineupItem.file)).streams - for (let i = 0, l = streams.length; i < l; i++) { - if (streams[i].codec_type === 'audio') { - if (streams[i].tags.language === this.opts.audioLanguage) { - audioIndex = i - break; - } - } - } + let videoIndex = lineupItem.opts.videoIndex + let audioIndex = lineupItem.opts.audioIndex + let subtitleIndex = lineupItem.opts.subtitleIndex + let uniqSubFileName = Date.now().valueOf().toString() + + for (let i = 0, l = lineupItem.streams.length; i < l; i++) { + if (videoIndex === '-1' && lineupItem.streams[i].streamType === 1) + if (lineupItem.streams[i].default) + videoIndex = i + if (audioIndex === '-1' && lineupItem.streams[i].streamType === 2) + if (lineupItem.streams[i].default || lineupItem.streams[i].selected) + audioIndex = i + if (subtitleIndex === '-1' && lineupItem.streams[i].streamType === 3) + if (lineupItem.streams[i].default || lineupItem.streams[i].forced) + subtitleIndex = i } + // if for some reason we didn't find a default track, let ffmpeg decide.. + if (videoIndex === '-1') + videoIndex = 'v' + if (audioIndex === '-1') + audioIndex === 'a' + + let sub = (subtitleIndex === '-1' || subtitleIndex === '-2') ? null : lineupItem.streams[subtitleIndex] + let tmpargs = JSON.parse(JSON.stringify(this.args)) let startTime = tmpargs.indexOf('STARTTIME') let dur = tmpargs.indexOf('DURATION') let input = tmpargs.indexOf('INPUTFILE') + let vidStream = tmpargs.indexOf('VIDEOSTREAM') let output = tmpargs.indexOf('OUTPUTFILE') let tsoffset = tmpargs.indexOf('TSOFFSET') let audStream = tmpargs.indexOf('AUDIOSTREAM') + let chanName = tmpargs.indexOf('CHANNELNAME') tmpargs[startTime] = lineupItem.start / 1000 tmpargs[dur] = lineupItem.duration / 1000 tmpargs[input] = lineupItem.file - tmpargs[audStream] = `0:${audioIndex === -1 ? 'a' : audioIndex}` + tmpargs[audStream] = `0:${audioIndex}` + tmpargs[chanName] = `service_name="${this.channel.name}"` tmpargs[tsoffset] = this.offset tmpargs[output] = 'pipe:1' + + let iconOverlay = `[0:${videoIndex}]null` + let deinterlace = 'null' + let posAry = [ '20:20', 'W-w-20:20', '20:H-h-20', 'W-w-20:H-h-20'] // top-left, top-right, bottom-left, bottom-right (with 20px padding) + let icnDur = '' + if (this.channel.iconDuration > 0) + icnDur = `:enable='between(t,0,${this.channel.iconDuration})'` + if (this.channel.icon !== '' && this.channel.overlayIcon && lineupItem.type === 'program') { + iconOverlay = `[1:v]scale=${this.channel.iconWidth}:-1[icn];[0:${videoIndex}][icn]overlay=${posAry[this.channel.iconPosition]}${icnDur}` + if (process.env.DEBUG) console.log('Channel Icon Overlay Enabled') + } + + if (videoIndex !== 'v') { + if (typeof lineupItem.streams[videoIndex].scanType === 'undefined' || lineupItem.streams[videoIndex].scanType !== 'progressive') { + deinterlace = 'yadif' + if (process.env.DEBUG) console.log('Deinterlacing Video') + } + } + + if (sub === null || lineupItem.type === 'commercial') { // No subs or icon overlays for Commercials + tmpargs[vidStream] = '[v]' + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v1];[v1]${deinterlace}[v]`) + console.log("No Subtitles") + } else if (sub.codec === 'pgs') { // If program has PGS subs + tmpargs[vidStream] = '[v]' + if (typeof sub.index === 'undefined') { // If external subs + console.log("PGS SUBS (external) - Not implemented..") + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v1];[v1]${deinterlace}[v]`) + } else { // Otherwise, internal/embeded pgs subs + console.log("PGS SUBS (embeded)") + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v2];[v2]${deinterlace}[v1];[v1][0:${sub.index}]overlay[v]`) + } + } else if (sub.codec === 'srt' || sub.codec === 'ass') { + tmpargs[vidStream] = '[v]' + if (typeof sub.index === 'undefined') { + console.log("SRT SUBS (external)") + await this.createSubsFromStream(sub.key, lineupItem.start / 1000, lineupItem.duration / 1000, 0, `${process.env.DATABASE}/${uniqSubFileName}.ass`) + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v1];[v1]${deinterlace},ass=${process.env.DATABASE}/${uniqSubFileName}.ass[v]`) + } else { + console.log("SRT SUBS (embeded) - This may take a few seconds..") + await this.createSubsFromStream(lineupItem.file, lineupItem.start / 1000, lineupItem.duration / 1000, sub.index, `${process.env.DATABASE}/${uniqSubFileName}.ass`) + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v1];[v1]${deinterlace},ass=${process.env.DATABASE}/${uniqSubFileName}.ass[v]`) + } + } else { // Can't do VobSub's as plex only hosts the .idx file, there is no access to the .sub file.. Who the fuck uses VobSubs anyways.. SRT/ASS FTW + tmpargs[vidStream] = '[v]' + tmpargs.splice(vidStream - 1, 0, "-filter_complex", `${iconOverlay}[v1];[v1]${deinterlace}[v]`) + console.log("No Compatible Subtitles") + } + + if (this.channel.icon !== '' && this.channel.overlayIcon && lineupItem.type === 'program') // Add the channel icon to ffmpeg input if enabled + tmpargs.splice(vidStream - 1, 0, '-i', this.channel.icon) + this.offset += lineupItem.duration / 1000 this.ffmpeg = spawn(this.ffmpegPath, tmpargs) this.ffmpeg.stdout.on('data', (chunk) => { @@ -71,6 +156,8 @@ class ffmpeg extends events.EventEmitter { }) } this.ffmpeg.on('close', (code) => { + if (fs.existsSync(`${process.env.DATABASE}/${uniqSubFileName}.ass`)) + fs.unlinkSync(`${process.env.DATABASE}/${uniqSubFileName}.ass`) if (code === null) this.emit('close', code) else if (code === 0) @@ -84,4 +171,4 @@ class ffmpeg extends events.EventEmitter { } } -module.exports = ffmpeg \ No newline at end of file +module.exports = FFMPEG \ No newline at end of file diff --git a/src/ffmpegText.js b/src/ffmpegText.js new file mode 100644 index 0000000..ed137bd --- /dev/null +++ b/src/ffmpegText.js @@ -0,0 +1,50 @@ +const spawn = require('child_process').spawn +const events = require('events') +const fs = require('fs') +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', + '-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', + '-f', 'mpegts', + 'pipe:1' + ] + + this.ffmpeg = spawn(opts.ffmpegPath, this.args) + + this.ffmpeg.stdout.on('data', (chunk) => { + this.emit('data', chunk) + }) + + if (opts.logFfmpeg) { + this.ffmpeg.stderr.on('data', (chunk) => { + process.stderr.write(chunk) + }) + } + + this.ffmpeg.on('close', (code) => { + if (code === null) + this.emit('close', code) + else + this.emit('error', { code: code, cmd: `${this.args.join(' ')}` }) + }) + } + kill() { + this.ffmpeg.kill() + } +} + +module.exports = FFMPEG_TEXT \ No newline at end of file diff --git a/src/hdhr.js b/src/hdhr.js index 34f7935..8ef4cfe 100644 --- a/src/hdhr.js +++ b/src/hdhr.js @@ -21,14 +21,14 @@ function hdhr(db) { var router = express.Router() router.get('/device.xml', (req, res) => { - var device = getDevice(db) + var device = getDevice(db, req.protocol + '://' + req.get('host')) res.header("Content-Type", "application/xml") var data = device.getXml() res.send(data) }) router.get('/discover.json', (req, res) => { - var device = getDevice(db) + var device = getDevice(db, req.protocol + '://' + req.get('host')) res.header("Content-Type", "application/json") res.send(JSON.stringify(device)) }) @@ -48,14 +48,16 @@ function hdhr(db) { var lineup = [] var channels = db['channels'].find() for (let i = 0, l = channels.length; i < l; i++) - lineup.push({ GuideNumber: channels[i].number.toString(), GuideName: channels[i].name, URL: `http://${process.env.HOST}:${process.env.PORT}/video?channel=${channels[i].number}` }) + lineup.push({ GuideNumber: channels[i].number.toString(), GuideName: channels[i].name, URL: `${req.protocol}://${req.get('host')}/video?channel=${channels[i].number}` }) + if (lineup.length === 0) + lineup.push({ GuideNumber: '1', GuideName: 'PseudoTV', URL: `${req.protocol}://${req.get('host')}/setup` }) res.send(JSON.stringify(lineup)) }) return { router: router, ssdp: server } } -function getDevice(db) { +function getDevice(db, host) { let hdhrSettings = db['hdhr-settings'].find()[0] var device = { FriendlyName: "PseudoTV", @@ -67,8 +69,8 @@ function getDevice(db) { FirmwareVersion: "20170930", DeviceID: 'PseudoTV', DeviceAuth: "", - BaseURL: `http://${process.env.HOST}:${process.env.PORT}`, - LineupURL: `http://${process.env.HOST}:${process.env.PORT}/lineup.json` + BaseURL: `${host}`, + LineupURL: `${host}/lineup.json` } device.getXml = () => { str = diff --git a/src/helperFuncs.js b/src/helperFuncs.js index f0694fe..7919366 100644 --- a/src/helperFuncs.js +++ b/src/helperFuncs.js @@ -1,29 +1,6 @@ -const os = require('os') - module.exports = { - getLineup: getLineup, getCurrentProgramAndTimeElapsed: getCurrentProgramAndTimeElapsed, - getIPAddresses: getIPAddresses -} - -function getIPAddresses() { - var ifaces = os.networkInterfaces(); - var addresses = [] - Object.keys(ifaces).forEach(function (ifname) { - ifaces[ifname].forEach(function (iface) { - if ('IPv4' !== iface.family || iface.internal !== false) { - return - } - addresses.push(iface.address) - }) - }) - return addresses -} - -function getLineup(date, channel) { - let _obj = getCurrentProgramAndTimeElapsed(date, channel) - let lineup = createProgramStreamTimeline(_obj) - return lineup + createLineup: createLineup } function getCurrentProgramAndTimeElapsed(date, channel) { @@ -46,7 +23,7 @@ function getCurrentProgramAndTimeElapsed(date, channel) { return { program: channel.programs[currentProgramIndex], timeElapsed: timeElapsed, programIndex: currentProgramIndex } } -function createProgramStreamTimeline(obj) { +function createLineup(obj) { let timeElapsed = obj.timeElapsed let activeProgram = obj.program let lineup = [] @@ -64,15 +41,19 @@ function createProgramStreamTimeline(obj) { lineup.push({ type: 'commercial', file: commercials[i][y].file, + streams: commercials[i][y].streams, start: timeElapsed, // start time will be the time elapsed, cause this is the first video - duration: commercials[i][y].duration - timeElapsed // duration set accordingly + duration: commercials[i][y].duration - timeElapsed, // duration set accordingly + opts: commercials[i][y].opts }) } else if (foundFirstVideo) { // Otherwise, if weve already found the starting video lineup.push({ // just add the video, starting at 0, playing the entire duration type: 'commercial', file: commercials[i][y].file, + streams: commercials[i][y].streams, start: 0, - duration: commercials[i][y].duration + duration: commercials[i][y].duration, + opts: commercials[i][y].opts }) } else { // Otherwise, this bitch has already been played.. Reduce the time elapsed by its duration timeElapsed -= commercials[i][y].duration @@ -84,8 +65,10 @@ function createProgramStreamTimeline(obj) { lineup.push({ type: 'program', file: activeProgram.file, + streams: activeProgram.streams, start: progTimeElapsed + timeElapsed, // add the duration of already played program chunks to the timeElapsed - duration: (programStartTimes[i + 1] - programStartTimes[i]) - timeElapsed + duration: (programStartTimes[i + 1] - programStartTimes[i]) - timeElapsed, + opts: activeProgram.opts }) } else if (foundFirstVideo) { if (lineup[lineup.length - 1].type === 'program') { // merge consecutive programs.. @@ -94,8 +77,10 @@ function createProgramStreamTimeline(obj) { lineup.push({ type: 'program', file: activeProgram.file, + streams: activeProgram.streams, start: programStartTimes[i], - duration: (programStartTimes[i + 1] - programStartTimes[i]) + duration: (programStartTimes[i + 1] - programStartTimes[i]), + opts: activeProgram.opts }) } } else { diff --git a/src/plex.js b/src/plex.js index 925d0ed..e9f0fdd 100644 --- a/src/plex.js +++ b/src/plex.js @@ -112,18 +112,18 @@ class Plex { }) }) } - GetDVRS = async function () { + async GetDVRS() { var result = await this.Get('/livetv/dvrs') var dvrs = result.Dvr dvrs = typeof dvrs === 'undefined' ? [] : dvrs return dvrs } - RefreshGuide = async function (_dvrs) { + async RefreshGuide(_dvrs) { var dvrs = typeof _dvrs !== 'undefined' ? _dvrs : await this.GetDVRS() for (var i = 0; i < dvrs.length; i++) this.Post(`/livetv/dvrs/${dvrs[i].key}/reloadGuide`).then(() => { }, (err) => { console.log(err) }) } - RefreshChannels = async function (channels, _dvrs) { + async RefreshChannels(channels, _dvrs) { var dvrs = typeof _dvrs !== 'undefined' ? _dvrs : await this.GetDVRS() var _channels = [] let qs = {} diff --git a/src/video.js b/src/video.js index ea60d33..9f9fedb 100644 --- a/src/video.js +++ b/src/video.js @@ -1,12 +1,40 @@ const express = require('express') const helperFuncs = require('./helperFuncs') -const ffmpeg = require('./ffmpeg') +const FFMPEG = require('./ffmpeg') +const FFMPEG_TEXT = require('./ffmpegText') const fs = require('fs') module.exports = { router: video } function video(db) { var router = express.Router() + + router.get('/setup', (req, res) => { + let ffmpegSettings = db['ffmpeg-settings'].find()[0] + // Check if ffmpeg path is valid + if (!fs.existsSync(ffmpegSettings.ffmpegPath)) { + res.status(500).send("FFMPEG path is invalid. The file (executable) doesn't exist.") + console.error("The FFMPEG Path is invalid. Please check your configuration.") + return + } + + console.log(`\r\nStream starting. Channel: 1 (PseudoTV)`) + + let ffmpeg = new FFMPEG_TEXT(ffmpegSettings, 'PseudoTV', 'Configure your channels using the PseudoTV Web UI') + + ffmpeg.on('data', (data) => { res.write(data) }) + + ffmpeg.on('error', (err) => { + console.error("FFMPEG ERROR", err) + res.status(500).send("FFMPEG ERROR") + }) + + res.on('close', () => { // on HTTP close, kill ffmpeg + ffmpeg.kill() + console.log(`\r\nStream ended. Channel: 1 (PseudoTV)`) + }) + }) + router.get('/video', (req, res) => { // Check if channel queried is valid if (typeof req.query.channel === 'undefined') { @@ -21,7 +49,8 @@ function video(db) { channel = channel[0] // Get video lineup (array of video urls with calculated start times and durations.) - let lineup = helperFuncs.getLineup(Date.now(), channel) + let prog = helperFuncs.getCurrentProgramAndTimeElapsed(Date.now(), channel) + let lineup = helperFuncs.createLineup(prog) let ffmpegSettings = db['ffmpeg-settings'].find()[0] // Check if ffmpeg path is valid @@ -31,26 +60,31 @@ function video(db) { return } - console.log(`Stream started. Channel: ${channel.number} (${channel.name})`) + console.log(`\r\nStream starting. Channel: ${channel.number} (${channel.name})`) - let ffmpeg2 = new ffmpeg(ffmpegSettings) // Set the transcoder options + let ffmpeg = new FFMPEG(ffmpegSettings, channel) // Set the transcoder options - ffmpeg2.on('data', (data) => { res.write(data) }) + ffmpeg.on('data', (data) => { res.write(data) }) - ffmpeg2.on('error', (err) => { console.error("FFMPEG ERROR", err) }) + ffmpeg.on('error', (err) => { + console.error("FFMPEG ERROR", err) + res.status(500).send("FFMPEG ERROR") + }) - ffmpeg2.on('end', () => { // On finish transcode - END of program or commercial... - if (lineup.length === 0) // refresh the expired program/lineup - lineup = helperFuncs.getLineup(Date.now(), channel) - ffmpeg2.spawn(lineup.shift()) // Spawn the next ffmpeg process + 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) + lineup = helperFuncs.createLineup(prog) + } + ffmpeg.spawn(lineup.shift(), prog.program) // Spawn the next ffmpeg process }) res.on('close', () => { // on HTTP close, kill ffmpeg - ffmpeg2.kill() - console.log(`Stream ended. Channel: ${channel.number} (${channel.name})`) + ffmpeg.kill() + console.log(`\r\nStream ended. Channel: ${channel.number} (${channel.name})`) }) - ffmpeg2.spawn(lineup.shift()) // Spawn the ffmpeg process, fire this bitch up + ffmpeg.spawn(lineup.shift(), prog.program) // Spawn the ffmpeg process, fire this bitch up }) return router diff --git a/src/xmltv.js b/src/xmltv.js index 789f5d2..854de00 100644 --- a/src/xmltv.js +++ b/src/xmltv.js @@ -12,9 +12,25 @@ function WriteXMLTV(channels, xmlSettings) { ws.on('close', () => { resolve() }) ws.on('error', (err) => { reject(err) }) _writeDocStart(xw) - _writeChannels(xw, channels) - for (var i = 0; i < channels.length; i++) - _writePrograms(xw, channels[i], date, xmlSettings.cache) + if (channels.length === 0) { + _writeChannels(xw, [{ number: 1, name: "PseudoTV", icon: null }]) + let program = { + program: { + type: 'movie', + title: 'No Channels Configured', + summary: 'Configure your channels using the PseudoTV Web UI.' + }, + channel: '1', + start: date, + stop: new Date(date.valueOf() + xmlSettings.cache * 60 * 60 * 1000) + } + _writeProgramme(xw, program) + } else { + _writeChannels(xw, channels) + for (var i = 0; i < channels.length; i++) + _writePrograms(xw, channels[i], date, xmlSettings.cache) + } + _writeDocEnd(xw, ws) ws.close() }) @@ -79,7 +95,7 @@ function _writeProgramme(xw, program) { xw.startElement('title') xw.writeAttribute('lang', 'en') - if (program.program.type == 'episode') { + if (program.program.type === 'episode') { xw.text(program.program.showTitle) xw.endElement() xw.writeRaw('\n ') @@ -98,9 +114,11 @@ function _writeProgramme(xw, program) { xw.endElement() } // Icon - xw.startElement('icon') - xw.writeAttribute('src', program.program.icon) - xw.endElement() + if (typeof program.program.icon !== 'undefined') { + xw.startElement('icon') + xw.writeAttribute('src', program.program.icon) + xw.endElement() + } // Desc xw.startElement('desc') xw.writeAttribute('lang', 'en') diff --git a/web/directives/channel-config.js b/web/directives/channel-config.js index 27cb3d6..17b504f 100644 --- a/web/directives/channel-config.js +++ b/web/directives/channel-config.js @@ -14,6 +14,9 @@ module.exports = function ($timeout) { scope.channel.programs = [] scope.isNewChannel = true scope.channel.icon = "" + scope.channel.iconWidth = 120 + scope.channel.iconDuration = 60 + scope.channel.iconPosition = "2" scope.channel.startTime = new Date() scope.channel.startTime.setMilliseconds(0) scope.channel.startTime.setSeconds(0) @@ -154,7 +157,7 @@ module.exports = function ($timeout) { return Math.floor(Math.random() * (max - min + 1)) + min } function shuffle(array) { - var currentIndex = array.length, temporaryValue, randomIndex + let currentIndex = array.length, temporaryValue, randomIndex while (0 !== currentIndex) { randomIndex = Math.floor(Math.random() * currentIndex) currentIndex -= 1 @@ -164,6 +167,7 @@ module.exports = function ($timeout) { } return array } + scope.updateChannelDuration = updateChannelDuration function updateChannelDuration() { scope.channel.duration = 0 for (let i = 0, l = scope.channel.programs.length; i < l; i++) { @@ -178,31 +182,30 @@ module.exports = function ($timeout) { scope.onDone() else { channelNumbers = [] - for (let i = 0, l = scope.channels.length; i < l; i++) { + for (let i = 0, l = scope.channels.length; i < l; i++) channelNumbers.push(scope.channels[i].number) - } // validate var now = new Date() - if (typeof channel.number === "undefined" || channel.number === null || channel.number === "") { + if (typeof channel.number === "undefined" || channel.number === null || channel.number === "") scope.error.number = "Select a channel number" - } else if (channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1 && scope.isNewChannel) { // we need the parseInt for indexOf to work properly + else if (channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1 && scope.isNewChannel) // we need the parseInt for indexOf to work properly scope.error.number = "Channel number already in use." - } else if (!scope.isNewChannel && channel.number !== scope.beforeEditChannelNumber && channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1) { + else if (!scope.isNewChannel && channel.number !== scope.beforeEditChannelNumber && channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1) scope.error.number = "Channel number already in use." - } else if (channel.number <= 0 || channel.number >= 2000) { + else if (channel.number <= 0 || channel.number >= 2000) scope.error.name = "Enter a valid number (1-2000)" - } else if (typeof channel.name === "undefined" || channel.name === null || channel.name === "") { + else if (typeof channel.name === "undefined" || channel.name === null || channel.name === "") scope.error.name = "Enter a channel name." - } else if (channel.icon !== "" && !validURL(channel.icon)) { + else if (channel.icon !== "" && !validURL(channel.icon)) scope.error.icon = "Please enter a valid image URL. Or leave blank." - } else if (now < channel.startTime) { + else if (channel.overlayIcon && !validURL(channel.icon)) + scope.error.icon = "Please enter a valid image URL. Cant overlay an invalid image." + else if (now < channel.startTime) scope.error.startTime = "Start time must not be set in the future." - } else if (channel.programs.length === 0) { + else if (channel.programs.length === 0) scope.error.programs = "No programs have been selected. Select at least one program." - } else { - // DONE. + else scope.onDone(JSON.parse(angular.toJson(channel))) - } $timeout(() => { scope.error = {} }, 3500) } } diff --git a/web/directives/ffmpeg-settings.js b/web/directives/ffmpeg-settings.js index c59a83b..0a07f21 100644 --- a/web/directives/ffmpeg-settings.js +++ b/web/directives/ffmpeg-settings.js @@ -31,23 +31,27 @@ -t DURATION -re -i INPUTFILE${ scope.settings.deinterlace ? `\n-vf yadif` : `` } --map 0:v +-map VIDEOSTREAM -map AUDIOSTREAM --c:v ${ scope.settings.videoEncoder} --c:a ${ scope.settings.audioEncoder} --ac ${ scope.settings.audioChannels} --ar ${ scope.settings.audioRate} --b:a ${ scope.settings.audioBitrate} --b:v ${ scope.settings.videoBitrate} --s ${ scope.settings.videoResolution} --r ${ scope.settings.videoFrameRate} +-c:v ${ scope.settings.videoEncoder } +-c:a ${ scope.settings.audioEncoder } +-ac ${ scope.settings.audioChannels } +-ar ${ scope.settings.audioRate } +-b:a ${ scope.settings.audioBitrate }k +-b:v ${ scope.settings.videoBitrate }k +-s ${ scope.settings.videoResolution } +-r ${ scope.settings.videoFrameRate } -flags cgop+ilme -sc_threshold 1000000000 --minrate:v ${ scope.settings.videoBitrate} --maxrate:v ${ scope.settings.videoBitrate} --bufsize:v ${ scope.settings.bufSize} +-minrate:v ${ scope.settings.videoBitrate }k +-maxrate:v ${ scope.settings.videoBitrate }k +-bufsize:v ${ scope.settings.bufSize }k +-metadata service_provider="PseudoTV" +-metadata CHANNELNAME -f mpegts -output_ts_offset TSOFFSET +-muxdelay 0 +-muxpreload 0 OUTPUTFILE` } diff --git a/web/directives/plex-library.js b/web/directives/plex-library.js index 0bdfc66..b48153c 100644 --- a/web/directives/plex-library.js +++ b/web/directives/plex-library.js @@ -15,12 +15,19 @@ module.exports = function (plex, pseudotv, $timeout) { updateLibrary(server) } scope._onFinish = (s) => { - scope.onFinish(JSON.parse(angular.toJson(s))) + scope.onFinish(s) scope.selection = [] scope.visible = false } scope.selectItem = (item) => { - scope.selection.push(JSON.parse(angular.toJson(item))) + return new Promise((resolve, reject) => { + $timeout(async () => { + item.streams = await plex.getStreams(scope.plexServer, item.key) + scope.selection.push(JSON.parse(angular.toJson(item))) + scope.$apply() + resolve() + }, 0) + }) } pseudotv.getPlexServers().then((servers) => { if (servers.length === 0) { @@ -50,39 +57,47 @@ module.exports = function (plex, pseudotv, $timeout) { scope.getNested = (list) => { $timeout(async () => { if (typeof list.nested === 'undefined') - list.nested = await plex.getNested(scope.plexServer, list.key) + list.nested = await plex.getNested(scope.plexServer, list.key) list.collapse = !list.collapse scope.$apply() }, 0) } - scope.selectSeason = async (season) => { - $timeout(async () => { - if (typeof season.nested === 'undefined') { - season.nested = await plex.getNested(scope.plexServer, season.key) - } - for (let i = 0, l = season.nested.length; i < l; i++) - scope.selectItem(season.nested[i]) - scope.$apply() - }, 0) + scope.selectSeason = (season) => { + return new Promise((resolve, reject) => { + $timeout(async () => { + if (typeof season.nested === 'undefined') + season.nested = await plex.getNested(scope.plexServer, season.key) + for (let i = 0, l = season.nested.length; i < l; i++) + await scope.selectItem(season.nested[i]) + scope.$apply() + resolve() + }, 0) + }) } - scope.selectShow = async (show) => { - $timeout(async () => { - if (typeof show.nested === 'undefined') - show.nested = await plex.getNested(scope.plexServer, show.key) - for (let i = 0, l = show.nested.length; i < l; i++) - await scope.selectSeason(show.nested[i]) - scope.$apply() - }, 0) + scope.selectShow = (show) => { + return new Promise((resolve, reject) => { + $timeout(async () => { + if (typeof show.nested === 'undefined') + show.nested = await plex.getNested(scope.plexServer, show.key) + for (let i = 0, l = show.nested.length; i < l; i++) + await scope.selectSeason(show.nested[i]) + scope.$apply() + resolve() + }, 0) + }) } scope.selectPlaylist = async (playlist) => { - $timeout(async () => { - if (typeof playlist.nested === 'undefined') - playlist.nested = await plex.getNested(scope.plexServer, playlist.key) - for (let i = 0, l = playlist.nested.length; i < l; i++) - scope.selectItem(playlist.nested[i]) - scope.$apply() - }, 0) + return new Promise((resolve, reject) => { + $timeout(async () => { + if (typeof playlist.nested === 'undefined') + playlist.nested = await plex.getNested(scope.plexServer, playlist.key) + for (let i = 0, l = playlist.nested.length; i < l; i++) + await scope.selectItem(playlist.nested[i]) + scope.$apply() + resolve() + }, 0) + }) } scope.createShowIdentifier = (season, ep) => { return 'S' + (season.toString().padStart(2, '0')) + 'E' + (ep.toString().padStart(2, '0')) diff --git a/web/directives/plex-settings.js b/web/directives/plex-settings.js index ca1df82..349d8e5 100644 --- a/web/directives/plex-settings.js +++ b/web/directives/plex-settings.js @@ -8,13 +8,11 @@ module.exports = function (plex, pseudotv, $timeout) { pseudotv.getPlexServers().then((servers) => { scope.servers = servers }) - scope.plex = { protocol: 'http', host: '127.0.0.1', port: '32400', username: '', password: '', arGuide: false, arChannels: false } + scope.plex = { protocol: 'http', host: '127.0.0.1', port: '32400', arGuide: false, arChannels: false } scope.addPlexServer = function (p) { scope.isProcessing = true plex.login(p) .then((result) => { - delete p['username'] - delete p['password'] p.token = result.token p.name = result.name return pseudotv.addPlexServer(p) diff --git a/web/directives/program-config.js b/web/directives/program-config.js index a24a15e..5012dd0 100644 --- a/web/directives/program-config.js +++ b/web/directives/program-config.js @@ -17,19 +17,18 @@ module.exports = function ($timeout) { } } scope.finished = (prog) => { - if (prog.title === "") { + if (prog.title === "") scope.error = { title: 'You must set a program title.' } - } else if (prog.type === "episode" && prog.showTitle == "") { + else if (prog.type === "episode" && prog.showTitle == "") scope.error = { showTitle: 'You must set a show title when the program type is an episode.' } - } else if (prog.type === "episode" && (prog.season == null)) { + else if (prog.type === "episode" && (prog.season == null)) scope.error = { season: 'You must set a season number when the program type is an episode.' } - } else if (prog.type === "episode" && prog.season <= 0) { + else if (prog.type === "episode" && prog.season <= 0) scope.error = { season: 'Season number musat be greater than 0' } - } else if (prog.type === "episode" && (prog.episode == null)) { + else if (prog.type === "episode" && (prog.episode == null)) scope.error = { episode: 'You must set a episode number when the program type is an episode.' } - } else if (prog.type === "episode" && prog.episode <= 0) { + else if (prog.type === "episode" && prog.episode <= 0) scope.error = { episode: 'Episode number musat be greater than 0' } - } if (scope.error != null) { $timeout(() => { diff --git a/web/public/index.html b/web/public/index.html index 7fd8500..452847a 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -11,7 +11,13 @@
-

PseudoTV

+

PseudoTV + + + + + +

Channels - Settings diff --git a/web/public/templates/channel-config.html b/web/public/templates/channel-config.html index e0493e1..252584c 100644 --- a/web/public/templates/channel-config.html +++ b/web/public/templates/channel-config.html @@ -1,6 +1,6 @@