|  | 
| 17 | 17 | from os.path import join, basename, getmtime, getsize | 
| 18 | 18 | from platform import system | 
| 19 | 19 | from time import ctime, sleep | 
| 20 |  | -#from copy import deepcopy | 
| 21 |  | -#from textwrap import wrap | 
|  | 20 | +from datetime import datetime | 
| 22 | 21 | 
 | 
| 23 | 22 | from .common import * | 
| 24 | 23 | from .config_window import * | 
| @@ -98,10 +97,14 @@ class PyRadio(object): | 
| 98 | 97 | 
 | 
| 99 | 98 |     _old_config_encoding = '' | 
| 100 | 99 | 
 | 
| 101 |  | - | 
| 102 |  | -    _update_version = '0.8' | 
| 103 |  | -    _update_notify_lock = threading.Lock() | 
|  | 100 | +    # update notification | 
|  | 101 | +    _update_version = '' | 
| 104 | 102 |     _update_version_do_display = '' | 
|  | 103 | +    _update_notification_thread = None | 
|  | 104 | +    stop_update_notification_thread = False | 
|  | 105 | +    _update_notify_lock = threading.Lock() | 
|  | 106 | + | 
|  | 107 | +    _locked = False | 
| 105 | 108 | 
 | 
| 106 | 109 |     def __init__(self, pyradio_config, play=False, req_player='', theme=''): | 
| 107 | 110 |         self._cnf = pyradio_config | 
| @@ -413,7 +416,14 @@ def run(self): | 
| 413 | 416 |         else: | 
| 414 | 417 |             # start update thread | 
| 415 | 418 |             if CAN_CHECK_FOR_UPDATES: | 
| 416 |  | -                pass | 
|  | 419 | +                if self._cnf.locked: | 
|  | 420 | +                    if logger.isEnabledFor(logging.INFO): | 
|  | 421 | +                        logger.info('(detectUpdateThread): session locked. Not starting!!!') | 
|  | 422 | +                else: | 
|  | 423 | +                    self._update_notification_thread = threading.Thread(target=self.detectUpdateThread, | 
|  | 424 | +                            args=(self._cnf.stations_dir, self._update_notify_lock, | 
|  | 425 | +                                lambda: self.stop_update_notification_thread)) | 
|  | 426 | +                    self._update_notification_thread.start() | 
| 417 | 427 | 
 | 
| 418 | 428 |             #signal.signal(signal.SIGINT, self.ctrl_c_handler) | 
| 419 | 429 |             self.log.write('Selected player: {}'.format(self._format_player_string()), help_msg=True) | 
| @@ -458,6 +468,24 @@ def ctrl_c_handler(self, signum, frame): | 
| 458 | 468 |         """ Try to auto save config on exit | 
| 459 | 469 |             Do not check result!!! """ | 
| 460 | 470 |         self._cnf.save_config() | 
|  | 471 | +        if not self._cnf.locked: | 
|  | 472 | +            lock_file = path.join(self._cnf.stations_dir, '.lock') | 
|  | 473 | +            if path.exists(lock_file): | 
|  | 474 | +                try: | 
|  | 475 | +                    os.remove(lock_file) | 
|  | 476 | +                    if logger.isEnabledFor(logging.INFO): | 
|  | 477 | +                        logger.info('Lock file removed...') | 
|  | 478 | +                except: | 
|  | 479 | +                    if logger.isEnabledFor(logging.INFO): | 
|  | 480 | +                        logger.info('Failed to remove Lock file...') | 
|  | 481 | +            else: | 
|  | 482 | +                if logger.isEnabledFor(logging.INFO): | 
|  | 483 | +                    logger.info('Lock file not found...') | 
|  | 484 | + | 
|  | 485 | +        if self._update_notification_thread: | 
|  | 486 | +            if self._update_notification_thread.is_alive(): | 
|  | 487 | +                self.stop_update_notification_thread = True | 
|  | 488 | +                self._update_notification_thread.join() | 
| 461 | 489 | 
 | 
| 462 | 490 |     def _goto_playing_station(self, changing_playlist=False): | 
| 463 | 491 |         """ make sure playing station is visible """ | 
| @@ -1510,6 +1538,169 @@ def _show_config_window(self): | 
| 1510 | 1538 |             self._config_win.parent = self.bodyWin | 
| 1511 | 1539 |             self._config_win.refresh_config_win() | 
| 1512 | 1540 | 
 | 
|  | 1541 | + | 
|  | 1542 | +    def detectUpdateThread(self, a_path, a_lock, stop): | 
|  | 1543 | +        """ a thread to check if an update is available """ | 
|  | 1544 | + | 
|  | 1545 | +        def delay(secs, stop): | 
|  | 1546 | +            for i in range(0, 2 * secs): | 
|  | 1547 | +                sleep(.5) | 
|  | 1548 | +                if stop(): | 
|  | 1549 | +                    return | 
|  | 1550 | + | 
|  | 1551 | +        def to_ver(this_version): | 
|  | 1552 | +            a_v = this_version.replace('-r', '.') | 
|  | 1553 | +            a_l = a_v.split('.') | 
|  | 1554 | +            a_n_l = [] | 
|  | 1555 | +            for n in a_l: | 
|  | 1556 | +                a_n_l.append(int(n)) | 
|  | 1557 | +            return a_n_l | 
|  | 1558 | + | 
|  | 1559 | +        def clean_date_files(files, start=0): | 
|  | 1560 | +            files_to_delete = files[start+1:] | 
|  | 1561 | +            for a_file in files_to_delete: | 
|  | 1562 | +                try: | 
|  | 1563 | +                    remove(a_file) | 
|  | 1564 | +                except: | 
|  | 1565 | +                    pass | 
|  | 1566 | + | 
|  | 1567 | +        def create_tadays_date_file(a_path): | 
|  | 1568 | +            d1 = datetime.now() | 
|  | 1569 | +            now_str = d1.strftime('%Y-%m-%d') | 
|  | 1570 | +            try: | 
|  | 1571 | +                with open(path.join(a_path, '.' + now_str + '.date'), 'w') as f: | 
|  | 1572 | +                    pass | 
|  | 1573 | +            except: | 
|  | 1574 | +                pass | 
|  | 1575 | + | 
|  | 1576 | +        if logger.isEnabledFor(logging.DEBUG): | 
|  | 1577 | +            logger.debug('detectUpdateThread: starting...') | 
|  | 1578 | +        ################## | 
|  | 1579 | +        #delay(5, stop) | 
|  | 1580 | +        from pyradio import version as this_version | 
|  | 1581 | +        connection_fail_count = 0 | 
|  | 1582 | +        delay(random.randint(25, 45), stop) | 
|  | 1583 | +        if stop(): | 
|  | 1584 | +            if logger.isEnabledFor(logging.DEBUG): | 
|  | 1585 | +                logger.debug('detectUpdateThread: Asked to stop. Stoping...') | 
|  | 1586 | +            return | 
|  | 1587 | +        files = glob.glob(path.join(a_path, '.*.date')) | 
|  | 1588 | +        if files: | 
|  | 1589 | +            files.sort(reverse=True) | 
|  | 1590 | +            if len(files) > 1: | 
|  | 1591 | +                clean_date_files(files) | 
|  | 1592 | +            a_date = path.split(path.splitext(files[0])[0])[1][1:] | 
|  | 1593 | + | 
|  | 1594 | + | 
|  | 1595 | +            d1 = datetime.now() | 
|  | 1596 | +            d2 = datetime.strptime(a_date, '%Y-%m-%d') | 
|  | 1597 | +            delta = (d1 - d2).days | 
|  | 1598 | + | 
|  | 1599 | +            if delta > 3: | 
|  | 1600 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1601 | +                    logger.debug('detectUpdateThread: checking for updates') | 
|  | 1602 | +            else: | 
|  | 1603 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1604 | +                    if 3 - delta == 1: | 
|  | 1605 | +                        logger.debug('detectUpdateThread: Will check tomorrow...') | 
|  | 1606 | +                    else: | 
|  | 1607 | +                        logger.debug('detectUpdateThread: Will check in {} days...'.format(3 - delta)) | 
|  | 1608 | +                return | 
|  | 1609 | + | 
|  | 1610 | +        url = 'https://api.github.com/repos/coderholic/pyradio/tags' | 
|  | 1611 | +        while True: | 
|  | 1612 | +            if stop(): | 
|  | 1613 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1614 | +                    logger.debug('detectUpdateThread: Asked to stop. Stoping...') | 
|  | 1615 | +                break | 
|  | 1616 | +            if version_info < (3, 0): | 
|  | 1617 | +                try: | 
|  | 1618 | +                    last_tag = urlopen(url).read(300) | 
|  | 1619 | +                except: | 
|  | 1620 | +                    last_tag = None | 
|  | 1621 | +            else: | 
|  | 1622 | +                try: | 
|  | 1623 | +                    with urlopen(url) as https_response: | 
|  | 1624 | +                        last_tag = https_response.read(300) | 
|  | 1625 | +                except: | 
|  | 1626 | +                    last_tag = None | 
|  | 1627 | + | 
|  | 1628 | +            if stop(): | 
|  | 1629 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1630 | +                    logger.debug('detectUpdateThread: Asked to stop. Stoping...') | 
|  | 1631 | +                break | 
|  | 1632 | +            if last_tag: | 
|  | 1633 | +                connection_fail_count = 0 | 
|  | 1634 | +                x = str(last_tag).split('"name":"') | 
|  | 1635 | +                last_tag = x[1].split('"')[0] | 
|  | 1636 | +                #last_tag = '0.9.9' | 
|  | 1637 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1638 | +                    logger.debug('detectUpdateThread: Upstream version found: {}'.format(last_tag)) | 
|  | 1639 | +                if this_version == last_tag: | 
|  | 1640 | +                    if logger.isEnabledFor(logging.DEBUG): | 
|  | 1641 | +                        logger.debug('detectUpdateThread: No update found. Exiting...') | 
|  | 1642 | +                    break | 
|  | 1643 | +                else: | 
|  | 1644 | +                    existing_version = to_ver(this_version) | 
|  | 1645 | +                    new_version = to_ver(last_tag) | 
|  | 1646 | +                    if existing_version < new_version: | 
|  | 1647 | +                        if stop(): | 
|  | 1648 | +                            if logger.isEnabledFor(logging.DEBUG): | 
|  | 1649 | +                                logger.debug('detectUpdateThread: Asked to stop. Stoping...') | 
|  | 1650 | +                            break | 
|  | 1651 | +                        # remove all existing date files | 
|  | 1652 | +                        clean_date_files(files, -1) | 
|  | 1653 | +                        ############ | 
|  | 1654 | +                        #delay(5 , stop) | 
|  | 1655 | +                        delay(random.randint(120, 300), stop) | 
|  | 1656 | +                        if stop(): | 
|  | 1657 | +                            if logger.isEnabledFor(logging.DEBUG): | 
|  | 1658 | +                                logger.debug('detectUpdateThread: Asked to stop. Stoping...') | 
|  | 1659 | +                            break | 
|  | 1660 | +                        # set new verion | 
|  | 1661 | +                        if logger.isEnabledFor(logging.INFO): | 
|  | 1662 | +                            logger.info('detectUpdateThread: Update available: {}'.format(last_tag)) | 
|  | 1663 | +                        a_lock.acquire() | 
|  | 1664 | +                        self._update_version = last_tag | 
|  | 1665 | +                        a_lock.release() | 
|  | 1666 | +                        while True: | 
|  | 1667 | +                            """ Wait until self._update_version becomes '' | 
|  | 1668 | +                                which means that notification window has been | 
|  | 1669 | +                                displayed. Then create date file and exit. | 
|  | 1670 | +                                If asked to terminate, do not write date file """ | 
|  | 1671 | +                            ########################33 | 
|  | 1672 | +                            #delay(5, stop) | 
|  | 1673 | +                            delay(60, stop) | 
|  | 1674 | +                            if stop(): | 
|  | 1675 | +                                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1676 | +                                    logger.debug('detectUpdateThread: Asked to stop. Stoping but not writing date file...') | 
|  | 1677 | +                                return | 
|  | 1678 | +                            a_lock.acquire() | 
|  | 1679 | +                            if self._update_version == '': | 
|  | 1680 | +                                a_lock.release() | 
|  | 1681 | +                                # create today's date file | 
|  | 1682 | +                                create_tadays_date_file(a_path) | 
|  | 1683 | +                                if logger.isEnabledFor(logging.INFO): | 
|  | 1684 | +                                    logger.info('detectUpdateThread: Terminating after notification... I will check again in 3 days') | 
|  | 1685 | +                                return | 
|  | 1686 | +                            a_lock.release() | 
|  | 1687 | +                    else: | 
|  | 1688 | +                        if logger.isEnabledFor(logging.ERROR): | 
|  | 1689 | +                            logger.error('detectUpdateThread: Ahead of upstream? (current version: {0}, upstream version: {1})'.format(this_version, last_tag)) | 
|  | 1690 | +                        break | 
|  | 1691 | + | 
|  | 1692 | +            else: | 
|  | 1693 | +                if logger.isEnabledFor(logging.DEBUG): | 
|  | 1694 | +                    logger.debug('detectUpdateThread: Error: Cannot get upstream version!!!') | 
|  | 1695 | +                connection_fail_count += 1 | 
|  | 1696 | +                if connection_fail_count > 4: | 
|  | 1697 | +                    if logger.isEnabledFor(logging.DEBUG): | 
|  | 1698 | +                        logger.debug('detectUpdateThread: Error: Too many connection failures. Exiting') | 
|  | 1699 | +                    break | 
|  | 1700 | +                delay(60, stop) | 
|  | 1701 | + | 
|  | 1702 | + | 
|  | 1703 | + | 
| 1513 | 1704 |     def keypress(self, char): | 
| 1514 | 1705 | 
 | 
| 1515 | 1706 |         if self.operation_mode == CONFIG_SAVE_ERROR_MODE: | 
| @@ -2595,13 +2786,4 @@ def keypress(self, char): | 
| 2595 | 2786 |                             self.selections[self.operation_mode] = (self.selection, self.startPos, self.playing, self._cnf.playlists) | 
| 2596 | 2787 |                         self.refreshBody() | 
| 2597 | 2788 | 
 | 
| 2598 |  | -    def detectUpdateThread(self, *args): | 
| 2599 |  | -        """ a thread to check if an update is available | 
| 2600 |  | -
 | 
| 2601 |  | -        arg[0]: config dir | 
| 2602 |  | -        arg[1]: lock | 
| 2603 |  | -        """ | 
| 2604 |  | -        while True: | 
| 2605 |  | - | 
| 2606 |  | -            pass | 
| 2607 | 2789 | # pymode:lint_ignore=W901 | 
0 commit comments