예제 #1
0
class Client(object):

    LOG = logging.getLogger(__name__)

    def __init__(self, config):
        self.executor = AsynchExecutor(2)
        self.status_monitor = StatusMonitor(config)
        self.pl_manager = PlaylistManager(config)
        self.POLL_TIME = config.getfloat('Client', 'playlist_poll_time')
        self.scheduler = Scheduler()

    def schedule_playlist(self, playlist, playlist_id, playlist_update_time):
        self.LOG.debug('Client scheduling playlist %s' % playlist)
        if len(playlist) == 0:
            self.LOG.debug('No media to schedule')
            return

        def replace_playlist(scheduled_pl):
            del scheduled_pl[:]
            for media in playlist:
                scheduled_pl.append(media)

        self.scheduler.modify_playlist_atomically(replace_playlist)
        self.status_monitor.confirm_new_playlist(playlist_id,
                                                 playlist_update_time)
        if not self.scheduler.running:
            self.scheduler.start()
        self.status_monitor.submit_collected_events()

    def start(self):
        # Get the first playlist from file. If there is no ready playlist,
        # this returns an empty playlist
        playlist = self.pl_manager.fetch_local_playlist()
        self.schedule_playlist(playlist, None, None)

        # Run by AsynchExecutor
        def get_new_playlist_and_free_up_space_if_necessary():
            return self.pl_manager.fetch_playlist()

        # Called by AsynchExecutor when there was an error
        def pl_fetch_error(error):
            if isinstance(error, PlaylistNotChanged):
                self.LOG.info(
                    'Playlist has not been changed on the server. Asynch task was aborted.'
                )
                self.status_monitor.submit_collected_events()
                return
            self.LOG.error('Exception fetching playlist: {0}'.format(
                error.message))
            self.status_monitor.add_status(StatusMonitor.EventTypes.ERROR,
                                           StatusMonitor.Categories.CONNECTION,
                                           str(error.message))
            self.LOG.debug('Creating status obj')
            self.status_monitor.submit_collected_events()

        self.executor.start()
        try:
            while True:
                if not self.executor.is_full():
                    self.executor.submit(
                        get_new_playlist_and_free_up_space_if_necessary,
                        on_success=self.schedule_playlist,
                        on_error=pl_fetch_error)
                else:
                    self.LOG.debug('Executor task queue is full')
                time.sleep(self.POLL_TIME)
        except KeyboardInterrupt:
            self.executor.shutdown()
            if self.scheduler:
                self.scheduler.shutdown()
예제 #2
0
    def __init__(self):
        wx.Frame.__init__(self, None, -1, title="YouTube Downloader", size=(FRAME_WIDTH, FRAME_HEIGHT), \
                          style=wx.DEFAULT_FRAME_STYLE)
        self.SetMinSize((FRAME_WIDTH, FRAME_HEIGHT))
        self.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_CLOSE, self.__onClose)

        panel = wx.Panel(self)
        vBox = wx.BoxSizer(wx.VERTICAL)
        hBoxes = []

        for i in range(5): # 5 boxsizer to place attributes properly
            hBoxes.append(wx.BoxSizer(wx.HORIZONTAL))

        sourceLabel = wx.StaticText(panel, label="URLs:")
        self.__addButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/addButtonIcon.png")), style=wx.NO_BORDER)
        self.__addButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickAddButton, self.__addButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanAdd, self.__addButton)

        self.__playlistButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/playlistButtonIcon.png")), style=wx.NO_BORDER)
        self.__playlistButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickPlaylistButton, self.__playlistButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanAddPlaylist, self.__playlistButton)

        addBox = wx.BoxSizer(wx.HORIZONTAL)
        addBox.Add(self.__addButton, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=8)
        addBox.Add(self.__playlistButton, flag=wx.ALIGN_CENTER_VERTICAL)

        # labelGridSizer includes attributes that place on the top
        labelGridSizer = wx.GridSizer(cols=3)
        labelGridSizer.Add(sourceLabel, 0, wx.ALIGN_LEFT)
        labelGridSizer.Add(wx.StaticText(panel, size=(wx.GetDisplaySize().Width, -1)), 0, wx.EXPAND | wx.ALIGN_CENTER)
        labelGridSizer.Add(addBox, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
        hBoxes[0].Add(labelGridSizer, flag=wx.EXPAND)
        vBox.Add(hBoxes[0], flag=wx.ALL, border=10)

        # text field to input urls
        self.__sourceText = wx.TextCtrl(panel, size=(-1, wx.GetDisplaySize().Height), style=wx.TE_MULTILINE)
        hBoxes[1].Add(self.__sourceText, proportion=1)
        vBox.Add(hBoxes[1], proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=10)

        # a button to change download directory
        dirBox = wx.BoxSizer(wx.HORIZONTAL)
        self.__changeDirButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/changeDirButtonIcon.png")), style=wx.NO_BORDER)
        self.__changeDirButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickChangeDirButton, self.__changeDirButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanChangeDir, self.__changeDirButton)
        dirBox.Add(self.__changeDirButton, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=8)

        defaultDir = ""
        # set default download directory
        if os.path.exists(CONFIGS): # if the user has already set default directory, read it
            conf = JsonUtil(CONFIGS).read()
            defaultDir = conf['dir']

            if not os.path.exists(defaultDir): # if saved default directory is corrupt, remove it and let user reset it
                os.remove(CONFIGS)
                os.execl(sys.executable, sys.executable, *sys.argv) # restart this program
        else: # otherwise, make the user set default directory
            dialog = wx.DirDialog(None)

            if dialog.ShowModal() == wx.ID_OK:
                defaultDir = dialog.GetPath()

                if os.name == "nt": # setting directory for Windows
                    if not defaultDir.endswith("\\"):
                        defaultDir += "\\"
                else: # for Linux or macOS
                    if not defaultDir.endswith("/"):
                        defaultDir += "/"

                conf = { 'dir': defaultDir }
                JsonUtil(CONFIGS).write(conf)
            else: # if the user click cancel, program should be exited
                self.Destroy()

            dialog.Destroy()

        # this text shows currently selected download directory
        self.__dirText = wx.TextCtrl(panel, value=defaultDir, size=(300, -1), style=wx.TE_READONLY)
        dirBox.Add(self.__dirText)

        # a meaningless icon
        optBox = wx.BoxSizer(wx.HORIZONTAL)
        prefIcon = wx.StaticBitmap(panel, -1, wx.Bitmap(resource_path("images/changePrefIcon.png")))
        prefIcon.SetBackgroundColour(BACKGROUND_COLOR)
        optBox.Add(prefIcon, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=8)

        # a combobox which includes all available stream options that are available on selected video
        self.__prefCombobox = wx.ComboBox(panel, size=(200, -1), style=wx.CB_DROPDOWN | wx.TE_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.__onSelectOption, self.__prefCombobox)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanChangeOption, self.__prefCombobox)
        optBox.Add(self.__prefCombobox)

        # optionGridSizer includes attributes which place on the center
        optionGridSizer = wx.GridSizer(cols=3)
        optionGridSizer.Add(dirBox, 0, wx.ALIGN_LEFT)
        optionGridSizer.Add(wx.StaticText(panel, size=(wx.GetDisplaySize().Width, -1)), 0, wx.EXPAND | wx.ALIGN_CENTER)
        optionGridSizer.Add(optBox, 0, wx.ALIGN_RIGHT)
        hBoxes[2].Add(optionGridSizer, flag=wx.EXPAND)
        vBox.Add(hBoxes[2], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=10)

        # a tabled list which includes download list
        self.__addedList = wx.ListCtrl(panel, style=wx.LC_REPORT | wx.BORDER_DOUBLE)
        cols = [ "제목", "저자", "길이", "옵션", "크기", "속도", "진행률", "남은 시간", "" ] # an empty column not to spoil UI when resizing
        columnWidths = [ 230, 80, 70, 180, 70, 85, 60, 70, wx.GetDisplaySize().Width ]

        for i in range(len(cols)):
            self.__addedList.InsertColumn(i, cols[i], wx.TEXT_ALIGNMENT_RIGHT if i == 0 else wx.TEXT_ALIGNMENT_CENTER)
            self.__addedList.SetColumnWidth(i, columnWidths[i])

        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__onSelectItem, self.__addedList)
        hBoxes[3].Add(self.__addedList, flag=wx.EXPAND | wx.LEFT | wx.RIGHT)
        vBox.Add(hBoxes[3], flag=wx.LEFT | wx.RIGHT, border=10)
        vBox.Add((-1, 10))

        # add 6 buttons (start, pause, skip, stop, info, remove)
        self.__startButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/startButtonIcon.png")), style=wx.NO_BORDER)
        self.__startButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickStartButton, self.__startButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanStart, self.__startButton)
        hBoxes[4].Add(self.__startButton, flag=wx.RIGHT, border=12)

        self.__pauseButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/pauseButtonIcon.png")), style=wx.NO_BORDER)
        self.__pauseButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickPauseButton, self.__pauseButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanPause, self.__pauseButton)
        hBoxes[4].Add(self.__pauseButton, flag=wx.RIGHT, border=12)

        self.__skipButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/skipButtonIcon.png")), style=wx.NO_BORDER)
        self.__skipButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickSkipButton, self.__skipButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanSkip, self.__skipButton)
        hBoxes[4].Add(self.__skipButton, flag=wx.RIGHT, border=12)

        self.__stopButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/stopButtonIcon.png")), style=wx.NO_BORDER)
        self.__stopButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickStopButton, self.__stopButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanStop, self.__stopButton)
        hBoxes[4].Add(self.__stopButton, flag=wx.RIGHT, border=12)

        self.__infoButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/infoButtonIcon.png")), style=wx.NO_BORDER)
        self.__infoButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickInfoButton, self.__infoButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanShowInfo, self.__infoButton)
        hBoxes[4].Add(self.__infoButton, flag=wx.RIGHT, border=12)

        self.__removeButton = wx.BitmapButton(panel, -1, wx.Bitmap(resource_path("images/removeButtonIcon.png")), style=wx.NO_BORDER)
        self.__removeButton.SetBackgroundColour(BACKGROUND_COLOR)
        self.Bind(wx.EVT_BUTTON, self.__onClickRemoveButton, self.__removeButton)
        self.Bind(wx.EVT_UPDATE_UI, self.__onCheckCanRemove, self.__removeButton)
        hBoxes[4].Add(self.__removeButton)

        vBox.Add(hBoxes[4], flag=wx.ALIGN_RIGHT | wx.RIGHT, border=10)
        vBox.Add((-1, 10))
        panel.SetSizer(vBox)

        # status bar to show events
        self.CreateStatusBar()
        self.GetStatusBar().SetBackgroundColour(BACKGROUND_COLOR)
        self.SetStatusText("")

        self.__downloadList = []
        self.__downloading = False
        self.__plm = PlaylistManager()

        self.__am = None # AddManager for adding urls
        self.__dm = None # DownloadManager for downloading videos
        self._lock = threading.Lock()

        self.Center()
        self.Show()
        PlaylistDialog(self, self.__plm).autoAddPlaylist()
예제 #3
0
 def __init__(self, config):
     self.executor = AsynchExecutor(2)
     self.status_monitor = StatusMonitor(config)
     self.pl_manager = PlaylistManager(config)
     self.POLL_TIME = config.getfloat('Client', 'playlist_poll_time')
     self.scheduler = Scheduler()
예제 #4
0
class Client(object):

    LOG = logging.getLogger(__name__)

    def __init__(self, config):
        self.executor = AsynchExecutor(2)
        self.status_monitor = StatusMonitor(config)
        self.pl_manager = PlaylistManager(config)
        self.POLL_TIME = config.getfloat('Client', 'playlist_poll_time')
        self.scheduler = Scheduler()

    def schedule_playlist(self, playlist, playlist_id, playlist_update_time):
        self.LOG.debug('Client scheduling playlist %s' % playlist)
        if len(playlist) == 0:
            self.LOG.debug('No media to schedule')
            return

        def replace_playlist(scheduled_pl):
            del scheduled_pl[:]
            for media in playlist:
                scheduled_pl.append(media)
        self.scheduler.modify_playlist_atomically(replace_playlist)
        self.status_monitor.confirm_new_playlist(playlist_id, playlist_update_time)
        if not self.scheduler.running:
            self.scheduler.start()
        self.status_monitor.submit_collected_events()

    def start(self):
        # Get the first playlist from file. If there is no ready playlist,
        # this returns an empty playlist
        playlist = self.pl_manager.fetch_local_playlist()
        self.schedule_playlist(playlist, None, None)

        # Run by AsynchExecutor
        def get_new_playlist_and_free_up_space_if_necessary():
            return self.pl_manager.fetch_playlist()

        # Called by AsynchExecutor when there was an error
        def pl_fetch_error(error):
            if isinstance(error, PlaylistNotChanged):
                self.LOG.info('Playlist has not been changed on the server. Asynch task was aborted.')
                self.status_monitor.submit_collected_events()
                return
            self.LOG.error('Exception fetching playlist: {0}'.format(error.message))
            self.status_monitor.add_status(
                StatusMonitor.EventTypes.ERROR,
                StatusMonitor.Categories.CONNECTION,
                str(error.message)
            )
            self.LOG.debug('Creating status obj')
            self.status_monitor.submit_collected_events()

        self.executor.start()
        try:
            while True:
                if not self.executor.is_full():
                    self.executor.submit(
                        get_new_playlist_and_free_up_space_if_necessary,
                        on_success=self.schedule_playlist,
                        on_error=pl_fetch_error
                    )
                else:
                    self.LOG.debug('Executor task queue is full')
                time.sleep(self.POLL_TIME)
        except KeyboardInterrupt:
            self.executor.shutdown()
            if self.scheduler:
                self.scheduler.shutdown()
예제 #5
0
 def __init__(self, config):
     self.executor = AsynchExecutor(2)
     self.status_monitor = StatusMonitor(config)
     self.pl_manager = PlaylistManager(config)
     self.POLL_TIME = config.getfloat('Client', 'playlist_poll_time')
     self.scheduler = Scheduler()
예제 #6
0
        "Copy music and playlists to Android Music folder? (Won't waste time overwriting, make sure to enable USB debugging) [y/n] "
    ) == "y"

account_manager = AccountManager(logger)
account_manager.login_spotify()

deezer_object = Deezer()
account_manager.login_deezer(deezer_object)

music_directory = str(Path.cwd().parents[0] / "music")

youtube_tag_dict = collections.OrderedDict()
youtube_manager = YoutubeManager(log_manager, logger, account_manager.spotipy,
                                 music_directory, youtube_tag_dict)

playlist_manager = PlaylistManager(logger=logger,
                                   account_manager=account_manager)

if get_user_playlists:
    playlist_manager.retrieve_spotify_playlists()
if get_custom_playlists:
    playlist_manager.retrieve_custom_playlists()

if len(playlist_manager.playlists) == 0:
    logger.info("You aren't tracking any playlists! I'm all done! :)")
    quit()

playlist_manager.create_playlist_files()

unique_spotify_tracks: list = []
len1 = playlist_manager.get_unique_tracks(unique_spotify_tracks)
예제 #7
0
 def __init__(self):
     self.executor = AsynchExecutor(2)
     self.status_monitor = StatusMonitor()
     self.pl_manager = PlaylistManager()
     self.scheduler = Scheduler()