Custom Plugins - User Script

So you made CouchPotato even more awsome?
User avatar
clinton.hall
Moderator
Posts: 9224
Joined: 28 Jun 2012 12:55
Has thanked: 94 times
Been thanked: 465 times
Contact:
Status: Offline

Custom Plugins - User Script

Postby clinton.hall » 17 Feb 2014 01:11

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.

gardnersm
Junior Member
Posts: 4
Joined: 17 Oct 2013 03:12
Has thanked: 1 time
Status: Offline

Re: Custom Plugins - User Script

Postby gardnersm » 21 Feb 2014 04:58

When trying to use the script I get the following error:
WindowsError: [Error 5] Access is denied

the command is defined as:

"c:\Program Files (x86)\GnuWin32\bin\wget" -q -O NUL --header="Content-Type: application/json" --post-data="{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"VideoLibrary.Scan\"}" http://username:password@127.0.0.1:9999/jsonrpc

Any suggestions?

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 » 21 Feb 2014 06:50

I think you need to pass this as

Code: Select all

command = ['c:\\Program Files (x86)\\GnuWin32\\bin\\wget']


So every "\" must be doubled

Code: Select all

command.append('-q')
command.append('-O')
command.append('--header="Content-Type: application/json"')
command.append('--post-data={\\id\\:1,\\jsonrpc\\:\\2.0\\,\\method\\:\\VideoLibrary.Scan\\}')
command.append('http://username:password@127.0.0.1:9999/jsonrpc')


I have removed a lot of quotes from the post-data... were these really necessary? If there are any replacements/substitutions, then need to be explicitly built into the string before appending to command.

gardnersm
Junior Member
Posts: 4
Joined: 17 Oct 2013 03:12
Has thanked: 1 time
Status: Offline

Re: Custom Plugins - User Script

Postby gardnersm » 24 Feb 2014 01:29

Thanks so much for the info Clinton. Problem ended up being the double slashes. On a side note I ended up having to wrap the command into a windows script file in order to keep xbmc from minimizing.

Wilkovf
Junior Member
Posts: 1
Joined: 01 Mar 2014 13:42
Status: Offline

Re: Custom Plugins - User Script

Postby Wilkovf » 01 Mar 2014 13:52

Am am trying to get a script for converting the movie from DTS to AC to run after the renamer. (http://forum.synology.com/enu/viewtopic.php?f=222&t=81266)

Have made te following adustment to the main.py

Code: Select all

    def callscript(self, message = None, group = None):
        foldername = group['final_folder_name']
               
        command = ['/volume1/video/tools/convert.sh']
        command.append(foldername)
   command.append('/volume1/video/tools/log-movies.txt')


But I thing ''final_folder_name' is not right, can anyone help me?

CP LOG:

Code: Select all

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

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 Mar 2014 22:32

Try

Code: Select all

moviefile = group['renamed_files']
foldername = os.path.split(moviefile[0])[0]

FuN_KeY
Junior Member
Posts: 9
Joined: 15 Mar 2014 18:21
Has thanked: 1 time
Been thanked: 2 times
Status: Offline

Re: Custom Plugins - User Script

Postby FuN_KeY » 15 Mar 2014 19:39

I did use this solution to remove unwanted tracks from mkv (using mkvmerge).

As I do append the language to the folder/file name the path of the files in then wrong. How could I update group['renamed_files'] with the new values to keep couchpotato in sync?

I might use the settings web page to allow easier configuration for this plugin; are there any guidelines how to do so?

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 » 15 Mar 2014 22:17

No real guidelines... Look at the __init__.py files for other modules/plugins.

I'm not sure you can pass the renamed files back... Easiest way way be to import fireevent and fire manage scan to rescan these files.

FuN_KeY
Junior Member
Posts: 9
Joined: 15 Mar 2014 18:21
Has thanked: 1 time
Been thanked: 2 times
Status: Offline

Re: Custom Plugins - User Script

Postby FuN_KeY » 20 Mar 2014 18:28

clinton.hall wrote:No real guidelines... Look at the __init__.py files for other modules/plugins.

I'm not sure you can pass the renamed files back... Easiest way way be to import fireevent and fire manage scan to rescan these files.


It is in fact possible to pass the renamed files. You just need to reaffect group['renamed_files'] to another list. Since it is all reference based it will work

FuN_KeY
Junior Member
Posts: 9
Joined: 15 Mar 2014 18:21
Has thanked: 1 time
Been thanked: 2 times
Status: Offline

Re: Custom Plugins - User Script

Postby FuN_KeY » 01 Jun 2014 21:17

@clinton.hall:

You should update this guide to the new version of couchpotato.

Here are the changes:
- In __init__: def start() should become def autoload()
- In main: dependencies that are not needed should get removed (get_session, toUnicode, ...)

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 Jun 2014 23:53

done...

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 » 07 Jun 2014 12:29

Hi clinton.hall

I want to integrate some postprocessing scripts after couchpotato has renamed my files:

1. background scrapping my renamed movies using Ember Media Manager
2. update xbmc library as last step.

I used to put my code inside nzbToCouchpotato.py but it would be harder to maintain after each pull from your repo (so that I'll have latest version)

Can I use this postprocessing steps here?

I'll put my code for each steps:

My nzbToCouchPotato.py was modified like this:

Code: Select all

if result == 0:
    # Logger.info("Checking SABnzbd status...")
    # autoProcessMovie.check_sabnzbd()
    # Run Ember Media Manager to scrapre additional data
    Logger.info("Launching Ember Media Manager to scrape additional data...")
    result = autoProcessMovie.run_ember()
    if result == 0:
        # SUCCESS: Ember Media Manager ran successfully!
        Logger.info("Ember Media Manager ran successfully.")
        # Update XBMC Video Library
        Logger.info("Building XBMC JSON Object")
        xbmc = autoProcessMovie.get_xbmc_json_obj()
        Logger.info("Update XBMC Video Library...")
        autoProcessMovie.update_videolibrary(xbmc)
        # SUCCESS: autoProcessMovie script ran successfully!
        Logger.info("The autoProcessMovie script completed successfully.")
    else:
        # FAILURE: Ember Media Manager didn't run as expected!
        Logger.info("Ember Media Manager didn't run as expected!")
        Logger.info("MUST Run Ember Media Manager manually before updating XBMC Video Library!")
    if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11
        sys.exit(POSTPROCESS_SUCCESS)
else:
    Logger.info("MAIN: A problem was reported in the autoProcessMovie script.")
    if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11
        sys.exit(POSTPROCESS_ERROR)


1. autoProcessMovie.run_ember() (Ember Media Manager command-line scrapping):

Code: Select all

def runCmd(cmd):
    Logger.info(str(shlex.split(cmd)))
    proc = subprocess.Popen(shlex.split(cmd),
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 stdin=subprocess.PIPE)
    out, err = proc.communicate()
    ret = proc.returncode
    proc.wait()
    return (ret, out, err, proc)
   
def run_ember():

    ###########################################
    #### Ember Media Manager Auto Scraping ####
    ###########################################
    ### Command lines
    ### -------------
    ### -fullask
    ### -fullauto
    ### -missask
    ### -missauto
    ### -newask
    ### -newauto
    ### -markask
    ### -markauto
    ### -file
    ### -folder
    ### -export
    ### -template
    ### -resize
    ### -all
    ### -nfo
    ### -posters
    ### -fanart
    ### -extra
    ### -nowindow
    ### -run
    ###########################################

    config = ConfigParser.ConfigParser()
    configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
   
    if not os.path.isfile(configFilename):
        Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
        return 1 # failure

    config.read(configFilename)

    #setings for Ember Media Manager part of script
    emberMM_path   = config.get("EmberMM", "path")
    emberMM_params = config.get("EmberMM", "params")
    cmd_line = emberMM_path + ' ' + emberMM_params
    Logger.info(cmd_line)

    # Lauch Ember Media Manager and store PID for future kill
    startTime = datetime.datetime.now()
    returnCode, stdOut, stdErr, sp = runCmd(cmd_line)
    Logger.info('- Ember Media Manager: running on PID: (' + str(sp.pid) + ')' + ' started at: ' + str(startTime))
    endTime = datetime.datetime.now()
    # Kill Lauch Media Manager's PID
    emberMM_pid = sp.pid
    subprocess.call("taskkill /F /T /PID %i"%sp.pid)   
    Logger.info('- Ember Media Manager ran for ' + str((endTime - startTime)))   
    Logger.info('- Killed Ember Media Manager on PID: (' + str(emberMM_pid) + ')' )   
    # Return Ember processing code
    return returnCode


2. autoProcessMovie.update_videolibrary(xbmc) (xbmc library update):

Code: Select all

def get_xbmc_json_obj():
   
    config = ConfigParser.ConfigParser()
    configFilename = os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg")
   
    if not os.path.isfile(configFilename):
        Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?")
        return 1 # failure

    config.read(configFilename)

    #setings for xbmc part of script
    host = config.get("XBMC", "host")
    port = config.get("XBMC", "port")
    username = config.get("XBMC", "username")
    password = config.get("XBMC", "password")
    http_address = 'http://%s:%s/jsonrpc' % (host, port)
   
    try:
         import json
    except ImportError:
         import simplejson as json
    import urllib2, base64

    class XBMCJSON:

         def __init__(self, server):
              self.server = server
              self.version = '2.0'

         def __call__(self, **kwargs):
              method = '.'.join(map(str, self.n))
              self.n = []
              return XBMCJSON.__dict__['Request'](self, method, kwargs)

         def __getattr__(self,name):
              if not self.__dict__.has_key('n'):
                    self.n=[]
              self.n.append(name)
              return self

         def Request(self, method, kwargs):
              data = [{}]
              data[0]['method'] = method
              data[0]['params'] = kwargs
              data[0]['jsonrpc'] = self.version
              data[0]['id'] = 1

              data = json.JSONEncoder().encode(data)
              content_length = len(data)

              content = {
                    'Content-Type': 'application/json',
                    'Content-Length': content_length,
              }
     
              request = urllib2.Request(self.server, data, content)
              base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
              request.add_header("Authorization", "Basic %s" % base64string)

              f = urllib2.urlopen(request)
              response = f.read()
              f.close()
              response = json.JSONDecoder().decode(response)

              try:
                    return response[0]['result']               
              except:
                    return response[0]['error']
                   
    xbmc = XBMCJSON(http_address)
    Logger.info('- XBMC JSON Object successfully created!')
    return xbmc
 
def update_videolibrary(xbmc):

    ## Command to update XBMC Video library
    xbmc.VideoLibrary.Scan()
    Logger.info('- XBMC: Updating Video Library.' )

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 » 08 Jun 2014 04:49

yes, you can certainly do this here. look at the examples above and see if all of the information you script needs is available via this method...

DivinityCycle
Junior Member
Posts: 4
Joined: 11 Jun 2014 22:50
Been thanked: 1 time
Status: Offline

Re: Custom Plugins - User Script

Postby DivinityCycle » 11 Jun 2014 23:38

Greetings, everyone :) I've been looking into developing some custom post-processing scripts that CP can run, which lead me here. One thing I'm not clear on how to do: How can I test a custom script I am working on? I've not found an easy way to run do a "dry run" and confirm what is and is not working / happening, aside from restarting CP (which triggers off the renamer). I'm pretty sure I know enough Python to get where I wanna go once I can do some basic debug stuff. Also, when an external script is triggered by CP in this the manner described above, is std_out captured somewhere, like in a log file? Or is that simply lost? Many thanks, love Couch Potato :)

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 » 12 Jun 2014 07:07

The easiest way to capture information is to add it to the logs

Code: Select all

from couchpotato.core.logger import CPLog
log = CPLog(__name__)
log.info('PostProcess Script was called successfully')


So this way you can directly write into Couchpotato's log from the external script.
You could also create your own log file, or dump any information into a text file etc...

I trigger the renamer, without restarting, do an api-call

http:\\localhost:5050\api\<api_key>\renamer.scan

DivinityCycle
Junior Member
Posts: 4
Joined: 11 Jun 2014 22:50
Been thanked: 1 time
Status: Offline

Re: Custom Plugins - User Script

Postby DivinityCycle » 12 Jun 2014 23:08

Thanks to clinton.hall, I'm making some progress. However, I'm stuck.
When testing out my renamer process, I'm getting the following error:
ERROR
[PostProcess] Failed to call script: Traceback (most recent call last):
File "/var/lib/couchpotato/custom_plugins/PostProcess/main.py", line 24, in callscript
try:
File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory


I've got CouchPotato set up to use /var/lib/couchpotato as its Data Directory. As a result, the first part of the plugin is /var/lib/couchpotato/custom_plugins/PostProcess/main.py, containing the following:

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

log = CPLog(__name__)

class PostProcess(Plugin):

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

        def callscript(self, message = None, group = None):
                moviefile = group['renamed_files']
                #foldername = moviefile[0]
                #foldername = os.path.split(moviefile[0])[0]
                command = ['python /datatank/software/Linux/scripts/couchpotato.py']
                #command.append(foldername)
                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


The file /datatank/software/Linux/scripts/couchpotato.py contains:

Code: Select all

#!/usr/bin/env python
import os
import sys
from couchpotato.core.logger import CPLog
log = CPLog(__name__)
log.info('Hey Buddy!')
arguments=str(len(sys.argv))
log.info('Received '+arguments+' arguments.')
cmdargs = str(sys.argv)
log.info('Arguments: '+cmdargs)


For troubleshooting purposes I have done a "chmod 777 /datatank/software/Linux/scripts/couchpotato.py". I've also set 777 on every directory on that path. Same issue.

I've tried to change the "command" around, like "command = ['/usr/bin/python /datatank/software/Linux/scripts/couchpotato.py'] (same result) and "command = ['/datatank/software/Linux/scripts/couchpotato.py']" (which returns an error code 1).

I'm not entirely sure what the hell is happening. Any pointers?

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 » 13 Jun 2014 03:38

try
command = ['python', '/datatank/software/Linux/scripts/couchpotato.py']
or
command = ['/usr/bin/python', '/datatank/software/Linux/scripts/couchpotato.py']

in your couchpotato.py script you are calling, I don't think the logging will work.
I apologise for the incorrect information, I thought you were trying to do the logging within your /var/lib/couchpotato/custom_plugins/PostProcess/main.py script.

What you would need to do is do a "print" within this external script, and inside of /var/lib/couchpotato/custom_plugins/PostProcess/main.py script you could log the output of p (your Popen command)

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 05:00

I realized a little after I posted that I was getting ahead of myself, trying to run the command before understanding the data CP was passing to the plugin. I've successfully created what I'd call a nice "debug" script that spits out the following output in your log:

06-12 19:54:19 INFO [ PostProcess] files={'subtitle_extra': [], 'subtitle': [], 'nfo': ['/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.dvdrip.xvid.repack.nfo'], 'movie': ['/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd1.dvdrip.xvid.repack.avi', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd2.dvdrip.xvid.repack.avi'], 'leftover': ['/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd2.dvdrip.xvid.repack.srr', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED-CD1.nzb', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd1.dvdrip.xvid.repack.sfv', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd1.dvdrip.xvid.repack.srr', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.dvdrip.xvid.repack-sample.srs', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.cd2.dvdrip.xvid.repack.sfv', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED-CD2.nzb', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/failed-tg.dvdrip.xvid.repack-sample.avi', '/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.nzb'], 'movie_extra': [], 'trailer': []}
06-12 19:54:19 INFO [ PostProcess] destination_dir=/datatank/downloads/Movies-Ready/Goonies, The (1985) (DVD)
06-12 19:54:19 INFO [ PostProcess] identifier=tt0089218
06-12 19:54:19 INFO [ PostProcess] media={'status': 'active', 'info': {'rating': {'imdb': [7.8, 137180]}, 'tmdb_id': 9340, 'genres': [u'Adventure', u'Comedy', u'Family'], 'via_imdb': True, 'images': {'disc_art': [u'http://assets.fanart.tv/fanart/movies/9340/moviedisc/the-goonies-513472aab7d7e.png'], 'poster': [u'https://image.tmdb.org/t/p/w154/bZUbpjwnarSHJK40W9sGpyedWhx.jpg', u'http://ia.media-imdb.com/images/M/MV5BMTEyMzM3NDQyMjJeQTJeQWpwZ15BbWU4MDE4ODY0NjEx._V1_.jpg', u'http://ia.media-imdb.com/images/M/MV5BMTEyMzM3NDQyMjJeQTJeQWpwZ15BbWU4MDE4ODY0NjEx._V1_SX300.jpg'], 'backdrop': [u'https://image.tmdb.org/t/p/w1280/5JFJjrWraRix9uHrDDcWR0NJBvf.jpg'], 'extra_thumbs': [u'https://image.tmdb.org/t/p/original/awhHFqiw6Dta0uHQVjgwQiyOgro.jpg', u'https://image.tmdb.org/t/p/original/2l04nGGKGo39NZlzt1Nga5uoyHE.jpg', u'https://image.tmdb.org/t/p/original/hWXJaTCLF0V5VxSAhNe03y8EZhS.jpg', u'https://image.tmdb.org/t/p/original/24fnuB3VX4dQP4f2F4zPfu08Gxr.jpg'], 'poster_original': [u'https://image.tmdb.org/t/p/original/bZUbpjwnarSHJK40W9sGpyedWhx.jpg'], 'actors': {u'John Matuszak': u'https://image.tmdb.org/t/p/w185/AvOqytADHckPxMEFVddrD4FHTU3.jpg', u'Curtis Hanson': u'https://image.tmdb.org/t/p/w185/e8o4pYzVjh4ier1n0bxD78HCbxg.jpg', u'Mary Ellen Trainor': u'https://image.tmdb.org/t/p/w185/w5QWW4oyQWNX51hMcnaCUTPToYX.jpg', u'Martha Plimpton': u'https://image.tmdb.org/t/p/w185/lbQT3s6F2wuVAgZJ6710V8KYspx.jpg', u'Joe Pantoliano': u'https://image.tmdb.org/t/p/w185/zBvDX2HWepvW9im6ikgoyOL2Xj0.jpg', u'Anne Ramsey': u'https://image.tmdb.org/t/p/w185/24AFp6szxbyExOewAGrQIVJzlmN.jpg', u'Josh Brolin': u'https://image.tmdb.org/t/p/w185/x8KKnvHyPvH16M6waAnY1OeCtA8.jpg', u'Steve Antin': u'https://image.tmdb.org/t/p/w185/3GVyNtFWsPz2nCxSgCo6WN6H0UN.jpg', u'Jeff Cohen': u'https://image.tmdb.org/t/p/w185/cd45BDXkwLVODiG5Xyhq7hfMdBq.jpg', u'Kerri Green': u'https://image.tmdb.org/t/p/w185/pktpAjKGdHfjBY7iavENfn2jxYC.jpg', u'Robert Davi': u'https://image.tmdb.org/t/p/w185/vKmIyAdXrO0G6N92xCmWSysxiZv.jpg', u'Sean Astin': u'https://image.tmdb.org/t/p/w185/jqF72oav6vmGAWl33GNO6EpZtwA.jpg', u'Jonathan Ke Quan': u'https://image.tmdb.org/t/p/w185/1cKtw6cBhWPHtjUBiY3si8odVIE.jpg', u'Lupe Ontiveros': u'https://image.tmdb.org/t/p/w185/7omMwfHNyQ6T2O8Trppbpj8ED2W.jpg', u'Corey Feldman': u'https://image.tmdb.org/t/p/w185/ouKwMKHJkqChoT2zPpQYpwjAF40.jpg'}, 'backdrop_original': [u'https://image.tmdb.org/t/p/original/5JFJjrWraRix9uHrDDcWR0NJBvf.jpg'], 'clear_art': [], 'logo': [u'http://assets.fanart.tv/fanart/movies/9340/hdmovielogo/the-goonies-53044087abc6b.png'], 'banner': [u'http://assets.fanart.tv/fanart/movies/9340/moviebanner/the-goonies-51d49de01b83e.jpg'], 'landscape': [u'http://assets.fanart.tv/fanart/movies/9340/moviethumb/the-goonies-51d36a032a519.jpg'], 'extra_fanart': []}, 'titles': [u'The Goonies', u'\u0411\u0430\u043b\u0431\u0435\u0441\u044b', u'Los Goonies', u'Goonies (Les)', u'Kincsvad\xe1szok'], 'imdb': u'tt0089218', 'year': 1985, 'via_tmdb': True, 'plot': u"A young teenager named Mikey Walsh finds an old treasure map in his father's attic. Hoping to save their homes from demolition, Mikey and his friends Data Wang, Chunk Cohen, and Mouth Devereaux run off on a big quest to find the secret stash of Pirate One-Eyed Willie.", 'actor_roles': {u'John Matuszak': u'Sloth', u'Curtis Hanson': u'Mr. Perkins', u'Mary Ellen Trainor': u'Mrs. Walsh', u'Martha Plimpton': u"Stephanie 'Stef' Steinbrenner", u'Joe Pantoliano': u'Francis Fratelli', u'Anne Ramsey': u'Mama Fratelli', u'Josh Brolin': u'Brand Walsh', u'Steve Antin': u'Troy', u'Jeff Cohen': u"Lawrence 'Chunk' Cohen", u'Kerri Green': u'Andy Carmichael', u'Robert Davi': u'Jake Fratelli', u'Sean Astin': u'Mikey Walsh', u'Jonathan Ke Quan': u"Richard 'Data' Wang", u'Lupe Ontiveros': u'Rosalita', u'Corey Feldman': u"Clark 'Mouth' Devereaux", u'Keith Walker': u'Mr. Walsh'}, 'released': '1985-06-06', 'tagline': u'The pirates map, The villainous crooks, The underground caverns, The booby traps, The skeletons, The monster, The lost treasure, and the magic that is... THE GOONIES.', 'original_title': u'The Goonies', 'directors': [u'Richard Donner'], 'writers': [u'Steven Spielberg (story)', u'Chris Columbus (screenplay)'], 'actors': [u'Sean Astin', u'Josh Brolin', u'Jeff Cohen', u'Corey Feldman'], 'mpaa': u'PG', 'runtime': 114, 'type': u'movie'}, '_t': 'media', 'title': u'The Goonies', '_rev': '003ff153', 'profile_id': u'648f9e772d1d42f7bca79403c95fa84b', '_id': '48a7cc981f9f4a4b92b1c8bc5918af04', 'last_edit': 1402627163, 'category_id': u'-1', 'type': 'movie', 'files': {'image_poster': [u'/var/lib/couchpotato/cache/9d2fe2fec5121a5a9806510453db60ed.jpg']}, 'identifiers': {'imdb': 'tt0089218'}}
06-12 19:54:19 INFO [ PostProcess] release_download=None
06-12 19:54:19 INFO [ PostProcess] identifiers=[u'the goonies 1985 dvdrip', u'the goonies 1985']
06-12 19:54:19 INFO [ PostProcess] is_dvd=False
06-12 19:54:19 INFO [ PostProcess] filename=The Goonies (1985) (DVD)
06-12 19:54:19 INFO [ PostProcess] meta_data={'quality_type': 'SD', 'resolution_width': 576, 'group': 'tg', 'resolution_height': 240, 'source': 'DVD', 'audio_channels': 2, 'video': 'XVID', 'aspect': 2.4, 'audio': 'MP3', 'quality': {'_id': '0c45e7eb4dad43f39e8ecf75ace7cc96', 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')], '_rev': '00011fc8', '_t': 'quality', 'size_max': 2400, 'size_min': 600, 'label': 'DVD-Rip', 'width': 720, 'ext': [], 'is_3d': False, 'allow': [], 'alternative': [], 'identifier': 'dvdrip', 'order': 5, 'size': (600, 2400)}, 'size': 1396}
06-12 19:54:19 INFO [ PostProcess] parentdir=/datatank/downloads/Movies-Unprocessed/The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)
06-12 19:54:19 INFO [ PostProcess] renamed_files=[u'/datatank/downloads/Movies-Ready/Goonies, The (1985) (DVD)/The Goonies (1985) (DVD).avi', u'/datatank/downloads/Movies-Ready/Goonies, The (1985) (DVD)/The Goonies (1985) (DVD).avi']
06-12 19:54:19 INFO [ PostProcess] before_rename=[]
06-12 19:54:19 INFO [ PostProcess] dirname=The.Goonies.1985.iNTERNAL.REPACK.DVDRip.XviD-FaiLED.cp(tt0089218)
06-12 19:54:19 INFO [ PostProcess] subtitle_language={}


Here's the main.py that gives you this log output:

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('Command TIME, SON!')
                log.info('files='+str(group['files']))
                log.info('destination_dir='+str(group['destination_dir']))
                log.info('identifier='+str(group['identifier']))
                log.info('media='+str(group['media']))
                log.info('release_download='+str(group['release_download']))
                log.info('identifiers='+str(group['identifiers']))
                log.info('is_dvd='+str(group['is_dvd']))
                log.info('filename='+str(group['filename']))
                log.info('meta_data='+str(group['meta_data']))
                log.info('parentdir='+str(group['parentdir']))
                log.info('renamed_files='+str(group['renamed_files']))
                log.info('before_rename='+str(group['before_rename']))
                log.info('dirname='+str(group['dirname']))
                log.info('subtitle_language='+str(group['subtitle_language']))             
                return True


I'm pretty sure that from here I can figure out what to do with my post-processing :)

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 11:44

Hey clinton

I want to run an external scrapping software. I suppose i could call it from the Popen in your example and log the output. I won't use any parameters from CP.

After that i want to update xbmc library. Does this call to update xbmc get trigfered from same main.py (calling an external .py script) or do i need to integrate this in other way?

Thanks

sent from my Nexus⁴
Plasma: Panasonic TX-55ST60E
HTPC: LC-Power 1320mi :: Sapphire PURE WHITE Fusion E350 :: 4GB DDR3 :: SSD Corsair Nova 2 [SO] :: 4TB [Storage] || Android PC: Minix X5
powered by Win7 :: XBMC Gotham :: SABnzbd :: CouchPotato :: SickBeard

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 14:13

I could also call XBMC notification after ember ran successfully.

Can you help me how?!

For now I have this:

Code: Select all

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

log = CPLog(__name__)

class PostProcess(Plugin, XBMC):
  ###########################################
  #### Ember Media Manager Auto Scraping ####
  ###########################################
  ### Command lines
  ### -------------
  ### -fullask
  ### -fullauto
  ### -missask
  ### -missauto
  ### -newask
  ### -newauto
  ### -markask
  ### -markauto
  ### -file
  ### -folder
  ### -export
  ### -template
  ### -resize
  ### -all
  ### -nfo
  ### -posters
  ### -fanart
  ### -extra
  ### -nowindow
  ### -run
  ###########################################
  def __init__(self):
    addEvent('renamer.after', self.run_ember)

  def run_ember(self, message = None, group = None):
    command = ['D:\EmberMediaManager\Ember Media Manager.exe', '-newauto -all -nowindow']
   
    # Lauch Ember Media Manager
    startTime = datetime.datetime.now()
    log.info('Start scrapping with Ember Media Manager with params: %s', str(command))
    try:
      p = Popen(command, stdout=PIPE)
      log.info('Ember Media Manager: running on PID: (' + str(p.pid) + ')' + ' started at: ' + str(startTime))
      res = p.wait()
      if res == 0:
        endTime = datetime.datetime.now()
        log.info('Ember Media Manager ran sucessfully for: ' + str((endTime - startTime)))
        # Now, update XBMC library with folder
        addEvent('renamer.after', self.notify_xbmc)
        #return True
      else:
        log.info('Ember Media Manager returned an error code: %s', str(res))
    except:
      log.error('Failed to call Ember Media Manager: %s', (traceback.format_exc()))

    return False
 
  def notify_xbmc(self, message = None, group = None):
    try:
      response = XBMC.notify()
      if response == 0:
        # success
        return True
      else:
        # failed
        log.info('XBMC notification returned an error code: %s', str(response))
    except:
      log.error('Failed to notify XBMC: %s', (traceback.format_exc()))
    return False
Last edited by redglory on 13 Jun 2014 18:11, edited 1 time in total.


Return to “External Tools”