#!/usr/bin/env -S python3 -B

# clifi
# play your favorite streams straight from the command line
#
# Copyright (c) 2020 kevinshome
# This software is released under the terms of the MIT License, which can be found either in the LICENSE file in the root directory of this
# source code, or if unavailable, can also be found at https://opensource.org/licenses/MIT


# initial python version checker
from sys import version_info

_pyminver = '3.2.6'
_currentpyver = str('{0}.{1}.{2}'.format(version_info[0], version_info[1], version_info[2]))
if _currentpyver < _pyminver:
    exit('Sorry, the minimum supported python version is 3.2.6 :(')

from subprocess import Popen, STDOUT
from os import devnull, remove, getuid, getenv, mkdir
from os.path import exists
from sys import stderr, platform
from argparse import ArgumentParser
from time import sleep
from json import load as json_load
from clifi.utils import config_read, vprint, write_json
from clifi import __version__

clifi_dir = '{}/.clifi/'.format(getenv('HOME'))

if exists(clifi_dir + 'clifi.cfg'):

    cfgdata = config_read()
    streamfile = clifi_dir + cfgdata['streamfile']

else:

    print('configuration file not found, creating it now...')
    sleep(0.5)

        
    try:
        mkdir('{}/.clifi'.format(getenv('HOME')))
    except: # if $HOME/.clifi directory already exists, obviously we can't create it again, so just skip mkdir(), and touch the config file
        pass

    f = open(clifi_dir + 'clifi.cfg', 'w')

    data = "# Configuration file for clifi\n\
\n\
streamfile=streams.json\n\
default_stream=lofi\n"

    f.write(data)
    f.close()

    cfgdata = config_read()
    streamfile = clifi_dir + cfgdata['streamfile']

        

parser = ArgumentParser(prog='clifi',
                        description='clifi: play your favorite streams straight from the command line',
                        epilog='created with love in 2020 by kevinshome')

parser.add_argument('stream',
                    help='name of stream to be launched',
                    type=str,
                    nargs='?',
                    default=cfgdata['default_stream'])
parser.add_argument('-v', '--verbose',
                    help='be verbose', 
                    action='store_true')
parser.add_argument('-k', '--kill',
                    help='kill an active session',
                    action='store_true')
parser.add_argument('-n', '--new-stream',
                    help='add a new stream to \'streams.json\'',
                    action='store_true')
parser.add_argument('-rm', '--rm-stream',
                    help='remove a stream from \'streams.json\'',
                    action='store_true')
parser.add_argument('-s', '--switch',
                    help='switch from one stream to another',
                    action='store_true')
parser.add_argument('-S', '--streams',
                    help='return list of streams',
                    action='store_true')
parser.add_argument('-U', '--url',
                    type=str,
                    help='stream directly from a URL, rather than an entry in your streamfile')
parser.add_argument('--version',
                    help='print program version',
                    action='store_true')
parser.add_argument('--devel',
                    help='for development use only, serves no purpose in regular releases',
                    action='store_true')

args = parser.parse_args()

def main(cfgdata, stream_name=args.stream, url=False):
    
    if not url:
        with open(streamfile) as f:
            streams = json_load(f)

        for i in range(len(streams['streams'])):
            stream_name = stream_name
            if streams['streams'][i]['name'] == stream_name:
                stream_url = streams['streams'][i]['url']

    if 'linux' in platform:
        vlc = '/usr/bin/vlc'
    elif platform == 'darwin':
        vlc = '/Applications/VLC.app/Contents/MacOS/VLC'

    try:
        open(vlc, 'r')
        vprint(args, 's', '{} found!'.format(vlc))
    except:
        vprint(args, 'e', '{} not found...'.format(vlc))
        vprint(args, 'f', 'failed to open VLC, please make sure it is installed properly and updated to the latest version')
        exit(1)

    if url:
        stream_url = args.url
        s = Popen("{} -I dummy -q --no-video {} &".format(vlc, stream_url), shell=True, stdout=open(devnull, 'w'), stderr=STDOUT) # run vlc quietly in the background
        print('Running stream from the URL \'{}\' on PID {}'.format(stream_url, s.pid + 1))
        exit(0)

    if stream_name == cfgdata['default_stream']:
        vprint(args, 'a', "no stream entered...")
        vprint(args, 'a', "starting default stream '{}' from {}".format(stream_name, stream_url))
    else:
        try:
            vprint(args, 'a', "starting stream '{}' from {}".format(stream_name, stream_url))
        except UnboundLocalError:
            exit(1)

    s = Popen("{} -I dummy -q --no-video {} &".format(vlc, stream_url), shell=True, stdout=open(devnull, 'w'), stderr=STDOUT) # run vlc quietly in the background

    print('Running stream {} on PID {}'.format(stream_name, s.pid + 1))
    exit(0)

    

if __name__ == '__main__':

    if args.devel:
        pass

    if not exists(streamfile):
        
        print('\'{}\' not found, creating it now...'.format(streamfile))
        sleep(0.5)

        try:
            mkdir('{}/.clifi'.format(getenv('HOME')))
        except: # if $HOME/.clifi directory already exists, obviously we can't create it again, so just skip mkdir(), and touch the JSON file
            pass

        f = open(streamfile, 'w')

        default_json = {
            "_description":"JSON file containing all streams to be used by clifi",
            "streams":[
                {
                    "name":"lofi",
                    "full-name":"lofi hip hop radio - beats to relax/study to",
                    "url":"https://www.youtube.com/watch?v=5qap5aO4i9A"
                }
            ]
        }

        try:
            write_json(streamfile, default_json)
        except:
            exit('failed to write data to \'streams.json\'')
        
        f.close()
    
    if args.rm_stream:
        with open(streamfile) as f:
            data = json_load(f)
        
        for i in range(len(data['streams'])):
            if data['streams'][i]['name'] == args.stream:
                del data['streams'][i]

        
        try:
            write_json(streamfile, data)
        except:
            exit('failed to write data to \'streams.json\'')

        f.close()
        exit(0)    
                
    if args.url:
        open('/tmp/clifi.lck', 'w').close()
        main(cfgdata, url=True)



    if args.switch:
        args.kill = True

    if args.streams:
        with open(streamfile) as f:
            streams = json_load(f)
        
        for i in range(len(streams['streams'])):
            if streams['streams'][i]['name'] == cfgdata['default_stream']:
                print('*' + streams['streams'][i]['name'] + ': \'' + streams['streams'][i]['full-name'] + '\' ({})'.format(streams['streams'][i]['url']))
            else:
                print(streams['streams'][i]['name'] + ': \'' + streams['streams'][i]['full-name'] + '\' ({})'.format(streams['streams'][i]['url']))
        exit(0)

    if args.new_stream:
        stream_name = input('Short name for stream (this is the name you\'ll use to launch the stream): ')
        stream_full_name = input('Full name of stream (not required, will only be used when \'--full-name\' argument is called): ')
        stream_url = input('Stream URL: ')

        with open(streamfile) as f: 
            data = json_load(f) 
            inject = {"name":stream_name, "full-name":stream_full_name, "url":stream_url}
            data['streams'].append(inject)
        
        try:
            write_json(streamfile, data)
        except:
            exit('failed to write data to \'streams.json\'')
        
        print('Successfully added {} to stream list!'.format(stream_name))
        exit(0)

    if args.version:
        stderr.write('clifi {} - this version is hella wavy\n'.format(__version__))
        stderr.flush()
        exit(0)

    if args.kill:
        vprint(args, 'a', 'attempting to kill all vlc instances')

        if 'linux' in platform:
            killall = Popen('killall vlc', shell=True, stdout=open(devnull, 'w'), stderr=STDOUT)
        elif platform == 'darwin': # because macOS is lame and has to be different
            killall = Popen('killall VLC', shell=True, stdout=open(devnull, 'w'), stderr=STDOUT)

        killall.communicate()[0]
        if killall.returncode != 0:
            exit('no instances currently running...')
        else:
            vprint(args, 's', 'killed running vlc instances')

        if not args.switch:
            try:
                vprint(args, 'a', 'attempting to remove \'/tmp/clifi.lck\'')
                remove('/tmp/clifi.lck')
                exit(0)
            except OSError:
                exit('\'/tmp/clifi.lck\' not found...')
        
        if args.switch:
            vprint(args, 'a', 'Launching new stream \'{}\''.format(args.stream))
            main(cfgdata)

    if exists('/tmp/clifi.lck'):
        print('sorry, it looks like there\'s already an instance running...')
        exit('if not, delete \'/tmp/clifi.lck\' and try again')
    else:
        open('/tmp/clifi.lck', 'w').close()
        main(cfgdata)
