aboutsummaryrefslogblamecommitdiffhomepage
path: root/src/components/services/qBittorrent.vue
blob: d47ed0b1eca77a6f45cdc165ab858131f909a69d (plain) (tree)












































                                                                      
                











































































                                                                         
<template>
  <Generic :item="item">
    <template #content>
      <p class="title is-4">{{ item.name }}</p>
      <p class="subtitle is-6">
        <span v-if="error" class="error">An error has occurred.</span>
        <template v-else>
          <span class="down monospace">
            <p class="fas fa-download"></p>
            {{ downRate }}
          </span>
          <span class="up monospace">
            <p class="fas fa-upload"></p>
            {{ upRate }}
          </span>
        </template>
      </p>
    </template>
    <template #indicator>
      <span v-if="!error" class="count"
        >{{ count }}
        <template v-if="count === 1">torrent</template>
        <template v-else>torrents</template>
      </span>
    </template>
  </Generic>
</template>

<script>
import service from "@/mixins/service.js";
import Generic from "./Generic.vue";
const units = ["B", "KB", "MB", "GB"];

// Take the rate in bytes and keep dividing it by 1k until the lowest
// value for which we have a unit is determined. Return the value with
// up to two decimals as a string and unit/s appended.
const displayRate = (rate) => {
  let i = 0;

  while (rate > 1000 && i < units.length) {
    rate /= 1000;
    i++;
  }
  return (
    Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(
      rate || 0,
    ) + ` ${units[i]}/s`
  );
};

export default {
  name: "qBittorrent",
  mixins: [service],
  props: { item: Object },
  components: { Generic },
  data: () => ({ dl: null, ul: null, count: null, error: null }),
  computed: {
    downRate: function () {
      return displayRate(this.dl);
    },
    upRate: function () {
      return displayRate(this.ul);
    },
  },
  created() {
    const rateInterval = parseInt(this.item.rateInterval, 10) || 0;
    const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0;
    if (rateInterval > 0) {
      setInterval(() => this.getRate(), rateInterval);
    }
    if (torrentInterval > 0) {
      setInterval(() => this.fetchCount(), torrentInterval);
    }

    this.getRate();
    this.fetchCount();
  },
  methods: {
    fetchCount: async function () {
      try {
        const body = await this.fetch("/api/v2/torrents/info");
        this.error = false;
        this.count = body.length;
      } catch (e) {
        this.error = true;
        console.error(e);
      }
    },
    getRate: async function () {
      try {
        const body = await this.fetch("/api/v2/transfer/info");
        this.error = false;
        this.dl = body.dl_info_speed;
        this.ul = body.up_info_speed;
      } catch (e) {
        this.error = true;
        console.error(e);
      }
    },
  },
};
</script>

<style scoped lang="scss">
.error {
  color: #e51111 !important;
}

.down {
  margin-right: 1em;
}

.count {
  color: var(--text);
  font-size: 0.8em;
}

.monospace {
  font-weight: 300;
  font-family: monospace;
}
</style>