403Webshell
Server IP : 93.86.61.54  /  Your IP : 216.73.216.60
Web Server : Apache/2.4.62 (Ubuntu)
System : Linux rasin.ddns.net 6.8.0-124-generic #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC x86_64
User : www-data ( 33)
PHP Version : 8.4.22
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/org.gnome.SoundRecorder/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/org.gnome.SoundRecorder/org.gnome.SoundRecorder.src.gresource
GVariant�(

��$0	�L��rZY��v�M�E�Mvh�,Ե�����,L�,�,��1��,v�,�6i�g�6v�63M�ra�3Mv@MzU���zUL�U�U�z?��Uv�U�vKP��vL�v�v|9e:�vv�v����v���-~�Z��	vȬx�.��x�v���^A�&�L$�(����T(�v@�;�gnome/recording.jsE/* exported Recording */
const { Gio, GLib, GObject, Gst, GstPbutils } = imports.gi;
const { CacheDir } = imports.application;
const ByteArray = imports.byteArray;
const Recorder = imports.recorder;

var Recording = new GObject.registerClass({
    Signals: {
        'peaks-updated': {},
        'peaks-loading': {},
    },
    Properties: {
        'duration': GObject.ParamSpec.int(
            'duration',
            'Recording Duration', 'Recording duration in nanoseconds',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            0, GLib.MAXINT16, 0),
        'name': GObject.ParamSpec.string(
            'name',
            'Recording Name', 'Recording name in string',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            null),
    },
}, class Recording extends GObject.Object {
    _init(file) {
        this._file = file;
        this._peaks = [];
        this._loadedPeaks = [];
        super._init({});

        let info = file.query_info('time::created,time::modified,standard::content-type', 0, null);
        const contentType = info.get_attribute_string('standard::content-type');

        for (let profile of Recorder.EncodingProfiles) {
            if (profile.contentType === contentType) {
                this._extension = profile.extension;
                break;
            }
        }

        let timeModified = info.get_attribute_uint64('time::modified');
        let timeCreated = info.get_attribute_uint64('time::created');
        this._timeModified = GLib.DateTime.new_from_unix_local(timeModified);
        this._timeCreated = GLib.DateTime.new_from_unix_local(timeCreated);

        var discoverer = new GstPbutils.Discoverer();
        discoverer.start();
        discoverer.connect('discovered', (_discoverer, audioInfo) => {
            this._duration = audioInfo.get_duration();

            this.notify('duration');
        });

        discoverer.discover_uri_async(this.uri);
    }

    get name() {
        return this._file.get_basename();
    }

    set name(filename) {
        if (filename && filename !== this.name) {
            this._file = this._file.set_display_name(filename, null);
            this.notify('name');
        }
    }

    get extension() {
        return this._extension;
    }

    get timeModified() {
        return this._timeModified;
    }

    get timeCreated() {
        return this._timeCreated;
    }

    get duration() {
        if (this._duration)
            return this._duration;
        else
            return 0;
    }

    get file() {
        return this._file;
    }

    get uri() {
        return this._file.get_uri();
    }

    // eslint-disable-next-line camelcase
    set peaks(data) {
        if (data.length > 0) {
            this._peaks = data;
            this.emit('peaks-updated');
            const buffer = new GLib.Bytes(JSON.stringify(data));
            this.waveformCache.replace_contents_bytes_async(buffer, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null, (obj, res) => {
                obj.replace_contents_finish(res);
            });
        }
    }

    // eslint-disable-next-line camelcase
    get peaks() {
        return this._peaks;
    }

    delete() {
        this._file.trash_async(GLib.PRIORITY_HIGH, null, null);
        this.waveformCache.trash_async(GLib.PRIORITY_DEFAULT, null, null);
    }

    save(dest) {
        this.file.copy_async(dest,
            Gio.FileCreateFlags.NONE, GLib.PRIORITY_DEFAULT, null, null, (obj, res) => {
                if (obj.copy_finish(res))
                    log('Exporting file: done');
            });
    }

    get waveformCache() {
        return CacheDir.get_child(`${this.name}_data`);
    }

    loadPeaks() {
        if (this.waveformCache.query_exists(null)) {
            this.waveformCache.load_bytes_async(null, (obj, res) => {
                const bytes = obj.load_bytes_finish(res)[0];
                try {
                    this._peaks = JSON.parse(ByteArray.toString(bytes.get_data()));
                    this.emit('peaks-updated');
                } catch (error) {
                    log(`Error reading waveform data file: ${this.name}_data`);
                }
            });
        } else {
            this.emit('peaks-loading');
            this.generatePeaks();
        }
    }

    generatePeaks() {
        this.pipeline = Gst.parse_launch('uridecodebin name=uridecodebin ! audioconvert ! audio/x-raw,channels=1 ! level name=level ! fakesink name=faked');


        let uridecodebin = this.pipeline.get_by_name('uridecodebin');
        uridecodebin.set_property('uri', this.uri);

        let fakesink = this.pipeline.get_by_name('faked');
        fakesink.set_property('qos', false);
        fakesink.set_property('sync', true);

        const bus = this.pipeline.get_bus();
        this.pipeline.set_state(Gst.State.PLAYING);
        bus.add_signal_watch();

        bus.connect('message', (_bus, message) => {
            let s;
            switch (message.type) {
            case Gst.MessageType.ELEMENT:
                s = message.get_structure();
                if (s && s.has_name('level')) {
                    const peakVal = s.get_value('peak');

                    if (peakVal) {
                        const peak = peakVal.get_nth(0);
                        this._loadedPeaks.push(Math.pow(10, peak / 20));
                    }
                }
                break;
            case Gst.MessageType.EOS:
                this.peaks = this._loadedPeaks;
                this.pipeline.set_state(Gst.State.NULL);
                this.pipeline = null;
                break;
            }
        });
    }
});

(uuay)recordingListWidget.js/* exported RecordingsListWidget */
const { Adw, GObject, GstPlayer, Gtk, Gst } = imports.gi;
const { Row, RowState } = imports.row;

var RecordingsListWidget = new GObject.registerClass({
    Signals: {
        'row-deleted': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
    },
}, class RecordingsListWidget extends Adw.Bin {
    _init(model, player) {
        super._init();
        this.list = Gtk.ListBox.new();
        this.list.valign = Gtk.Align.START;
        this.list.margin_start = 8;
        this.list.margin_end = 8;
        this.list.margin_top = 12;
        this.list.margin_bottom = 12;
        this.list.activate_on_single_click = true;
        this.list.add_css_class('boxed-list');

        this.set_child(this.list);

        this._player = player;
        this._player.connect('state-changed', (_player, state) => {
            if (state === GstPlayer.PlayerState.STOPPED && this.activePlayingRow) {
                this.activePlayingRow.state = RowState.PAUSED;
                this.activePlayingRow.waveform.position = 0.0;
            } else if (state === GstPlayer.PlayerState.PLAYING) {
                this.activePlayingRow.state = RowState.PLAYING;
            }
        });

        this._player.connect('position-updated', (_player, pos) => {
            const duration = this.activePlayingRow._recording.duration;
            this.activePlayingRow.waveform.position = pos / duration;
        });

        this.list.bind_model(model, recording => {
            let row = new Row(recording);

            row.waveform.connect('gesture-pressed', _ => {
                if (!this.activePlayingRow || this.activePlayingRow !== row) {

                    if (this.activePlayingRow)
                        this.activePlayingRow.waveform.position = 0.0;

                    this.activePlayingRow = row;
                    this._player.set_uri(recording.uri);
                }
            });

            row.waveform.connect('position-changed', (_wave, _position) => {
                this._player.seek(_position * row._recording.duration);
            });

            row.connect('play', _row => {
                if (this.activePlayingRow) {
                    if (this.activePlayingRow !== _row) {
                        this.activePlayingRow.state = RowState.PAUSED;
                        this.activePlayingRow.waveform.position = 0.0;
                        this._player.set_uri(recording.uri);
                    }
                } else {
                    this._player.set_uri(recording.uri);
                }

                this.activePlayingRow = _row;
                this._player.play();
            });

            row.connect('pause', _row => {
                this._player.pause();
            });

            row.connect('seek-backward', _row => {
                let position = this._player.position - 10 * Gst.SECOND;
                position = position < 0 || position > _row._recording.duration ? 0 : position;
                this._player.seek(position);
            });
            row.connect('seek-forward', _row => {
                let position = this._player.position + 10 * Gst.SECOND;
                position = position < 0 || position > _row._recording.duration ? 0 : position;
                this._player.seek(position);
            });

            row.connect('deleted', () => {
                if (row === this.activeRow)
                    this.activeRow = null;

                if (row === this.activePlayingRow) {
                    this.activePlayingRow = null;
                    this._player.stop();
                }

                const index = row.get_index();
                this.isolateAt(index, false);
                this.emit('row-deleted', row._recording, index);
            });

            return row;
        });

        this.list.connect('row-activated', this.rowActivated.bind(this));
    }

    rowActivated(list, row) {
        if (row.editMode && row.expanded || this.activeRow && this.activeRow.editMode && this.activeRow.expanded)
            return;

        if (this.activeRow && this.activeRow !== row) {
            this.activeRow.expanded = false;
            this.isolateAt(this.activeRow.get_index(), false);
        }
        row.expanded = !row.expanded;
        this.isolateAt(row.get_index(), row.expanded);

        this.activeRow = row;
    }

    isolateAt(index, expanded) {
        const before = this.list.get_row_at_index(index - 1);
        const current = this.list.get_row_at_index(index);
        const after = this.list.get_row_at_index(index + 1);

        if (expanded) {
            if (current)
                current.add_css_class('expanded');
            if (before)
                before.add_css_class('expanded-before');
            if (after)
                after.add_css_class('expanded-after');
        } else {
            if (current)
                current.remove_css_class('expanded');
            if (before)
                before.remove_css_class('expanded-before');
            if (after)
                after.remove_css_class('expanded-after');
        }
    }
});
(uuay)/	utils.js�	/* exported displayDateTime formatTime */
/*
 * Copyright 2013 Meg Ford
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Meg Ford <megford@gnome.org>
 *
 */
const Gettext = imports.gettext;
const { GLib, Gst } = imports.gi;

var formatTime = nanoSeconds => {
    const time = new Date(0, 0, 0, 0, 0, 0, parseInt(nanoSeconds / Gst.MSECOND));

    const miliseconds = parseInt(time.getMilliseconds() / 100).toString();
    const seconds = time.getSeconds().toString().padStart(2, '0');
    const minutes = time.getMinutes().toString().padStart(2, '0');
    const hours = time.getHours().toString().padStart(2, '0');

    // eslint-disable-next-line no-irregular-whitespace
    return `${hours} ∶ ${minutes} ∶ ${seconds} . <small>${miliseconds}</small>`;
};

var displayDateTime = time => {
    const DAY = 86400000000;
    const now = GLib.DateTime.new_now_local();
    const difference = now.difference(time);

    const days = Math.floor(difference / DAY);
    const weeks = Math.floor(difference / (7 * DAY));
    const months = Math.floor(difference / (30 * DAY));
    const years = Math.floor(difference / (365 * DAY));

    if (difference < DAY)
        return time.format('%X');
    else if (difference < 2 * DAY)
        return _('Yesterday');
    else if (difference < 7 * DAY)
        return Gettext.ngettext('%d day ago', '%d days ago', days).format(days);
    else if (difference < 14 * DAY)
        return _('Last week');
    else if (difference < 28 * DAY)
        return Gettext.ngettext('%d week ago', '%d weeks ago',  weeks).format(weeks);
    else if (difference < 60 * DAY)
        return _('Last month');
    else if (difference < 360 * DAY)
        return Gettext.ngettext('%d month ago', '%d months ago', months).format(months);
    else if (difference < 730 * DAY)
        return _('Last year');

    return Gettext.ngettext('%d year ago', '%d years ago', years).format(years);
};
(uuay)application.jsk/* exported Application RecordingsDir CacheDir Settings */
/*
* Copyright 2013 Meg Ford
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Meg Ford <megford@gnome.org>
*
*/

const { Adw, Gio, GLib, GObject, Gst, Gtk } = imports.gi;

var RecordingsDir = Gio.file_new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), pkg.name]));
var CacheDir = Gio.file_new_for_path(GLib.build_filenamev([GLib.get_user_cache_dir(), pkg.name]));
var Settings = new Gio.Settings({ schema: pkg.name });

const { Window } = imports.window;

var Application = GObject.registerClass(class Application extends Adw.Application {
    _init() {
        super._init({ application_id: pkg.name, resource_base_path: '/org/gnome/SoundRecorder/' });
        GLib.set_application_name(_('Sound Recorder'));
        GLib.setenv('PULSE_PROP_media.role', 'production', 1);
        GLib.setenv('PULSE_PROP_application.icon_name', pkg.name, 1);

        this.add_main_option('version', 'v'.charCodeAt(0), GLib.OptionFlags.NONE, GLib.OptionArg.NONE,
            'Print version information and exit', null);

        this.connect('handle-local-options', (app, options) => {
            if (options.contains('version')) {
                print(pkg.version);
                /* quit the invoked process after printing the version number
                 * leaving the running instance unaffected
                 */
                return 0;
            }
            return -1;
        });
    }

    _initAppMenu() {
        const profileAction = Settings.create_action('audio-profile');
        this.add_action(profileAction);

        const channelAction = Settings.create_action('audio-channel');
        this.add_action(channelAction);

        let aboutAction = new Gio.SimpleAction({ name: 'about' });
        aboutAction.connect('activate', this._showAbout.bind(this));
        this.add_action(aboutAction);

        let quitAction = new Gio.SimpleAction({ name: 'quit' });
        quitAction.connect('activate', () => {
            this.get_active_window().close();
        });
        this.add_action(quitAction);

        this.set_accels_for_action('app.quit', ['<Primary>q']);
        this.set_accels_for_action('win.open-primary-menu', ['F10']);
        this.set_accels_for_action('win.show-help-overlay', ['<Primary>question']);
        this.set_accels_for_action('recorder.start', ['<Primary>r']);
        this.set_accels_for_action('recorder.pause', ['space']);
        this.set_accels_for_action('recorder.resume', ['space']);
        this.set_accels_for_action('recorder.cancel', ['Delete']);
        this.set_accels_for_action('recorder.stop', ['s']);
        /* TODO: Fix recording.* keybindings */
        this.set_accels_for_action('recording.play', ['space']);
        this.set_accels_for_action('recording.pause', ['space']);
        this.set_accels_for_action('recording.seek-backward', ['b']);
        this.set_accels_for_action('recording.seek-forward', ['n']);
        this.set_accels_for_action('recording.rename', ['F2']);
        this.set_accels_for_action('recording.delete', ['Delete']);
        this.set_accels_for_action('recording.export', ['<Primary>s']);
    }

    vfunc_startup() {
        super.vfunc_startup();
        log('Sound Recorder (%s)'.format(pkg.name));
        log('Version: %s'.format(pkg.version));

        Gst.init(null);

        try {
            CacheDir.make_directory_with_parents(null);
            RecordingsDir.make_directory_with_parents(null);
        } catch (e) {
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))
                error(`Failed to create directory ${e}`);

        }
        this._initAppMenu();
    }

    vfunc_activate() {
        this.window = new Window({ application: this });
        if (pkg.name.endsWith('Devel'))
            this.window.add_css_class('devel');
        this.window.show();
    }

    _showAbout() {
        let aboutDialog = new Gtk.AboutDialog({
            artists: ['Reda Lazri <the.red.shortcut@gmail.com>',
                'Garrett LeSage <garrettl@gmail.com>',
                'Hylke Bons <hylkebons@gmail.com>',
                'Sam Hewitt <hewittsamuel@gmail.com>'],
            authors: ['Meg Ford <megford@gnome.org>',
                'Bilal Elmoussaoui <bil.elmoussaoui@gmail.com>',
                'Felipe Borges <felipeborges@gnome.org>',
                'Kavan Mevada <kavanmevada@gmail.com>'],
            /* Translators: Replace "translator-credits" with your names, one name per line */
            translator_credits: _('translator-credits'),
            program_name: GLib.get_application_name(),
            comments: _('A Sound Recording Application for GNOME'),
            license_type: Gtk.License.GPL_2_0,
            logo_icon_name: pkg.name,
            version: pkg.version,
            website: 'https://wiki.gnome.org/Apps/SoundRecorder',
            copyright: 'Copyright 2013-2019 Meg Ford\nCopyright 2019-2020 Bilal Elmoussaoui & Felipe Borges',
            wrap_license: true,
            modal: true,
            transient_for: this.window,
        });
        aboutDialog.show();
    }
});
(uuay)main.js*// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
//
// Copyright (c) 2013 Giovanni Campagna <scampa.giovanni@gmail.com>
// Copyright (c) 2013 Meg Ford <megford@gnome.org>
//
// Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are met:
//   * Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//   * Neither the name of the GNOME Foundation nor the
//     names of its contributors may be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* exported main */

pkg.initGettext();
pkg.initFormat();
pkg.require({
    'Gdk': '4.0',
    'GdkPixbuf': '2.0',
    'GLib': '2.0',
    'GObject': '2.0',
    'Gtk': '4.0',
    'Gst': '1.0',
    'GstAudio': '1.0',
    'GstPlayer': '1.0',
    'GstPbutils': '1.0',
    'Adw': '1',
});

const { Application } = imports.application;

function main(argv) {
    return new Application().run(argv);
}
(uuay)js/

recorder.js� /* exported EncodingProfiles Recorder */
/*
 * Copyright 2013 Meg Ford
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 *  Author: Meg Ford <megford@gnome.org>
 *
 */
const { GLib, GObject, Gst, GstPbutils } = imports.gi;
const { RecordingsDir, Settings } = imports.application;
const { Recording } = imports.recording;

// All supported encoding profiles.
var EncodingProfiles = [
    { name: 'VORBIS',
        containerCaps: 'application/ogg;audio/ogg;video/ogg',
        audioCaps: 'audio/x-vorbis',
        contentType: 'audio/x-vorbis+ogg',
        extension: 'ogg' },

    { name: 'OPUS',
        containerCaps: 'application/ogg',
        audioCaps: 'audio/x-opus',
        contentType: 'audio/x-opus+ogg',
        extension: 'opus' },

    { name: 'FLAC',
        containerCaps: 'audio/x-flac',
        audioCaps: 'audio/x-flac',
        contentType: 'audio/flac',
        extension: 'flac' },

    { name: 'MP3',
        containerCaps: 'application/x-id3',
        audioCaps: 'audio/mpeg,mpegversion=(int)1,layer=(int)3',
        contentType: 'audio/mpeg',
        extension: 'mp3' },

    { name: 'M4A',
        containerCaps: 'video/quicktime,variant=(string)iso',
        audioCaps: 'audio/mpeg,mpegversion=(int)4',
        contentType: 'video/mp4',
        extension: 'm4a' },
];

var AudioChannels = {
    0: { name: 'stereo', channels: 2 },
    1: { name: 'mono', channels: 1 },
};

var Recorder = new GObject.registerClass({
    Properties: {
        'duration': GObject.ParamSpec.int(
            'duration',
            'Recording Duration', 'Recording duration in nanoseconds',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            0, GLib.MAXINT16, 0),
        'current-peak': GObject.ParamSpec.float(
            'current-peak',
            'Waveform current peak', 'Waveform current peak in float [0, 1]',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            0.0, 1.0, 0.0),
    },
}, class Recorder extends GObject.Object {
    _init() {
        this._peaks = [];
        super._init({});

        let srcElement, audioConvert, caps;
        try {
            this.pipeline = new Gst.Pipeline({ name: 'pipe' });
            srcElement = Gst.ElementFactory.make('pulsesrc', 'srcElement');
            audioConvert = Gst.ElementFactory.make('audioconvert', 'audioConvert');
            caps = Gst.Caps.from_string('audio/x-raw');
            this.level = Gst.ElementFactory.make('level', 'level');
            this.ebin = Gst.ElementFactory.make('encodebin', 'ebin');
            this.filesink = Gst.ElementFactory.make('filesink', 'filesink');
        } catch (error) {
            log(`Not all elements could be created.\n${error}`);
        }

        try {
            this.pipeline.add(srcElement);
            this.pipeline.add(audioConvert);
            this.pipeline.add(this.level);
            this.pipeline.add(this.ebin);
            this.pipeline.add(this.filesink);
        } catch (error) {
            log(`Not all elements could be addded.\n${error}`);
        }

        srcElement.link(audioConvert);
        audioConvert.link_filtered(this.level, caps);
    }

    start() {
        let index = 1;

        do {
            /* Translators: ""Recording %d"" is the default name assigned to a file created
            by the application (for example, "Recording 1"). */
            this.file = RecordingsDir.get_child_for_display_name(_('Recording %d').format(index++));
        } while (this.file.query_exists(null));

        this.recordBus = this.pipeline.get_bus();
        this.recordBus.add_signal_watch();
        this.handlerId = this.recordBus.connect('message', (_, message) => {
            if (message !== null)
                this._onMessageReceived(message);
        });


        this.ebin.set_property('profile', this._getProfile());
        this.filesink.set_property('location', this.file.get_path());
        this.level.link(this.ebin);
        this.ebin.link(this.filesink);

        this.state = Gst.State.PLAYING;

        this.timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => {
            const pos = this.pipeline.query_position(Gst.Format.TIME)[1];
            if (pos > 0)
                this.duration = pos;
            return true;
        });
    }

    pause() {
        this.state = Gst.State.PAUSED;
    }

    resume() {
        if (this.state === Gst.State.PAUSED)
            this.state = Gst.State.PLAYING;
    }

    stop() {
        this.state = Gst.State.NULL;
        this.duration = 0;
        if (this.timeout) {
            GLib.source_remove(this.timeout);
            this.timeout = null;
        }

        if (this.recordBus) {
            this.recordBus.remove_watch();
            this.recordBus.disconnect(this.handlerId);
            this.recordBus = null;
        }


        if (this.file && this.file.query_exists(null) && this._peaks.length > 0) {
            let recording = new Recording(this.file);
            recording.peaks = this._peaks.slice();
            this._peaks.length = 0;
            return recording;
        }

        return null;
    }

    _onMessageReceived(message) {
        switch (message.type) {
        case Gst.MessageType.ELEMENT: {
            if (GstPbutils.is_missing_plugin_message(message)) {
                let detail = GstPbutils.missing_plugin_message_get_installer_detail(message);
                let description = GstPbutils.missing_plugin_message_get_description(message);
                log(`Detail: ${detail}\nDescription: ${description}`);
                break;
            }

            let s = message.get_structure();
            if (s && s.has_name('level')) {
                const peakVal = s.get_value('peak');

                if (peakVal)
                    this.current_peak = peakVal.get_nth(0);
            }
            break;
        }

        case Gst.MessageType.EOS:
            this.stop();
            break;
        case Gst.MessageType.WARNING:
            log(message.parse_warning()[0].toString());
            break;
        case Gst.MessageType.ERROR:
            log(message.parse_error().toString());
            break;
        }
    }

    _getChannel() {
        let channelIndex = Settings.get_enum('audio-channel');
        return AudioChannels[channelIndex].channels;
    }

    _getProfile() {
        let profileIndex = Settings.get_enum('audio-profile');
        const profile = EncodingProfiles[profileIndex];

        let audioCaps = Gst.Caps.from_string(profile.audioCaps);
        audioCaps.set_value('channels', this._getChannel());

        let encodingProfile = GstPbutils.EncodingAudioProfile.new(audioCaps, null, null, 1);
        let containerCaps = Gst.Caps.from_string(profile.containerCaps);
        let containerProfile = GstPbutils.EncodingContainerProfile.new('record', null, containerCaps, null);
        containerProfile.add_profile(encodingProfile);

        return containerProfile;
    }

    get duration() {
        return this._duration;
    }

    // eslint-disable-next-line camelcase
    get current_peak() {
        return this._current_peak;
    }

    // eslint-disable-next-line camelcase
    set current_peak(peak) {
        if (peak > 0)
            peak = 0;

        this._current_peak = Math.pow(10, peak / 20);
        this._peaks.push(this._current_peak);
        this.notify('current-peak');
    }

    set duration(val) {
        this._duration = val;
        this.notify('duration');
    }

    get state() {
        return this._pipeState;
    }

    set state(s) {
        this._pipeState = s;
        const ret = this.pipeline.set_state(this._pipeState);

        if (ret === Gst.StateChangeReturn.FAILURE)
            log('Unable to update the recorder pipeline state');
    }

});
(uuay)org/waveform.js
/* exported WaveForm
/*
 * Copyright 2013 Meg Ford
             2020 Kavan Mevada
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 *  Author: Meg Ford <megford@gnome.org>
 *          Kavan Mevada <kavanmevada@gmail.com>
 *
 */

// based on code from Pitivi

const { Adw, GObject, Gtk } = imports.gi;
const Cairo = imports.cairo;

var WaveType = {
    RECORDER: 0,
    PLAYER: 1,
};

const GUTTER = 4;

var WaveForm = GObject.registerClass({
    Properties: {
        'position': GObject.ParamSpec.float(
            'position',
            'Waveform position', 'Waveform position',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            0.0, 1.0, 0.0),
        'peak': GObject.ParamSpec.float(
            'peak',
            'Waveform current peak', 'Waveform current peak in float [0, 1]',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            0.0, 1.0, 0.0),
    },
    Signals: {
        'position-changed': {  param_types: [GObject.TYPE_FLOAT]  },
        'gesture-pressed': {},
    },
}, class WaveForm extends Gtk.DrawingArea {
    _init(params, type) {
        this._peaks = [];
        this._position = 0;
        this.lastPosition = 0;
        this.waveType = type;
        super._init(params);

        if (this.waveType === WaveType.PLAYER) {
            this._dragGesture = Gtk.GestureDrag.new();
            this._dragGesture.connect('drag-begin', this.dragBegin.bind(this));
            this._dragGesture.connect('drag-update', this.dragUpdate.bind(this));
            this._dragGesture.connect('drag-end', this.dragEnd.bind(this));
            this.add_controller(this._dragGesture);
        }

        this._hcId = Adw.StyleManager.get_default().connect('notify::high-contrast', _ => {
            this.queue_draw();
        });

        this.set_draw_func(this.drawFunc);
    }

    dragBegin(gesture, _) {
        gesture.set_state(Gtk.EventSequenceState.CLAIMED);
        this.emit('gesture-pressed');
    }

    dragUpdate(_, offsetX) {
        this._position = this._clamped(offsetX + this._lastX);
        this.queue_draw();
    }

    dragEnd() {
        this._lastX = this._position;
        this.emit('position-changed', this.position);
    }

    drawFunc(da, ctx) {
        const maxHeight = da.get_allocated_height();
        const vertiCenter = maxHeight / 2;
        const horizCenter = da.get_allocated_width() / 2;

        let pointer = horizCenter + da._position;

        const styleContext = da.get_style_context();
        const leftColor = styleContext.get_color();

        const [_, rightColor] = styleContext.lookup_color('dimmed_color');

        const dividerName = da.waveType === WaveType.PLAYER ? 'accent_color' : 'destructive_color';
        let [ok, dividerColor] = styleContext.lookup_color(dividerName);
        if (!ok)
            dividerColor = styleContext.get_color();

        ctx.setLineCap(Cairo.LineCap.ROUND);
        ctx.setLineWidth(2);

        da._setSourceRGBA(ctx, dividerColor);

        ctx.moveTo(horizCenter, vertiCenter - maxHeight);
        ctx.lineTo(horizCenter, vertiCenter + maxHeight);
        ctx.stroke();

        ctx.setLineWidth(1);

        da._peaks.forEach(peak => {
            if (da.waveType === WaveType.PLAYER && pointer > horizCenter)
                da._setSourceRGBA(ctx, rightColor);
            else
                da._setSourceRGBA(ctx, leftColor);

            ctx.moveTo(pointer, vertiCenter + peak * maxHeight);
            ctx.lineTo(pointer, vertiCenter - peak * maxHeight);
            ctx.stroke();

            if (da.waveType === WaveType.PLAYER)
                pointer += GUTTER;
            else
                pointer -= GUTTER;
        });
    }

    set peak(p) {
        if (this._peaks.length > this.get_allocated_width() / (2 * GUTTER))
            this._peaks.pop();

        this._peaks.unshift(p.toFixed(2));
        this.queue_draw();
    }

    set peaks(p) {
        this._peaks = p;
        this.queue_draw();
    }

    set position(pos) {
        this._position = this._clamped(-pos * this._peaks.length * GUTTER);
        this._lastX = this._position;
        this.queue_draw();
        this.notify('position');
    }

    get position() {
        return -this._position / (this._peaks.length * GUTTER);
    }

    _clamped(position) {
        if (position > 0)
            position = 0;
        else if (position < -this._peaks.length * GUTTER)
            position = -this._peaks.length * GUTTER;

        return position;
    }

    _setSourceRGBA(cr, rgba) {
        cr.setSourceRGBA(rgba.red, rgba.green, rgba.blue, rgba.alpha);
    }

    destroy() {
        Adw.StyleManager.get_default().disconnect(this._hcId);
        this._peaks.length = 0;
        this.queue_draw();
    }
});
(uuay)row.js� /* exported Row */
const { Gdk, Gio, GObject, Gtk } = imports.gi;
const { displayDateTime, formatTime } = imports.utils;
const { WaveForm, WaveType } = imports.waveform;

var RowState = {
    PLAYING: 0,
    PAUSED: 1,
};

var Row = GObject.registerClass({
    Template: 'resource:///org/gnome/SoundRecorder/ui/row.ui',
    InternalChildren: [
        'playbackStack', 'mainStack', 'waveformStack', 'rightStack',
        'name', 'entry', 'date', 'duration', 'revealer', 'playbackControls',
        'saveBtn', 'playBtn', 'pauseBtn',
    ],
    Signals: {
        'play': { param_types: [GObject.TYPE_STRING] },
        'pause': {},
        'seek-backward': {},
        'seek-forward': {},
        'deleted': {},
    },
    Properties: {
        'expanded': GObject.ParamSpec.boolean(
            'expanded',
            'Row active status', 'Row active status',
            GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
            false),
    },
}, class Row extends Gtk.ListBoxRow {
    _init(recording) {
        this._recording = recording;
        this._expanded = false;
        this._editMode = false;

        super._init({});

        this.waveform = new WaveForm({
            margin_top: 18,
            height_request: 60,
        }, WaveType.PLAYER);
        this._waveformStack.add_named(this.waveform, 'wave');

        if (this._recording._peaks.length > 0) {
            this.waveform.peaks = this._recording.peaks;
            this._waveformStack.visible_child_name = 'wave';
        } else {
            this._recording.loadPeaks();
        }

        if (recording.timeCreated > 0)
            this._date.label = displayDateTime(recording.timeCreated);
        else
            this._date.label = displayDateTime(recording.timeModified);

        recording.bind_property('name', this._name, 'label', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.DEFAULT);
        recording.bind_property('name', this._entry, 'text', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.DEFAULT);
        this.bind_property('expanded', this._revealer, 'reveal_child', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.DEFAULT);

        this.actionGroup = new Gio.SimpleActionGroup();

        let exportAction = new Gio.SimpleAction({ name: 'export' });
        exportAction.connect('activate', () => {
            const window = Gio.Application.get_default().get_active_window();
            this.exportDialog = Gtk.FileChooserNative.new(_('Export Recording'), window, Gtk.FileChooserAction.SAVE, _('_Export'), _('_Cancel'));
            this.exportDialog.set_current_name(`${this._recording.name}.${this._recording.extension}`);
            this.exportDialog.connect('response', (_dialog, response) => {
                if (response === Gtk.ResponseType.ACCEPT) {
                    const dest = this.exportDialog.get_file();
                    this._recording.save(dest);
                }
                this.exportDialog.destroy();
                this.exportDialog = null;
            });
            this.exportDialog.show();
        });
        this.actionGroup.add_action(exportAction);

        this.saveRenameAction = new Gio.SimpleAction({ name: 'save', enabled: false });
        this.saveRenameAction.connect('activate', this.onRenameRecording.bind(this));
        this.actionGroup.add_action(this.saveRenameAction);

        this.renameAction = new Gio.SimpleAction({ name: 'rename', enabled: true });
        this.renameAction.connect('activate', action => {
            this.editMode = true;
            action.enabled = false;
        });
        this.renameAction.bind_property('enabled', this.saveRenameAction, 'enabled', GObject.BindingFlags.INVERT_BOOLEAN);
        this.actionGroup.add_action(this.renameAction);

        let pauseAction = new Gio.SimpleAction({ name: 'pause', enabled: false });
        pauseAction.connect('activate', () => {
            this.emit('pause');
            this.state = RowState.PAUSED;
        });
        this.actionGroup.add_action(pauseAction);

        let playAction = new Gio.SimpleAction({ name: 'play', enabled: true });
        playAction.connect('activate', () => {
            this.emit('play', this._recording.uri);
            this.state = RowState.PLAYING;
        });
        this.actionGroup.add_action(playAction);

        let deleteAction = new Gio.SimpleAction({ name: 'delete' });
        deleteAction.connect('activate', () => {
            this.emit('deleted');
        });
        this.actionGroup.add_action(deleteAction);

        let seekBackAction = new Gio.SimpleAction({ name: 'seek-backward' });
        seekBackAction.connect('activate', () => {
            this.emit('seek-backward');
        });
        this.actionGroup.add_action(seekBackAction);

        let seekForwardAction = new Gio.SimpleAction({ name: 'seek-forward' });
        seekForwardAction.connect('activate', () => {
            this.emit('seek-forward');
        });
        this.actionGroup.add_action(seekForwardAction);

        this.insert_action_group('recording', this.actionGroup);

        this.waveform.connect('gesture-pressed', _ => {
            pauseAction.activate(null);
        });

        this.keyController = Gtk.EventControllerKey.new();
        this.keyController.connect('key-pressed', (controller, key, _code, _state) => {
            this._entry.remove_css_class('error');

            if (key === Gdk.KEY_Escape)
                this.editMode = false;
        });
        this._entry.add_controller(this.keyController);

        this._entry.connect('activate', _ => {
            this.saveRenameAction.activate(null);
        });

        this._recording.connect('peaks-updated', _recording => {
            this._waveformStack.visible_child_name = 'wave';
            this.waveform.peaks = _recording.peaks;
        });

        this._recording.connect('peaks-loading', _ => {
            this._waveformStack.visible_child_name = 'loading';
        });

        // Force LTR, we don't want forward/play/backward
        this._playbackControls.direction = Gtk.TextDirection.LTR;

        // Force LTR, we don't want reverse hh:mm::ss
        this._duration.direction = Gtk.TextDirection.LTR;
        this._duration.markup = formatTime(recording.duration);
        recording.connect('notify::duration', () => {
            this._duration.label = formatTime(recording.duration);
        });
    }

    onRenameRecording() {
        try {
            if (this._name.label !== this._entry.text)
                this._recording.name = this._entry.text;

            this.editMode = false;
            this.renameAction.enabled = true;
            this._entry.remove_css_class('error');
        } catch (e) {
            this._entry.add_css_class('error');
        }
    }

    set editMode(state) {
        this._mainStack.visible_child_name = state ? 'edit' : 'display';
        this._editMode = state;

        if (state) {
            if (!this.expanded)
                this.activate();
            this._entry.grab_focus();
            /* TODO: this._saveBtn.grab_default(); */
            this._rightStack.visible_child_name = 'save';
        } else {
            this._rightStack.visible_child_name = 'options';
            this.grab_focus();
        }

        for (const action of this.actionGroup.list_actions()) {
            if (action !== 'save')
                this.actionGroup.lookup(action).enabled = !state;
        }
    }

    get editMode() {
        return this._editMode;
    }

    set expanded(state) {
        this._expanded = state;
        this.notify('expanded');
    }

    get expanded() {
        return this._expanded;
    }

    set state(rowState) {
        this._state = rowState;

        switch (rowState) {
        case RowState.PLAYING:
            this.actionGroup.lookup('play').enabled = false;
            this.actionGroup.lookup('pause').enabled = true;
            this._playbackStack.visible_child_name = 'pause';
            this._pauseBtn.grab_focus();
            break;
        case RowState.PAUSED:
            this.actionGroup.lookup('play').enabled = true;
            this.actionGroup.lookup('pause').enabled = false;
            this._playbackStack.visible_child_name = 'play';
            this._playBtn.grab_focus();
            break;
        }
    }

    get state() {
        return this._state;
    }
});
(uuay)window.js�/* exported Window */
/*
* Copyright 2013 Meg Ford
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Meg Ford <megford@gnome.org>
*
*/

const { Adw, Gio, GLib, GObject, Gst, GstPlayer, Gtk } = imports.gi;

const { Recorder } = imports.recorder;
const { RecordingList } = imports.recordingList;
const { RecordingsListWidget } = imports.recordingListWidget;
const { RecorderWidget } = imports.recorderWidget;

var WindowState = {
    EMPTY: 0,
    LIST: 1,
    RECORDER: 2,
};

var Window = GObject.registerClass({
    Template: 'resource:///org/gnome/SoundRecorder/ui/window.ui',
    InternalChildren: [
        'mainStack', 'emptyPage', 'column', 'headerRevealer', 'toastOverlay',
    ],
}, class Window extends Adw.ApplicationWindow {

    _init(params) {
        super._init(Object.assign({
            icon_name: pkg.name,
        }, params));

        this.recorder = new Recorder();
        this.recorderWidget = new RecorderWidget(this.recorder);
        this._mainStack.add_named(this.recorderWidget, 'recorder');

        const dispatcher = GstPlayer.PlayerGMainContextSignalDispatcher.new(null);
        this.player = GstPlayer.Player.new(null, dispatcher);
        this.player.connect('end-of-stream', _p => this.player.stop());


        this._recordingList = new RecordingList();
        this.itemsSignalId = this._recordingList.connect('items-changed', _ => {
            if (this.state !== WindowState.RECORDER) {
                if (this._recordingList.get_n_items() === 0)
                    this.state = WindowState.EMPTY;
                else
                    this.state = WindowState.LIST;
            }
        });

        this._recordingListWidget = new RecordingsListWidget(this._recordingList, this.player);

        this._recordingListWidget.connect('row-deleted', (_listBox, recording, index) => {
            this._recordingList.remove(index);
            this.sendNotification(_('"%s" deleted').format(recording.name), recording, index);
        });

        const builder = Gtk.Builder.new_from_resource('/org/gnome/SoundRecorder/gtk/help-overlay.ui');
        const dialog = builder.get_object('help_overlay');
        this.set_help_overlay(dialog);

        this.toastUndo = false;
        this.undoSignalID = null;
        this.undoAction = new Gio.SimpleAction({ name: 'undo' });
        this.add_action(this.undoAction);

        let openMenuAction = new Gio.SimpleAction({ name: 'open-primary-menu', state: new GLib.Variant('b', true) });
        openMenuAction.connect('activate', action => {
            const state = action.get_state().get_boolean();
            action.state = new GLib.Variant('b', !state);
        });
        this.add_action(openMenuAction);
        this._column.set_child(this._recordingListWidget);

        this.recorderWidget.connect('started', this.onRecorderStarted.bind(this));
        this.recorderWidget.connect('canceled', this.onRecorderCanceled.bind(this));
        this.recorderWidget.connect('stopped', this.onRecorderStopped.bind(this));
        this.insert_action_group('recorder', this.recorderWidget.actionsGroup);
        this._emptyPage.icon_name = `${pkg.name}-symbolic`;
    }

    vfunc_close_request() {
        this._recordingList.cancellable.cancel();
        if (this.itemsSignalId)
            this._recordingList.disconnect(this.itemsSignalId);

        for (let i = 0; i < this._recordingList.get_n_items(); i++) {
            const recording = this._recordingList.get_item(i);
            if (recording.pipeline)
                recording.pipeline.set_state(Gst.State.NULL);
        }

        this.recorder.stop();
        this.application.quit();
    }

    onRecorderStarted() {
        this.player.stop();

        const activeRow = this._recordingListWidget.activeRow;
        if (activeRow && activeRow.editMode)
            activeRow.editMode = false;

        this.state = WindowState.RECORDER;
    }

    onRecorderCanceled() {
        if (this._recordingList.get_n_items() === 0)
            this.state = WindowState.EMPTY;
        else
            this.state = WindowState.LIST;
    }

    onRecorderStopped(widget, recording) {
        this._recordingList.insert(0, recording);
        this._recordingListWidget.list.get_row_at_index(0).editMode = true;
        this.state = WindowState.LIST;
    }

    sendNotification(message, recording, index) {
        const toast = Adw.Toast.new(message);
        toast.connect('dismissed', () => {
            if (!this.toastUndo)
                recording.delete();

            this.toastUndo = false;
        });

        if (this.undoSignalID !== null)
            this.undoAction.disconnect(this.undoSignalID);

        this.undoSignalID = this.undoAction.connect('activate', () => {
            this._recordingList.insert(index, recording);
            this.toastUndo = true;
        });

        toast.set_action_name('win.undo');
        toast.set_button_label(_('Undo'));
        this._toastOverlay.add_toast(toast);
    }

    set state(state) {
        let visibleChild;
        let isHeaderVisible;

        switch (state) {
        case WindowState.RECORDER:
            visibleChild = 'recorder';
            isHeaderVisible = false;
            break;
        case WindowState.LIST:
            visibleChild = 'recordings';
            isHeaderVisible = true;
            break;
        case WindowState.EMPTY:
            visibleChild = 'empty';
            isHeaderVisible = true;
            break;
        }

        this._mainStack.visible_child_name = visibleChild;
        this._headerRevealer.reveal_child = isHeaderVisible;
        this._state = state;
    }

    get state() {
        return this._state;
    }
});
(uuay)recordingList.js|/* exported RecordingList */
const { Gio, GLib, GObject } = imports.gi;

const { RecordingsDir } = imports.application;
const { Recording } = imports.recording;

var RecordingList = new GObject.registerClass(class RecordingList extends Gio.ListStore {
    _init() {
        super._init({ });

        this.cancellable = new Gio.Cancellable();
        // Monitor Direcotry actions
        this.dirMonitor = RecordingsDir.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, this.cancellable);
        this.dirMonitor.connect('changed', (_dirMonitor, file1, file2, eventType) => {
            const index = this.getIndex(file1);

            switch (eventType) {
            case Gio.FileMonitorEvent.MOVED_OUT:
                if (index >= 0)
                    this.remove(index);
                break;
            case Gio.FileMonitorEvent.MOVED_IN:
                if (index === -1)
                    this.sortedInsert(new Recording(file1));
                break;
            }

        });

        RecordingsDir.enumerate_children_async('standard::name',
            Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
            GLib.PRIORITY_LOW,
            this.cancellable,
            this._enumerateDirectory.bind(this));

        this.copyOldFiles();
    }

    copyOldFiles() {
        // Necessary code to move old recordings into the new location for few releases
        // FIXME: Remove by 3.40/3.42
        const oldDir = Gio.file_new_for_path(GLib.build_filenamev([GLib.get_home_dir(), _('Recordings')]));

        if (!oldDir.query_exists(this.cancellable))
            return;

        const fileEnumerator = oldDir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, this.cancellable);
        let allCopied = true;

        const copyFiles = function (obj, res) {
            try {
                const fileInfos = obj.next_files_finish(res);
                if (fileInfos.length) {
                    fileInfos.forEach(info => {
                        const name = info.get_name();
                        const src = oldDir.get_child(name);
                        /* Translators: ""%s (Old)"" is the new name assigned to a file moved from
                            the old recordings location */
                        const dest = RecordingsDir.get_child(_('%s (Old)').format(name));

                        src.copy_async(dest, Gio.FileCopyFlags.OVERWRITE, GLib.PRIORITY_LOW, this.cancellable, null, (objCopy, resCopy) => {
                            try {
                                objCopy.copy_finish(resCopy);
                                objCopy.trash_async(GLib.PRIORITY_LOW, this.cancellable, null);
                                this.dirMonitor.emit_event(dest, src, Gio.FileMonitorEvent.MOVED_IN);
                            } catch (e) {
                                if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
                                    error(`Failed to copy recording ${name} to the new location`);
                                    log(e);
                                }
                                allCopied = false;
                            }
                        });

                    });
                    fileEnumerator.next_files_async(5, GLib.PRIORITY_LOW, this.cancellable, copyFiles);
                } else {
                    fileEnumerator.close(this.cancellable);
                    if (allCopied) {
                        oldDir.delete_async(GLib.PRIORITY_LOW, this.cancellable, (objDelete, resDelete) => {
                            try {
                                objDelete.delete_finish(resDelete);
                            } catch (e) {
                                log('Failed to remove the old Recordings directory. Ignore if you\'re using flatpak');
                                log(e);
                            }
                        });
                    }
                }
            } catch (e) {
                if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
                    error(`Failed to copy old  recordings ${e}`);

            }
        }.bind(this);
        fileEnumerator.next_files_async(5, GLib.PRIORITY_LOW, this.cancellable, copyFiles);
    }

    _enumerateDirectory(obj, res) {
        this._enumerator = obj.enumerate_children_finish(res);
        if (this._enumerator === null) {
            log('The contents of the Recordings directory were not indexed.');
            return;
        }
        this._enumerator.next_files_async(5, GLib.PRIORITY_LOW, this.cancellable, this._onNextFiles.bind(this));
    }

    _onNextFiles(obj, res) {
        try {
            let fileInfos = obj.next_files_finish(res);
            if (fileInfos.length) {
                fileInfos.forEach(info => {
                    const file = RecordingsDir.get_child(info.get_name());
                    const recording = new Recording(file);
                    this.sortedInsert(recording);
                });
                this._enumerator.next_files_async(5, GLib.PRIORITY_LOW, this.cancellable, this._onNextFiles.bind(this));
            } else {
                this._enumerator.close(this.cancellable);
            }
        } catch (e) {
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
                error(`Failed to load recordings ${e}`);

        }
    }

    getIndex(file) {
        for (let i = 0; i < this.get_n_items(); i++) {
            if (this.get_item(i).uri === file.get_uri())
                return i;
        }
        return -1;
    }

    sortedInsert(recording) {
        let added = false;

        for (let i = 0; i < this.get_n_items(); i++) {
            const curr = this.get_item(i);
            if (curr.timeModified.difference(recording.timeModified) <= 0) {
                this.insert(i, recording);
                added = true;
                break;
            }
        }

        if (!added)
            this.append(recording);
    }
});
(uuay)SoundRecorder/recorderWidget.js�/* exported RecorderState RecorderWidget */
const { Gio, GObject, Gtk } = imports.gi;
const { formatTime } = imports.utils;
const { WaveForm, WaveType } = imports.waveform;

var RecorderState = {
    RECORDING: 0,
    PAUSED: 1,
    STOPPED: 2,
};

var RecorderWidget = GObject.registerClass({
    Template: 'resource:///org/gnome/SoundRecorder/ui/recorder.ui',
    InternalChildren: [
        'recorderBox', 'playbackStack', 'recorderTime',
        'pauseBtn', 'resumeBtn',
    ],
    Signals: {
        'canceled': {},
        'paused': {},
        'resumed': {},
        'started': {},
        'stopped': { param_types: [GObject.TYPE_OBJECT] },
    },
}, class RecorderWidget extends Gtk.Box {
    _init(recorder) {
        super._init({});
        this.recorder = recorder;

        this.waveform = new WaveForm({
            vexpand: true,
            valign: Gtk.Align.FILL,
        }, WaveType.RECORDER);
        this._recorderBox.prepend(this.waveform);

        this.recorder.bind_property('current-peak', this.waveform, 'peak', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.DEFAULT);
        this.recorder.connect('notify::duration', _recorder => {
            this._recorderTime.set_markup(formatTime(_recorder.duration));
        });


        const actions = [
            { name: 'start', callback: this.onStart.bind(this), enabled: true },
            { name: 'pause', callback: this.onPause.bind(this), enabled: false },
            { name: 'stop', callback: this.onStop.bind(this), enabled: false  },
            { name: 'resume', callback: this.onResume.bind(this), enabled: false },
            { name: 'cancel', callback: this.onCancel.bind(this), enabled: false },
        ];

        this.actionsGroup = new Gio.SimpleActionGroup();

        for (let { name, callback, enabled } of actions) {
            const action = new Gio.SimpleAction({ name, enabled });
            action.connect('activate', callback);
            this.actionsGroup.add_action(action);
        }

        const cancelAction = this.actionsGroup.lookup('cancel');
        const startAction = this.actionsGroup.lookup('start');
        startAction.bind_property('enabled', cancelAction, 'enabled', GObject.BindingFlags.INVERT_BOOLEAN);
    }

    onPause() {
        this._playbackStack.visible_child_name = 'recorder-start';
        this.state = RecorderState.PAUSED;

        this.recorder.pause();
        this.emit('paused');
    }

    onResume() {
        this._playbackStack.visible_child_name = 'recorder-pause';
        this.state = RecorderState.RECORDING;

        this.recorder.resume();
        this.emit('resumed');
    }

    onStart() {
        this._playbackStack.visible_child_name = 'recorder-pause';
        this.state = RecorderState.RECORDING;

        this.recorder.start();
        this.emit('started');
    }

    onCancel() {
        this.onPause();
        let dialog = new Gtk.MessageDialog({
            modal: true,
            destroy_with_parent: true,
            buttons: Gtk.ButtonsType.NONE,
            message_type: Gtk.MessageType.QUESTION,
            text: _('Delete recording?'),
            secondary_text: _('This recording will not be saved.'),
        });

        dialog.set_default_response(Gtk.ResponseType.NO);
        dialog.add_button(_('Resume'), Gtk.ResponseType.NO);
        dialog.add_button(_('Delete'), Gtk.ResponseType.YES)
            .add_css_class('destructive-action');

        dialog.set_transient_for(Gio.Application.get_default().get_active_window());
        dialog.connect('response', (_, response) => {
            switch (response) {
            case Gtk.ResponseType.YES: {
                const recording = this.recorder.stop();
                this.state = RecorderState.STOPPED;
                this.waveform.destroy();

                recording.delete();
                this.emit('canceled');
                break;
            }
            case Gtk.ResponseType.NO:
                this.onResume();
                break;
            }

            dialog.close();
        });

        dialog.show();
    }

    onStop() {
        this.state = RecorderState.STOPPED;
        const recording = this.recorder.stop();
        this.waveform.destroy();
        this.emit('stopped', recording);
    }

    set state(recorderState) {
        switch (recorderState) {
        case RecorderState.PAUSED:
            this.actionsGroup.lookup('pause').enabled = false;
            this.actionsGroup.lookup('resume').enabled = true;
            this._resumeBtn.grab_focus();
            this._recorderTime.add_css_class('paused');
            break;
        case RecorderState.RECORDING:
            this.actionsGroup.lookup('start').enabled = false;
            this.actionsGroup.lookup('stop').enabled = true;
            this.actionsGroup.lookup('resume').enabled = false;
            this.actionsGroup.lookup('pause').enabled = true;
            this._pauseBtn.grab_focus();
            this._recorderTime.remove_css_class('paused');
            break;
        case RecorderState.STOPPED:
            this.actionsGroup.lookup('start').enabled = true;
            this.actionsGroup.lookup('stop').enabled = false;
            this.actionsGroup.lookup('pause').enabled = false;
            this.actionsGroup.lookup('resume').enabled = false;
            break;
        }
    }
});
(uuay)

Youez - 2016 - github.com/yon3zu
LinuXploit