Alors, ca vaut ce que ca vaut, c'est un peu brut de decoffrage et pas 100% testé.
A la base, c'est pour mon usage perso. Je veut que sur ma seedbox je puisse telecharger un torrent depuis mon mobile, changer l'etiquette via transdroid, et avoir automatiquement le contenu de ce torrent dans la bonne librairie plex. (et pouvoir lancer la video illico en stream sur mon mobile ou sur le chromecast)
Pour l'utiliser, il faut creer des categories dans plex et les affecter a des dossiers, par exemple TV a /home/monlogin/plex/tv
Ensuite, le script verifie dans le dossier de rtorrent si il y a des nouveaux fichiers avec le label TV, crée des liens pour chacun des torrents vers les bons repertoires et met a jour plex et subsonic.
Si vous avez des suggestions d'amélioration, je prend.
Je pense notament a deux trucs :
1- Si quelqu'un sait comment faire les appels xmlrpc a rtorrent en localhost, ce serait plus clean.
Pour fonctionner, il vous faut le paquet php5-xmlrpc et php5-curl.
Edit :
J'ai un peu retravaillé mon script, c'est encore un peu brouillon mais bon en theorie ca devrais marcher (au conditionnel car j'ai pas encore parfaitement testé)
Alors, le script est a foutre dans un fichier dans /usr/bin et mettre les droit exec. Ensuite ca peut tourner dans un cron avec execution toute les minutes
#!/usr/bin/php
<?php
set_time_limit(1200);
$need_plex_update = 0;
$need_subsonic_update = 0;
$plex_array_to_update = array();
if(is_file("/root/.update_plex_global.ini")==false) die("ERREUR : fichier global ini introuvable");
$ini_global = @parse_ini_file("/root/.update_plex_global.ini");
if($ini_global === false) die("ERREUR : fichier global ini invalide");
$update_subsonic = @$ini_global["update_subsonic"]*1;
$subsonic_url = @$ini_global["subsonic_url"];
$subsonic_login = @$ini_global["subsonic_login"];
$subsonic_passwd = @$ini_global["subsonic_passwd"];
$update_plex = @$ini_global["update_plex"]*1;
$plex_url = @$ini_global["plex_url"];
if($update_subsonic == 1){
if (filter_var($subsonic_url, FILTER_VALIDATE_URL) == false) die("ERREUR : url subsonic invalide");
if(strlen($subsonic_login)==0) die("ERREUR : pas de login subsonic");
if(strlen($subsonic_passwd)==0) die("ERREUR : pas de pass subsonic");
}
if($update_plex == 1){
if (filter_var($plex_url, FILTER_VALIDATE_URL) == false) die("ERREUR : url plex invalide");
}
if (substr($subsonic_url, -1) != '/') $subsonic_url .= '/';
if (substr($plex_url, -1) != '/') $plex_url .= '/';
//Verif lock
$lock_scan_file = "/root/.update_plex_lock";
if(is_file($lock_scan_file) == false){
exec('echo "" > '.$lock_scan_file);
exec("chmod 777 ".$lock_scan_file);
if(is_file($lock_scan_file) == false) return "ERREUR : erreur fichier $lock_scan_file inconnu";
}
$fp = fopen($lock_scan_file, "r+");
if (flock($fp, LOCK_EX)) { // acquière un verrou exclusif
ftruncate($fp, 0); // effacement du contenu
if ($handle = opendir('/home/')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && $entry != "global") {
echo update($entry,$ini_global);
echo "\n\r";
}
}
closedir($handle);
}
echo "\n\r";
//MISE A JOUR DE PLEX ET SUBSONIC
if($update_plex == 1 && $need_plex_update == 1){
foreach($plex_array_to_update as $s) get_curl_content("http://localhost:32400/library/sections/".$s."/refresh");
}
if($update_subsonic == 1 && $need_subsonic_update == 1){
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12');
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_COOKIEFILE,"/dev/null");
curl_setopt($ch,CURLOPT_COOKIEJAR,"/dev/null");
$fields = array(
'j_username' => $subsonic_login,
'j_password' => $subsonic_passwd,
'submit' => 'Entrer',
);
$coded = array();
foreach($fields as $field => $value)
$coded[] = $field . '=' . urlencode($value);
$string = implode('&', $coded);
curl_setopt($ch, CURLOPT_URL,"http://127.0.0.1:4040/j_spring_security_check"); //same URL as before, the login url generating
curl_setopt($ch, CURLOPT_POST, True);
curl_setopt($ch, CURLOPT_POSTFIELDS, $string);
$result = curl_exec($ch);
curl_setopt($ch, CURLOPT_POST, False);
curl_setopt($ch, CURLOPT_URL,"http://127.0.0.1:4040/index.view"); //same URL as before, the login url generating the session
$result = curl_exec($ch);
curl_close($ch);
}
fflush($fp); // libère le contenu avant d'enlever le verrou
flock($fp, LOCK_UN); // Enlève le verrou
}
else {
echo "Impossible de verrouiller le fichier !";
}
fclose($fp);
function update($user,$ini_global){
$home_dir = "/home/".$user;
if (substr($home_dir, -1) != '/') $home_dir .= '/';
if(is_file("/root/.update_plex_".$user.".ini")==false) return "ERREUR : fichier ini introuvable dans $home_dir";
$ini = @parse_ini_file("/root/.update_plex_".$user.".ini");
//----------------------------------------------------------------------------
//-------PARAMS------------------------------------------------------------
//----------------------------------------------------------------------------
$login=$user;
echo "USER=$user \n\r";
$password=@$ini["password"];
$host = @$ini_global["host"];
$scgi = "/".strtoupper($login);
$url = "https://".$login."@".$host.$scgi;
$torrent_dir = @realpath(@$ini["torrent_dir"]);
$precedent_scan_file = "/root/.update_plex_precedent_".$login.".txt";
$label = @$ini["label"];
$update_subsonic = @$ini_global["update_subsonic"]*1;
$update_plex = @$ini_global["update_plex"]*1;
$plex_sections = @$ini["plex_sections"];
if($update_plex == 1){
if(is_array($plex_sections)==false || count($plex_sections)==0) die("ERREUR : pas de section configure");
}
//----------------------------------------------------------------------------
//-------CODE-----------------------------------------------------------------
//----------------------------------------------------------------------------
//Verifs All params
if (filter_var($url, FILTER_VALIDATE_URL) == false) return "ERREUR : url invalide";
if(is_dir($torrent_dir) == false) return "ERREUR : repertoire torrent invalide";
if(startsWith($torrent_dir,"/home/".$user."/")==false ) return "ERREUR : repertoire torrent invalide";
if(is_array($label)==false || count($label)==0) return "ERREUR : pas de label configure";
if (substr($torrent_dir, -1) != '/') $torrent_dir .= '/';
if(is_dir($torrent_dir) == false) return "ERREUR : erreur rep $torrent_dir inconnu";
if(startsWith($torrent_dir,"/home/".$user."/")==false ) return "ERREUR : repertoire torrent invalide";
$label2=$label;
foreach($label as $k => $l){
if (substr($l, -1) != '/') $label2[$k] .= '/';
if(startsWith($l,"/home/".$user."/")==false ) return "ERREUR : repertoire label $k : rep $l invalide";
if(is_dir($l) == false){
exec('mkdir -p "'.$l.'"');
if(is_dir($l) == false) return "ERREUR : erreur label $k : rep $l inconnu";
}
}
$label = $label2;
if(is_file($precedent_scan_file) == false){
exec('echo "" > '.$precedent_scan_file);
exec("chmod 777 ".$precedent_scan_file);
exec("chown ".$login.":".$login." ".$precedent_scan_file);
if(is_file($precedent_scan_file) == false) return "ERREUR : erreur fichier $precedent_scan_file inconnu";
}
$precedent_scan = array();
if(file_exists($precedent_scan_file)) $precedent_scan = @unserialize(file_get_contents($precedent_scan_file));
//Fix Perm
exec("chmod 777 ".$precedent_scan_file);
exec('chown '.$login.':'.$login.' '.$precedent_scan_file);
foreach($label as $l){
exec('chmod -R 777 "'.$l.'"');
exec('chown -R '.$login.':'.$login.' "'.$l.'"');
}
$tableau_torrent = array();
$response = do_call(xmlrpc_encode_request('download_list', ''),$login,$password,$url);
$p = xml_parser_create();
xml_parse_into_struct($p, $response, $vals, $index);
xml_parser_free($p);
$index = $index["STRING"];
if(count($index)==0) return "erreur";
foreach($index as $keyhash){
$hash = $vals[intval($keyhash)]["value"];
$response = do_call(xmlrpc_encode_request('d.get_custom1', $hash),$login,$password,$url);
@preg_match('#<value><string>(.*)</string></value>#', $response, $matches);
$tableau_torrent[$hash]["label"] = html_entity_decode(@$matches[1]);
$response = do_call(xmlrpc_encode_request('d.get_base_filename', $hash),$login,$password,$url);
@preg_match('#<value><string>(.*)</string></value>#', $response, $matches);
$tableau_torrent[$hash]["repertoire"] = html_entity_decode(@$matches[1]);
$response = do_call(xmlrpc_encode_request('d.get_complete', $hash),$login,$password,$url);
@preg_match('#<value><i8>(.*)</i8></value>#', $response, $matches);
$tableau_torrent[$hash]["complete"] = intval(@$matches[1]);
}
//html_show_array($tableau_torrent);
if(is_array($precedent_scan) && count($precedent_scan)>0) if(identical_values($precedent_scan,$tableau_torrent)) return "ERREUR : torrents identique";
if(is_array($precedent_scan) && count($precedent_scan)>0){
foreach($precedent_scan as $k => $v){
if(isset($tableau_torrent[$k])==false || $tableau_torrent[$k]["complete"]==0 || ($v["label"] != $tableau_torrent[$k]["label"] && $v["label"] != "")){
foreach($label as $l){
$aeffacer = $l.$v["repertoire"];
if(is_file($aeffacer)) @unlink($aeffacer,$user);
elseif(is_dir($aeffacer)) @unlinkRecursive($l.$v["repertoire"],true,$user);
}
}
}
}
else{
//On clean et on remet en place
foreach($label as $l){
exec("rm -Rf ".$l."/*");
}
}
foreach($tableau_torrent as $k => $v){
if(isset($label[$v["label"]])){
$liste_label = @explode("|",$v["label"]);
if(is_array($liste_label)){
if(count($liste_label)<2) $liste_label = array($v["label"]);
}
else $liste_label = array($v["label"]);
foreach($liste_label as $label_torrent){
$labeldir = $label[$label_torrent];
if(is_file($labeldir.$v["repertoire"])==false && is_dir($labeldir.$v["repertoire"])==false){
@creer_lien($torrent_dir.$v["repertoire"],$labeldir.$v["repertoire"]);
}
}
}
}
file_put_contents($precedent_scan_file,serialize($tableau_torrent));
//Fix Perm
exec("chmod 777 ".$precedent_scan_file);
exec('chown '.$login.':'.$login.' '.$precedent_scan_file);
foreach($label as $l){
exec('chmod -R 777 "'.$l.'"');
exec('chown -R '.$login.':'.$login.' "'.$l.'"');
}
if($update_subsonic == 1) $GLOBALS["need_subsonic_update"] = 1;
if($update_plex == 1){
$GLOBALS["need_plex_update"] = 1;
if(is_array($plex_sections)){
$plex_array_to_update = $GLOBALS["plex_array_to_update"];
foreach($plex_sections as $sec){
$plex_array_to_update[@$sec*1] = @$sec*1;
}
$GLOBALS["plex_array_to_update"] = $plex_array_to_update;
}
}
}
//----------------------------------------------------------------------------
//-------FONCTIONS------------------------------------------------------------
//----------------------------------------------------------------------------
function startsWith($haystack, $needle)
{
return $needle === "" || strpos($haystack, $needle) === 0;
}
function endsWith($haystack, $needle)
{
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
function get_curl_content($url,$post=array()){
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12');
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_COOKIEFILE, "/dev/null");
curl_setopt($ch,CURLOPT_COOKIEJAR,"/dev/null");
if(is_array($post) && count($post)>0){
$coded = array();
foreach($post as $post => $value)
$coded[] = $post . '=' . urlencode($value);
$string = implode('&', $coded);
curl_setopt($ch, CURLOPT_POST, True);
curl_setopt($ch, CURLOPT_POSTFIELDS, $string);
}
echo $url."\n\r";
curl_setopt($ch, CURLOPT_URL, $url);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
function unlock($txt){
fflush($GLOBALS["fp"]); // libère le contenu avant d'enlever le verrou
flock($GLOBALS["fp"], LOCK_UN); // Enlève le verrou
fclose($GLOBALS["fp"]);
echo($txt);
}
function decode_entities($text) {
$text= html_entity_decode($text,ENT_QUOTES,"ISO-8859-1"); #NOTE: UTF-8 does not work!
$text= preg_replace('/&#(\d+);/me',"chr(\\1)",$text); #decimal notation
$text= preg_replace('/&#x([a-f0-9]+);/mei',"chr(0x\\1)",$text); #hex notation
return $text;
}
function identical_values( $arrayA , $arrayB ) {
sort( $arrayA );
sort( $arrayB );
return $arrayA == $arrayB;
}
function makeRecusLink($orig, $dest)
{
if (is_dir($orig)) {
if (substr($orig, -1) != '/') {
$orig .= '/';
}
$handle = opendir($orig);
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..') {
$path = $orig.$file;
if (is_file($path)) {
@link($path, $dest.'/'.$file);
} else if (is_dir($path)) {
@mkdir($dest.'/'.$file, 0755);
makeRecusLink($path, $dest.'/'.$file);
}
}
}
}
@closedir($handle);
}
function creer_lien($source,$dest){
if(is_file($source)) $type=1;
elseif(is_dir($source)) $type=2;
else return 0;
$source=realpath($source);
if($type==2){
if (substr($dest, -1) != '/') {
$dest .= '/';
}
}
if($type==1){
echo $source;
link($source, $dest);
}
elseif($type==2){
@mkdir($dest, 0755);
makeRecusLink($source,$dest);
}
}
function unlinkNoRecursive($dir,$user)
{
$dir = realpath($dir);
if(startsWith($dir,"/home/".$user."/")==false ) return "ERREUR : repertoire a effacer $dir invalide";
@unlink($dir);
}
function unlinkRecursive($dir, $deleteRootToo,$user)
{
$dir = realpath($dir);
if(startsWith($dir,"/home/".$user."/")==false ) return "ERREUR : repertoire a effacer $dir invalide";
if(!$dh = @opendir($dir))
{
return;
}
while (false !== ($obj = readdir($dh)))
{
if($obj == '.' || $obj == '..')
{
continue;
}
if (!@unlink($dir . '/' . $obj))
{
unlinkRecursive($dir.'/'.$obj, true,$user);
}
}
closedir($dh);
if ($deleteRootToo)
{
@rmdir($dir);
}
return;
}
function do_call($request,$login,$password,$url) {
$header[] = "Content-type: text/xml";
$header[] = "Content-length: ".strlen($request);
$header[] = 'Authorization: Basic '. base64_encode($login.":".$password);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$data = curl_exec($ch);
if (curl_errno($ch)) {
print curl_error($ch);
} else {
curl_close($ch);
return $data;
}
}
?>
Et il vous faut des fichiers de config dans /root/ :
Tout d'abord /root/.update_plex_global.ini
Qui contient :
[rtorrent]
host = "monserveur.com"
[plex]
update_subsonic = 1
subsonic_url = "http://127.0.0.1:4040/"
subsonic_login = "admin"
subsonic_passwd = "monmdp"
update_plex = 1;
plex_url = "http://localhost:32400/";
Et pour chaque user pour qui on souhaite activer ce script : /root/.update_plex_
nomutilisateur.ini :
[rtorrent]
password = "MDPuser"
torrent_dir = "/home/user/torrents"
[plex]
label["TV"] = "/home/user/plexdir/tv"
label["FILM"] = "/home/user/plexdir/film"
plex_sections[] = 1
plex_sections[] = 2
plex_sections[] = 3
plex_sections[] = 4
Petite subtilité sur les plex_sections. En gros pour chaque playlist configuré dans plex on a un identifiant numerique. Donc ca sert a definir les numeros des playlist a mettre a jour.
Et voila.