Custom Plugins - User Script

So you made CouchPotato even more awsome?
DivinityCycle
Junior Member
Posts: 4
Joined: 11 Jun 2014 22:50
Been thanked: 1 time
Status: Offline

Re: Custom Plugins - User Script

Postby DivinityCycle » 13 Jun 2014 18:08

Actually, before I got to the Couch Potato part of my automation work, I wrote up a pretty easy to use (I think) XBMC controller method.
This may be useful for you, I wrote a single file "make XBMC do a thing" Python script. Its fully documented in the comments, so it may suit your purposes.

Code: Select all

#!/bin/env/python
import json
import urllib2
import base64

# Setings
# The IP address for the XBMC instance you want to talk to
ip = '192.168.1.10'
# The port number XBMC's web interface is listening on
port = '8080'
# The username on XBMC's web interface (just comment or delete this line if you don't use authentication
username = 'xbmc'
# Same as the username.
password = 'xbmc'

# Here you specify the method and parameters you want to pass to the XBMC JSON API
# For a LOT of info on the kinds of things you can do with the interface go here:
# http://wiki.xbmc.org/index.php?title=JSON-RPC_API/v6
# Here's an example of just sending an on-screen notification. This should help you understand the syntax
# method = 'GUI.ShowNotification'
# parameters = {"title":"Hello There!", "message":"This is a notification!", "displaytime":3000}
# This is what I am actually doing with this script, running the Artwork Downloader.
# Note: I am using the "silent" mode to avoid having a pop-up dialog box that would need to be closed.
# Also note: this stuff is very syntax-specific. Boolean and Int values must not be quoted. Strings must be doublequoted.
method = 'Addons.ExecuteAddon'
parameters = {"addonid":"script.artwork.downloader", "params":{"silent":"true"}, "wait":True}

# This is a single, reusable method that makes a call to XBMC and gives you back the response

def getJsonRemote(host,port,username,password,method,parameters):
    # First we build the URL we're going to talk to
    url = 'http://%s:%s/jsonrpc' %(host, port)
    # Next we'll build out the Data to be sent
    values ={}
    values["jsonrpc"] = "2.0"
    values["method"] = method
    # This fork handles instances where no parameters are specified
    if parameters:
        values["params"] = parameters
    values["id"] = "1"
    headers = {"Content-Type":"application/json",}
    # Format the data
    data = json.dumps(values)
    # Now we're just about ready to actually initiate the connection
    req = urllib2.Request(url, data, headers)
    # This fork kicks in only if both a username & password are provided
    if username and password:
        # This properly formats the provided username & password and adds them to the request header
        base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
        req.add_header("Authorization", "Basic %s" % base64string)
    # Now we're ready to talk to XBMC
    # I wrapped this up in a try: statement to allow for graceful error handling
    try:
        response = urllib2.urlopen(req)
        response = response.read()
        response = json.loads(response)
        # A lot of the XBMC responses include the value "result", which lets you know how your call went
        # This logic fork grabs the value of "result" if one is present, and then returns that.
        # Note, if no "result" is included in the response from XBMC, the JSON response is returned instead.
        # You can then print out the whole thing, or pull info you want for further processing or additional calls.
        if 'result' in response:
            response = response['result']
    # This error handling is specifically to catch HTTP errors and connection errors
    except urllib2.URLError as e:
        # In the event of an error, I am making the output begin with "ERROR " first, to allow for easy scripting.
        # You will get a couple different kinds of error messages in here, so I needed a consistent error condition to check for.
        response = 'ERROR '+str(e.reason)
    return response

# Here's an example of using the above method and variable values to make XBMC run the add-on
results=getJsonRemote(ip,port,username,password,method,parameters)
# I just print the results out
print results

User avatar
redglory
Junior Member
Posts: 24
Joined: 22 Aug 2012 00:16
Been thanked: 1 time
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby redglory » 13 Jun 2014 18:14

Hey DivinityCycle,

Thanks for your input, i've just seen it and i think I'll use some for my purpose.

nevertheless, clinton.hall can we explicitly call embeded XBMC class notification (see my pseudo-code)

Thanks

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 14 Jun 2014 13:32

I don't think this is necessary... XBMC notify already listens to renamer after.

But in any case, I think you would be better off importing and calling the existing XBMC class...

To be honest, this is probably a bit beyond me... you could Ask RuudBurger over at github issues...

User avatar
redglory
Junior Member
Posts: 24
Joined: 22 Aug 2012 00:16
Been thanked: 1 time
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby redglory » 14 Jun 2014 13:42

But i have XBMC notify disable as i want to only update library AFTER Ember media Manager has run.

So i was looking forward to call CP's XBMC notify from my custom script, after ember has run successfully.

I'll ask ruud how/if i can do it.

Or else i might have to replicate it's xbmc notifiy implementation on my script.

Thanks :)

Standarduser
Junior Member
Posts: 3
Joined: 30 Jun 2014 20:00
Status: Offline

Re: Custom Plugins - User Script

Postby Standarduser » 30 Jun 2014 20:06

Hi,

my Couchpotato is installed on a Synology NAS with version 45b2dff6.

I want to use a custom pp script and followed the first post of this thread.
For testing my own script just lets the LED blink.
But I get a 'KeyError':


Version of CouchPotato: git:(RuudBurger:CouchPotatoServer master) 45b2dff6 (2014-06-29 11:01:09)

Code: Select all

06-30 20:03:43 ERROR [   couchpotato.core.event] Error in event "renamer.after", that wasn't caught: Traceback (most recent call last):
  File "/volume1/@appstore/couchpotatoserver/share/CouchPotatoServer/couchpotato/core/event.py", line 15, in runHandler
    return handler(*args, **kwargs)
  File "/usr/local/couchpotatoserver/var/custom_plugins/PostProcess/main.py", line 17, in callscript
    imdbid = group['library']['identifier']
KeyError: 'library'
encoding=UTF-8 debug=True args=['--daemon', '--pid_file', '/usr/local/couchpotatoserver/var/couchpotatoserver.pid', '--config_file', '/usr/local/couchpotatoserver/var/settings.conf'] app_dir=/usr/local/couchpotatoserver/share/CouchPotatoServer data_dir=/usr/local/couchpotatoserver/var desktop=None options=Namespace(config_file='/usr/local/couchpotatoserver/var/settings.conf', console_log=False, daemon=True, data_dir=None, debug=False, pid_file='/usr/local/couchpotatoserver/var/couchpotatoserver.pid', quiet=False)


Does anyone have an idea what the problem is?

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 30 Jun 2014 23:44

This happened after a movie was correctly renamed?
I'm not sure why group wouldn't contain any "library" key.
Perhaps this should be in a try. When this failed just set imdb id = None.
Also, if you don't need imdb id for your script, just remove this line...

Standarduser
Junior Member
Posts: 3
Joined: 30 Jun 2014 20:00
Status: Offline

Re: Custom Plugins - User Script

Postby Standarduser » 01 Jul 2014 21:32

Can I get from somewhere a List of all available Keys?

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 01 Jul 2014 23:05

If you have set this to run on the renamer after, the details are passed from https://github.com/RuudBurger/CouchPotatoServer/blob/master/couchpotato/core/plugins/renamer.py#L626

Checkout that page. Above this line, you will see everywhere that the "group" is built and what goes into it.

Otherwise you could run a script that just captures the group data and prints to file... You can then study this to see what is available.

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 31 Jul 2014 09:33

clinton.hall wrote:Hi All,

CouchPotato supports Custom plugins. This post is simply an example of how a user script can be called after renaming, using the Custom Plugin.

what you need to do is create a PostProcess directory inside the "custom_plugins" directory (this in is your data_dir.. look in settings, about, for location).

Now, inside this PostProcess plugin, you create 2 files

__init__.py

Code: Select all

from .main import PostProcess


def autoload():
    return PostProcess()


main.py

Code: Select all

from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from subprocess import Popen, PIPE
import traceback

log = CPLog(__name__)


class PostProcess(Plugin):

    def __init__(self):
        addEvent('renamer.after', self.callscript)

   
    def callscript(self, message = None, group = None):
        imdbid = group['library']['identifier']
        moviefile = group['renamed_files']
        original = group['files']['movie'][0]
       
        command = ['<full/path/to/your/script>']
        command.append(imdbid)
        command.append(original)
        for x in moviefile:
            command.append(x)

        try:
            p = Popen(command, stdout=PIPE)
            res = p.wait()
            if res == 0:
                log.info('PostProcess Script was called successfully')
                return True
            else:
                log.info('PostProcess Script returned an error code: %s', str(res))

        except:
            log.error('Failed to call script: %s', (traceback.format_exc()))


        return False


Here you need to enter the full path to the script you want to call... (if anyone so wants, they could add to the __init__.py to allow this to be set from the web UI...

Also, you may need to change the details of what gets passed to the userscript. this example will run "<full/path/to/your/script> <imdbid> <original_movie_filepath> <renamed_movie_filepath1> <renamed_movie_filepath2> ... <renamed_movie_filepathn>"

There is a lot you can do with this... the above is a simple example only. Please feel free to add your own user scripts and details.


I did all of above i Think

I put the Postprocess in C:\Documents and Settings\Stephan.MEDIA-MYLE\Application Data\CouchPotato\custom_plugins\PostProcess created the 2 files
change the command = ['C:\\Python27\\MovieCleaner.py']

if I run it from the command line python C:\Python27\MovieCleaner.py it works

and yes i rebooted couch because there are two new files in the PostProcess folder .pyc

what have i miss

thanks again
hope this help

See clear as mud
:)
Image

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 31 Jul 2014 13:17

well I change my thinking a bit

What I find with CP it does not like the . in the file name and if the year has () around it find it beater
so I wrote a vbscript to rename the file by right clicking them
but that got to hard work to do i'm a lazy IT guy
so
and a lot of reading and testing and testing

I can up with this python script number 2

so My question is
can I how do I put this into cp and have run when cp checks said file


I know It needs some more work on to get it right I'm leaning

if some can show how to write this beater i be a happy camper.

Code: Select all

import sys,getopt
import glob
import os
import datetime

def MyClean(thisitem):
    '''
    *************************************
    Written By Stephan Mckillen
    MYLE (Making Your Life Easy)
    (c) 2014
    What i have found when Cp rename it does not like the . in the file name
    So this will replace the . spaces and the - with a space
    but does not do the extion.
    this is my very first python SCRIPT
    took me 12 hours to write
    as im a vbscript writer
    '''
    #Its a List so join it
    thisone = " ".join(thisitem)
    #Get the Extion from it
    ext = thisone[-4:]
    #drop the ext and replace all . with a space
    thisone = thisone.replace(ext,"").replace("."," ").replace("-"," ")
    #get the Year
    yy = datetime.date.today().year + 1
    # loop the year and find it and add some () around the year
    for i in xrange(1900,yy):
        # but beater check it the () are NOT there
        CC = thisone.find('('+str(i)+')')
        if CC<1:
            #find the Year and put the () around it
            if thisone.find(str(i))>0:
                return thisone.replace(str(i),'('+str(i)+')')+ext
    return thisone + ext

#print MyClean(sys.argv[1:])
Last edited by MYLE on 31 Jul 2014 13:25, edited 1 time in total.
hope this help

See clear as mud
:)
Image

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 31 Jul 2014 13:24

just insert this code into the postprocess script posted above...

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 31 Jul 2014 13:28

clinton.hall wrote:just insert this code into the postprocess script posted above...


OK then
that the bit i dont understand

I think its something to do with the moviefile variable :huh:
hope this help

See clear as mud
:)
Image

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 01 Aug 2014 02:43

plug it in to the renamer.before, or renamer.after call.

Code: Select all

originalfiles = group['files']['movie']
moviefiles = group['renamed_files']
this creates lists of files to do what you want with.

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 05 Aug 2014 07:42

clinton.hall wrote:plug it in to the renamer.before, or renamer.after call.

Code: Select all

originalfiles = group['files']['movie']
moviefiles = group['renamed_files']
this creates lists of files to do what you want with.


Thanks so what you are saying is

in the Main.py
is
def __init__(self):
addEvent('renamer.after', self.callscript)

so if i did
addEvent('renamer.before,self.MovieCleaner)


and copyed that My def into the Main.py should be all good ???

i try it when im home
hope this help

See clear as mud
:)
Image

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 05 Aug 2014 08:30

yeah, that should work (may need to debug the specific details)

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 05 Aug 2014 14:37

clinton.hall wrote:yeah, that should work (may need to debug the specific details)


Thanks I home have no idea on the debuging of it

I just copy and pasted the code got the indending right and did a alt+x got a couple of error spaceing problem

just going to jump in and see what i break LOL

could u show how to i would deug it

when i run it it come up with importerror No module named couchpotato.core.event my guess is i have to add the Couchpotato to the Path browser what every that call


Just want to say thanks for your time.
hope this help

See clear as mud
:)
Image

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 06 Aug 2014 01:19

This needs to be called from CouchPotato, with the correct data passed in. So running manually isn't going to work.

To debug, add a stack of logging so that you can see where it gets to before it breaks. Then start logging all of the data that is needed to be passed into the next step etc... This takes a lot of time to debug this way.

MYLE
Junior Member
Posts: 8
Joined: 17 Jul 2014 20:26
Status: Offline

Re: Custom Plugins - User Script

Postby MYLE » 07 Aug 2014 13:35

Snap Though you would say that been Reading
hope this help

See clear as mud
:)
Image

craig91
Member
Posts: 57
Joined: 30 Mar 2013 03:49
Has thanked: 2 times
Been thanked: 2 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby craig91 » 22 Dec 2014 07:07

Code: Select all

import os
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from subprocess import Popen, PIPE
import traceback
import pprint

log = CPLog(__name__)

class PostProcess(Plugin):

    def __init__(self):
        addEvent('renamer.after', self.callscript)


    def callscript(self, message = None, group = None):
        log.info('PostProcess Script was called successfully')

        destination = group['destination_dir']

        log.info('Command TIME, SON!')
        log.info('destination_dir='+str(group['destination_dir']))
        command = ['/home/ctrought/scripts/processmovie.sh']
        command.append(destination)

        try:
            p = Popen(command, stdout=PIPE)
            res = p.wait()
            if res == 0:
                log.info('PostProcess Script was called successfully')
                return True
            else:
                log.info('PostProcess Script returned an error code: %s', str(res))

        except:
            log.error('Failed to call script: %s', (traceback.format_exc()))



Can anyone tell me why my script is not called?

Here is the CP log.

Code: Select all

12-22 00:53:59INFO[tato.core.plugins.renamer] Moving "/home/ctrought/Downloads/movies/Gone Girl (2014).mp4" to "/mnt/media/Video/Movies/Gone Girl (2014)/Gone Girl (2014).mp4"
12-22 00:54:24INFO[              PostProcess] PostProcess Script was called successfully
12-22 00:54:24INFO[              PostProcess] Command TIME, SON!
12-22 00:54:24INFO[              PostProcess] destination_dir=/mnt/media/Video/Movies/Gone Girl (2014)
12-22 00:54:24INFO[              PostProcess] PostProcess Script returned an error code: 1
12-22 00:54:24INFO[e.providers.metadata.base] Creating XBMC metadata.


the script

Code: Select all

[root@rhel7 PostProcess]# cd /home/ctrought/scripts/
[root@rhel7 scripts]# ls -lth
total 24K
drwxrwxrwx 2 root root   29 Dec 22 00:55 logs
-rwxr-xr-x 1 root root  280 Dec 22 00:50 processmovie.sh

[root@rhel7 scripts]# cat processmovie.sh
#!/bin/bash

DESTINATION="$1"

echo "POST PROCESS: DESTINATION $DESTINATION" > logs/processmovie.log  2>&1

cp -p _h5ai.header.html "$DESTINATION" >> logs/processmovie.log  2>&1

echo "COPY HEADER RETURN: $?" >> logs/processmovie.log  2>&1

if [[ "$?" == "1" ]]
then
        exit 1
fi


As you can see the script I'm calling will log to logs/processmovie.log but the log is blank which makes me think CP is not calling it. Also the file is not copied that I try to copy in the script.

User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Re: Custom Plugins - User Script

Postby clinton.hall » 22 Dec 2014 21:53

What user runs CouchPotato? Does that user have permissions to write into logs/processmovie.log?


Also, should that actually be /logs/processmovie.log? Without the "/" it is looking for a logs directory inside the cureny directory!!!


Return to “External Tools”