Exemple #1
0
def process_magnet_items(name, raw=False, verify=True, maxnum=10):
    time0 = time.time()
    #
    ## check for jackett
    if core.get_jackett_credentials() is None:
        pool = Pool(processes=5)
        jobs = list(
            map(
                lambda func: pool.apply_async(func, args=(name, maxnum)),
                (
                    get_items_zooqle,
                    get_items_rarbg,  #get_items_kickass,
                    get_items_torrentz,
                    get_items_eztv_io)))
        jobs.append(
            pool.apply_async(get_items_tpb,
                             args=(name, maxnum, False,
                                   False)))  # args.do_any = False
    else:
        pool = Pool(processes=3)
        jobs = list(
            map(
                lambda func: pool.apply_async(func,
                                              args=(name, maxnum, verify)),
                (get_items_zooqle, get_items_eztv_io)))
        jobs.append(
            pool.apply_async(get_items_jackett,
                             args=(name, maxnum, raw, verify)))
    items_all = list(
        chain.from_iterable(filter(None, map(lambda job: job.get(), jobs))))
    logging.info('search for torrents took %0.3f seconds.' %
                 (time.time() - time0))
    pool.close()
    pool.join()
    if len(items_all) != 0: return items_all
    return None
Exemple #2
0
def get_book_torrent_jackett(name, maxnum=10, keywords=[], verify=True):
    """
    Returns a :py:class:`tuple` of candidate book Magnet links found using the main Jackett_ torrent searching service and the string ``"SUCCESS"``, if successful.

    :param str name: the book to search for.
    :param int maxnum: optional argumeent, the maximum number of magnet links to return. Default is 10. Must be :math:`\ge 5`.
    :param list keywords: optional argument. If not empty, the title of the candidate element must have at least one of the keywords in ``keywords``.
    :param bool verify:  optional argument, whether to verify SSL connections. Default is ``True``.
    
    :returns: if successful, then returns a two member :py:class:`tuple` the first member is a :py:class:`list` of elements that match the searched episode, ordered from *most* seeds and leechers to least. The second element is the string ``"SUCCESS"``. The keys in each element of the list are,
       
      * ``title`` is the name of the candidate book to download, and in parentheses the size of the candidate in MB or GB.
      * ``rawtitle`` also the name of the candidate episode to download.
      * ``seeders`` is the number of seeds for this Magnet link.
      * ``leechers`` is the number of leeches for this Magnet link.
      * ``link`` is the Magnet URI link.
      * ``torrent_size`` is the size of this torrent in Megabytes.
    
    If this is unsuccessful, then returns an error :py:class:`tuple` of the form returned by :py:meth:`return_error_raw <howdy.core.return_error_raw>`.
    
    :rtype: tuple

    .. _Jackett: https://github.com/Jackett/Jackett
    """
    import validators
    assert (maxnum >= 5)
    data = core.get_jackett_credentials()
    if data is None:
        return return_error_raw(
            'FAILURE, COULD NOT GET JACKETT SERVER CREDENTIALS')
    url, apikey = data
    if not url.endswith('/'): url = '%s/' % url
    endpoint = 'api/v2.0/indexers/all/results/torznab/api'
    name_split = name.split()
    last_tok = name_split[-1].lower()
    status = re.match('^s[0-9]{2}e[0-9]{2}', last_tok)

    def _return_params(name):
        params = {'apikey': apikey, 'q': name, 'cat': '7020'}
        return params

    logging.info('URL ENDPOINT: %s, PARAMS = %s.' % (urljoin(url, endpoint), {
        'apikey': apikey,
        'q': name,
        'cat': '7020'
    }))
    response = requests.get(urljoin(url, endpoint),
                            params={
                                'apikey': apikey,
                                'q': name,
                                'cat': '7020'
                            },
                            verify=verify)  # tv shows
    if response.status_code != 200:
        return return_error_raw(
            'FAILURE, PROBLEM WITH JACKETT SERVER ACCESSIBLE AT %s.' % url)
    html = BeautifulSoup(response.content, 'lxml')
    if len(html.find_all('item')) == 0:
        return return_error_raw(
            'FAILURE, NO BOOKS SATISFYING CRITERIA FOR GETTING %s' % name)
    items = []

    def _get_magnet_url(item):
        magnet_url = item.find('torznab:attr', {'name': 'magneturl'})
        if magnet_url is not None and 'magnet' in magnet_url['value']:
            return magnet_url['value']
        #
        ## not found it here, must go into URL
        url2 = item.find('guid')
        if url2 is None: return None
        url2 = url2.text
        if not validators.url(url2): return None
        resp2 = requests.get(url2, verify=verify)
        if resp2.status_code != 200: return None
        h2 = BeautifulSoup(resp2.content, 'lxml')
        valid_magnet_links = set(
            map(
                lambda elem: elem['href'],
                filter(
                    lambda elem: 'href' in elem.attrs and 'magnet' in elem[
                        'href'], h2.find_all('a'))))
        if len(valid_magnet_links) == 0: return None
        return max(valid_magnet_links)

    if status is None: last_tok = None
    for item in html('item'):
        title = item.find('title')
        if title is None: continue
        title = title.text
        #
        ## now check if the sXXeYY in name
        if last_tok is not None:
            if last_tok not in title.lower(): continue
        torrent_size = item.find('size')
        if torrent_size is not None:
            torrent_size = float(torrent_size.text) / 1024**2
        seeders = item.find('torznab:attr', {'name': 'seeders'})
        if seeders is None: seeders = -1
        else: seeders = int(seeders['value'])
        leechers = item.find('torznab:attr', {'name': 'peers'})
        if leechers is None: leechers = -1
        else: leechers = int(leechers['value'])
        #
        ## now do one of two things to get the magnet URL
        magnet_url = _get_magnet_url(item)
        if magnet_url is None: continue
        myitem = {
            'title': title,
            'rawtitle': title,
            'seeders': seeders,
            'leechers': leechers,
            'link': magnet_url
        }
        if torrent_size is not None:
            myitem['title'] = '%s (%0.1f MiB)' % (title, torrent_size)
            myitem['torrent_size'] = torrent_size
        pubdate_elem = item.find('pubdate')
        if pubdate_elem is not None:
            try:
                pubdate_s = pubdate_elem.get_text().split(',')[-1].strip()
                pubdate_s = ' '.join(pubdate_s.split()[:3])
                pubdate = datetime.datetime.strptime(pubdate_s,
                                                     '%d %B %Y').date()
                myitem['pubdate'] = pubdate
            except:
                pass
        items.append(myitem)

    items = sorted(items,
                   key=lambda elem: elem['seeders'] + elem['leechers'])[::-1]
    if len(keywords) != 0:
        items = list(
            filter(
                lambda item: any(
                    map(lambda tok: tok.lower() in item['rawtitle'].lower(
                    ), keywords)) and not any(
                        map(
                            lambda tok: tok.lower() in item['rawtitle'].lower(
                            ), keywords_exc)) and all(
                                map(
                                    lambda tok: tok.lower() in item['rawtitle']
                                    .lower(), must_have)), items))
    if len(items) == 0:
        return return_error_raw(
            'FAILURE, NO BOOKS SATISFYING CRITERIA FOR GETTING %s' % name)

    return items[:maxnum], 'SUCCESS'
Exemple #3
0
def get_movie_torrent_jackett(name,
                              maxnum=10,
                              verify=True,
                              doRaw=False,
                              tmdb_id=None):
    """
    Returns a :py:class:`tuple` of candidate movie Magnet links found using the main Jackett_ torrent searching service and the string ``"SUCCESS"``, if successful.

    :param str name: the movie string on which to search.
    :param int maxnum: optional argumeent, the maximum number of magnet links to return. Default is 10. Must be :math:`\ge 5`.
    :param bool verify: optional argument, whether to verify SSL connections. Default is ``True``.
    :param bool doRaw: optional argument. If ``True``, uses the IMDb_ information to search for the movie. Otherwise, uses the full string in ``name`` to search for the movie.
    :param int tmdb_id: optional argument. If defined, use this TMDB_ movie ID to search for magnet links.
    
    :returns: if successful, then returns a two member :py:class:`tuple` the first member is a :py:class:`list` of elements that match the searched movie, ordered from *most* seeds and leechers to least. The second element is the string ``"SUCCESS"``. The keys in each element of the list are,
       
      * ``title`` is the name of the candidate movie to download, and in parentheses the size of the candidate in MB or GB.
      * ``rawtitle`` is *only* the name of the candidate movie to download.
      * ``seeders`` is the number of seeds for this Magnet link.
      * ``leechers`` is the number of leeches for this Magnet link.
      * ``link`` is the Magnet URI link.
      * ``torrent_size`` is the size of this torrent in GB.
    
    If this is unsuccessful, then returns an error :py:class:`tuple` of the form returned by :py:meth:`return_error_raw <howdy.core.return_error_raw>`.
    
    :rtype: tuple
    
    .. _Jackett: https://github.com/Jackett/Jackett
    """
    time0 = time.time()
    data = core.get_jackett_credentials()
    if data is None:
        return return_error_raw(
            'failure, could not get jackett server credentials')
    url, apikey = data
    endpoint = 'api/v2.0/indexers/all/results/torznab/api'
    popName = False
    if tmdb_id is not None: popName = True

    def _return_params(name, popName, tmdb_id):
        params = {'apikey': apikey, 'cat': 2000}
        if tmdb_id is not None:
            imdb_id = movie.get_imdbid_from_id(tmdb_id, verify=verify)
            params['imdbid'] = imdb_id
            return params
        elif doRaw:
            params['q'] = name
            return params

        tmdb_id = movie.get_movie_tmdbids(name, verify=verify)
        #if tmdb_id is None or doRaw and not popName:
        #    params['q'] = name
        #    return params
        #
        ## check that the name matches
        movie_name = movie.get_movie_info(
            tmdb_id, verify=verify)['title'].lower().strip()
        if movie_name != name.lower().strip():
            params['q'] = name
            return params
        imdb_id = movie.get_imdbid_from_id(tmdb_id, verify=verify)
        if imdb_id is None:
            params['q'] = name
            return params
        params['imdbid'] = imdb_id
        return params

    params = _return_params(name, popName, tmdb_id)
    if popName and 'q' in params: params.pop('q')
    logging.info('params: %s, mainURL = %s' % (params, urljoin(url, endpoint)))
    response = requests.get(urljoin(url, endpoint),
                            verify=verify,
                            params=params)
    if response.status_code != 200:
        return return_error_raw(' '.join([
            'failure, problem with jackett server accessible at %s.' % url,
            'Error code = %d. Error data = %s.' %
            (response.status_code, response.content)
        ]))
    logging.info('processed jackett torrents for %s in %0.3f seconds.' %
                 (name, time.time() - time0))
    html = BeautifulSoup(response.content, 'lxml')
    if len(html.find_all('item')) == 0:
        return return_error_raw(
            'failure, could not find movie %s with jackett.' % name)
    items = []

    def _get_magnet_url(item):
        magnet_url = item.find('torznab:attr', {'name': 'magneturl'})
        if magnet_url is not None and 'magnet' in magnet_url['value']:
            return magnet_url['value']
        #
        ## not found it here, must go into URL
        url2 = item.find('guid')
        if url2 is None: return None
        url2 = url2.text
        if not validators.url(url2): return None
        resp2 = requests.get(url2, verify=verify)
        if resp2.status_code != 200: return None
        h2 = BeautifulSoup(resp2.content, 'lxml')
        valid_magnet_links = set(
            map(
                lambda elem: elem['href'],
                filter(
                    lambda elem: 'href' in elem.attrs and 'magnet' in elem[
                        'href'], h2.find_all('a'))))
        if len(valid_magnet_links) == 0: return None
        return max(valid_magnet_links)

    for item in html.find_all('item'):
        title = item.find('title')
        if title is None: continue
        title = title.text
        torrent_size = item.find('size')
        if torrent_size is not None:
            torrent_size = float(torrent_size.text) / 1024**2
        seeders = item.find('torznab:attr', {'name': 'seeders'})
        if seeders is None: seeders = -1
        else: seeders = int(seeders['value'])
        leechers = item.find('torznab:attr', {'name': 'peers'})
        if leechers is None: leechers = -1
        else: leechers = int(leechers['value'])
        #
        ## now do one of two things to get the magnet URL
        magnet_url = _get_magnet_url(item)
        if magnet_url is None: continue
        myitem = {
            'raw_title': title,
            'title': title,
            'seeders': seeders,
            'leechers': leechers,
            'link': magnet_url
        }
        if torrent_size is not None:
            myitem['title'] = '%s (%s)' % (
                title, get_formatted_size(torrent_size * 1024**2))
            myitem['torrent_size'] = torrent_size
        items.append(myitem)
    if len(items) == 0:
        return return_error_raw('FAILURE, JACKETT CANNOT FIND %s' % name)
    return items[:maxnum], 'SUCCESS'
Exemple #4
0
def main( ):
    parser = ArgumentParser( )
    parser.add_argument('-n', '--name', dest='name', type=str, action='store',
                        help = 'Name of the movie to get.', required = True )
    parser.add_argument('-y', '--year', dest='year', type=int, action='store',
                        help = 'Year to look for the movie to get.')
    parser.add_argument('--maxnum', dest='maxnum', type=int, action='store', default = 10,
                        help = 'Maximum number of torrents to look through. Default is 10.')
    parser.add_argument('--timeout', dest='timeout', type=int, action='store', default = 60,
                        help = 'Timeout on when to quit searching for torrents (in seconds). Default is 60 seconds.' )
    #parser.add_argument('--any', dest='do_any', action='store_true', default = False,
    #                  help = 'If chosen, make no filter on movie format.')
    parser.add_argument('-f', '--filename', dest='filename', action='store', type=str,
                        help = 'If defined, put torrent or magnet file into filename.')
    parser.add_argument('--bypass', dest='do_bypass', action='store_true', default=False,
                        help = 'If chosen, bypass YTS.')
    parser.add_argument('--nozooq', dest='do_nozooq', action='store_true', default=False,
                        help = 'If chosen, bypass ZOOQLE.')
    #parser.add_argument('--torrentz', dest='do_torrentz', action='store_true', default=False,
    #                  help = 'If chosen, also look through TORRENTZ to get magnet link.')
    parser.add_argument('--info', dest='do_info', action='store_true', default = False,
                        help = 'If chosen, run in info mode.' )
    parser.add_argument('--add', dest='do_add', action='store_true', default = False,
                        help = 'If chosen, push the magnet link or torrent file into the deluge server.' )  
    parser.add_argument('--noverify', dest='do_verify', action='store_false', default = True,
                        help = 'If chosen, do not verify SSL connections.' )
    parser.add_argument('--raw', dest='do_raw', action='store_true', default = False,
                        help = 'If chosen, do not use IMDB matching for Jackett torrents.')
    args = parser.parse_args( )
    assert( args.timeout >= 10 )
    if args.do_info: logging.basicConfig( level = logging.INFO )
    #
    num_both = 0
    if args.filename is not None: num_both += 1
    if args.do_add: num_both += 1
    assert( num_both != 2 ), "error, at most either one of --f or --add must be set, NOT both."
    #
    time0 = time.time( )
    tmdb_id = None
    if args.year is not None and not args.do_raw:
        tmdb_id = movie.get_movie_tmdbids( args.name, year = args.year )
    if not args.do_bypass:
        try:
            get_movie_yts( args.name, verify = args.do_verify,
                           raiseError = True, to_torrent = args.do_add )
            logging.info( 'search for YTS torrents took %0.3f seconds.' %
                          ( time.time( ) - time0 ) )
            return
        except ValueError: pass

    pool = Pool( processes = 4 )
    if not args.do_nozooq: jobs = [
            pool.apply_async( get_items_zooqle, args = ( args.name, args.maxnum ) ) ]
    else: jobs = [ ]
    #
    ## check for jackett
    if get_jackett_credentials( ) is None:
        jobs += list(map(lambda func: pool.apply_async( func, args = ( args.name, args.maxnum ) ),
                         ( get_items_rarbg, get_items_tpb ) ) )
        #if args.do_torrentz:
        #    jobs.append( pool.apply_async( get_items_torrentz, args = ( args.name, args.maxnum ) ) )
    else:
        jobs.append( pool.apply_async(
            get_items_jackett, args = ( args.name, tmdb_id, args.maxnum, args.do_verify, args.do_raw ) ) )
        jobs.append( pool.apply_async(
            get_items_eztv_io, args = ( args.name, tmdb_id, args.maxnum, args.do_verify ) ) )
    items_lists = [ ]
    for job in jobs:
        try:
            items = job.get( args.timeout )   # 60 second timeout on process
            if items is None: continue
            items_lists.append( items )
        except: pass
    items = list( chain.from_iterable( items_lists ) )
    logging.info( 'search for %d torrents took %0.3f seconds.' % (
        len( items ), time.time( ) - time0 ) )    
    if len( items ) == 0: return
    #
    ## sort from most seeders + leecher to least
    items_sorted = sorted( items, key = lambda tup: -tup['seeders'] - tup['leechers'] )[:args.maxnum]
    get_movie_torrent_items( items_sorted, filename = args.filename, to_torrent = args.do_add )
Exemple #5
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-n',
                        '--name',
                        dest='name',
                        type=str,
                        action='store',
                        required=True,
                        help='Name of the book to get.')
    parser.add_argument(
        '--maxnum',
        dest='maxnum',
        type=int,
        action='store',
        default=10,
        help='Maximum number of torrents to look through. Default is 10.')
    parser.add_argument('-f',
                        '--filename',
                        dest='filename',
                        action='store',
                        type=str,
                        help='If defined, put magnet link into filename.')
    parser.add_argument(
        '--add',
        dest='do_add',
        action='store_true',
        default=False,
        help='If chosen, push the magnet link into the deluge server.')
    parser.add_argument('--info',
                        dest='do_info',
                        action='store_true',
                        default=False,
                        help='If chosen, run in info mode.')
    parser.add_argument('--noverify',
                        dest='do_verify',
                        action='store_false',
                        default=True,
                        help='If chosen, do not verify SSL connections.')
    args = parser.parse_args()
    logger = logging.getLogger()
    if args.do_info: logger.setLevel(logging.INFO)
    #
    time0 = time.time()
    if core.get_jackett_credentials() is None:
        print('Error, Jackett server does not work. Exiting...')
        retur
    items = get_items_jackett(args.name,
                              maxnum=args.maxnum,
                              verify=args.do_verify)
    logging.info('search for %s took %0.3f seconds.' %
                 (args.name, time.time() - time0))
    if items is None: return
    #
    ## sort from most seeders + leecher to least
    items_sorted = sorted(
        items,
        key=lambda tup:
        (-tup['seeders'] - tup['leechers'], tup['title']))[:args.maxnum]
    get_book_torrent_items(items_sorted,
                           filename=args.filename,
                           to_torrent_server=args.do_add)