Project

General

Profile

RE: IPTV Services problem ยป service_channel_fix.php

Juraj Bobak, 2017-02-06 22:21

 
1
#!/usr/bin/php-cgi -q
2
<?php
3
/**
4
* This fix was written for HTS Tvheadend 4.1-2415~ge5f5a42-dirty
5
* I'm using it with incron (https://linux.die.net/man/5/incrontab) this way:
6
* When new service appears, MUX file is changed. This event is the trigger to run this script and it's triggered by incron.
7
* Example of incrontab configuration
8
* /home/ivan/.hts/tvheadend/input/iptv/networks/36a38dsw1eed25461d765ave4c60d9c9/muxes IN_ALL_EVENTS /home/ivan/.hts/tvheadend/scripts/service_channel_fix.php $$ $@ $# $% $&
9
* When some file in directory /home/ivan/.hts/tvheadend/input/iptv/networks/36a38dsw1eed25461d765ave4c60d9c9/muxes changes (IN_ALL_EVENTS)
10
* incron will trigger this script with 5 parameters.
11
* Read incron documentation for further information about all those parameters.
12
* Third arugment is the file name that changed and it is MUX ID of service that was created and it is a key to have this working.
13
*/
14

    
15
ob_start();
16
register_shutdown_function('writeOutputToLog', LOCK_FILE);
17

    
18
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Process started with PID: `" . getmypid() . "`\n";
19

    
20
define('LOG_FILE', '/tmp/service_channel_fix.log');
21
define('USER', ''); //use your admin username
22
define('PASS', ''); //use your admin password
23
define('AUTH_STRING', (strlen(USER) && strlen(PASS)) ? USER . ':' . PASS . '@' : '');
24
define('SERVER_ADDR', '127.0.0.1');
25
define('SERVER_PORT', '9981');
26
define('SERVICE_GRIG_LIMIT', 999999999);
27
define('SERVICES_URL', 'http://' . AUTH_STRING . SERVER_ADDR . ':' . SERVER_PORT . '/api/mpegts/service/grid');
28
define('SAVE_ID_NODE_URL',  'http://' . AUTH_STRING . SERVER_ADDR . ':' . SERVER_PORT . '/api/idnode/save');
29
define('DELETE_ID_NODE_URL',  'http://' . AUTH_STRING . SERVER_ADDR . ':' . SERVER_PORT . '/api/idnode/delete');
30

    
31
$curlDefaultOpt = array(
32
	CURLOPT_RETURNTRANSFER => true
33
);
34

    
35
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Passed arguments: " . print_r($argv, true) . "\n";
36
$muxId = $argv[3]; //third arugment passed from incron regarding name of file that changed. It is also a MUX ID
37
if (!strlen($muxId)) die("(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": MUX ID is empty\n");
38

    
39
$services = getServices($muxId); //getting all services related to that mux ID
40
if (!count($services)) die("(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": No services found for MUX ID: `" . $muxId . "`\n");
41

    
42
$channelIds = getChannelIds($services); //getting all channels stored for services. This should return array made mainly from only one channel ID
43
if (!count($channelIds)) die("(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": No channel IDs found for services of MUX ID: `" . $muxId . "`\n");
44

    
45
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Channel IDs: " . print_r($channelIds, true) . "\n";
46
$newServiceIds = getNewServiceIds($services); //getting all service IDs that are new. These IDs we need to pair with our channel(s)
47
if (!count($newServiceIds)) die("(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": No new channel IDs found for services of MUX ID: `" . $muxId . "`\n");
48

    
49
$oldServiceIds = getOldServiceIds($services); //getting all service IDs that are old, not working. These IDs we need to delete because they are not necessary anymore
50

    
51
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": New service IDs: " . print_r($newServiceIds, true) . "\n";
52
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Saving channels to services\n";
53
saveServiceForChannel($newServiceIds, $channelIds);
54

    
55
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Old service IDs to delete: " . print_r($oldServiceIds, true) . "\n";
56
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Deleting services\n";
57
if (count($oldServiceIds))
58
	deleteServices($oldServiceIds);
59

    
60
echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Process finished\n";
61

    
62
exit;
63

    
64
/**
65
* Parses all services and looks only for services that are realted to mux ID
66
* @param string muxId ID of your MUX
67
* @return array Array of service objects
68
*/
69
function getServices($muxId) {
70
	$services		= array();
71
	$allServices	= getAllServices();
72
	foreach($allServices->{'entries'} as $serviceKey => $service) {
73
		if ($service->{'multiplex_uuid'} == $muxId) {
74
			$services[] = $service;
75
		}
76
	}
77
	return $services;
78
}
79

    
80
/**
81
* Requests all services from TVheadend through JSON API
82
* @return array Array of all service objects
83
*/
84
function getAllServices() {
85
	global $curlDefaultOpt;
86
	$curlResource					= curl_init(SERVICES_URL);
87
	$curlOpts						= $curlDefaultOpt;
88
	$curlOpts[CURLOPT_POST]			= true;
89
	$curlOpts[CURLOPT_POSTFIELDS]	= 'start=0&limit=' . SERVICE_GRIG_LIMIT;
90

    
91
	curl_setopt_array($curlResource, $curlOpts);
92

    
93
	$answer = curl_exec($curlResource);
94

    
95
	curl_close($curlResource);
96
	return json_decode($answer);
97
}
98

    
99
/**
100
* Parses services and gets distinct values of all channels from them
101
* @param array services Array of service objects
102
* @return array Array of distinct channel values
103
*/
104
function getChannelIds($services) {
105
	$channels = array();
106
	foreach($services as $serviceKey => $service) {
107
		foreach($service->{'channel'} as $channelId) {
108
			if (!in_array($channelId, $channels))
109
				$channels[] = $channelId; //this is already an array
110
		}
111
	}
112
	return $channels;
113
}
114

    
115
/**
116
* Parses service object and looks for services that have empty channel array.
117
* These are new services that need set the channel(s)
118
* @param array services Array of service objects
119
* @return array Array of service IDs
120
*/
121
function getNewServiceIds($services) {
122
	$newServices = array();
123
	foreach($services as $serviceKey => $service) {
124
		if (!count($service->{'channel'})) {
125
			$newServices[] = $service->{'uuid'};
126
		}
127
	}
128
	return $newServices;
129
}
130

    
131
/**
132
* Parses service object and looks for services that don't have empty channel array.
133
* These are old services that don't work and we want to delete them later
134
* @param array services Array of service objects
135
* @return array Array of service IDs
136
*/
137
function  getOldServiceIds($services) {
138
	$oldServices = array();
139
	foreach($services as $serviceKey => $service) {
140
		if (count($service->{'channel'})) {
141
			$oldServices[] = $service->{'uuid'};
142
		}
143
	}
144
	return $oldServices;
145
}
146

    
147
/**
148
* Saves channnel(s) for service(s)
149
* @param array newServiceIds Array of service objects
150
* @param array channelIds Array of distinct channel values
151
* @return void
152
*/
153
function saveServiceForChannel($newServiceIds, $channelIds) {
154
	foreach($newServiceIds as $newServiceId) {
155
		echo "(" . __FILE__ . ":" . __LINE__ . ") " . date("Y-m-d H:i:s") . ": Saving service ID `" . print_r($newServiceId, true) . "` for channels " . print_r($channelIds, true) . "\n";
156
		saveIdNodes($newServiceId, $channelIds);
157
	}
158
}
159

    
160
/**
161
* Requests TVheadend to store channel ID(s) to service
162
* @param string newServiceId ID of service
163
* @param array channelIds Array of distinct channel values
164
* @return array Array returned from TVheadend as a response
165
*/
166
function saveIdNodes($newServiceId, $channelIds) {
167
	global $curlDefaultOpt;
168
	$curlResource					= curl_init(SAVE_ID_NODE_URL);
169
	$curlOpts						= $curlDefaultOpt;
170
	$curlOpts[CURLOPT_POST]			= true;
171
	//only this way the server accepted the parameters. Don't use postfields as php array. Use this string format to get this work
172
	$curlOpts[CURLOPT_POSTFIELDS]	= 'node=' . json_encode(array(array('channel' => $channelIds, 'uuid' => $newServiceId)));
173
	curl_setopt_array($curlResource, $curlOpts);
174
	curl_setopt($curlResource, CURLINFO_HEADER_OUT, true);
175
	$answer = curl_exec($curlResource);
176
	curl_close($curlResource);
177
	return json_decode($answer);
178
}
179

    
180
/**
181
* Requests TVheadend to delete service ID(s)
182
* @param array oldServiceIds ID of old service(s) to delete
183
* @return array Array returned from TVheadend as a response
184
*/
185
function deleteServices($oldServiceIds) {
186
	global $curlDefaultOpt;
187
	$curlResource					= curl_init(DELETE_ID_NODE_URL);
188
	$curlOpts						= $curlDefaultOpt;
189
	$curlOpts[CURLOPT_POST]			= true;
190
	//only this way the server accepted the parameters. Don't use postfields as php array. Use this string format to get this work
191
	$curlOpts[CURLOPT_POSTFIELDS]	= 'uuid=' . json_encode($oldServiceIds);
192
	curl_setopt_array($curlResource, $curlOpts);
193
	curl_setopt($curlResource, CURLINFO_HEADER_OUT, true);
194
	$answer = curl_exec($curlResource);
195
	curl_close($curlResource);
196
	return json_decode($answer);
197
}
198

    
199
/**
200
* All outputs of this file will be written to log file defined
201
* @return void
202
*/
203
function writeOutputToLog() {
204
	$output = ob_get_clean();
205
	file_put_contents(LOG_FILE, $output, FILE_APPEND);
206
}
    (1-1/1)